summaryrefslogtreecommitdiff
path: root/tools
diff options
context:
space:
mode:
Diffstat (limited to 'tools')
-rw-r--r--tools/aapt/Command.cpp436
-rw-r--r--tools/layoutlib/.idea/encodings.xml7
-rw-r--r--tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java5
-rw-r--r--tools/layoutlib/bridge/src/android/view/BridgeInflater.java43
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java77
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/android/BridgeContext.java6
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java22
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java20
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java4
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java5
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java10
-rw-r--r--tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java3
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java24
-rw-r--r--tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java8
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java58
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java10
-rw-r--r--tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java30
18 files changed, 553 insertions, 220 deletions
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index d12ab3b725c8..5e2e82601b47 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -383,6 +383,16 @@ static void printUsesPermission(const String8& name, bool optional=false, int ma
}
}
+static void printUsesPermissionSdk23(const String8& name, int maxSdkVersion=-1) {
+ printf("uses-permission-sdk-23: ");
+
+ printf("name='%s'", ResTable::normalizeForOutput(name.string()).string());
+ if (maxSdkVersion != -1) {
+ printf(" maxSdkVersion='%d'", maxSdkVersion);
+ }
+ printf("\n");
+}
+
static void printUsesImpliedPermission(const String8& name, const String8& reason) {
printf("uses-implied-permission: name='%s' reason='%s'\n",
ResTable::normalizeForOutput(name.string()).string(),
@@ -463,12 +473,20 @@ static void printComponentPresence(const char* componentName) {
* a pre-requisite or some other reason.
*/
struct ImpliedFeature {
+ ImpliedFeature() : impliedBySdk23(false) {}
+ ImpliedFeature(const String8& n, bool sdk23) : name(n), impliedBySdk23(sdk23) {}
+
/**
* Name of the implied feature.
*/
String8 name;
/**
+ * Was this implied by a permission from SDK 23 (<uses-permission-sdk-23 />)?
+ */
+ bool impliedBySdk23;
+
+ /**
* List of human-readable reasons for why this feature was implied.
*/
SortedVector<String8> reasons;
@@ -497,18 +515,24 @@ struct FeatureGroup {
};
static void addImpliedFeature(KeyedVector<String8, ImpliedFeature>* impliedFeatures,
- const char* name, const char* reason) {
+ const char* name, const char* reason, bool sdk23) {
String8 name8(name);
ssize_t idx = impliedFeatures->indexOfKey(name8);
if (idx < 0) {
- idx = impliedFeatures->add(name8, ImpliedFeature());
- impliedFeatures->editValueAt(idx).name = name8;
+ idx = impliedFeatures->add(name8, ImpliedFeature(name8, sdk23));
}
- impliedFeatures->editValueAt(idx).reasons.add(String8(reason));
+
+ ImpliedFeature* feature = &impliedFeatures->editValueAt(idx);
+
+ // A non-sdk 23 implied feature takes precedence.
+ if (feature->impliedBySdk23 && !sdk23) {
+ feature->impliedBySdk23 = false;
+ }
+ feature->reasons.add(String8(reason));
}
-static void printFeatureGroup(const FeatureGroup& grp,
- const KeyedVector<String8, ImpliedFeature>* impliedFeatures = NULL) {
+static void printFeatureGroupImpl(const FeatureGroup& grp,
+ const KeyedVector<String8, ImpliedFeature>* impliedFeatures) {
printf("feature-group: label='%s'\n", grp.label.string());
if (grp.openGLESVersion > 0) {
@@ -536,9 +560,11 @@ static void printFeatureGroup(const FeatureGroup& grp,
String8 printableFeatureName(ResTable::normalizeForOutput(
impliedFeature.name.string()));
- printf(" uses-feature: name='%s'\n", printableFeatureName.string());
- printf(" uses-implied-feature: name='%s' reason='",
- printableFeatureName.string());
+ const char* sdk23Suffix = impliedFeature.impliedBySdk23 ? "-sdk-23" : "";
+
+ printf(" uses-feature%s: name='%s'\n", sdk23Suffix, printableFeatureName.string());
+ printf(" uses-implied-feature%s: name='%s' reason='", sdk23Suffix,
+ printableFeatureName.string());
const size_t numReasons = impliedFeature.reasons.size();
for (size_t j = 0; j < numReasons; j++) {
printf("%s", impliedFeature.reasons[j].string());
@@ -552,6 +578,15 @@ static void printFeatureGroup(const FeatureGroup& grp,
}
}
+static void printFeatureGroup(const FeatureGroup& grp) {
+ printFeatureGroupImpl(grp, NULL);
+}
+
+static void printDefaultFeatureGroup(const FeatureGroup& grp,
+ const KeyedVector<String8, ImpliedFeature>& impliedFeatures) {
+ printFeatureGroupImpl(grp, &impliedFeatures);
+}
+
static void addParentFeatures(FeatureGroup* grp, const String8& name) {
if (name == "android.hardware.camera.autofocus" ||
name == "android.hardware.camera.flash") {
@@ -572,6 +607,72 @@ static void addParentFeatures(FeatureGroup* grp, const String8& name) {
}
}
+static void addImpliedFeaturesForPermission(const int targetSdk, const String8& name,
+ KeyedVector<String8, ImpliedFeature>* impliedFeatures,
+ bool impliedBySdk23Permission) {
+ if (name == "android.permission.CAMERA") {
+ addImpliedFeature(impliedFeatures, "android.hardware.camera",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
+ addImpliedFeature(impliedFeatures, "android.hardware.location.gps",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ addImpliedFeature(impliedFeatures, "android.hardware.location",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
+ addImpliedFeature(impliedFeatures, "android.hardware.location",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
+ addImpliedFeature(impliedFeatures, "android.hardware.location.network",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ addImpliedFeature(impliedFeatures, "android.hardware.location",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
+ name == "android.permission.INSTALL_LOCATION_PROVIDER") {
+ addImpliedFeature(impliedFeatures, "android.hardware.location",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.BLUETOOTH" ||
+ name == "android.permission.BLUETOOTH_ADMIN") {
+ if (targetSdk > 4) {
+ addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ addImpliedFeature(impliedFeatures, "android.hardware.bluetooth",
+ "targetSdkVersion > 4", impliedBySdk23Permission);
+ }
+ } else if (name == "android.permission.RECORD_AUDIO") {
+ addImpliedFeature(impliedFeatures, "android.hardware.microphone",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
+ name == "android.permission.CHANGE_WIFI_STATE" ||
+ name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
+ addImpliedFeature(impliedFeatures, "android.hardware.wifi",
+ String8::format("requested %s permission", name.string())
+ .string(), impliedBySdk23Permission);
+ } else if (name == "android.permission.CALL_PHONE" ||
+ name == "android.permission.CALL_PRIVILEGED" ||
+ name == "android.permission.MODIFY_PHONE_STATE" ||
+ name == "android.permission.PROCESS_OUTGOING_CALLS" ||
+ name == "android.permission.READ_SMS" ||
+ name == "android.permission.RECEIVE_SMS" ||
+ name == "android.permission.RECEIVE_MMS" ||
+ name == "android.permission.RECEIVE_WAP_PUSH" ||
+ name == "android.permission.SEND_SMS" ||
+ name == "android.permission.WRITE_APN_SETTINGS" ||
+ name == "android.permission.WRITE_SMS") {
+ addImpliedFeature(impliedFeatures, "android.hardware.telephony",
+ String8("requested a telephony permission").string(),
+ impliedBySdk23Permission);
+ }
+}
+
/*
* Handle the "dump" command, to extract select data from an archive.
*/
@@ -712,7 +813,8 @@ int doDump(Bundle* bundle)
size_t len;
ResXMLTree::event_code_t code;
int depth = 0;
- while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
+ code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
continue;
@@ -735,25 +837,53 @@ int doDump(Bundle* bundle)
}
String8 pkg = AaptXml::getAttribute(tree, NULL, "package", NULL);
printf("package: %s\n", ResTable::normalizeForOutput(pkg.string()).string());
- } else if (depth == 2 && tag == "permission") {
- String8 error;
- String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
- goto bail;
- }
- printf("permission: %s\n",
- ResTable::normalizeForOutput(name.string()).string());
- } else if (depth == 2 && tag == "uses-permission") {
- String8 error;
- String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
- if (error != "") {
- fprintf(stderr, "ERROR: %s\n", error.string());
- goto bail;
+ } else if (depth == 2) {
+ if (tag == "permission") {
+ String8 error;
+ String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR: %s\n", error.string());
+ goto bail;
+ }
+
+ if (name == "") {
+ fprintf(stderr, "ERROR: missing 'android:name' for permission\n");
+ goto bail;
+ }
+ printf("permission: %s\n",
+ ResTable::normalizeForOutput(name.string()).string());
+ } else if (tag == "uses-permission") {
+ String8 error;
+ String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR: %s\n", error.string());
+ goto bail;
+ }
+
+ if (name == "") {
+ fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
+ goto bail;
+ }
+ printUsesPermission(name,
+ AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
+ AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+ } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
+ String8 error;
+ String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
+ fprintf(stderr, "ERROR: %s\n", error.string());
+ goto bail;
+ }
+
+ if (name == "") {
+ fprintf(stderr, "ERROR: missing 'android:name' for "
+ "uses-permission-sdk-23\n");
+ goto bail;
+ }
+ printUsesPermissionSdk23(
+ name,
+ AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
}
- printUsesPermission(name,
- AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
- AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
}
}
} else if (strcmp("badging", option) == 0) {
@@ -893,7 +1023,8 @@ int doDump(Bundle* bundle)
Vector<FeatureGroup> featureGroups;
KeyedVector<String8, ImpliedFeature> impliedFeatures;
- while ((code=tree.next()) != ResXMLTree::END_DOCUMENT && code != ResXMLTree::BAD_DOCUMENT) {
+ while ((code=tree.next()) != ResXMLTree::END_DOCUMENT &&
+ code != ResXMLTree::BAD_DOCUMENT) {
if (code == ResXMLTree::END_TAG) {
depth--;
if (depth < 2) {
@@ -924,8 +1055,10 @@ int doDump(Bundle* bundle)
ResTable::normalizeForOutput(aName.string()).string());
}
printf(" label='%s' icon='%s'\n",
- ResTable::normalizeForOutput(activityLabel.string()).string(),
- ResTable::normalizeForOutput(activityIcon.string()).string());
+ ResTable::normalizeForOutput(activityLabel.string())
+ .string(),
+ ResTable::normalizeForOutput(activityIcon.string())
+ .string());
}
if (isLeanbackLauncherActivity) {
printf("leanback-launchable-activity:");
@@ -934,9 +1067,12 @@ int doDump(Bundle* bundle)
ResTable::normalizeForOutput(aName.string()).string());
}
printf(" label='%s' icon='%s' banner='%s'\n",
- ResTable::normalizeForOutput(activityLabel.string()).string(),
- ResTable::normalizeForOutput(activityIcon.string()).string(),
- ResTable::normalizeForOutput(activityBanner.string()).string());
+ ResTable::normalizeForOutput(activityLabel.string())
+ .string(),
+ ResTable::normalizeForOutput(activityIcon.string())
+ .string(),
+ ResTable::normalizeForOutput(activityBanner.string())
+ .string());
}
}
if (!hasIntentFilter) {
@@ -964,18 +1100,21 @@ int doDump(Bundle* bundle)
hasLauncher |= catLauncher;
hasCameraActivity |= actCamera;
hasCameraSecureActivity |= actCameraSecure;
- hasOtherActivities |= !actMainActivity && !actCamera && !actCameraSecure;
+ hasOtherActivities |=
+ !actMainActivity && !actCamera && !actCameraSecure;
} else if (withinReceiver) {
hasWidgetReceivers |= actWidgetReceivers;
hasDeviceAdminReceiver |= (actDeviceAdminEnabled &&
hasBindDeviceAdminPermission);
- hasOtherReceivers |= (!actWidgetReceivers && !actDeviceAdminEnabled);
+ hasOtherReceivers |=
+ (!actWidgetReceivers && !actDeviceAdminEnabled);
} else if (withinService) {
hasImeService |= actImeService;
hasWallpaperService |= actWallpaperService;
hasAccessibilityService |= (actAccessibilityService &&
hasBindAccessibilityServicePermission);
- hasPrintService |= (actPrintService && hasBindPrintServicePermission);
+ hasPrintService |=
+ (actPrintService && hasBindPrintServicePermission);
hasNotificationListenerService |= actNotificationListenerService &&
hasBindNotificationListenerServicePermission;
hasDreamService |= actDreamService && hasBindDreamServicePermission;
@@ -984,7 +1123,8 @@ int doDump(Bundle* bundle)
!actHostApduService && !actOffHostApduService &&
!actNotificationListenerService);
} else if (withinProvider) {
- hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
+ hasDocumentsProvider |=
+ actDocumentsProvider && hasRequiredSafAttributes;
}
}
withinIntentFilter = false;
@@ -1125,7 +1265,8 @@ int doDump(Bundle* bundle)
goto bail;
}
- String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR, &error);
+ String8 banner = AaptXml::getResolvedAttribute(res, tree, BANNER_ATTR,
+ &error);
if (error != "") {
fprintf(stderr, "ERROR getting 'android:banner' attribute: %s\n",
error.string());
@@ -1135,7 +1276,8 @@ int doDump(Bundle* bundle)
ResTable::normalizeForOutput(label.string()).string());
printf("icon='%s'", ResTable::normalizeForOutput(icon.string()).string());
if (banner != "") {
- printf(" banner='%s'", ResTable::normalizeForOutput(banner.string()).string());
+ printf(" banner='%s'",
+ ResTable::normalizeForOutput(banner.string()).string());
}
printf("\n");
if (testOnly != 0) {
@@ -1178,13 +1320,15 @@ int doDump(Bundle* bundle)
}
}
} else if (tag == "uses-sdk") {
- int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR, &error);
+ int32_t code = AaptXml::getIntegerAttribute(tree, MIN_SDK_VERSION_ATTR,
+ &error);
if (error != "") {
error = "";
String8 name = AaptXml::getResolvedAttribute(res, tree,
MIN_SDK_VERSION_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:minSdkVersion' attribute: %s\n",
+ fprintf(stderr,
+ "ERROR getting 'android:minSdkVersion' attribute: %s\n",
error.string());
goto bail;
}
@@ -1205,7 +1349,8 @@ int doDump(Bundle* bundle)
String8 name = AaptXml::getResolvedAttribute(res, tree,
TARGET_SDK_VERSION_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
+ fprintf(stderr,
+ "ERROR getting 'android:targetSdkVersion' attribute: %s\n",
error.string());
goto bail;
}
@@ -1297,90 +1442,58 @@ int doDump(Bundle* bundle)
}
} else if (tag == "uses-permission") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
- if (name != "" && error == "") {
- if (name == "android.permission.CAMERA") {
- addImpliedFeature(&impliedFeatures, "android.hardware.camera",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.ACCESS_FINE_LOCATION") {
- addImpliedFeature(&impliedFeatures, "android.hardware.location.gps",
- String8::format("requested %s permission", name.string())
- .string());
- addImpliedFeature(&impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.ACCESS_MOCK_LOCATION") {
- addImpliedFeature(&impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.ACCESS_COARSE_LOCATION") {
- addImpliedFeature(&impliedFeatures, "android.hardware.location.network",
- String8::format("requested %s permission", name.string())
- .string());
- addImpliedFeature(&impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" ||
- name == "android.permission.INSTALL_LOCATION_PROVIDER") {
- addImpliedFeature(&impliedFeatures, "android.hardware.location",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.BLUETOOTH" ||
- name == "android.permission.BLUETOOTH_ADMIN") {
- if (targetSdk > 4) {
- addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
- String8::format("requested %s permission", name.string())
- .string());
- addImpliedFeature(&impliedFeatures, "android.hardware.bluetooth",
- "targetSdkVersion > 4");
- }
- } else if (name == "android.permission.RECORD_AUDIO") {
- addImpliedFeature(&impliedFeatures, "android.hardware.microphone",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.ACCESS_WIFI_STATE" ||
- name == "android.permission.CHANGE_WIFI_STATE" ||
- name == "android.permission.CHANGE_WIFI_MULTICAST_STATE") {
- addImpliedFeature(&impliedFeatures, "android.hardware.wifi",
- String8::format("requested %s permission", name.string())
- .string());
- } else if (name == "android.permission.CALL_PHONE" ||
- name == "android.permission.CALL_PRIVILEGED" ||
- name == "android.permission.MODIFY_PHONE_STATE" ||
- name == "android.permission.PROCESS_OUTGOING_CALLS" ||
- name == "android.permission.READ_SMS" ||
- name == "android.permission.RECEIVE_SMS" ||
- name == "android.permission.RECEIVE_MMS" ||
- name == "android.permission.RECEIVE_WAP_PUSH" ||
- name == "android.permission.SEND_SMS" ||
- name == "android.permission.WRITE_APN_SETTINGS" ||
- name == "android.permission.WRITE_SMS") {
- addImpliedFeature(&impliedFeatures, "android.hardware.telephony",
- String8("requested a telephony permission").string());
- } else if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
- hasWriteExternalStoragePermission = true;
- } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
- hasReadExternalStoragePermission = true;
- } else if (name == "android.permission.READ_PHONE_STATE") {
- hasReadPhoneStatePermission = true;
- } else if (name == "android.permission.READ_CONTACTS") {
- hasReadContactsPermission = true;
- } else if (name == "android.permission.WRITE_CONTACTS") {
- hasWriteContactsPermission = true;
- } else if (name == "android.permission.READ_CALL_LOG") {
- hasReadCallLogPermission = true;
- } else if (name == "android.permission.WRITE_CALL_LOG") {
- hasWriteCallLogPermission = true;
- }
+ if (error != "") {
+ fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
+ error.string());
+ goto bail;
+ }
- printUsesPermission(name,
- AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
- AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
- } else {
+ if (name == "") {
+ fprintf(stderr, "ERROR: missing 'android:name' for uses-permission\n");
+ goto bail;
+ }
+
+ addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, false);
+
+ if (name == "android.permission.WRITE_EXTERNAL_STORAGE") {
+ hasWriteExternalStoragePermission = true;
+ } else if (name == "android.permission.READ_EXTERNAL_STORAGE") {
+ hasReadExternalStoragePermission = true;
+ } else if (name == "android.permission.READ_PHONE_STATE") {
+ hasReadPhoneStatePermission = true;
+ } else if (name == "android.permission.READ_CONTACTS") {
+ hasReadContactsPermission = true;
+ } else if (name == "android.permission.WRITE_CONTACTS") {
+ hasWriteContactsPermission = true;
+ } else if (name == "android.permission.READ_CALL_LOG") {
+ hasReadCallLogPermission = true;
+ } else if (name == "android.permission.WRITE_CALL_LOG") {
+ hasWriteCallLogPermission = true;
+ }
+
+ printUsesPermission(name,
+ AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
+ AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+
+ } else if (tag == "uses-permission-sdk-23" || tag == "uses-permission-sdk-m") {
+ String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
+ if (error != "") {
fprintf(stderr, "ERROR getting 'android:name' attribute: %s\n",
error.string());
goto bail;
}
+
+ if (name == "") {
+ fprintf(stderr, "ERROR: missing 'android:name' for "
+ "uses-permission-sdk-23\n");
+ goto bail;
+ }
+
+ addImpliedFeaturesForPermission(targetSdk, name, &impliedFeatures, true);
+
+ printUsesPermissionSdk23(
+ name, AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
+
} else if (tag == "uses-package") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
@@ -1422,7 +1535,8 @@ int doDump(Bundle* bundle)
} else if (tag == "package-verifier") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (name != "" && error == "") {
- String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR, &error);
+ String8 publicKey = AaptXml::getAttribute(tree, PUBLIC_KEY_ATTR,
+ &error);
if (publicKey != "" && error == "") {
printf("package-verifier: name='%s' publicKey='%s'\n",
ResTable::normalizeForOutput(name.string()).string(),
@@ -1485,12 +1599,18 @@ int doDump(Bundle* bundle)
if (error == "") {
if (orien == 0 || orien == 6 || orien == 8) {
// Requests landscape, sensorLandscape, or reverseLandscape.
- addImpliedFeature(&impliedFeatures, "android.hardware.screen.landscape",
- "one or more activities have specified a landscape orientation");
+ addImpliedFeature(&impliedFeatures,
+ "android.hardware.screen.landscape",
+ "one or more activities have specified a "
+ "landscape orientation",
+ false);
} else if (orien == 1 || orien == 7 || orien == 9) {
// Requests portrait, sensorPortrait, or reversePortrait.
- addImpliedFeature(&impliedFeatures, "android.hardware.screen.portrait",
- "one or more activities have specified a portrait orientation");
+ addImpliedFeature(&impliedFeatures,
+ "android.hardware.screen.portrait",
+ "one or more activities have specified a "
+ "portrait orientation",
+ false);
}
}
} else if (tag == "uses-library") {
@@ -1524,8 +1644,10 @@ int doDump(Bundle* bundle)
hasBindDeviceAdminPermission = true;
}
} else {
- fprintf(stderr, "ERROR getting 'android:permission' attribute for"
- " receiver '%s': %s\n", receiverName.string(), error.string());
+ fprintf(stderr,
+ "ERROR getting 'android:permission' attribute for"
+ " receiver '%s': %s\n",
+ receiverName.string(), error.string());
}
} else if (tag == "service") {
withinService = true;
@@ -1542,20 +1664,24 @@ int doDump(Bundle* bundle)
if (error == "") {
if (permission == "android.permission.BIND_INPUT_METHOD") {
hasBindInputMethodPermission = true;
- } else if (permission == "android.permission.BIND_ACCESSIBILITY_SERVICE") {
+ } else if (permission ==
+ "android.permission.BIND_ACCESSIBILITY_SERVICE") {
hasBindAccessibilityServicePermission = true;
- } else if (permission == "android.permission.BIND_PRINT_SERVICE") {
+ } else if (permission ==
+ "android.permission.BIND_PRINT_SERVICE") {
hasBindPrintServicePermission = true;
- } else if (permission == "android.permission.BIND_NFC_SERVICE") {
+ } else if (permission ==
+ "android.permission.BIND_NFC_SERVICE") {
hasBindNfcServicePermission = true;
- } else if (permission == "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
+ } else if (permission ==
+ "android.permission.BIND_NOTIFICATION_LISTENER_SERVICE") {
hasBindNotificationListenerServicePermission = true;
} else if (permission == "android.permission.BIND_DREAM_SERVICE") {
hasBindDreamServicePermission = true;
}
} else {
- fprintf(stderr, "ERROR getting 'android:permission' attribute for"
- " service '%s': %s\n", serviceName.string(), error.string());
+ fprintf(stderr, "ERROR getting 'android:permission' attribute for "
+ "service '%s': %s\n", serviceName.string(), error.string());
}
} else if (tag == "provider") {
withinProvider = true;
@@ -1563,7 +1689,8 @@ int doDump(Bundle* bundle)
bool exported = AaptXml::getResolvedIntegerAttribute(res, tree,
EXPORTED_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:exported' attribute for provider:"
+ fprintf(stderr,
+ "ERROR getting 'android:exported' attribute for provider:"
" %s\n", error.string());
goto bail;
}
@@ -1571,16 +1698,17 @@ int doDump(Bundle* bundle)
bool grantUriPermissions = AaptXml::getResolvedIntegerAttribute(
res, tree, GRANT_URI_PERMISSIONS_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:grantUriPermissions' attribute for provider:"
- " %s\n", error.string());
+ fprintf(stderr,
+ "ERROR getting 'android:grantUriPermissions' attribute for "
+ "provider: %s\n", error.string());
goto bail;
}
String8 permission = AaptXml::getResolvedAttribute(res, tree,
PERMISSION_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:permission' attribute for provider:"
- " %s\n", error.string());
+ fprintf(stderr, "ERROR getting 'android:permission' attribute for "
+ "provider: %s\n", error.string());
goto bail;
}
@@ -1661,8 +1789,9 @@ int doDump(Bundle* bundle)
} else if (withinService && tag == "meta-data") {
String8 name = AaptXml::getAttribute(tree, NAME_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:name' attribute for"
- " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+ fprintf(stderr, "ERROR getting 'android:name' attribute for "
+ "meta-data tag in service '%s': %s\n", serviceName.string(),
+ error.string());
goto bail;
}
@@ -1676,8 +1805,9 @@ int doDump(Bundle* bundle)
String8 xmlPath = AaptXml::getResolvedAttribute(res, tree,
RESOURCE_ATTR, &error);
if (error != "") {
- fprintf(stderr, "ERROR getting 'android:resource' attribute for"
- " meta-data tag in service '%s': %s\n", serviceName.string(), error.string());
+ fprintf(stderr, "ERROR getting 'android:resource' attribute for "
+ "meta-data tag in service '%s': %s\n",
+ serviceName.string(), error.string());
goto bail;
}
@@ -1731,15 +1861,19 @@ int doDump(Bundle* bundle)
actImeService = true;
} else if (action == "android.service.wallpaper.WallpaperService") {
actWallpaperService = true;
- } else if (action == "android.accessibilityservice.AccessibilityService") {
+ } else if (action ==
+ "android.accessibilityservice.AccessibilityService") {
actAccessibilityService = true;
- } else if (action == "android.printservice.PrintService") {
+ } else if (action =="android.printservice.PrintService") {
actPrintService = true;
- } else if (action == "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
+ } else if (action ==
+ "android.nfc.cardemulation.action.HOST_APDU_SERVICE") {
actHostApduService = true;
- } else if (action == "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
+ } else if (action ==
+ "android.nfc.cardemulation.action.OFF_HOST_APDU_SERVICE") {
actOffHostApduService = true;
- } else if (action == "android.service.notification.NotificationListenerService") {
+ } else if (action ==
+ "android.service.notification.NotificationListenerService") {
actNotificationListenerService = true;
} else if (action == "android.service.dreams.DreamService") {
actDreamService = true;
@@ -1814,12 +1948,12 @@ int doDump(Bundle* bundle)
}
addImpliedFeature(&impliedFeatures, "android.hardware.touchscreen",
- "default feature for all apps");
+ "default feature for all apps", false);
const size_t numFeatureGroups = featureGroups.size();
if (numFeatureGroups == 0) {
// If no <feature-group> tags were defined, apply auto-implied features.
- printFeatureGroup(commonFeatures, &impliedFeatures);
+ printDefaultFeatureGroup(commonFeatures, impliedFeatures);
} else {
// <feature-group> tags are defined, so we ignore implied features and
diff --git a/tools/layoutlib/.idea/encodings.xml b/tools/layoutlib/.idea/encodings.xml
index e206d70d8595..f758959656c7 100644
--- a/tools/layoutlib/.idea/encodings.xml
+++ b/tools/layoutlib/.idea/encodings.xml
@@ -1,5 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
- <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false" />
-</project>
-
+ <component name="Encoding" useUTFGuessing="true" native2AsciiForPropertiesFiles="false">
+ <file url="PROJECT" charset="UTF-8" />
+ </component>
+</project> \ No newline at end of file
diff --git a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
index 5a595970e195..44ce7311a95c 100644
--- a/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/Hyphenator_Delegate.java
@@ -20,9 +20,10 @@ import com.android.layoutlib.bridge.impl.DelegateManager;
import com.android.tools.layoutlib.annotations.LayoutlibDelegate;
import java.io.File;
+import java.nio.ByteBuffer;
/**
- * Delegate that overrides implementation for certain methods in {@link android.text.StaticLayout}
+ * Delegate that overrides implementation for certain methods in {@link android.text.Hyphenator}
* <p/>
* Through the layoutlib_create tool, selected methods of StaticLayout have been replaced
* by calls to methods of the same name in this delegate class.
@@ -38,7 +39,7 @@ public class Hyphenator_Delegate {
return null;
}
- /*package*/ static long loadHyphenator(String patternData) {
+ /*package*/ static long loadHyphenator(ByteBuffer buf, int offset) {
return sDelegateManager.addNewDelegate(new Hyphenator_Delegate());
}
}
diff --git a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
index 1b0ba5156acd..65c0a07bbac4 100644
--- a/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
+++ b/tools/layoutlib/bridge/src/android/text/StaticLayout_Delegate.java
@@ -13,6 +13,7 @@ import android.icu.util.ULocale;
import android.text.Primitive.PrimitiveType;
import android.text.StaticLayout.LineBreaks;
+import java.nio.ByteBuffer;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
@@ -52,8 +53,8 @@ public class StaticLayout_Delegate {
}
@LayoutlibDelegate
- /*package*/ static long nLoadHyphenator(String patternData) {
- return Hyphenator_Delegate.loadHyphenator(patternData);
+ /*package*/ static long nLoadHyphenator(ByteBuffer buf, int offset) {
+ return Hyphenator_Delegate.loadHyphenator(buf, offset);
}
@LayoutlibDelegate
diff --git a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
index 5db1bde5f3f0..723e8278bcc0 100644
--- a/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
+++ b/tools/layoutlib/bridge/src/android/view/BridgeInflater.java
@@ -23,6 +23,7 @@ import com.android.ide.common.rendering.api.ResourceReference;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.BridgeConstants;
+import com.android.layoutlib.bridge.MockView;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.android.BridgeXmlBlockParser;
import com.android.layoutlib.bridge.android.support.DrawerLayoutUtil;
@@ -126,6 +127,9 @@ public final class BridgeInflater extends LayoutInflater {
if (view == null) {
view = loadCustomView(name, attrs);
}
+ } catch (InflateException e) {
+ // Don't catch the InflateException below as that results in hiding the real cause.
+ throw e;
} catch (Exception e) {
// Wrap the real exception in a ClassNotFoundException, so that the calling method
// can deal with it.
@@ -154,23 +158,30 @@ public final class BridgeInflater extends LayoutInflater {
}
ta.recycle();
}
- final Object lastContext = mConstructorArgs[0];
- mConstructorArgs[0] = context;
- // try to load the class from using the custom view loader
- try {
- view = loadCustomView(name, attrs);
- } catch (Exception e2) {
- // Wrap the real exception in an InflateException so that the calling
- // method can deal with it.
- InflateException exception = new InflateException();
- if (!e2.getClass().equals(ClassNotFoundException.class)) {
- exception.initCause(e2);
- } else {
- exception.initCause(e);
+ if (!(e.getCause() instanceof ClassNotFoundException)) {
+ // There is some unknown inflation exception in inflating a View that was found.
+ view = new MockView(context, attrs);
+ ((MockView) view).setText(name);
+ Bridge.getLog().error(LayoutLog.TAG_BROKEN, e.getMessage(), e, null);
+ } else {
+ final Object lastContext = mConstructorArgs[0];
+ mConstructorArgs[0] = context;
+ // try to load the class from using the custom view loader
+ try {
+ view = loadCustomView(name, attrs);
+ } catch (Exception e2) {
+ // Wrap the real exception in an InflateException so that the calling
+ // method can deal with it.
+ InflateException exception = new InflateException();
+ if (!e2.getClass().equals(ClassNotFoundException.class)) {
+ exception.initCause(e2);
+ } else {
+ exception.initCause(e);
+ }
+ throw exception;
+ } finally {
+ mConstructorArgs[0] = lastContext;
}
- throw exception;
- } finally {
- mConstructorArgs[0] = lastContext;
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
index 44a9aad55daa..d392f213e5c8 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/MockView.java
@@ -17,39 +17,90 @@
package com.android.layoutlib.bridge;
import android.content.Context;
-import android.graphics.Canvas;
import android.util.AttributeSet;
import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.FrameLayout;
import android.widget.TextView;
/**
* Base class for mocked views.
- *
- * TODO: implement onDraw and draw a rectangle in a random color with the name of the class
- * (or better the id of the view).
+ * <p/>
+ * FrameLayout with a single TextView. Doesn't allow adding any other views to itself.
*/
-public class MockView extends TextView {
+public class MockView extends FrameLayout {
+
+ private final TextView mView;
+
+ public MockView(Context context) {
+ this(context, null);
+ }
public MockView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
- public MockView(Context context, AttributeSet attrs, int defStyle) {
- this(context, attrs, defStyle, 0);
+ public MockView(Context context, AttributeSet attrs, int defStyleAttr) {
+ this(context, attrs, defStyleAttr, 0);
}
public MockView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
-
- setText(this.getClass().getSimpleName());
- setTextColor(0xFF000000);
+ mView = new TextView(context, attrs);
+ mView.setTextColor(0xFF000000);
setGravity(Gravity.CENTER);
+ setText(getClass().getSimpleName());
+ addView(mView);
+ setBackgroundColor(0xFF7F7F7F);
+ }
+
+ // Only allow adding one TextView.
+ @Override
+ public void addView(View child) {
+ if (child == mView) {
+ super.addView(child);
+ }
+ }
+
+ @Override
+ public void addView(View child, int index) {
+ if (child == mView) {
+ super.addView(child, index);
+ }
}
@Override
- public void onDraw(Canvas canvas) {
- canvas.drawARGB(0xFF, 0x7F, 0x7F, 0x7F);
+ public void addView(View child, int width, int height) {
+ if (child == mView) {
+ super.addView(child, width, height);
+ }
+ }
+
+ @Override
+ public void addView(View child, ViewGroup.LayoutParams params) {
+ if (child == mView) {
+ super.addView(child, params);
+ }
+ }
+
+ @Override
+ public void addView(View child, int index, ViewGroup.LayoutParams params) {
+ if (child == mView) {
+ super.addView(child, index, params);
+ }
+ }
+
+ // The following methods are called by the IDE via reflection, and should be considered part
+ // of the API.
+ // Historically, MockView used to be a textView and had these methods. Now, we simply delegate
+ // them to the contained textView.
+
+ public void setText(CharSequence text) {
+ mView.setText(text);
+ }
- super.onDraw(canvas);
+ public void setGravity(int gravity) {
+ mView.setGravity(gravity);
}
}
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 b2dc29a90fb1..f2d214c43135 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
@@ -409,7 +409,7 @@ public final class BridgeContext extends Context {
pushParser(blockParser);
return Pair.of(
mBridgeInflater.inflate(blockParser, parent, attachToRoot),
- true);
+ Boolean.TRUE);
} finally {
popParser();
}
@@ -447,7 +447,7 @@ public final class BridgeContext extends Context {
pushParser(blockParser);
return Pair.of(
mBridgeInflater.inflate(blockParser, parent, attachToRoot),
- false);
+ Boolean.FALSE);
} finally {
popParser();
}
@@ -470,7 +470,7 @@ public final class BridgeContext extends Context {
resource.getName()), null);
}
- return Pair.of(null, false);
+ return Pair.of(null, Boolean.FALSE);
}
@SuppressWarnings("deprecation")
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
index 868c6d328e8e..cdcf0ea1ca76 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/AppCompatActionBar.java
@@ -16,10 +16,13 @@
package com.android.layoutlib.bridge.bars;
+import com.android.ide.common.rendering.api.LayoutLog;
+import com.android.ide.common.rendering.api.LayoutlibCallback;
import com.android.ide.common.rendering.api.RenderResources;
import com.android.ide.common.rendering.api.ResourceValue;
import com.android.ide.common.rendering.api.SessionParams;
import com.android.ide.common.rendering.api.StyleResourceValue;
+import com.android.layoutlib.bridge.Bridge;
import com.android.layoutlib.bridge.android.BridgeContext;
import com.android.layoutlib.bridge.impl.ResourceHelper;
import com.android.resources.ResourceType;
@@ -45,6 +48,8 @@ public class AppCompatActionBar extends BridgeActionBar {
private Object mWindowDecorActionBar;
private static final String WINDOW_ACTION_BAR_CLASS = "android.support.v7.internal.app.WindowDecorActionBar";
+ // This is used on v23.1.1 and later.
+ private static final String WINDOW_ACTION_BAR_CLASS_NEW = "android.support.v7.app.WindowDecorActionBar";
private Class<?> mWindowActionBarClass;
/**
@@ -70,14 +75,25 @@ public class AppCompatActionBar extends BridgeActionBar {
try {
Class[] constructorParams = {View.class};
Object[] constructorArgs = {getDecorContent()};
- mWindowDecorActionBar = params.getLayoutlibCallback().loadView(WINDOW_ACTION_BAR_CLASS,
- constructorParams, constructorArgs);
+ LayoutlibCallback callback = params.getLayoutlibCallback();
+
+ // Check if the old action bar class is present.
+ String actionBarClass = WINDOW_ACTION_BAR_CLASS;
+ try {
+ callback.findClass(actionBarClass);
+ } catch (ClassNotFoundException expected) {
+ // Failed to find the old class, use the newer one.
+ actionBarClass = WINDOW_ACTION_BAR_CLASS_NEW;
+ }
+ mWindowDecorActionBar = callback.loadView(actionBarClass,
+ constructorParams, constructorArgs);
mWindowActionBarClass = mWindowDecorActionBar == null ? null :
mWindowDecorActionBar.getClass();
setupActionBar();
} catch (Exception e) {
- e.printStackTrace();
+ Bridge.getLog().warning(LayoutLog.TAG_BROKEN,
+ "Failed to load AppCompat ActionBar with unknown error.", e);
}
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
index 567002e564b7..a6e5fb841bff 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/CustomBar.java
@@ -33,7 +33,6 @@ import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import android.annotation.NonNull;
-import android.annotation.Nullable;
import android.content.res.ColorStateList;
import android.graphics.Bitmap;
import android.graphics.Bitmap_Delegate;
@@ -117,11 +116,11 @@ abstract class CustomBar extends LinearLayout {
density = iconLoader.getDensity();
String path = iconLoader.getPath();
// look for a cached bitmap
- Bitmap bitmap = Bridge.getCachedBitmap(path, true /*isFramework*/);
+ Bitmap bitmap = Bridge.getCachedBitmap(path, Boolean.TRUE /*isFramework*/);
if (bitmap == null) {
try {
bitmap = Bitmap_Delegate.createBitmap(stream, false /*isMutable*/, density);
- Bridge.setCachedBitmap(path, bitmap, true /*isFramework*/);
+ Bridge.setCachedBitmap(path, bitmap, Boolean.TRUE /*isFramework*/);
} catch (IOException e) {
return;
}
@@ -228,18 +227,16 @@ abstract class CustomBar extends LinearLayout {
* Find the background color for this bar from the theme attributes. Only relevant to StatusBar
* and NavigationBar.
* <p/>
- * Returns null if not found.
+ * Returns 0 if not found.
*
* @param colorAttrName the attribute name for the background color
* @param translucentAttrName the attribute name for the translucency property of the bar.
*
* @throws NumberFormatException if color resolved to an invalid string.
*/
- @Nullable
- protected Integer getBarColor(@NonNull String colorAttrName,
- @NonNull String translucentAttrName) {
+ protected int getBarColor(@NonNull String colorAttrName, @NonNull String translucentAttrName) {
if (!Config.isGreaterOrEqual(mSimulatedPlatformVersion, LOLLIPOP)) {
- return null;
+ return 0;
}
RenderResources renderResources = getContext().getRenderResources();
// First check if the bar is translucent.
@@ -254,11 +251,10 @@ abstract class CustomBar extends LinearLayout {
if (transparent) {
return getColor(renderResources, colorAttrName);
}
- return null;
+ return 0;
}
- @Nullable
- private static Integer getColor(RenderResources renderResources, String attr) {
+ private static int getColor(RenderResources renderResources, String attr) {
// From ?attr/foo to @color/bar. This is most likely an ItemResourceValue.
ResourceValue resource = renderResources.findItemInTheme(attr, true);
// Form @color/bar to the #AARRGGBB
@@ -279,7 +275,7 @@ abstract class CustomBar extends LinearLayout {
}
}
}
- return null;
+ return 0;
}
private ResourceValue getResourceValue(String reference) {
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
index d50ce23a0902..9c89bfe2a28f 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/NavigationBar.java
@@ -65,8 +65,8 @@ public class NavigationBar extends CustomBar {
super(context, orientation, getShortestWidth(context)>= 600 ? LAYOUT_600DP_XML : LAYOUT_XML,
"navigation_bar.xml", simulatedPlatformVersion);
- Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
- setBackgroundColor(color == null ? 0xFF000000 : color);
+ int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
+ setBackgroundColor(color == 0 ? 0xFF000000 : color);
// Cannot access the inside items through id because no R.id values have been
// created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
index 95a5a58c535f..2dc7c65e2085 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/bars/StatusBar.java
@@ -71,9 +71,8 @@ public class StatusBar extends CustomBar {
// FIXME: use FILL_H?
setGravity(Gravity.START | Gravity.TOP | Gravity.RIGHT);
- Integer color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
- setBackgroundColor(
- color == null ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
+ int color = getBarColor(ATTR_COLOR, ATTR_TRANSLUCENT);
+ setBackgroundColor(color == 0 ? Config.getStatusBarColor(simulatedPlatformVersion) : color);
// Cannot access the inside items through id because no R.id values have been
// created for them.
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
index 95880355ada9..80d7c68bcf06 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/PorterDuffUtility.java
@@ -21,6 +21,7 @@ import com.android.layoutlib.bridge.Bridge;
import android.graphics.BlendComposite;
import android.graphics.BlendComposite.BlendingMode;
+import android.graphics.PorterDuff;
import android.graphics.PorterDuff.Mode;
import android.graphics.PorterDuffColorFilter_Delegate;
import android.graphics.PorterDuffXfermode_Delegate;
@@ -34,6 +35,8 @@ import java.awt.Composite;
*/
public final class PorterDuffUtility {
+ private static final int MODES_COUNT = Mode.values().length;
+
// Make the class non-instantiable.
private PorterDuffUtility() {
}
@@ -43,12 +46,11 @@ public final class PorterDuffUtility {
* {@link Mode#SRC_OVER} for invalid modes.
*/
public static Mode getPorterDuffMode(int porterDuffMode) {
- Mode[] values = Mode.values();
- if (porterDuffMode >= 0 && porterDuffMode < values.length) {
- return values[porterDuffMode];
+ if (porterDuffMode >= 0 && porterDuffMode < MODES_COUNT) {
+ return PorterDuff.intToMode(porterDuffMode);
}
Bridge.getLog().error(LayoutLog.TAG_BROKEN,
- String.format("Unknown PorterDuff.Mode: %1$d", porterDuffMode), null /*data*/);
+ String.format("Unknown PorterDuff.Mode: %1$d", porterDuffMode), null);
assert false;
return Mode.SRC_OVER;
}
diff --git a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
index 2a4f58381aee..0ffa35733180 100644
--- a/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
+++ b/tools/layoutlib/bridge/src/com/android/layoutlib/bridge/impl/RenderSessionImpl.java
@@ -421,7 +421,8 @@ public class RenderSessionImpl extends RenderAction<SessionParams> {
gc.setComposite(AlphaComposite.Src);
gc.setColor(new Color(0x00000000, true));
- gc.fillRect(0, 0, mMeasuredScreenWidth, mMeasuredScreenHeight);
+ gc.fillRect(0, 0,
+ mMeasuredScreenWidth, mMeasuredScreenHeight);
// done
gc.dispose();
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
index ae4a57d8eea4..7ef75662aad4 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateClassAdapter.java
@@ -17,6 +17,7 @@
package com.android.tools.layoutlib.create;
import org.objectweb.asm.ClassVisitor;
+import org.objectweb.asm.FieldVisitor;
import org.objectweb.asm.MethodVisitor;
import org.objectweb.asm.Opcodes;
@@ -40,6 +41,7 @@ public class DelegateClassAdapter extends ClassVisitor {
private final String mClassName;
private final Set<String> mDelegateMethods;
private final Log mLog;
+ private boolean mIsStaticInnerClass;
/**
* Creates a new {@link DelegateClassAdapter} that can transform some methods
@@ -62,16 +64,30 @@ public class DelegateClassAdapter extends ClassVisitor {
mLog = log;
mClassName = className;
mDelegateMethods = delegateMethods;
+ // If this is an inner class, by default, we assume it's static. If it's not we will detect
+ // by looking at the fields (see visitField)
+ mIsStaticInnerClass = className.contains("$");
}
//----------------------------------
// Methods from the ClassAdapter
@Override
+ public FieldVisitor visitField(int access, String name, String desc, String signature,
+ Object value) {
+ if (mIsStaticInnerClass && "this$0".equals(name)) {
+ // Having a "this$0" field, proves that this class is not a static inner class.
+ mIsStaticInnerClass = false;
+ }
+
+ return super.visitField(access, name, desc, signature, value);
+ }
+
+ @Override
public MethodVisitor visitMethod(int access, String name, String desc,
String signature, String[] exceptions) {
- boolean isStatic = (access & Opcodes.ACC_STATIC) != 0;
+ boolean isStaticMethod = (access & Opcodes.ACC_STATIC) != 0;
boolean isNative = (access & Opcodes.ACC_NATIVE) != 0;
boolean useDelegate = (isNative && mDelegateMethods.contains(ALL_NATIVES)) ||
@@ -96,7 +112,8 @@ public class DelegateClassAdapter extends ClassVisitor {
MethodVisitor mwDelegate = super.visitMethod(access, name, desc, signature, exceptions);
DelegateMethodAdapter a = new DelegateMethodAdapter(
- mLog, null, mwDelegate, mClassName, name, desc, isStatic);
+ mLog, null, mwDelegate, mClassName, name, desc, isStaticMethod,
+ mIsStaticInnerClass);
// A native has no code to visit, so we need to generate it directly.
a.generateDelegateCode();
@@ -120,6 +137,7 @@ public class DelegateClassAdapter extends ClassVisitor {
desc, signature, exceptions);
return new DelegateMethodAdapter(
- mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStatic);
+ mLog, mwOriginal, mwDelegate, mClassName, name, desc, isStaticMethod,
+ mIsStaticInnerClass);
}
}
diff --git a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
index 12690db547a9..cca9e574b7ea 100644
--- a/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
+++ b/tools/layoutlib/create/src/com/android/tools/layoutlib/create/DelegateMethodAdapter.java
@@ -85,6 +85,8 @@ class DelegateMethodAdapter extends MethodVisitor {
private String mDesc;
/** True if the original method is static. */
private final boolean mIsStatic;
+ /** True if the method is contained in a static inner class */
+ private final boolean mIsStaticInnerClass;
/** The internal class name (e.g. <code>com/android/SomeClass$InnerClass</code>.) */
private final String mClassName;
/** The method name. */
@@ -120,7 +122,8 @@ class DelegateMethodAdapter extends MethodVisitor {
String className,
String methodName,
String desc,
- boolean isStatic) {
+ boolean isStatic,
+ boolean isStaticClass) {
super(Opcodes.ASM4);
mLog = log;
mOrgWriter = mvOriginal;
@@ -129,6 +132,7 @@ class DelegateMethodAdapter extends MethodVisitor {
mMethodName = methodName;
mDesc = desc;
mIsStatic = isStatic;
+ mIsStaticInnerClass = isStaticClass;
}
/**
@@ -206,7 +210,7 @@ class DelegateMethodAdapter extends MethodVisitor {
// by the 'this' of any outer class, if any.
if (!mIsStatic) {
- if (outerType != null) {
+ if (outerType != null && !mIsStaticInnerClass) {
// The first-level inner class has a package-protected member called 'this$0'
// that points to the outer class.
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
index 648cea430de2..e37a09b348b8 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/DelegateClassAdapterTest.java
@@ -27,6 +27,7 @@ import static org.junit.Assert.fail;
import com.android.tools.layoutlib.create.dataclass.ClassWithNative;
import com.android.tools.layoutlib.create.dataclass.OuterClass;
import com.android.tools.layoutlib.create.dataclass.OuterClass.InnerClass;
+import com.android.tools.layoutlib.create.dataclass.OuterClass.StaticInnerClass;
import org.junit.Before;
import org.junit.Test;
@@ -56,6 +57,8 @@ public class DelegateClassAdapterTest {
private static final String OUTER_CLASS_NAME = OuterClass.class.getCanonicalName();
private static final String INNER_CLASS_NAME = OuterClass.class.getCanonicalName() + "$" +
InnerClass.class.getSimpleName();
+ private static final String STATIC_INNER_CLASS_NAME =
+ OuterClass.class.getCanonicalName() + "$" + StaticInnerClass.class.getSimpleName();
@Before
public void setUp() throws Exception {
@@ -294,6 +297,61 @@ public class DelegateClassAdapterTest {
}
}
+ @Test
+ public void testDelegateStaticInner() throws Throwable {
+ // We'll delegate the "get" method of both the inner and outer class.
+ HashSet<String> delegateMethods = new HashSet<String>();
+ delegateMethods.add("get");
+
+ // Generate the delegate for the outer class.
+ ClassWriter cwOuter = new ClassWriter(0 /*flags*/);
+ String outerClassName = OUTER_CLASS_NAME.replace('.', '/');
+ DelegateClassAdapter cvOuter = new DelegateClassAdapter(
+ mLog, cwOuter, outerClassName, delegateMethods);
+ ClassReader cr = new ClassReader(OUTER_CLASS_NAME);
+ cr.accept(cvOuter, 0 /* flags */);
+
+ // Generate the delegate for the static inner class.
+ ClassWriter cwInner = new ClassWriter(0 /*flags*/);
+ String innerClassName = STATIC_INNER_CLASS_NAME.replace('.', '/');
+ DelegateClassAdapter cvInner = new DelegateClassAdapter(
+ mLog, cwInner, innerClassName, delegateMethods);
+ cr = new ClassReader(STATIC_INNER_CLASS_NAME);
+ cr.accept(cvInner, 0 /* flags */);
+
+ // Load the generated classes in a different class loader and try them
+ ClassLoader2 cl2 = null;
+ try {
+ cl2 = new ClassLoader2() {
+ @Override
+ public void testModifiedInstance() throws Exception {
+
+ // Check the outer class
+ Class<?> outerClazz2 = loadClass(OUTER_CLASS_NAME);
+ Object o2 = outerClazz2.newInstance();
+ assertNotNull(o2);
+
+ // Check the inner class. Since it's not a static inner class, we need
+ // to use the hidden constructor that takes the outer class as first parameter.
+ Class<?> innerClazz2 = loadClass(STATIC_INNER_CLASS_NAME);
+ Constructor<?> innerCons = innerClazz2.getConstructor();
+ Object i2 = innerCons.newInstance();
+ assertNotNull(i2);
+
+ // The original StaticInner.get returns 100+10+20,
+ // but the delegate makes it return 6+10+20
+ assertEquals(6+10+20, callGet(i2, 10, 20));
+ assertEquals(100+10+20, callGet_Original(i2, 10, 20));
+ }
+ };
+ cl2.add(OUTER_CLASS_NAME, cwOuter.toByteArray());
+ cl2.add(STATIC_INNER_CLASS_NAME, cwInner.toByteArray());
+ cl2.testModifiedInstance();
+ } catch (Throwable t) {
+ throw dumpGeneratedClass(t, cl2);
+ }
+ }
+
//-------
/**
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
index f083e76d995c..6dfb81662e40 100644
--- a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass.java
@@ -45,6 +45,16 @@ public class OuterClass {
}
}
+ public static class StaticInnerClass {
+ public StaticInnerClass() {
+ }
+
+ // StaticInnerClass.get returns 100 + a + b
+ public int get(int a, long b) {
+ return 100 + a + (int) b;
+ }
+ }
+
@SuppressWarnings("unused")
private String privateMethod() {
return "outerPrivateMethod";
diff --git a/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java
new file mode 100644
index 000000000000..a29439ee3fee
--- /dev/null
+++ b/tools/layoutlib/create/tests/com/android/tools/layoutlib/create/dataclass/OuterClass_StaticInnerClass_Delegate.java
@@ -0,0 +1,30 @@
+/*
+ * Copyright (C) 2015 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.tools.layoutlib.create.dataclass;
+
+import com.android.tools.layoutlib.create.DelegateClassAdapterTest;
+import com.android.tools.layoutlib.create.dataclass.OuterClass.StaticInnerClass;
+
+/**
+ * Used by {@link DelegateClassAdapterTest}.
+ */
+public class OuterClass_StaticInnerClass_Delegate {
+ // The delegate override of Inner.get return 6 + a + b
+ public static int get(StaticInnerClass inner, int a, long b) {
+ return 6 + a + (int) b;
+ }
+}