Merge "Add support for aapt:attr attributes"
diff --git a/core/java/android/content/pm/PackageParser.java b/core/java/android/content/pm/PackageParser.java
index 2664dc6..56f1e0c 100644
--- a/core/java/android/content/pm/PackageParser.java
+++ b/core/java/android/content/pm/PackageParser.java
@@ -2745,15 +2745,15 @@
String cls = clsSeq.toString();
char c = cls.charAt(0);
if (c == '.') {
- return (pkg + cls).intern();
+ return pkg + cls;
}
if (cls.indexOf('.') < 0) {
StringBuilder b = new StringBuilder(pkg);
b.append('.');
b.append(cls);
- return b.toString().intern();
+ return b.toString();
}
- return cls.intern();
+ return cls;
}
private static String buildCompoundName(String pkg,
@@ -2773,7 +2773,7 @@
+ pkg + ": " + nameError;
return null;
}
- return (pkg + proc).intern();
+ return pkg + proc;
}
String nameError = validateName(proc, true, false);
if (nameError != null && !"system".equals(proc)) {
@@ -2781,7 +2781,7 @@
+ pkg + ": " + nameError;
return null;
}
- return proc.intern();
+ return proc;
}
private static String buildProcessName(String pkg, String defProc,
@@ -5083,7 +5083,7 @@
if (v != null) {
if (v.type == TypedValue.TYPE_STRING) {
CharSequence cs = v.coerceToString();
- data.putString(name, cs != null ? cs.toString().intern() : null);
+ data.putString(name, cs != null ? cs.toString() : null);
} else if (v.type == TypedValue.TYPE_INT_BOOLEAN) {
data.putBoolean(name, v.data != 0);
} else if (v.type >= TypedValue.TYPE_FIRST_INT
@@ -5866,7 +5866,7 @@
// We use the boot classloader for all classes that we load.
final ClassLoader boot = Object.class.getClassLoader();
- packageName = dest.readString();
+ packageName = dest.readString().intern();
manifestPackageName = dest.readString();
splitNames = dest.readStringArray();
volumeUuid = dest.readString();
@@ -5879,6 +5879,9 @@
splitPrivateFlags = dest.createIntArray();
baseHardwareAccelerated = (dest.readInt() == 1);
applicationInfo = dest.readParcelable(boot);
+ if (applicationInfo.permission != null) {
+ applicationInfo.permission = applicationInfo.permission.intern();
+ }
// We don't serialize the "owner" package and the application info object for each of
// these components, in order to save space and to avoid circular dependencies while
@@ -5899,7 +5902,10 @@
fixupOwner(instrumentation);
dest.readStringList(requestedPermissions);
+ internStringArrayList(requestedPermissions);
protectedBroadcasts = dest.createStringArrayList();
+ internStringArrayList(protectedBroadcasts);
+
parentPackage = dest.readParcelable(boot);
childPackages = new ArrayList<>();
@@ -5909,16 +5915,23 @@
}
staticSharedLibName = dest.readString();
+ if (staticSharedLibName != null) {
+ staticSharedLibName = staticSharedLibName.intern();
+ }
staticSharedLibVersion = dest.readInt();
libraryNames = dest.createStringArrayList();
+ internStringArrayList(libraryNames);
usesLibraries = dest.createStringArrayList();
+ internStringArrayList(usesLibraries);
usesOptionalLibraries = dest.createStringArrayList();
+ internStringArrayList(usesOptionalLibraries);
usesLibraryFiles = dest.readStringArray();
final int libCount = dest.readInt();
if (libCount > 0) {
usesStaticLibraries = new ArrayList<>(libCount);
dest.readStringList(usesStaticLibraries);
+ internStringArrayList(usesStaticLibraries);
usesStaticLibrariesVersions = new int[libCount];
dest.readIntArray(usesStaticLibrariesVersions);
usesStaticLibrariesCertDigests = new String[libCount];
@@ -5937,7 +5950,13 @@
mAppMetaData = dest.readBundle();
mVersionCode = dest.readInt();
mVersionName = dest.readString();
+ if (mVersionName != null) {
+ mVersionName = mVersionName.intern();
+ }
mSharedUserId = dest.readString();
+ if (mSharedUserId != null) {
+ mSharedUserId = mSharedUserId.intern();
+ }
mSharedUserLabel = dest.readInt();
mSignatures = (Signature[]) dest.readParcelableArray(boot, Signature.class);
@@ -5988,6 +6007,15 @@
restrictUpdateHash = dest.createByteArray();
}
+ private static void internStringArrayList(List<String> list) {
+ if (list != null) {
+ final int N = list.size();
+ for (int i = 0; i < N; ++i) {
+ list.set(i, list.get(i).intern());
+ }
+ }
+ }
+
/**
* Sets the package owner and the the {@code applicationInfo} for every component
* owner by this package.
@@ -6375,6 +6403,10 @@
super(in);
final ClassLoader boot = Object.class.getClassLoader();
info = in.readParcelable(boot);
+ if (info.group != null) {
+ info.group = info.group.intern();
+ }
+
tree = (in.readInt() == 1);
group = in.readParcelable(boot);
}
@@ -6651,6 +6683,10 @@
for (ActivityIntentInfo aii : intents) {
aii.activity = this;
}
+
+ if (info.permission != null) {
+ info.permission = info.permission.intern();
+ }
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Activity>() {
@@ -6735,6 +6771,10 @@
for (ServiceIntentInfo aii : intents) {
aii.service = this;
}
+
+ if (info.permission != null) {
+ info.permission = info.permission.intern();
+ }
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Service>() {
@@ -6816,6 +6856,18 @@
for (ProviderIntentInfo aii : intents) {
aii.provider = this;
}
+
+ if (info.readPermission != null) {
+ info.readPermission = info.readPermission.intern();
+ }
+
+ if (info.writePermission != null) {
+ info.writePermission = info.writePermission.intern();
+ }
+
+ if (info.authority != null) {
+ info.authority = info.authority.intern();
+ }
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Provider>() {
@@ -6888,6 +6940,14 @@
private Instrumentation(Parcel in) {
super(in);
info = in.readParcelable(Object.class.getClassLoader());
+
+ if (info.targetPackage != null) {
+ info.targetPackage = info.targetPackage.intern();
+ }
+
+ if (info.targetProcess != null) {
+ info.targetProcess = info.targetProcess.intern();
+ }
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator<Instrumentation>() {
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 5591029..384f49f 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -140,6 +140,36 @@
assertAllFieldsExist(deserialized);
}
+ @Test
+ public void test_stringInterning() throws Exception {
+ PackageParser.Package pkg = new PackageParser.Package("foo");
+ setKnownFields(pkg);
+
+ Parcel p = Parcel.obtain();
+ pkg.writeToParcel(p, 0 /* flags */);
+
+ p.setDataPosition(0);
+ PackageParser.Package deserialized = new PackageParser.Package(p);
+
+ p.setDataPosition(0);
+ PackageParser.Package deserialized2 = new PackageParser.Package(p);
+
+ assertSame(deserialized.packageName, deserialized2.packageName);
+ assertSame(deserialized.applicationInfo.permission,
+ deserialized2.applicationInfo.permission);
+ assertSame(deserialized.requestedPermissions.get(0),
+ deserialized2.requestedPermissions.get(0));
+ assertSame(deserialized.protectedBroadcasts.get(0),
+ deserialized2.protectedBroadcasts.get(0));
+ assertSame(deserialized.usesLibraries.get(0),
+ deserialized2.usesLibraries.get(0));
+ assertSame(deserialized.usesOptionalLibraries.get(0),
+ deserialized2.usesOptionalLibraries.get(0));
+ assertSame(deserialized.mVersionName, deserialized2.mVersionName);
+ assertSame(deserialized.mSharedUserId, deserialized2.mSharedUserId);
+ }
+
+
/**
* A trivial subclass of package parser that only caches the package name, and throws away
* all other information.
@@ -407,11 +437,11 @@
pkg.mTrustedOverlay = true;
pkg.use32bitAbi = true;
pkg.packageName = "foo";
- pkg.splitNames = new String[] { "foo" };
- pkg.volumeUuid = "foo";
- pkg.codePath = "foo";
- pkg.baseCodePath = "foo";
- pkg.splitCodePaths = new String[] { "foo" };
+ pkg.splitNames = new String[] { "foo2" };
+ pkg.volumeUuid = "foo3";
+ pkg.codePath = "foo4";
+ pkg.baseCodePath = "foo5";
+ pkg.splitCodePaths = new String[] { "foo6" };
pkg.splitRevisionCodes = new int[] { 100 };
pkg.splitFlags = new int[] { 100 };
pkg.splitPrivateFlags = new int[] { 100 };
@@ -428,48 +458,55 @@
pkg.providers.add(new PackageParser.Provider(dummy, new ProviderInfo()));
pkg.services.add(new PackageParser.Service(dummy, new ServiceInfo()));
pkg.instrumentation.add(new PackageParser.Instrumentation(dummy, new InstrumentationInfo()));
- pkg.requestedPermissions.add("foo");
+ pkg.requestedPermissions.add("foo7");
pkg.protectedBroadcasts = new ArrayList<>();
- pkg.protectedBroadcasts.add("foo");
+ pkg.protectedBroadcasts.add("foo8");
- pkg.parentPackage = new PackageParser.Package("foo");
+ pkg.parentPackage = new PackageParser.Package("foo9");
pkg.childPackages = new ArrayList<>();
pkg.childPackages.add(new PackageParser.Package("bar"));
+ pkg.staticSharedLibName = "foo23";
+ pkg.staticSharedLibVersion = 100;
+ pkg.usesStaticLibraries = new ArrayList<>();
+ pkg.usesStaticLibraries.add("foo23");
+ pkg.usesStaticLibrariesCertDigests = new String[] { "digest" };
+ pkg.usesStaticLibrariesVersions = new int[] { 100 };
+
pkg.libraryNames = new ArrayList<>();
- pkg.libraryNames.add("foo");
+ pkg.libraryNames.add("foo10");
pkg.usesLibraries = new ArrayList<>();
- pkg.usesLibraries.add("foo");
+ pkg.usesLibraries.add("foo11");
pkg.usesOptionalLibraries = new ArrayList<>();
- pkg.usesOptionalLibraries.add("foo");
+ pkg.usesOptionalLibraries.add("foo12");
- pkg.usesLibraryFiles = new String[] { "foo "};
+ pkg.usesLibraryFiles = new String[] { "foo13"};
pkg.mOriginalPackages = new ArrayList<>();
- pkg.mOriginalPackages.add("foo");
+ pkg.mOriginalPackages.add("foo14");
- pkg.mRealPackage = "foo";
+ pkg.mRealPackage = "foo15";
pkg.mAdoptPermissions = new ArrayList<>();
- pkg.mAdoptPermissions.add("foo");
+ pkg.mAdoptPermissions.add("foo16");
pkg.mAppMetaData = new Bundle();
- pkg.mVersionName = "foo";
- pkg.mSharedUserId = "foo";
+ pkg.mVersionName = "foo17";
+ pkg.mSharedUserId = "foo18";
pkg.mSignatures = new Signature[] { new Signature(new byte[16]) };
pkg.mCertificates = new Certificate[][] { new Certificate[] { null }};
pkg.mExtras = new Bundle();
- pkg.mRestrictedAccountType = "foo";
- pkg.mRequiredAccountType = "foo";
- pkg.mOverlayTarget = "foo";
+ pkg.mRestrictedAccountType = "foo19";
+ pkg.mRequiredAccountType = "foo20";
+ pkg.mOverlayTarget = "foo21";
pkg.mSigningKeys = new ArraySet<>();
pkg.mUpgradeKeySets = new ArraySet<>();
pkg.mKeySetMapping = new ArrayMap<>();
- pkg.cpuAbiOverride = "foo";
+ pkg.cpuAbiOverride = "foo22";
pkg.restrictUpdateHash = new byte[16];
pkg.preferredActivityFilters = new ArrayList<>();
@@ -504,7 +541,7 @@
// Sanity check for list fields: Assume they're non-null and contain precisely
// one element.
List<?> list = (List<?>) f.get(pkg);
- assertNotNull(list);
+ assertNotNull("List was null: " + f, list);
assertEquals(1, list.size());
} else if (fieldType.getComponentType() != null) {
// Sanity check for array fields: Assume they're non-null and contain precisely
@@ -514,15 +551,16 @@
} else if (fieldType == String.class) {
// String fields: Check that they're set to "foo".
String value = (String) f.get(pkg);
- assertEquals("foo", value);
+
+ assertTrue("Bad value for field: " + f, value != null && value.startsWith("foo"));
} else if (fieldType == int.class) {
// int fields: Check that they're set to 100.
int value = (int) f.get(pkg);
- assertEquals(100, value);
+ assertEquals("Bad value for field: " + f, 100, value);
} else {
// All other fields: Check that they're set.
Object o = f.get(pkg);
- assertNotNull("Field was null: " + f.getName(), o);
+ assertNotNull("Field was null: " + f, o);
}
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
index 2c9fe29..3d5d5c6 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java
@@ -65,6 +65,7 @@
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteDatabase.CursorFactory;
import android.graphics.Bitmap;
+import android.graphics.Color;
import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.net.Uri;
@@ -381,6 +382,18 @@
return true;
}
+ String stringValue = value.getValue();
+ if (!stringValue.isEmpty()) {
+ if (stringValue.charAt(0) == '#') {
+ outValue.type = TypedValue.TYPE_INT_COLOR_ARGB8;
+ outValue.data = Color.parseColor(value.getValue());
+ }
+ else if (stringValue.charAt(0) == '@') {
+ outValue.type = TypedValue.TYPE_REFERENCE;
+ }
+
+ }
+
int a;
// if this is a framework value.
if (value.isFramework()) {
@@ -399,7 +412,7 @@
}
// If the value is not a valid reference, fallback to pass the value as a string.
- outValue.string = value.getValue();
+ outValue.string = stringValue;
return true;
}
diff --git a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
index 913519c..9e60f0f 100644
--- a/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
+++ b/tools/layoutlib/bridge/tests/src/com/android/layoutlib/bridge/intensive/RenderTests.java
@@ -36,6 +36,7 @@
import android.content.res.Configuration;
import android.content.res.Resources;
import android.util.DisplayMetrics;
+import android.util.TypedValue;
import java.lang.reflect.Field;
import java.util.concurrent.TimeUnit;
@@ -43,6 +44,7 @@
import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertNotEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
@@ -334,6 +336,7 @@
AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);
+ //noinspection deprecation
Resources resources = new Resources(assetManager, metrics, configuration);
resources.mLayoutlibCallback = params.getLayoutlibCallback();
resources.mContext =
@@ -370,6 +373,7 @@
AssetManager assetManager = AssetManager.getSystem();
DisplayMetrics metrics = new DisplayMetrics();
Configuration configuration = RenderAction.getConfiguration(params);
+ //noinspection deprecation
Resources resources = new Resources(assetManager, metrics, configuration);
resources.mLayoutlibCallback = params.getLayoutlibCallback();
resources.mContext =
@@ -390,4 +394,34 @@
// TODO: styles seem to be broken in TextView
renderAndVerify("fonts_test.xml", "font_test.png");
}
+
+ @Test
+ public void testColorTypedValue() throws Exception {
+ // Setup
+ // Create the layout pull parser for our resources (empty.xml can not be part of the test
+ // app as it won't compile).
+ LayoutPullParser parser = new LayoutPullParser("/empty.xml");
+ // Create LayoutLibCallback.
+ LayoutLibTestCallback layoutLibCallback =
+ new LayoutLibTestCallback(RenderTestBase.getLogger(), mDefaultClassLoader);
+ layoutLibCallback.initResources();
+ SessionParams params = getSessionParams(parser, ConfigGenerator.NEXUS_4,
+ layoutLibCallback, "AppTheme", true, RenderingMode.NORMAL, 22);
+ AssetManager assetManager = AssetManager.getSystem();
+ DisplayMetrics metrics = new DisplayMetrics();
+ Configuration configuration = RenderAction.getConfiguration(params);
+ //noinspection deprecation
+ Resources resources = new Resources(assetManager, metrics, configuration);
+ resources.mLayoutlibCallback = params.getLayoutlibCallback();
+ resources.mContext =
+ new BridgeContext(params.getProjectKey(), metrics, params.getResources(),
+ params.getAssets(), params.getLayoutlibCallback(), configuration,
+ params.getTargetSdkVersion(), params.isRtlSupported());
+
+ TypedValue outValue = new TypedValue();
+ resources.mContext.resolveThemeAttribute(android.R.attr.colorPrimary, outValue, true);
+ assertEquals(TypedValue.TYPE_INT_COLOR_ARGB8, outValue.type);
+ assertNotEquals(0, outValue.data);
+ assertTrue(sRenderMessages.isEmpty());
+ }
}