implement obtainStyledAttributes() functions properly

This commit is contained in:
Julian Winkler
2023-08-17 10:00:50 +02:00
parent aa5d9b16df
commit c60e97f13f
5 changed files with 269 additions and 149 deletions

View File

@@ -33,6 +33,14 @@ extern "C" {
#define android_content_res_AssetManager_STYLE_CHANGING_CONFIGURATIONS 4L
#undef android_content_res_AssetManager_STYLE_DENSITY
#define android_content_res_AssetManager_STYLE_DENSITY 5L
/*
* Class: android_content_res_AssetManager
* Method: list
* Signature: (Ljava/lang/String;)[Ljava/lang/String;
*/
JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_list
(JNIEnv *, jobject, jstring);
/*
* Class: android_content_res_AssetManager
* Method: addAssetPathNative
@@ -65,22 +73,6 @@ JNIEXPORT void JNICALL Java_android_content_res_AssetManager_setLocale
JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getLocales
(JNIEnv *, jobject);
/*
* Class: android_content_res_AssetManager
* Method: setConfiguration
* Signature: (IILjava/lang/String;IIIIIIIIIIIIII)V
*/
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_setConfiguration
(JNIEnv *, jobject, jint, jint, jstring, jint, jint, jint, jint, jint, jint, jint, jint, jint, jint, jint, jint, jint, jint);
/*
* Class: android_content_res_AssetManager
* Method: getResourceName
* Signature: (I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceName
(JNIEnv *, jobject, jint);
/*
* Class: android_content_res_AssetManager
* Method: getResourcePackageName
@@ -89,14 +81,6 @@ JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceName
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourcePackageName
(JNIEnv *, jobject, jint);
/*
* Class: android_content_res_AssetManager
* Method: getResourceTypeName
* Signature: (I)Ljava/lang/String;
*/
JNIEXPORT jstring JNICALL Java_android_content_res_AssetManager_getResourceTypeName
(JNIEnv *, jobject, jint);
/*
* Class: android_content_res_AssetManager
* Method: getResourceEntryName
@@ -193,14 +177,6 @@ JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceValue
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_loadResourceBagValue
(JNIEnv *, jobject, jint, jint, jobject, jboolean);
/*
* Class: android_content_res_AssetManager
* Method: applyStyle
* Signature: (IIII[I[I[I)Z
*/
JNIEXPORT jboolean JNICALL Java_android_content_res_AssetManager_applyStyle
(JNIEnv *, jclass, jint, jint, jint, jint, jintArray, jintArray, jintArray);
/*
* Class: android_content_res_AssetManager
* Method: retrieveAttributes
@@ -281,6 +257,14 @@ JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_getGlobalAssetManag
JNIEXPORT jint JNICALL Java_android_content_res_AssetManager_newTheme
(JNIEnv *, jobject);
/*
* Class: android_content_res_AssetManager
* Method: deleteTheme
* Signature: (I)V
*/
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_deleteTheme
(JNIEnv *, jobject, jint);
/*
* Class: android_content_res_AssetManager
* Method: applyThemeStyle
@@ -329,6 +313,14 @@ JNIEXPORT jobjectArray JNICALL Java_android_content_res_AssetManager_getArrayStr
JNIEXPORT jintArray JNICALL Java_android_content_res_AssetManager_getArrayStringInfo
(JNIEnv *, jobject, jint);
/*
* Class: android_content_res_AssetManager
* Method: destroy
* Signature: ()V
*/
JNIEXPORT void JNICALL Java_android_content_res_AssetManager_destroy
(JNIEnv *, jobject);
#ifdef __cplusplus
}
#endif

View File

@@ -57,6 +57,7 @@ public class Context extends Object {
static Configuration config;
static Resources r;
static ApplicationInfo application_info;
static Resources.Theme theme;
static String apk_path = "/tmp/APK_PATH_SHOULD_HAVE_BEEN_FILLED_IN_BY_CODE_IN_main.c/";
@@ -74,6 +75,7 @@ public class Context extends Object {
config = new Configuration();
r = new Resources(assets, dm, config);
this_application = new Application(); // TODO: the application context is presumably not identical to the Activity context, what is the difference for us though?
theme = r.newTheme();
application_info = new ApplicationInfo();
InputStream inStream = ClassLoader.getSystemClassLoader().getResourceAsStream("AndroidManifest.xml");
@@ -93,7 +95,7 @@ public class Context extends Object {
}
public Resources.Theme getTheme() {
return r.newTheme();
return theme;
}
public ApplicationInfo getApplicationInfo() {
@@ -313,9 +315,20 @@ public class Context extends Object {
System.out.println("------------------");
}
// these may not look like typical stubs, but they definitely are stubs
public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) { return new TypedArray(r, new int[1000], new int[1000], 0); }
public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) { return new TypedArray(r, new int[1000], new int[1000], 0); }
public final TypedArray obtainStyledAttributes(int resid, int[] attrs) { return new TypedArray(r, new int[1000], new int[1000], 0); }
public final TypedArray obtainStyledAttributes(int[] attrs) { return new TypedArray(r, new int[1000], new int[1000], 0); }
public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs) {
return getTheme().obtainStyledAttributes(set, attrs, 0, 0);
}
public final TypedArray obtainStyledAttributes(AttributeSet set, int[] attrs, int defStyleAttr, int defStyleRes) {
return getTheme().obtainStyledAttributes(set, attrs, defStyleAttr, defStyleRes);
}
public final TypedArray obtainStyledAttributes(int resid, int[] attrs) {
return getTheme().obtainStyledAttributes(resid, attrs);
}
public final TypedArray obtainStyledAttributes(int[] attrs) {
return getTheme().obtainStyledAttributes(attrs);
}
public void setTheme(int resId) {
theme.applyStyle(resId, true);
}
}

View File

@@ -19,16 +19,22 @@ package android.content.res;
import android.content.Context;
import android.os.ParcelFileDescriptor;
import android.os.Trace;
import android.util.AttributeSet;
import android.util.Log;
import android.util.TypedValue;
import com.reandroid.arsc.array.ResValueMapArray;
import com.reandroid.arsc.chunk.PackageBlock;
import com.reandroid.arsc.chunk.TableBlock;
import com.reandroid.arsc.chunk.xml.ResXmlDocument;
import com.reandroid.arsc.chunk.xml.ResXmlPullParser;
import com.reandroid.arsc.group.EntryGroup;
import com.reandroid.arsc.item.StringItem;
import com.reandroid.arsc.value.Entry;
import com.reandroid.arsc.value.EntryHeaderMap;
import com.reandroid.arsc.value.ResValue;
import com.reandroid.arsc.value.ResValueMap;
import com.reandroid.arsc.value.ValueItem;
import com.reandroid.arsc.value.ValueType;
import java.io.FileDescriptor;
import java.io.FileNotFoundException;
@@ -42,6 +48,7 @@ import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import org.xmlpull.v1.XmlPullParser;
@@ -244,6 +251,7 @@ public final class AssetManager {
ResValue resValue = entryGroup.pickOne().getResValue();
if (resValue == null)
return false; // not found
outValue.resourceId = ident;
outValue.type = resValue.getType();
outValue.data = resValue.getData();
if (outValue.type == TypedValue.TYPE_STRING)
@@ -257,36 +265,63 @@ public final class AssetManager {
* @param id Resource id of the string array
*/
/*package*/ final CharSequence[] getResourceTextArray(final int id) {
int[] rawInfoArray = getArrayStringInfo(id);
int rawInfoArrayLen = rawInfoArray.length;
final int infoArrayLen = rawInfoArrayLen / 2;
int block;
int index;
CharSequence[] retArray = new CharSequence[infoArrayLen];
for (int i = 0, j = 0; i < rawInfoArrayLen; i = i + 2, j++) {
block = rawInfoArray[i];
index = rawInfoArray[i + 1];
retArray[j] = index >= 0 ? mStringBlocks[block].get(index) : null;
ResValueMap children[] = tableBlock.search(id).pickOne().getResValueMapArray().getChildes();
CharSequence values[] = new CharSequence[children.length];
for (int i = 0; i < children.length; i++) {
StringItem stringItem = children[i].getDataAsPoolString();
values[i] = (stringItem != null) ? stringItem.get() : "";
}
return retArray;
return values;
}
public Map<Integer,ValueItem> loadStyle(int resId) {
Map<Integer,ValueItem> map = new HashMap<>();
EntryGroup entryGroup = tableBlock.search(resId);
while (entryGroup != null) {
Entry entry = entryGroup.pickOne();
ResValueMapArray array = entry.getResValueMapArray();
for (int i = 0; i < array.childesCount(); i++) {
map.putIfAbsent(array.get(i).getName(), array.get(i));
}
int parent_id = ((EntryHeaderMap)entry.getHeader()).getParentId();
entryGroup = tableBlock.search(parent_id);
}
return map;
}
/*package*/ final boolean getThemeValue(int theme, int ident,
TypedValue outValue, boolean resolveRefs) {
int block = loadThemeAttributeValue(theme, ident, outValue, resolveRefs);
if (block >= 0) {
if (outValue.type != TypedValue.TYPE_STRING) {
return true;
}
StringBlock[] blocks = mStringBlocks;
if (blocks == null) {
ensureStringBlocks();
blocks = mStringBlocks;
}
outValue.string = blocks[block].get(outValue.data);
return true;
}
Map<Integer,ValueItem> style = loadStyle(theme);
EntryGroup entryGroup = tableBlock.search(ident);
if (entryGroup == null)
return false;
Entry entry = entryGroup.pickOne();
ValueItem valueItem = null;
while ("attr".equals(entry.getTypeName())) {
valueItem = null;
if (style.containsKey(ident))
valueItem = style.get(ident);
if (valueItem != null && valueItem.getValueType() == ValueType.ATTRIBUTE) {
ident = valueItem.getData();
entryGroup = tableBlock.search(ident);
if (entryGroup == null) {
break;
}
entry = entryGroup.pickOne();
} else {
break;
}
}
if (valueItem == null)
return false;
outValue.resourceId = 0;
outValue.type = valueItem.getType();
outValue.data = valueItem.getData();
outValue.assetCookie = -1;
if (outValue.type == TypedValue.TYPE_STRING) {
outValue.string = valueItem.getDataAsPoolString().get();
}
return true;
}
/*package*/ final void ensureStringBlocks() {
@@ -318,7 +353,7 @@ public final class AssetManager {
// System.out.println("Get pooled: block=" + block
// + ", id=#" + Integer.toHexString(id)
// + ", blocks=" + mStringBlocks);
return mStringBlocks[block - 1].get(id);
return tableBlock.getStringPool().get(id).get();
}
/**
@@ -584,7 +619,7 @@ public final class AssetManager {
/*package*/ final void releaseTheme(int theme) {
synchronized (this) {
deleteTheme(theme);
// deleteTheme(theme);
decRefsLocked(theme);
}
}
@@ -748,11 +783,11 @@ public final class AssetManager {
* applications.
* {@hide}
*/
public native final void setConfiguration(int mcc, int mnc, String locale,
public /*native*/ final void setConfiguration(int mcc, int mnc, String locale,
int orientation, int touchscreen, int density, int keyboard,
int keyboardHidden, int navigation, int screenWidth, int screenHeight,
int smallestScreenWidthDp, int screenWidthDp, int screenHeightDp,
int screenLayout, int uiMode, int majorVersion);
int screenLayout, int uiMode, int majorVersion) {}
/**
* Retrieve the resource identifier for the given resource name.
@@ -769,9 +804,13 @@ public final class AssetManager {
return -1;
}
/*package*/ native final String getResourceName(int resid);
/*package*/ /*native*/ final String getResourceName(int resid) {
return tableBlock.search(resid).pickOne().getName();
}
/*package*/ native final String getResourcePackageName(int resid);
/*package*/ native final String getResourceTypeName(int resid);
/*package*/ /*native*/ final String getResourceTypeName(int resid) {
return tableBlock.search(resid).pickOne().getTypeName();
}
/*package*/ native final String getResourceEntryName(int resid);
private native final int openAsset(String fileName, int accessMode);
@@ -808,9 +847,82 @@ public final class AssetManager {
/*package*/ static final int STYLE_RESOURCE_ID = 3;
/*package*/ static final int STYLE_CHANGING_CONFIGURATIONS = 4;
/*package*/ static final int STYLE_DENSITY = 5;
/*package*/ native static final boolean applyStyle(int theme,
int defStyleAttr, int defStyleRes, int xmlParser,
int[] inAttrs, int[] outValues, int[] outIndices);
/*package*/ /*native*/ final boolean applyStyle(Map<Integer,ValueItem> theme,
int defStyleAttr, int defStyleRes, AttributeSet set,
int[] inAttrs, int[] outValues, int[] outIndices) {
if (defStyleRes == 0 && theme.containsKey(defStyleAttr))
defStyleRes = theme.get(defStyleAttr).getData();
Map<Integer,ValueItem> defStyle = loadStyle(defStyleRes);
ResXmlPullParser parser = (ResXmlPullParser)set;
for (int i = 0; i < inAttrs.length; i++) {
int d = i*AssetManager.STYLE_NUM_ENTRIES;
// reset values in case of cached array
outValues[d+AssetManager.STYLE_RESOURCE_ID] = 0;
outValues[d+AssetManager.STYLE_TYPE] = 0;
outValues[d+AssetManager.STYLE_DATA] = 0;
outValues[d+AssetManager.STYLE_ASSET_COOKIE] = 0;
int resId = inAttrs[i];
EntryGroup entryGroup = tableBlock.search(resId);
if (entryGroup == null)
continue;
Entry entry = entryGroup.pickOne();
ValueItem valueItem = null;
while ("attr".equals(entry.getTypeName())) {
valueItem = null;
if (set != null) {
for (int j=0; j<set.getAttributeCount(); j++) {
if (set.getAttributeNameResource(j) == resId) {
valueItem = parser.getResXmlAttributeAt(j);
break;
}
}
}
if (valueItem == null) {
valueItem = defStyle.get(resId);
if (valueItem != null && valueItem.getValueType() == ValueType.ATTRIBUTE && valueItem.getData() == resId)
valueItem = null;
}
if (valueItem == null)
valueItem = theme.get(resId);
if (valueItem != null && valueItem.getValueType() == ValueType.ATTRIBUTE) {
resId = valueItem.getData();
entryGroup = tableBlock.search(resId);
if (entryGroup == null) {
break;
}
entry = entryGroup.pickOne();
} else {
break;
}
}
if (valueItem == null)
continue;
if (valueItem.getValueType() == ValueType.REFERENCE) {
resId = valueItem.getData();
if (resId == 0)
continue;
entry = tableBlock.search(resId).pickOne();
outValues[d + AssetManager.STYLE_RESOURCE_ID] = resId;
ResValue resValue = entry.getResValue();
if (resValue != null) {
outValues[d + AssetManager.STYLE_TYPE] = entry.getResValue().getType();
outValues[d + AssetManager.STYLE_DATA] = entry.getResValue().getData();
} else {
outValues[d + AssetManager.STYLE_TYPE] = -1;
}
outValues[d + AssetManager.STYLE_ASSET_COOKIE] = -1;
} else {
outValues[d+AssetManager.STYLE_RESOURCE_ID] = 0;
outValues[d+AssetManager.STYLE_TYPE] = valueItem.getType();
outValues[d+AssetManager.STYLE_DATA] = valueItem.getData();
outValues[d+AssetManager.STYLE_ASSET_COOKIE] = -1;
}
}
return true;
}
/*package*/ native final boolean retrieveAttributes(
int xmlParser, int[] inAttrs, int[] outValues, int[] outIndices);
/*package*/ native final int getArraySize(int resource);

View File

@@ -33,11 +33,16 @@ import android.util.LongSparseArray;
import android.util.Slog;
import android.util.TypedValue;
import com.android.internal.util.XmlUtils;
import com.reandroid.arsc.chunk.xml.ResXmlPullParser;
import com.reandroid.arsc.value.ValueItem;
// import android.view.DisplayAdjustments;
import java.io.IOException;
import java.io.InputStream;
import java.lang.ref.WeakReference;
import java.util.HashMap;
import java.util.Locale;
import java.util.Map;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
@@ -1187,6 +1192,7 @@ public class Resources {
* retrieve XML attributes with style and theme information applied.
*/
public final class Theme {
private Map<Integer,ValueItem> themeMap = new HashMap<>();
/**
* Place new attribute values into the theme. The style resource
* specified by <var>resid</var> will be retrieved from this Theme's
@@ -1205,7 +1211,7 @@ public class Resources {
* if not already defined in the theme.
*/
public void applyStyle(int resid, boolean force) {
AssetManager.applyThemeStyle(mTheme, resid, force);
themeMap = mAssets.loadStyle(resid);
}
/**
@@ -1218,7 +1224,7 @@ public class Resources {
* @param other The existing Theme to copy from.
*/
public void setTo(Theme other) {
AssetManager.copyTheme(mTheme, other.mTheme);
themeMap = other.themeMap;
}
/**
@@ -1244,8 +1250,7 @@ public class Resources {
int len = attrs.length;
TypedArray array = getCachedStyledAttributes(len);
array.mRsrcs = attrs;
/* AssetManager.applyStyle(mTheme, 0, 0, 0, attrs,
array.mData, array.mIndices);*/
mAssets.applyStyle(themeMap, 0, 0, null, attrs, array.mData, array.mIndices);
return array;
}
@@ -1274,8 +1279,7 @@ public class Resources {
int len = attrs.length;
TypedArray array = getCachedStyledAttributes(len);
array.mRsrcs = attrs;
/*
AssetManager.applyStyle(mTheme, 0, resid, 0, attrs,
mAssets.applyStyle(themeMap, 0, resid, null, attrs,
array.mData, array.mIndices);
if (false) {
int[] data = array.mData;
@@ -1302,7 +1306,7 @@ public class Resources {
+ "=" + value;
}
System.out.println(s);
}*/
}
return array;
}
@@ -1358,20 +1362,16 @@ public class Resources {
int[] attrs, int defStyleAttr, int defStyleRes) {
int len = attrs.length;
TypedArray array = getCachedStyledAttributes(len);
/*
// XXX note that for now we only work with compiled XML files.
// To support generic XML files we will need to manually parse
// out the attributes from the XML file (applying type information
// contained in the resources and such).
XmlBlock.Parser parser = (XmlBlock.Parser)set;
AssetManager.applyStyle(
mTheme, defStyleAttr, defStyleRes,
parser != null ? parser.mParseState : 0, attrs,
array.mData, array.mIndices);
ResXmlPullParser parser = (ResXmlPullParser)set;
mAssets.applyStyle(themeMap, defStyleAttr, defStyleRes,
set, attrs, array.mData, array.mIndices);
array.mRsrcs = attrs;
array.mXml = parser;
if (false) {
int[] data = array.mData;
@@ -1400,7 +1400,6 @@ public class Resources {
}
System.out.println(s);
}
*/
return array;
}
@@ -1491,7 +1490,7 @@ public class Resources {
array.mData, array.mIndices);
array.mRsrcs = attrs;
array.mXml = parser;
// array.mXml = parser;
return array;
}

View File

@@ -23,6 +23,9 @@ import android.util.DisplayMetrics;
import android.util.Log;
import android.util.TypedValue;
import com.android.internal.util.XmlUtils;
import com.reandroid.arsc.chunk.xml.ResXmlPullParser;
import com.reandroid.arsc.item.ResXmlString;
import java.util.Arrays;
/**
@@ -36,7 +39,7 @@ import java.util.Arrays;
*/
public class TypedArray {
private final Resources mResources;
/*package*/ XmlBlock.Parser mXml;
/*package*/ ResXmlPullParser mXml;
/*package*/ int[] mRsrcs;
/*package*/ int[] mData;
/*package*/ int[] mIndices;
@@ -153,9 +156,7 @@ public class TypedArray {
if (type == TypedValue.TYPE_STRING) {
final int cookie = data[index + AssetManager.STYLE_ASSET_COOKIE];
if (cookie < 0) {
return mXml.getPooledString(
data[index + AssetManager.STYLE_DATA])
.toString();
return mXml.getResXmlDocument().getStringPool().get(data[index + AssetManager.STYLE_DATA]).get();
}
}
return null;
@@ -689,10 +690,13 @@ public class TypedArray {
final int cookie = data[index + AssetManager.STYLE_ASSET_COOKIE];
if (cookie < 0) {
if (mXml != null) {
return mXml.getPooledString(
data[index + AssetManager.STYLE_DATA]);
ResXmlString xmlString = mXml.getResXmlDocument().getStringPool().get(data[index + AssetManager.STYLE_DATA]);
if (xmlString != null)
return xmlString.get();
}
if (data[index + AssetManager.STYLE_RESOURCE_ID] != 0) {
return mResources.mAssets.getResourceText(data[index + AssetManager.STYLE_RESOURCE_ID]);
}
return null;
}
// System.out.println("Getting pooled from: " + v);
return mResources.mAssets.getPooledString(