Merge "Making ViewRootImpl drop input events when the Activity is in ambient mode." into cw-e-dev
diff --git a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
index 1fb7825..002f63f 100644
--- a/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
+++ b/core/java/android/bluetooth/BluetoothHeadsetClientCall.java
@@ -19,6 +19,8 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 
+import java.util.UUID;
+
 /**
  * This class represents a single call, its state and properties.
  * It implements {@link Parcelable} for inter-process message passing.
@@ -67,14 +69,21 @@
     private String mNumber;
     private boolean mMultiParty;
     private final boolean mOutgoing;
+    private final UUID mUUID;
 
     /**
      * Creates BluetoothHeadsetClientCall instance.
      */
     public BluetoothHeadsetClientCall(BluetoothDevice device, int id, int state, String number,
             boolean multiParty, boolean outgoing) {
+        this(device, id, UUID.randomUUID(), state, number, multiParty, outgoing);
+    }
+
+    public BluetoothHeadsetClientCall(BluetoothDevice device, int id, UUID uuid, int state,
+            String number, boolean multiParty, boolean outgoing) {
         mDevice = device;
         mId = id;
+        mUUID = uuid;
         mState = state;
         mNumber = number != null ? number : "";
         mMultiParty = multiParty;
@@ -134,6 +143,16 @@
     }
 
     /**
+     * Gets call's UUID.
+     *
+     * @return call uuid
+     * @hide
+     */
+    public UUID getUUID() {
+        return mUUID;
+    }
+
+    /**
      * Gets call's current state.
      *
      * @return state of this particular phone call.
@@ -180,6 +199,8 @@
         builder.append(loggable ? mDevice.hashCode() : mDevice);
         builder.append(", mId: ");
         builder.append(mId);
+        builder.append(", mUUID: ");
+        builder.append(mUUID);
         builder.append(", mState: ");
         switch (mState) {
             case CALL_STATE_ACTIVE: builder.append("ACTIVE"); break;
@@ -210,8 +231,8 @@
                 @Override
                 public BluetoothHeadsetClientCall createFromParcel(Parcel in) {
                     return new BluetoothHeadsetClientCall((BluetoothDevice)in.readParcelable(null),
-                            in.readInt(), in.readInt(), in.readString(),
-                            in.readInt() == 1, in.readInt() == 1);
+                            in.readInt(), UUID.fromString(in.readString()), in.readInt(),
+                            in.readString(), in.readInt() == 1, in.readInt() == 1);
                 }
 
                 @Override
@@ -224,6 +245,7 @@
     public void writeToParcel(Parcel out, int flags) {
         out.writeParcelable(mDevice, 0);
         out.writeInt(mId);
+        out.writeString(mUUID.toString());
         out.writeInt(mState);
         out.writeString(mNumber);
         out.writeInt(mMultiParty ? 1 : 0);
diff --git a/core/java/android/bluetooth/BluetoothProfile.java b/core/java/android/bluetooth/BluetoothProfile.java
index cbce22c..6bf3fab 100644
--- a/core/java/android/bluetooth/BluetoothProfile.java
+++ b/core/java/android/bluetooth/BluetoothProfile.java
@@ -131,6 +131,18 @@
     public static final int HEADSET_CLIENT = 16;
 
     /**
+     * HID Profile
+     * @hide
+     */
+    public static final int HID = 17;
+
+    /**
+     * HDP Profile
+     * @hide
+     */
+    public static final int HDP = 18;
+
+    /**
      * Default priority for devices that we try to auto-connect to and
      * and allow incoming connections for the profile
      * @hide
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index 746e110..9a7d7bb 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -6030,6 +6030,13 @@
         public static final String AIRPLANE_MODE_TOGGLEABLE_RADIOS = "airplane_mode_toggleable_radios";
 
         /**
+         * A Long representing a bitmap of profiles that should be disabled when bluetooth starts.
+         * See {@link android.bluetooth.BluetoothProfile}.
+         * {@hide}
+         */
+        public static final String BLUETOOTH_DISABLED_PROFILES = "bluetooth_disabled_profiles";
+
+        /**
          * The policy for deciding when Wi-Fi should go to sleep (which will in
          * turn switch to using the mobile data as an Internet connection).
          * <p>
diff --git a/packages/SettingsProvider/res/values/defaults.xml b/packages/SettingsProvider/res/values/defaults.xml
index 1cd2908..ef32c19 100644
--- a/packages/SettingsProvider/res/values/defaults.xml
+++ b/packages/SettingsProvider/res/values/defaults.xml
@@ -25,6 +25,7 @@
     <!-- Comma-separated list of bluetooth, wifi, and cell. -->
     <string name="def_airplane_mode_radios" translatable="false">cell,bluetooth,wifi,nfc,wimax</string>
     <string name="airplane_mode_toggleable_radios" translatable="false">bluetooth,wifi,nfc</string>
+    <string name="def_bluetooth_disabled_profiles" translatable="false">0</string>
     <bool name="def_auto_time">true</bool>
     <bool name="def_auto_time_zone">true</bool>
     <bool name="def_accelerometer_rotation">true</bool>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
index 73971ad..aa00f7d 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsProvider.java
@@ -1855,7 +1855,7 @@
         }
 
         private final class UpgradeController {
-            private static final int SETTINGS_VERSION = 122;
+            private static final int SETTINGS_VERSION = 123;
 
             private final int mUserId;
 
@@ -2007,6 +2007,16 @@
                     }
                     currentVersion = 122;
                 }
+
+                if (currentVersion == 122) {
+                    final SettingsState globalSettings = getGlobalSettingsLocked();
+                    String defaultDisabledProfiles = (getContext().getResources().getString(
+                            R.string.def_bluetooth_disabled_profiles));
+                    globalSettings.insertSettingLocked(Settings.Global.BLUETOOTH_DISABLED_PROFILES,
+                            defaultDisabledProfiles, SettingsState.SYSTEM_PACKAGE_NAME);
+                    currentVersion = 123;
+                }
+
                 // vXXX: Add new settings above this point.
 
                 // Return the current version.
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 6b1b6296..7276980 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -766,7 +766,7 @@
             IPhoneSubInfo info = getSubscriberInfo();
             if (info == null)
                 return null;
-            return info.getDeviceIdForPhone(slotId);
+            return info.getDeviceIdForPhone(slotId, mContext.getOpPackageName());
         } catch (RemoteException ex) {
             return null;
         } catch (NullPointerException ex) {
diff --git a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
index ed85392..dc2b297 100644
--- a/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
+++ b/telephony/java/com/android/internal/telephony/IPhoneSubInfo.aidl
@@ -36,7 +36,7 @@
      * Retrieves the unique device ID of a phone for the device, e.g., IMEI
      * for GSM phones.
      */
-    String getDeviceIdForPhone(int phoneId);
+    String getDeviceIdForPhone(int phoneId, String callingPackage);
 
     /**
      * Retrieves the IMEI.
diff --git a/tools/aapt/Command.cpp b/tools/aapt/Command.cpp
index 8a0a39c..d63fe31 100644
--- a/tools/aapt/Command.cpp
+++ b/tools/aapt/Command.cpp
@@ -383,6 +383,16 @@
     }
 }
 
+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 @@
  * 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 @@
 };
 
 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 @@
 
         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) {
+    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 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 @@
             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 @@
                     }
                     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;
+                } 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));
                     }
-                    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;
-                    }
-                    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 @@
             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 @@
                                             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 @@
                                             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 @@
                                 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 @@
                                         !actHostApduService && !actOffHostApduService &&
                                         !actNotificationListenerService);
                             } else if (withinProvider) {
-                                hasDocumentsProvider |= actDocumentsProvider && hasRequiredSafAttributes;
+                                hasDocumentsProvider |=
+                                        actDocumentsProvider && hasRequiredSafAttributes;
                             }
                         }
                         withinIntentFilter = false;
@@ -1125,7 +1265,8 @@
                             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 @@
                                 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 @@
                             }
                         }
                     } 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 @@
                             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 @@
                         }
                     } 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;
-                            }
-
-                            printUsesPermission(name,
-                                    AaptXml::getIntegerAttribute(tree, REQUIRED_ATTR, 1) == 0,
-                                    AaptXml::getIntegerAttribute(tree, MAX_SDK_VERSION_ATTR));
-                       } else {
+                        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\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 @@
                     } 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 @@
                             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 @@
                                     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 @@
                             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 @@
                             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 @@
                             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 @@
                     } 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 @@
                             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 @@
                                 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 @@
             }
 
             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