Merge "Glop layer mesh rendering"
diff --git a/api/current.txt b/api/current.txt
index 7d8b892..bd5596b 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -1711,6 +1711,7 @@
     field public static final int paste = 16908322; // 0x1020022
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
+    field public static final int redo = 16908338; // 0x1020032
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1727,6 +1728,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int undo = 16908337; // 0x1020031
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -5530,6 +5532,7 @@
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_START_ENCRYPTION = "android.app.action.START_ENCRYPTION";
@@ -28745,6 +28748,7 @@
     method public boolean isInCall();
     method public void showInCallScreen(boolean);
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_DISCONNECT_CAUSE = "android.telecom.extra.CALL_DISCONNECT_CAUSE";
diff --git a/api/system-current.txt b/api/system-current.txt
index 6968896..36ac196 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -1787,6 +1787,7 @@
     field public static final int paste = 16908322; // 0x1020022
     field public static final int primary = 16908300; // 0x102000c
     field public static final int progress = 16908301; // 0x102000d
+    field public static final int redo = 16908338; // 0x1020032
     field public static final int secondaryProgress = 16908303; // 0x102000f
     field public static final int selectAll = 16908319; // 0x102001f
     field public static final int selectTextMode = 16908333; // 0x102002d
@@ -1803,6 +1804,7 @@
     field public static final int text2 = 16908309; // 0x1020015
     field public static final int title = 16908310; // 0x1020016
     field public static final int toggle = 16908311; // 0x1020017
+    field public static final int undo = 16908337; // 0x1020031
     field public static final int widget_frame = 16908312; // 0x1020018
   }
 
@@ -5631,6 +5633,7 @@
     method public void uninstallCaCert(android.content.ComponentName, byte[]);
     method public void wipeData(int);
     field public static final java.lang.String ACTION_ADD_DEVICE_ADMIN = "android.app.action.ADD_DEVICE_ADMIN";
+    field public static final java.lang.String ACTION_MANAGED_PROFILE_PROVISIONED = "android.app.action.MANAGED_PROFILE_PROVISIONED";
     field public static final java.lang.String ACTION_PROVISION_MANAGED_PROFILE = "android.app.action.PROVISION_MANAGED_PROFILE";
     field public static final java.lang.String ACTION_SET_NEW_PASSWORD = "android.app.action.SET_NEW_PASSWORD";
     field public static final java.lang.String ACTION_SET_PROFILE_OWNER = "android.app.action.SET_PROFILE_OWNER";
@@ -15118,6 +15121,8 @@
     field public static final android.os.Parcelable.Creator<android.media.AudioAttributes> CREATOR;
     field public static final int FLAG_AUDIBILITY_ENFORCED = 1; // 0x1
     field public static final int FLAG_BEACON = 8; // 0x8
+    field public static final int FLAG_BYPASS_INTERRUPTION_POLICY = 64; // 0x40
+    field public static final int FLAG_BYPASS_MUTE = 128; // 0x80
     field public static final int FLAG_HW_AV_SYNC = 16; // 0x10
     field public static final int FLAG_HW_HOTWORD = 32; // 0x20
     field public static final int USAGE_ALARM = 4; // 0x4
@@ -30863,6 +30868,7 @@
     field public static final java.lang.String ACTION_CHANGE_PHONE_ACCOUNTS = "android.telecom.action.CHANGE_PHONE_ACCOUNTS";
     field public static final java.lang.String ACTION_CONNECTION_SERVICE_CONFIGURE = "android.telecom.action.CONNECTION_SERVICE_CONFIGURE";
     field public static final java.lang.String ACTION_SHOW_CALL_SETTINGS = "android.telecom.action.SHOW_CALL_SETTINGS";
+    field public static final java.lang.String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS = "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
     field public static final char DTMF_CHARACTER_PAUSE = 44; // 0x002c ','
     field public static final char DTMF_CHARACTER_WAIT = 59; // 0x003b ';'
     field public static final java.lang.String EXTRA_CALL_BACK_NUMBER = "android.telecom.extra.CALL_BACK_NUMBER";
diff --git a/core/java/android/alsa/AlsaCardsParser.java b/core/java/android/alsa/AlsaCardsParser.java
index 26a61ae..5e88bca 100644
--- a/core/java/android/alsa/AlsaCardsParser.java
+++ b/core/java/android/alsa/AlsaCardsParser.java
@@ -117,6 +117,9 @@
                 cardRecord.parse(line, 0);
 
                 line = bufferedReader.readLine();
+                if (line == null) {
+                    break;
+                }
                 if (DEBUG) {
                     Slog.i(TAG, "  " + line);
                 }
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index a8eb076..653b951 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -1101,7 +1101,7 @@
         @Override
         public void dumpGfxInfo(FileDescriptor fd, String[] args) {
             dumpGraphicsInfo(fd);
-            WindowManagerGlobal.getInstance().dumpGfxInfo(fd);
+            WindowManagerGlobal.getInstance().dumpGfxInfo(fd, args);
         }
 
         private void dumpDatabaseInfo(FileDescriptor fd, String[] args) {
diff --git a/core/java/android/app/ContextImpl.java b/core/java/android/app/ContextImpl.java
index 0098d86..db380ed 100644
--- a/core/java/android/app/ContextImpl.java
+++ b/core/java/android/app/ContextImpl.java
@@ -2294,8 +2294,10 @@
         if (container != null) {
             compatInfo = container.getDisplayAdjustments(displayId).getCompatibilityInfo();
         }
-        if (compatInfo == null && displayId == Display.DEFAULT_DISPLAY) {
-            compatInfo = packageInfo.getCompatibilityInfo();
+        if (compatInfo == null) {
+            compatInfo = (displayId == Display.DEFAULT_DISPLAY)
+                    ? packageInfo.getCompatibilityInfo()
+                    : CompatibilityInfo.DEFAULT_COMPATIBILITY_INFO;
         }
         mDisplayAdjustments.setCompatibilityInfo(compatInfo);
         mDisplayAdjustments.setConfiguration(overrideConfiguration);
diff --git a/core/java/android/app/Service.java b/core/java/android/app/Service.java
index c8e0031..21a3543 100644
--- a/core/java/android/app/Service.java
+++ b/core/java/android/app/Service.java
@@ -16,6 +16,7 @@
 
 package android.app;
 
+import android.annotation.Nullable;
 import android.content.ComponentCallbacks2;
 import android.content.ComponentName;
 import android.content.Intent;
@@ -498,6 +499,7 @@
      * @return Return an IBinder through which clients can call on to the 
      *         service.
      */
+    @Nullable
     public abstract IBinder onBind(Intent intent);
 
     /**
diff --git a/core/java/android/app/admin/DevicePolicyManager.java b/core/java/android/app/admin/DevicePolicyManager.java
index 318a314..a10b133 100644
--- a/core/java/android/app/admin/DevicePolicyManager.java
+++ b/core/java/android/app/admin/DevicePolicyManager.java
@@ -111,9 +111,11 @@
      *
      * <p>This intent must contain the extra {@link #EXTRA_PROVISIONING_DEVICE_ADMIN_PACKAGE_NAME}.
      *
-     * <p> When managed provisioning has completed, an intent of the type
-     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} is broadcasted to the
-     * managed profile.
+     * <p> When managed provisioning has completed, broadcasts are sent to the application specified
+     * in the provisioning intent. The
+     * {@link DeviceAdminReceiver#ACTION_PROFILE_PROVISIONING_COMPLETE} broadcast is sent in the
+     * managed profile and the {@link #ACTION_MANAGED_PROFILE_PROVISIONED} broadcast is sent in
+     * the primary profile.
      *
      * <p> If provisioning fails, the managedProfile is removed so the device returns to its
      * previous state.
@@ -332,6 +334,20 @@
         = "android.app.extra.PROVISIONING_DEVICE_ADMIN_PACKAGE_CHECKSUM";
 
     /**
+     * Broadcast Action: This broadcast is sent to indicate that provisioning of a managed profile
+     * has completed successfully.
+     *
+     * <p>The broadcast is limited to the primary profile, to the app specified in the provisioning
+     * intent (@see #ACTION_PROVISION_MANAGED_PROFILE).
+     *
+     * <p>This intent will contain the extra {@link EXTRA_PROVISIONING_ACCOUNT_TO_MIGRATE} which
+     * corresponds to the account requested to be migrated at provisioning time, if any.
+     */
+    @SdkConstant(SdkConstantType.ACTIVITY_INTENT_ACTION)
+    public static final String ACTION_MANAGED_PROFILE_PROVISIONED
+        = "android.app.action.MANAGED_PROFILE_PROVISIONED";
+
+    /**
      * A boolean extra indicating whether device encryption is required as part of Device Owner
      * provisioning.
      *
diff --git a/core/java/android/os/BatteryStats.java b/core/java/android/os/BatteryStats.java
index cd45cfb..4dadda2 100644
--- a/core/java/android/os/BatteryStats.java
+++ b/core/java/android/os/BatteryStats.java
@@ -592,6 +592,86 @@
         }
     }
 
+    /**
+     * Optional detailed information that can go into a history step.  This is typically
+     * generated each time the battery level changes.
+     */
+    public final static class HistoryStepDetails {
+        // Time (in 1/100 second) spent in user space and the kernel since the last step.
+        public int userTime;
+        public int systemTime;
+
+        // Top three apps using CPU in the last step, with times in 1/100 second.
+        public int appCpuUid1;
+        public int appCpuUTime1;
+        public int appCpuSTime1;
+        public int appCpuUid2;
+        public int appCpuUTime2;
+        public int appCpuSTime2;
+        public int appCpuUid3;
+        public int appCpuUTime3;
+        public int appCpuSTime3;
+
+        // Information from /proc/stat
+        public int statUserTime;
+        public int statSystemTime;
+        public int statIOWaitTime;
+        public int statIrqTime;
+        public int statSoftIrqTime;
+        public int statIdlTime;
+
+        public HistoryStepDetails() {
+            clear();
+        }
+
+        public void clear() {
+            userTime = systemTime = 0;
+            appCpuUid1 = appCpuUid2 = appCpuUid3 = -1;
+            appCpuUTime1 = appCpuSTime1 = appCpuUTime2 = appCpuSTime2
+                    = appCpuUTime3 = appCpuSTime3 = 0;
+        }
+
+        public void writeToParcel(Parcel out) {
+            out.writeInt(userTime);
+            out.writeInt(systemTime);
+            out.writeInt(appCpuUid1);
+            out.writeInt(appCpuUTime1);
+            out.writeInt(appCpuSTime1);
+            out.writeInt(appCpuUid2);
+            out.writeInt(appCpuUTime2);
+            out.writeInt(appCpuSTime2);
+            out.writeInt(appCpuUid3);
+            out.writeInt(appCpuUTime3);
+            out.writeInt(appCpuSTime3);
+            out.writeInt(statUserTime);
+            out.writeInt(statSystemTime);
+            out.writeInt(statIOWaitTime);
+            out.writeInt(statIrqTime);
+            out.writeInt(statSoftIrqTime);
+            out.writeInt(statIdlTime);
+        }
+
+        public void readFromParcel(Parcel in) {
+            userTime = in.readInt();
+            systemTime = in.readInt();
+            appCpuUid1 = in.readInt();
+            appCpuUTime1 = in.readInt();
+            appCpuSTime1 = in.readInt();
+            appCpuUid2 = in.readInt();
+            appCpuUTime2 = in.readInt();
+            appCpuSTime2 = in.readInt();
+            appCpuUid3 = in.readInt();
+            appCpuUTime3 = in.readInt();
+            appCpuSTime3 = in.readInt();
+            statUserTime = in.readInt();
+            statSystemTime = in.readInt();
+            statIOWaitTime = in.readInt();
+            statIrqTime = in.readInt();
+            statSoftIrqTime = in.readInt();
+            statIdlTime = in.readInt();
+        }
+    }
+
     public final static class HistoryItem implements Parcelable {
         public HistoryItem next;
 
@@ -687,6 +767,9 @@
         // Kernel wakeup reason at this point.
         public HistoryTag wakeReasonTag;
 
+        // Non-null when there is more detailed information at this step.
+        public HistoryStepDetails stepDetails;
+
         public static final int EVENT_FLAG_START = 0x8000;
         public static final int EVENT_FLAG_FINISH = 0x4000;
 
@@ -3692,10 +3775,115 @@
                     }
                 }
                 pw.println();
+                if (rec.stepDetails != null) {
+                    if (!checkin) {
+                        pw.print("                 Details: cpu=");
+                        pw.print(rec.stepDetails.userTime);
+                        pw.print("u+");
+                        pw.print(rec.stepDetails.systemTime);
+                        pw.print("s");
+                        if (rec.stepDetails.appCpuUid1 >= 0) {
+                            pw.print(" (");
+                            printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid1,
+                                    rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1);
+                            if (rec.stepDetails.appCpuUid2 >= 0) {
+                                pw.print(", ");
+                                printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid2,
+                                        rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2);
+                            }
+                            if (rec.stepDetails.appCpuUid3 >= 0) {
+                                pw.print(", ");
+                                printStepCpuUidDetails(pw, rec.stepDetails.appCpuUid3,
+                                        rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3);
+                            }
+                            pw.print(')');
+                        }
+                        pw.println();
+                        pw.print("                          /proc/stat=");
+                        pw.print(rec.stepDetails.statUserTime);
+                        pw.print(" usr, ");
+                        pw.print(rec.stepDetails.statSystemTime);
+                        pw.print(" sys, ");
+                        pw.print(rec.stepDetails.statIOWaitTime);
+                        pw.print(" io, ");
+                        pw.print(rec.stepDetails.statIrqTime);
+                        pw.print(" irq, ");
+                        pw.print(rec.stepDetails.statSoftIrqTime);
+                        pw.print(" sirq, ");
+                        pw.print(rec.stepDetails.statIdlTime);
+                        pw.print(" idle");
+                        int totalRun = rec.stepDetails.statUserTime + rec.stepDetails.statSystemTime
+                                + rec.stepDetails.statIOWaitTime + rec.stepDetails.statIrqTime
+                                + rec.stepDetails.statSoftIrqTime;
+                        int total = totalRun + rec.stepDetails.statIdlTime;
+                        if (total > 0) {
+                            pw.print(" (");
+                            float perc = ((float)totalRun) / ((float)total) * 100;
+                            pw.print(String.format("%.1f%%", perc));
+                            pw.print(" of ");
+                            StringBuilder sb = new StringBuilder(64);
+                            formatTimeMsNoSpace(sb, total*10);
+                            pw.print(sb);
+                            pw.print(")");
+                        }
+                        pw.println();
+                    } else {
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(",0,Dcpu=");
+                        pw.print(rec.stepDetails.userTime);
+                        pw.print(":");
+                        pw.print(rec.stepDetails.systemTime);
+                        if (rec.stepDetails.appCpuUid1 >= 0) {
+                            printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid1,
+                                    rec.stepDetails.appCpuUTime1, rec.stepDetails.appCpuSTime1);
+                            if (rec.stepDetails.appCpuUid2 >= 0) {
+                                printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid2,
+                                        rec.stepDetails.appCpuUTime2, rec.stepDetails.appCpuSTime2);
+                            }
+                            if (rec.stepDetails.appCpuUid3 >= 0) {
+                                printStepCpuUidCheckinDetails(pw, rec.stepDetails.appCpuUid3,
+                                        rec.stepDetails.appCpuUTime3, rec.stepDetails.appCpuSTime3);
+                            }
+                        }
+                        pw.println();
+                        pw.print(BATTERY_STATS_CHECKIN_VERSION); pw.print(',');
+                        pw.print(HISTORY_DATA); pw.print(",0,Dpst=");
+                        pw.print(rec.stepDetails.statUserTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statSystemTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIOWaitTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIrqTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statSoftIrqTime);
+                        pw.print(',');
+                        pw.print(rec.stepDetails.statIdlTime);
+                        pw.println();
+                    }
+                }
                 oldState = rec.states;
                 oldState2 = rec.states2;
             }
         }
+
+        private void printStepCpuUidDetails(PrintWriter pw, int uid, int utime, int stime) {
+            UserHandle.formatUid(pw, uid);
+            pw.print("=");
+            pw.print(utime);
+            pw.print("u+");
+            pw.print(stime);
+            pw.print("s");
+        }
+
+        private void printStepCpuUidCheckinDetails(PrintWriter pw, int uid, int utime, int stime) {
+            pw.print('/');
+            pw.print(uid);
+            pw.print(":");
+            pw.print(utime);
+            pw.print(":");
+            pw.print(stime);
+        }
     }
 
     private void printSizeValue(PrintWriter pw, long size) {
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index 60ab05c..650f3b3 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -116,6 +116,7 @@
 
     /**
      * Specifies if a user is disallowed from configuring bluetooth.
+     * This does <em>not</em> restrict the user from turning bluetooth on or off.
      * The default value is <code>false</code>.
      * <p/>This restriction has no effect in a managed profile.
      *
diff --git a/core/java/android/preference/SeekBarVolumizer.java b/core/java/android/preference/SeekBarVolumizer.java
index c3dd4ce..30da0e7 100644
--- a/core/java/android/preference/SeekBarVolumizer.java
+++ b/core/java/android/preference/SeekBarVolumizer.java
@@ -21,6 +21,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.database.ContentObserver;
+import android.media.AudioAttributes;
 import android.media.AudioManager;
 import android.media.Ringtone;
 import android.media.RingtoneManager;
@@ -174,6 +175,11 @@
             }
             if (mRingtone != null) {
                 try {
+                    mRingtone.setAudioAttributes(new AudioAttributes.Builder(mRingtone
+                            .getAudioAttributes())
+                            .setFlags(AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY |
+                                    AudioAttributes.FLAG_BYPASS_MUTE)
+                            .build());
                     mRingtone.play();
                 } catch (Throwable e) {
                     Log.w(TAG, "Error playing ringtone, stream " + mStreamType, e);
diff --git a/core/java/android/provider/CallLog.java b/core/java/android/provider/CallLog.java
index f023df7..266922d 100644
--- a/core/java/android/provider/CallLog.java
+++ b/core/java/android/provider/CallLog.java
@@ -33,7 +33,9 @@
 import android.provider.ContactsContract.CommonDataKinds.Phone;
 import android.provider.ContactsContract.Data;
 import android.provider.ContactsContract.DataUsageFeedback;
+import android.telecom.PhoneAccount;
 import android.telecom.PhoneAccountHandle;
+import android.telecom.TelecomManager;
 import android.telephony.PhoneNumberUtils;
 import android.text.TextUtils;
 
@@ -336,22 +338,33 @@
         // that was encoded into call log databases.
 
         /**
-         * The component name of the account in string form.
+         * The component name of the account used to place or receive the call; in string form.
          * <P>Type: TEXT</P>
          */
         public static final String PHONE_ACCOUNT_COMPONENT_NAME = "subscription_component_name";
 
         /**
-         * The identifier of a account that is unique to a specified component.
+         * The identifier for the account used to place or receive the call.
          * <P>Type: TEXT</P>
          */
         public static final String PHONE_ACCOUNT_ID = "subscription_id";
 
         /**
-         * The identifier of a account that is unique to a specified component. Equivalent value
-         * to {@link #PHONE_ACCOUNT_ID}. For ContactsProvider internal use only.
+         * The address associated with the account used to place or receive the call; in string
+         * form. For SIM-based calls, this is the user's own phone number.
+         * <P>Type: TEXT</P>
+         *
+         * @hide
+         */
+        public static final String PHONE_ACCOUNT_ADDRESS = "phone_account_address";
+
+        /**
+         * The subscription ID used to place this call.  This is no longer used and has been
+         * replaced with PHONE_ACCOUNT_COMPONENT_NAME/PHONE_ACCOUNT_ID.
+         * For ContactsProvider internal use only.
          * <P>Type: INTEGER</P>
          *
+         * @Deprecated
          * @hide
          */
         public static final String SUB_ID = "sub_id";
@@ -422,6 +435,19 @@
             final ContentResolver resolver = context.getContentResolver();
             int numberPresentation = PRESENTATION_ALLOWED;
 
+            TelecomManager tm = null;
+            try {
+                tm = TelecomManager.from(context);
+            } catch (UnsupportedOperationException e) {}
+
+            String accountAddress = null;
+            if (tm != null && accountHandle != null) {
+                PhoneAccount account = tm.getPhoneAccount(accountHandle);
+                if (account != null) {
+                    accountAddress = account.getSubscriptionAddress().getSchemeSpecificPart();
+                }
+            }
+
             // Remap network specified number presentation types
             // PhoneConstants.PRESENTATION_xxx to calllog number presentation types
             // Calls.PRESENTATION_xxx, in order to insulate the persistent calllog
@@ -463,6 +489,7 @@
             }
             values.put(PHONE_ACCOUNT_COMPONENT_NAME, accountComponentString);
             values.put(PHONE_ACCOUNT_ID, accountId);
+            values.put(PHONE_ACCOUNT_ADDRESS, accountAddress);
             values.put(NEW, Integer.valueOf(1));
 
             if (callType == MISSED_TYPE) {
diff --git a/core/java/android/text/TextUtils.java b/core/java/android/text/TextUtils.java
index 48bb5dd..1bb35f6 100644
--- a/core/java/android/text/TextUtils.java
+++ b/core/java/android/text/TextUtils.java
@@ -16,6 +16,7 @@
 
 package android.text;
 
+import android.annotation.Nullable;
 import android.content.res.Resources;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -457,7 +458,7 @@
      * @param str the string to be examined
      * @return true if str is null or zero length
      */
-    public static boolean isEmpty(CharSequence str) {
+    public static boolean isEmpty(@Nullable CharSequence str) {
         if (str == null || str.length() == 0)
             return true;
         else
diff --git a/core/java/android/view/Choreographer.java b/core/java/android/view/Choreographer.java
index f41afcf..c8149d9 100644
--- a/core/java/android/view/Choreographer.java
+++ b/core/java/android/view/Choreographer.java
@@ -141,6 +141,19 @@
     private long mFrameIntervalNanos;
 
     /**
+     * Contains information about the current frame for jank-tracking,
+     * mainly timings of key events along with a bit of metadata about
+     * view tree state
+     *
+     * TODO: Is there a better home for this? Currently Choreographer
+     * is the only one with CALLBACK_ANIMATION start time, hence why this
+     * resides here.
+     *
+     * @hide
+     */
+    FrameInfo mFrameInfo = new FrameInfo();
+
+    /**
      * Callback type: Input callback.  Runs first.
      * @hide
      */
@@ -513,6 +526,7 @@
                 return; // no work to do
             }
 
+            long intendedFrameTimeNanos = frameTimeNanos;
             startNanos = System.nanoTime();
             final long jitterNanos = startNanos - frameTimeNanos;
             if (jitterNanos >= mFrameIntervalNanos) {
@@ -541,12 +555,18 @@
                 return;
             }
 
+            mFrameInfo.setVsync(intendedFrameTimeNanos, frameTimeNanos);
             mFrameScheduled = false;
             mLastFrameTimeNanos = frameTimeNanos;
         }
 
+        mFrameInfo.markInputHandlingStart();
         doCallbacks(Choreographer.CALLBACK_INPUT, frameTimeNanos);
+
+        mFrameInfo.markAnimationsStart();
         doCallbacks(Choreographer.CALLBACK_ANIMATION, frameTimeNanos);
+
+        mFrameInfo.markPerformTraversalsStart();
         doCallbacks(Choreographer.CALLBACK_TRAVERSAL, frameTimeNanos);
 
         if (DEBUG) {
diff --git a/core/java/android/view/FrameInfo.java b/core/java/android/view/FrameInfo.java
new file mode 100644
index 0000000..c79547c
--- /dev/null
+++ b/core/java/android/view/FrameInfo.java
@@ -0,0 +1,118 @@
+/*
+ * 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 android.view;
+
+import android.annotation.IntDef;
+
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+/**
+ * Class that contains all the timing information for the current frame. This
+ * is used in conjunction with the hardware renderer to provide
+ * continous-monitoring jank events
+ *
+ * All times in nanoseconds from CLOCK_MONOTONIC/System.nanoTime()
+ *
+ * To minimize overhead from System.nanoTime() calls we infer durations of
+ * things by knowing the ordering of the events. For example, to know how
+ * long layout & measure took it's displayListRecordStart - performTraversalsStart.
+ *
+ * These constants must be kept in sync with FrameInfo.h in libhwui and are
+ * used for indexing into AttachInfo's mFrameInfo long[], which is intended
+ * to be quick to pass down to native via JNI, hence a pre-packed format
+ *
+ * @hide
+ */
+final class FrameInfo {
+
+    long[] mFrameInfo = new long[9];
+
+    // Various flags set to provide extra metadata about the current frame
+    private static final int FLAGS = 0;
+
+    // Is this the first-draw following a window layout?
+    public static final long FLAG_WINDOW_LAYOUT_CHANGED = 1;
+
+    @IntDef(flag = true, value = {
+            FLAG_WINDOW_LAYOUT_CHANGED })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface FrameInfoFlags {}
+
+    // The intended vsync time, unadjusted by jitter
+    private static final int INTENDED_VSYNC = 1;
+
+    // Jitter-adjusted vsync time, this is what was used as input into the
+    // animation & drawing system
+    private static final int VSYNC = 2;
+
+    // The time of the oldest input event
+    private static final int OLDEST_INPUT_EVENT = 3;
+
+    // The time of the newest input event
+    private static final int NEWEST_INPUT_EVENT = 4;
+
+    // When input event handling started
+    private static final int HANDLE_INPUT_START = 5;
+
+    // When animation evaluations started
+    private static final int ANIMATION_START = 6;
+
+    // When ViewRootImpl#performTraversals() started
+    private static final int PERFORM_TRAVERSALS_START = 7;
+
+    // When View:draw() started
+    private static final int DRAW_START = 8;
+
+    public void setVsync(long intendedVsync, long usedVsync) {
+        mFrameInfo[INTENDED_VSYNC] = intendedVsync;
+        mFrameInfo[VSYNC] = usedVsync;
+        mFrameInfo[OLDEST_INPUT_EVENT] = Long.MAX_VALUE;
+        mFrameInfo[NEWEST_INPUT_EVENT] = 0;
+        mFrameInfo[FLAGS] = 0;
+    }
+
+    public void updateInputEventTime(long inputEventTime, long inputEventOldestTime) {
+        if (inputEventOldestTime < mFrameInfo[OLDEST_INPUT_EVENT]) {
+            mFrameInfo[OLDEST_INPUT_EVENT] = inputEventOldestTime;
+        }
+        if (inputEventTime > mFrameInfo[NEWEST_INPUT_EVENT]) {
+            mFrameInfo[NEWEST_INPUT_EVENT] = inputEventTime;
+        }
+    }
+
+    public void markInputHandlingStart() {
+        mFrameInfo[HANDLE_INPUT_START] = System.nanoTime();
+    }
+
+    public void markAnimationsStart() {
+        mFrameInfo[ANIMATION_START] = System.nanoTime();
+    }
+
+    public void markPerformTraversalsStart() {
+        mFrameInfo[PERFORM_TRAVERSALS_START] = System.nanoTime();
+    }
+
+    public void markDrawStart() {
+        mFrameInfo[DRAW_START] = System.nanoTime();
+    }
+
+    public void addFlags(@FrameInfoFlags long flags) {
+        mFrameInfo[FLAGS] |= flags;
+    }
+
+}
diff --git a/core/java/android/view/HardwareRenderer.java b/core/java/android/view/HardwareRenderer.java
index c5c3f83..aa61885 100644
--- a/core/java/android/view/HardwareRenderer.java
+++ b/core/java/android/view/HardwareRenderer.java
@@ -278,7 +278,7 @@
     /**
      * Outputs extra debugging information in the specified file descriptor.
      */
-    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd);
+    abstract void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args);
 
     /**
      * Loads system properties used by the renderer. This method is invoked
diff --git a/core/java/android/view/PhoneWindow.java b/core/java/android/view/PhoneWindow.java
index ca8a68a..c1498ec 100644
--- a/core/java/android/view/PhoneWindow.java
+++ b/core/java/android/view/PhoneWindow.java
@@ -25,7 +25,9 @@
 import android.app.ActivityManagerNative;
 import android.app.SearchManager;
 import android.os.UserHandle;
+
 import com.android.internal.R;
+import com.android.internal.view.ActionModeWrapper;
 import com.android.internal.view.RootViewSurfaceTaker;
 import com.android.internal.view.StandaloneActionMode;
 import com.android.internal.view.menu.ContextMenuBuilder;
@@ -2689,72 +2691,78 @@
             if (mode != null) {
                 mActionMode = mode;
             } else {
-                if (mActionModeView == null) {
-                    if (isFloating()) {
-                        // Use the action bar theme.
-                        final TypedValue outValue = new TypedValue();
-                        final Theme baseTheme = mContext.getTheme();
-                        baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
-
-                        final Context actionBarContext;
-                        if (outValue.resourceId != 0) {
-                            final Theme actionBarTheme = mContext.getResources().newTheme();
-                            actionBarTheme.setTo(baseTheme);
-                            actionBarTheme.applyStyle(outValue.resourceId, true);
-
-                            actionBarContext = new ContextThemeWrapper(mContext, 0);
-                            actionBarContext.getTheme().setTo(actionBarTheme);
-                        } else {
-                            actionBarContext = mContext;
-                        }
-
-                        mActionModeView = new ActionBarContextView(actionBarContext);
-                        mActionModePopup = new PopupWindow(actionBarContext, null,
-                                R.attr.actionModePopupWindowStyle);
-                        mActionModePopup.setWindowLayoutType(
-                                WindowManager.LayoutParams.TYPE_APPLICATION);
-                        mActionModePopup.setContentView(mActionModeView);
-                        mActionModePopup.setWidth(MATCH_PARENT);
-
-                        actionBarContext.getTheme().resolveAttribute(
-                                R.attr.actionBarSize, outValue, true);
-                        final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
-                                actionBarContext.getResources().getDisplayMetrics());
-                        mActionModeView.setContentHeight(height);
-                        mActionModePopup.setHeight(WRAP_CONTENT);
-                        mShowActionModePopup = new Runnable() {
-                            public void run() {
-                                mActionModePopup.showAtLocation(
-                                        mActionModeView.getApplicationWindowToken(),
-                                        Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
-                            }
-                        };
-                    } else {
-                        ViewStub stub = (ViewStub) findViewById(
-                                R.id.action_mode_bar_stub);
-                        if (stub != null) {
-                            mActionModeView = (ActionBarContextView) stub.inflate();
-                        }
-                    }
-                }
-
                 if (mActionModeView != null) {
                     mActionModeView.killMode();
-                    mode = new StandaloneActionMode(mActionModeView.getContext(), mActionModeView,
-                            wrappedCallback, mActionModePopup == null);
-                    if (callback.onCreateActionMode(mode, mode.getMenu())) {
-                        mode.invalidate();
-                        mActionModeView.initForMode(mode);
-                        mActionModeView.setVisibility(View.VISIBLE);
-                        mActionMode = mode;
-                        if (mActionModePopup != null) {
-                            post(mShowActionModePopup);
+                }
+                ActionModeWrapper wrapperMode =
+                        new ActionModeWrapper(mContext, wrappedCallback);
+                if (callback.onCreateActionMode(wrapperMode, wrapperMode.getMenu())) {
+                    if (wrapperMode.getType() == ActionMode.TYPE_PRIMARY) {
+                        if (mActionModeView == null) {
+                            if (isFloating()) {
+                                // Use the action bar theme.
+                                final TypedValue outValue = new TypedValue();
+                                final Theme baseTheme = mContext.getTheme();
+                                baseTheme.resolveAttribute(R.attr.actionBarTheme, outValue, true);
+
+                                final Context actionBarContext;
+                                if (outValue.resourceId != 0) {
+                                    final Theme actionBarTheme = mContext.getResources().newTheme();
+                                    actionBarTheme.setTo(baseTheme);
+                                    actionBarTheme.applyStyle(outValue.resourceId, true);
+
+                                    actionBarContext = new ContextThemeWrapper(mContext, 0);
+                                    actionBarContext.getTheme().setTo(actionBarTheme);
+                                } else {
+                                    actionBarContext = mContext;
+                                }
+
+                                mActionModeView = new ActionBarContextView(actionBarContext);
+                                mActionModePopup = new PopupWindow(actionBarContext, null,
+                                        R.attr.actionModePopupWindowStyle);
+                                mActionModePopup.setWindowLayoutType(
+                                        WindowManager.LayoutParams.TYPE_APPLICATION);
+                                mActionModePopup.setContentView(mActionModeView);
+                                mActionModePopup.setWidth(MATCH_PARENT);
+
+                                actionBarContext.getTheme().resolveAttribute(
+                                        R.attr.actionBarSize, outValue, true);
+                                final int height = TypedValue.complexToDimensionPixelSize(outValue.data,
+                                        actionBarContext.getResources().getDisplayMetrics());
+                                mActionModeView.setContentHeight(height);
+                                mActionModePopup.setHeight(WRAP_CONTENT);
+                                mShowActionModePopup = new Runnable() {
+                                    public void run() {
+                                        mActionModePopup.showAtLocation(
+                                                mActionModeView.getApplicationWindowToken(),
+                                                Gravity.TOP | Gravity.FILL_HORIZONTAL, 0, 0);
+                                    }
+                                };
+                            } else {
+                                ViewStub stub = (ViewStub) findViewById(
+                                        R.id.action_mode_bar_stub);
+                                if (stub != null) {
+                                    mActionModeView = (ActionBarContextView) stub.inflate();
+                                }
+                            }
                         }
-                        mActionModeView.sendAccessibilityEvent(
-                                AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
-                    } else {
-                        mActionMode = null;
+                        if (mActionModeView != null) {
+                            wrapperMode.setActionModeView(mActionModeView);
+                            wrapperMode.setFocusable(mActionModePopup == null);
+                            wrapperMode.lockType();
+                            wrapperMode.invalidate();
+                            mActionModeView.initForMode(wrapperMode);
+                            mActionModeView.setVisibility(View.VISIBLE);
+                            mActionMode = wrapperMode;
+                            if (mActionModePopup != null) {
+                                post(mShowActionModePopup);
+                            }
+                            mActionModeView.sendAccessibilityEvent(
+                                    AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED);
+                        }
                     }
+                } else {
+                    mActionMode = null;
                 }
             }
             if (mActionMode != null && getCallback() != null && !isDestroyed()) {
diff --git a/core/java/android/view/ThreadedRenderer.java b/core/java/android/view/ThreadedRenderer.java
index ad4a048..df0838f 100644
--- a/core/java/android/view/ThreadedRenderer.java
+++ b/core/java/android/view/ThreadedRenderer.java
@@ -16,8 +16,7 @@
 
 package android.view;
 
-import com.android.internal.R;
-
+import android.annotation.IntDef;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
@@ -27,16 +26,18 @@
 import android.os.IBinder;
 import android.os.RemoteException;
 import android.os.ServiceManager;
-import android.os.SystemProperties;
 import android.os.Trace;
 import android.util.Log;
 import android.util.LongSparseArray;
-import android.util.TimeUtils;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
 
+import com.android.internal.R;
+
 import java.io.FileDescriptor;
 import java.io.PrintWriter;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
 import java.util.ArrayList;
 import java.util.HashSet;
 
@@ -74,6 +75,14 @@
         PROFILE_PROPERTY_VISUALIZE_BARS,
     };
 
+    private static final int FLAG_DUMP_FRAMESTATS   = 1 << 0;
+    private static final int FLAG_DUMP_RESET        = 1 << 1;
+
+    @IntDef(flag = true, value = {
+            FLAG_DUMP_FRAMESTATS, FLAG_DUMP_RESET })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface DumpFlags {}
+
     // Size of the rendered content.
     private int mWidth, mHeight;
 
@@ -93,12 +102,12 @@
     private final float mLightRadius;
     private final int mAmbientShadowAlpha;
     private final int mSpotShadowAlpha;
+    private final float mDensity;
 
     private long mNativeProxy;
     private boolean mInitialized = false;
     private RenderNode mRootNode;
     private Choreographer mChoreographer;
-    private boolean mProfilingEnabled;
     private boolean mRootNodeNeedsUpdate;
 
     ThreadedRenderer(Context context, boolean translucent) {
@@ -110,6 +119,7 @@
                 (int) (255 * a.getFloat(R.styleable.Lighting_ambientShadowAlpha, 0) + 0.5f);
         mSpotShadowAlpha = (int) (255 * a.getFloat(R.styleable.Lighting_spotShadowAlpha, 0) + 0.5f);
         a.recycle();
+        mDensity = context.getResources().getDisplayMetrics().density;
 
         long rootNodePtr = nCreateRootRenderNode();
         mRootNode = RenderNode.adopt(rootNodePtr);
@@ -214,7 +224,7 @@
         mRootNode.setLeftTopRightBottom(-mInsetLeft, -mInsetTop, mSurfaceWidth, mSurfaceHeight);
         nSetup(mNativeProxy, mSurfaceWidth, mSurfaceHeight,
                 lightX, mLightY, mLightZ, mLightRadius,
-                mAmbientShadowAlpha, mSpotShadowAlpha);
+                mAmbientShadowAlpha, mSpotShadowAlpha, mDensity);
     }
 
     @Override
@@ -233,32 +243,25 @@
     }
 
     @Override
-    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd) {
+    void dumpGfxInfo(PrintWriter pw, FileDescriptor fd, String[] args) {
         pw.flush();
-        nDumpProfileInfo(mNativeProxy, fd);
-    }
-
-    private static int search(String[] values, String value) {
-        for (int i = 0; i < values.length; i++) {
-            if (values[i].equals(value)) return i;
+        int flags = 0;
+        for (int i = 0; i < args.length; i++) {
+            switch (args[i]) {
+                case "framestats":
+                    flags |= FLAG_DUMP_FRAMESTATS;
+                    break;
+                case "reset":
+                    flags |= FLAG_DUMP_RESET;
+                    break;
+            }
         }
-        return -1;
-    }
-
-    private static boolean checkIfProfilingRequested() {
-        String profiling = SystemProperties.get(HardwareRenderer.PROFILE_PROPERTY);
-        int graphType = search(VISUALIZERS, profiling);
-        return (graphType >= 0) || Boolean.parseBoolean(profiling);
+        nDumpProfileInfo(mNativeProxy, fd, flags);
     }
 
     @Override
     boolean loadSystemProperties() {
         boolean changed = nLoadSystemProperties(mNativeProxy);
-        boolean wantProfiling = checkIfProfilingRequested();
-        if (wantProfiling != mProfilingEnabled) {
-            mProfilingEnabled = wantProfiling;
-            changed = true;
-        }
         if (changed) {
             invalidateRoot();
         }
@@ -307,20 +310,12 @@
     @Override
     void draw(View view, AttachInfo attachInfo, HardwareDrawCallbacks callbacks) {
         attachInfo.mIgnoreDirtyState = true;
-        long frameTimeNanos = mChoreographer.getFrameTimeNanos();
-        attachInfo.mDrawingTime = frameTimeNanos / TimeUtils.NANOS_PER_MS;
 
-        long recordDuration = 0;
-        if (mProfilingEnabled) {
-            recordDuration = System.nanoTime();
-        }
+        final Choreographer choreographer = attachInfo.mViewRootImpl.mChoreographer;
+        choreographer.mFrameInfo.markDrawStart();
 
         updateRootDisplayList(view, callbacks);
 
-        if (mProfilingEnabled) {
-            recordDuration = System.nanoTime() - recordDuration;
-        }
-
         attachInfo.mIgnoreDirtyState = false;
 
         // register animating rendernodes which started animating prior to renderer
@@ -337,8 +332,8 @@
             attachInfo.mPendingAnimatingRenderNodes = null;
         }
 
-        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameTimeNanos,
-                recordDuration, view.getResources().getDisplayMetrics().density);
+        final long[] frameInfo = choreographer.mFrameInfo.mFrameInfo;
+        int syncResult = nSyncAndDrawFrame(mNativeProxy, frameInfo, frameInfo.length);
         if ((syncResult & SYNC_LOST_SURFACE_REWARD_IF_FOUND) != 0) {
             setEnabled(false);
             attachInfo.mViewRootImpl.mSurface.release();
@@ -500,10 +495,9 @@
     private static native boolean nPauseSurface(long nativeProxy, Surface window);
     private static native void nSetup(long nativeProxy, int width, int height,
             float lightX, float lightY, float lightZ, float lightRadius,
-            int ambientShadowAlpha, int spotShadowAlpha);
+            int ambientShadowAlpha, int spotShadowAlpha, float density);
     private static native void nSetOpaque(long nativeProxy, boolean opaque);
-    private static native int nSyncAndDrawFrame(long nativeProxy,
-            long frameTimeNanos, long recordDuration, float density);
+    private static native int nSyncAndDrawFrame(long nativeProxy, long[] frameInfo, int size);
     private static native void nDestroy(long nativeProxy);
     private static native void nRegisterAnimatingRenderNode(long rootRenderNode, long animatingNode);
 
@@ -523,5 +517,6 @@
     private static native void nStopDrawing(long nativeProxy);
     private static native void nNotifyFramePending(long nativeProxy);
 
-    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd);
+    private static native void nDumpProfileInfo(long nativeProxy, FileDescriptor fd,
+            @DumpFlags int dumpFlags);
 }
diff --git a/core/java/android/view/ViewRootImpl.java b/core/java/android/view/ViewRootImpl.java
index 24fae8a..f392682 100644
--- a/core/java/android/view/ViewRootImpl.java
+++ b/core/java/android/view/ViewRootImpl.java
@@ -56,6 +56,7 @@
 import android.util.DisplayMetrics;
 import android.util.Log;
 import android.util.Slog;
+import android.util.TimeUtils;
 import android.util.TypedValue;
 import android.view.Surface.OutOfResourcesException;
 import android.view.View.AttachInfo;
@@ -1342,7 +1343,7 @@
 
         boolean insetsChanged = false;
 
-        boolean layoutRequested = mLayoutRequested && !mStopped;
+        boolean layoutRequested = mLayoutRequested && (!mStopped || mReportNextDraw);
         if (layoutRequested) {
 
             final Resources res = mView.getContext().getResources();
@@ -1513,6 +1514,7 @@
                         // to resume them
                         mDirty.set(0, 0, mWidth, mHeight);
                     }
+                    mChoreographer.mFrameInfo.addFlags(FrameInfo.FLAG_WINDOW_LAYOUT_CHANGED);
                 }
                 final int surfaceGenerationId = mSurface.getGenerationId();
                 relayoutResult = relayoutWindow(params, viewVisibility, insetsPending);
@@ -1774,7 +1776,7 @@
                 }
             }
 
-            if (!mStopped) {
+            if (!mStopped || mReportNextDraw) {
                 boolean focusChangedDueToTouchMode = ensureTouchModeLocally(
                         (relayoutResult&WindowManagerGlobal.RELAYOUT_RES_IN_TOUCH_MODE) != 0);
                 if (focusChangedDueToTouchMode || mWidth != host.getMeasuredWidth()
@@ -1847,7 +1849,7 @@
             }
         }
 
-        final boolean didLayout = layoutRequested && !mStopped;
+        final boolean didLayout = layoutRequested && (!mStopped || mReportNextDraw);
         boolean triggerGlobalLayoutListener = didLayout
                 || mAttachInfo.mRecomputeGlobalAttributes;
         if (didLayout) {
@@ -2516,6 +2518,9 @@
             }
         }
 
+        mAttachInfo.mDrawingTime =
+                mChoreographer.getFrameTimeNanos() / TimeUtils.NANOS_PER_MS;
+
         if (!dirty.isEmpty() || mIsAnimating || accessibilityFocusDirty) {
             if (mAttachInfo.mHardwareRenderer != null && mAttachInfo.mHardwareRenderer.isEnabled()) {
                 // If accessibility focus moved, always invalidate the root.
@@ -2635,7 +2640,6 @@
 
             dirty.setEmpty();
             mIsAnimating = false;
-            attachInfo.mDrawingTime = SystemClock.uptimeMillis();
             mView.mPrivateFlags |= View.PFLAG_DRAWN;
 
             if (DEBUG_DRAW) {
@@ -5789,6 +5793,16 @@
             Trace.traceCounter(Trace.TRACE_TAG_INPUT, mPendingInputEventQueueLengthCounterName,
                     mPendingInputEventCount);
 
+            long eventTime = q.mEvent.getEventTimeNano();
+            long oldestEventTime = eventTime;
+            if (q.mEvent instanceof MotionEvent) {
+                MotionEvent me = (MotionEvent)q.mEvent;
+                if (me.getHistorySize() > 0) {
+                    oldestEventTime = me.getHistoricalEventTimeNano(0);
+                }
+            }
+            mChoreographer.mFrameInfo.updateInputEventTime(eventTime, oldestEventTime);
+
             deliverInputEvent(q);
         }
 
diff --git a/core/java/android/view/WindowManagerGlobal.java b/core/java/android/view/WindowManagerGlobal.java
index 279627a..1cebe3f 100644
--- a/core/java/android/view/WindowManagerGlobal.java
+++ b/core/java/android/view/WindowManagerGlobal.java
@@ -492,7 +492,7 @@
         }
     }
 
-    public void dumpGfxInfo(FileDescriptor fd) {
+    public void dumpGfxInfo(FileDescriptor fd, String[] args) {
         FileOutputStream fout = new FileOutputStream(fd);
         PrintWriter pw = new FastPrintWriter(fout);
         try {
@@ -509,7 +509,7 @@
                     HardwareRenderer renderer =
                             root.getView().mAttachInfo.mHardwareRenderer;
                     if (renderer != null) {
-                        renderer.dumpGfxInfo(pw, fd);
+                        renderer.dumpGfxInfo(pw, fd, args);
                     }
                 }
 
diff --git a/core/java/android/view/WindowManagerPolicy.java b/core/java/android/view/WindowManagerPolicy.java
index 3f35612..9199af1 100644
--- a/core/java/android/view/WindowManagerPolicy.java
+++ b/core/java/android/view/WindowManagerPolicy.java
@@ -365,6 +365,11 @@
          * @return true if window is on default display.
          */
         public boolean isDefaultDisplay();
+
+        /**
+         * Check whether the window is currently dimming.
+         */
+        public boolean isDimming();
     }
 
     /**
diff --git a/core/java/android/view/inputmethod/InputMethodSubtype.java b/core/java/android/view/inputmethod/InputMethodSubtype.java
index 1671faa..c2f3777 100644
--- a/core/java/android/view/inputmethod/InputMethodSubtype.java
+++ b/core/java/android/view/inputmethod/InputMethodSubtype.java
@@ -23,6 +23,8 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.inputmethod.InputMethodUtils;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -379,7 +381,7 @@
      */
     public CharSequence getDisplayName(
             Context context, String packageName, ApplicationInfo appInfo) {
-        final Locale locale = constructLocaleFromString(mSubtypeLocale);
+        final Locale locale = InputMethodUtils.constructLocaleFromString(mSubtypeLocale);
         final String localeStr = locale != null ? locale.getDisplayName() : mSubtypeLocale;
         if (mSubtypeNameResId == 0) {
             return localeStr;
@@ -503,22 +505,6 @@
         }
     };
 
-    private static Locale constructLocaleFromString(String localeStr) {
-        if (TextUtils.isEmpty(localeStr))
-            return null;
-        String[] localeParams = localeStr.split("_", 3);
-        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
-        // because localeStr is not empty.
-        if (localeParams.length == 1) {
-            return new Locale(localeParams[0]);
-        } else if (localeParams.length == 2) {
-            return new Locale(localeParams[0], localeParams[1]);
-        } else if (localeParams.length == 3) {
-            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
-        }
-        return null;
-    }
-
     private static int hashCodeInternal(String locale, String mode, String extraValue,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
             boolean isAsciiCapable) {
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index 4752594..8601d2b 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -50,6 +50,7 @@
 import android.inputmethodservice.ExtractEditText;
 import android.os.Bundle;
 import android.os.Handler;
+import android.os.ParcelableParcel;
 import android.os.SystemClock;
 import android.provider.Settings;
 import android.text.DynamicLayout;
@@ -118,15 +119,18 @@
  */
 public class Editor {
     private static final String TAG = "Editor";
-    static final boolean DEBUG_UNDO = false;
+    private static final boolean DEBUG_UNDO = false;
 
     static final int BLINK = 500;
     private static final float[] TEMP_POSITION = new float[2];
     private static int DRAG_SHADOW_MAX_TEXT_LENGTH = 20;
+    // Tag used when the Editor maintains its own separate UndoManager.
+    private static final String UNDO_OWNER_TAG = "Editor";
 
-    UndoManager mUndoManager;
-    UndoOwner mUndoOwner;
-    InputFilter mUndoInputFilter;
+    // Each Editor manages its own undo stack.
+    private final UndoManager mUndoManager = new UndoManager();
+    private UndoOwner mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
+    final InputFilter mUndoInputFilter = new UndoInputFilter(this);
 
     // Cursor Controllers.
     InsertionPointCursorController mInsertionPointCursorController;
@@ -222,6 +226,39 @@
 
     Editor(TextView textView) {
         mTextView = textView;
+        // Synchronize the filter list, which places the undo input filter at the end.
+        mTextView.setFilters(mTextView.getFilters());
+    }
+
+    ParcelableParcel saveInstanceState() {
+        // For now there is only undo state.
+        return (ParcelableParcel) mUndoManager.saveInstanceState();
+    }
+
+    void restoreInstanceState(ParcelableParcel state) {
+        mUndoManager.restoreInstanceState(state);
+        // Re-associate this object as the owner of undo state.
+        mUndoOwner = mUndoManager.getOwner(UNDO_OWNER_TAG, this);
+    }
+
+    boolean canUndo() {
+        UndoOwner[] owners = { mUndoOwner };
+        return mUndoManager.countUndos(owners) > 0;
+    }
+
+    boolean canRedo() {
+        UndoOwner[] owners = { mUndoOwner };
+        return mUndoManager.countRedos(owners) > 0;
+    }
+
+    void undo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.undo(owners, 1);  // Undo 1 action.
+    }
+
+    void redo() {
+        UndoOwner[] owners = { mUndoOwner };
+        mUndoManager.redo(owners, 1);  // Redo 1 action.
     }
 
     void onAttachedToWindow() {
@@ -1706,7 +1743,7 @@
 
     /**
      * Called by the framework in response to a text auto-correction (such as fixing a typo using a
-     * a dictionnary) from the current input method, provided by it calling
+     * a dictionary) from the current input method, provided by it calling
      * {@link InputConnection#commitCorrection} InputConnection.commitCorrection()}. The default
      * implementation flashes the background of the corrected word to provide feedback to the user.
      *
@@ -4161,8 +4198,12 @@
         int mChangedStart, mChangedEnd, mChangedDelta;
     }
 
+    /**
+     * An InputFilter that monitors text input to maintain undo history. It does not modify the
+     * text being typed (and hence always returns null from the filter() method).
+     */
     public static class UndoInputFilter implements InputFilter {
-        final Editor mEditor;
+        private final Editor mEditor;
 
         public UndoInputFilter(Editor editor) {
             mEditor = editor;
@@ -4192,6 +4233,8 @@
                     // The current operation is an add...  are we adding more?  We are adding
                     // more if we are either appending new text to the end of the last edit or
                     // completely replacing some or all of the last edit.
+                    // TODO: This sequence doesn't work right: a, left-arrow, b, undo, undo.
+                    // The two edits are incorrectly merged, so there is only one undo available.
                     if (start < end && ((dstart >= op.mRangeStart && dend <= op.mRangeEnd)
                             || (dstart == op.mRangeEnd && dend == op.mRangeEnd))) {
                         op.mRangeEnd = dstart + (end-start);
@@ -4245,7 +4288,10 @@
         }
     }
 
-    public static class TextModifyOperation extends UndoOperation<TextView> {
+    /**
+     * An operation to undo a single "edit" to a text view.
+     */
+    public static class TextModifyOperation extends UndoOperation<Editor> {
         int mRangeStart, mRangeEnd;
         CharSequence mOldText;
 
@@ -4277,8 +4323,8 @@
         private void swapText() {
             // Both undo and redo involves swapping the contents of the range
             // in the text view with our local text.
-            TextView tv = getOwnerData();
-            Editable editable = (Editable)tv.getText();
+            Editor editor = getOwnerData();
+            Editable editable = (Editable)editor.mTextView.getText();
             CharSequence curText;
             if (mRangeStart >= mRangeEnd) {
                 curText = null;
@@ -4309,14 +4355,17 @@
 
         public static final Parcelable.ClassLoaderCreator<TextModifyOperation> CREATOR
                 = new Parcelable.ClassLoaderCreator<TextModifyOperation>() {
+            @Override
             public TextModifyOperation createFromParcel(Parcel in) {
                 return new TextModifyOperation(in, null);
             }
 
+            @Override
             public TextModifyOperation createFromParcel(Parcel in, ClassLoader loader) {
                 return new TextModifyOperation(in, loader);
             }
 
+            @Override
             public TextModifyOperation[] newArray(int size) {
                 return new TextModifyOperation[size];
             }
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index f33ef75..9297731 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -47,6 +47,7 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
+import android.os.ParcelableParcel;
 import android.os.SystemClock;
 import android.os.UserHandle;
 import android.provider.Settings;
@@ -1612,7 +1613,8 @@
      * @hide
      */
     public final UndoManager getUndoManager() {
-        return mEditor == null ? null : mEditor.mUndoManager;
+        // TODO: Consider supporting a global undo manager.
+        throw new UnsupportedOperationException("not implemented");
     }
 
     /**
@@ -1630,22 +1632,12 @@
      * @hide
      */
     public final void setUndoManager(UndoManager undoManager, String tag) {
-        if (undoManager != null) {
-            createEditorIfNeeded();
-            mEditor.mUndoManager = undoManager;
-            mEditor.mUndoOwner = undoManager.getOwner(tag, this);
-            mEditor.mUndoInputFilter = new Editor.UndoInputFilter(mEditor);
-            if (!(mText instanceof Editable)) {
-                setText(mText, BufferType.EDITABLE);
-            }
-
-            setFilters((Editable) mText, mFilters);
-        } else if (mEditor != null) {
-            // XXX need to destroy all associated state.
-            mEditor.mUndoManager = null;
-            mEditor.mUndoOwner = null;
-            mEditor.mUndoInputFilter = null;
-        }
+        // TODO: Consider supporting a global undo manager. An implementation will need to:
+        // * createEditorIfNeeded()
+        // * Promote to BufferType.EDITABLE if needed.
+        // * Update the UndoManager and UndoOwner.
+        // Likewise it will need to be able to restore the default UndoManager.
+        throw new UnsupportedOperationException("not implemented");
     }
 
     /**
@@ -3899,6 +3891,9 @@
 
             ss.error = getError();
 
+            if (mEditor != null) {
+                ss.editorState = mEditor.saveInstanceState();
+            }
             return ss;
         }
 
@@ -3968,6 +3963,11 @@
                 }
             });
         }
+
+        if (ss.editorState != null) {
+            createEditorIfNeeded();
+            mEditor.restoreInstanceState(ss.editorState);
+        }
     }
 
     /**
@@ -8375,14 +8375,19 @@
 
     @Override
     public boolean onKeyShortcut(int keyCode, KeyEvent event) {
-        final int filteredMetaState = event.getMetaState() & ~KeyEvent.META_CTRL_MASK;
-        if (KeyEvent.metaStateHasNoModifiers(filteredMetaState)) {
+        if (event.hasModifiers(KeyEvent.META_CTRL_ON)) {
+            // Handle Ctrl-only shortcuts.
             switch (keyCode) {
             case KeyEvent.KEYCODE_A:
                 if (canSelectText()) {
                     return onTextContextMenuItem(ID_SELECT_ALL);
                 }
                 break;
+            case KeyEvent.KEYCODE_Z:
+                if (canUndo()) {
+                    return onTextContextMenuItem(ID_UNDO);
+                }
+                break;
             case KeyEvent.KEYCODE_X:
                 if (canCut()) {
                     return onTextContextMenuItem(ID_CUT);
@@ -8399,6 +8404,15 @@
                 }
                 break;
             }
+        } else if (event.hasModifiers(KeyEvent.META_CTRL_ON | KeyEvent.META_SHIFT_ON)) {
+            // Handle Ctrl-Shift shortcuts.
+            switch (keyCode) {
+                case KeyEvent.KEYCODE_Z:
+                    if (canRedo()) {
+                        return onTextContextMenuItem(ID_REDO);
+                    }
+                    break;
+            }
         }
         return super.onKeyShortcut(keyCode, event);
     }
@@ -8775,6 +8789,8 @@
     }
 
     static final int ID_SELECT_ALL = android.R.id.selectAll;
+    static final int ID_UNDO = android.R.id.undo;
+    static final int ID_REDO = android.R.id.redo;
     static final int ID_CUT = android.R.id.cut;
     static final int ID_COPY = android.R.id.copy;
     static final int ID_PASTE = android.R.id.paste;
@@ -8805,6 +8821,18 @@
                 selectAllText();
                 return true;
 
+            case ID_UNDO:
+                if (mEditor != null) {
+                    mEditor.undo();
+                }
+                return true;  // Returns true even if nothing was undone.
+
+            case ID_REDO:
+                if (mEditor != null) {
+                    mEditor.redo();
+                }
+                return true;  // Returns true even if nothing was undone.
+
             case ID_PASTE:
                 paste(min, max);
                 return true;
@@ -8934,7 +8962,17 @@
      * @hide
      */
     protected void stopSelectionActionMode() {
-        mEditor.stopSelectionActionMode();
+        if (mEditor != null) {
+            mEditor.stopSelectionActionMode();
+        }
+    }
+
+    boolean canUndo() {
+        return mEditor != null && mEditor.canUndo();
+    }
+
+    boolean canRedo() {
+        return mEditor != null && mEditor.canRedo();
     }
 
     boolean canCut() {
@@ -9304,6 +9342,7 @@
         CharSequence text;
         boolean frozenWithFocus;
         CharSequence error;
+        ParcelableParcel editorState;  // Optional state from Editor.
 
         SavedState(Parcelable superState) {
             super(superState);
@@ -9323,6 +9362,13 @@
                 out.writeInt(1);
                 TextUtils.writeToParcel(error, out, flags);
             }
+
+            if (editorState == null) {
+                out.writeInt(0);
+            } else {
+                out.writeInt(1);
+                editorState.writeToParcel(out, flags);
+            }
         }
 
         @Override
@@ -9358,6 +9404,10 @@
             if (in.readInt() != 0) {
                 error = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             }
+
+            if (in.readInt() != 0) {
+                editorState = ParcelableParcel.CREATOR.createFromParcel(in);
+            }
         }
     }
 
diff --git a/core/java/com/android/internal/inputmethod/InputMethodUtils.java b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
index 183527c..9aa36d3 100644
--- a/core/java/com/android/internal/inputmethod/InputMethodUtils.java
+++ b/core/java/com/android/internal/inputmethod/InputMethodUtils.java
@@ -35,6 +35,8 @@
 import android.view.textservice.SpellCheckerInfo;
 import android.view.textservice.TextServicesManager;
 
+import com.android.internal.annotations.VisibleForTesting;
+
 import java.util.ArrayList;
 import java.util.Arrays;
 import java.util.HashMap;
@@ -409,6 +411,24 @@
         return false;
     }
 
+    public static Locale constructLocaleFromString(String localeStr) {
+        if (TextUtils.isEmpty(localeStr)) {
+            return null;
+        }
+        // TODO: Use {@link Locale#toLanguageTag()} and {@link Locale#forLanguageTag(languageTag)}.
+        String[] localeParams = localeStr.split("_", 3);
+        // The length of localeStr is guaranteed to always return a 1 <= value <= 3
+        // because localeStr is not empty.
+        if (localeParams.length == 1) {
+            return new Locale(localeParams[0]);
+        } else if (localeParams.length == 2) {
+            return new Locale(localeParams[0], localeParams[1]);
+        } else if (localeParams.length == 3) {
+            return new Locale(localeParams[0], localeParams[1], localeParams[2]);
+        }
+        return null;
+    }
+
     public static boolean containsSubtypeOf(final InputMethodInfo imi,
             @Nullable final Locale locale, final boolean checkCountry, final String mode) {
         if (locale == null) {
@@ -418,15 +438,16 @@
         for (int i = 0; i < N; ++i) {
             final InputMethodSubtype subtype = imi.getSubtypeAt(i);
             if (checkCountry) {
-                // TODO: Use {@link Locale#toLanguageTag()} and
-                // {@link Locale#forLanguageTag(languageTag)} instead.
-                if (!TextUtils.equals(subtype.getLocale(), locale.toString())) {
+                final Locale subtypeLocale = constructLocaleFromString(subtype.getLocale());
+                if (subtypeLocale == null ||
+                        !TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage()) ||
+                        !TextUtils.equals(subtypeLocale.getCountry(), locale.getCountry())) {
                     continue;
                 }
             } else {
                 final Locale subtypeLocale = new Locale(getLanguageFromLocaleString(
                         subtype.getLocale()));
-                if (!subtypeLocale.getLanguage().equals(locale.getLanguage())) {
+                if (!TextUtils.equals(subtypeLocale.getLanguage(), locale.getLanguage())) {
                     continue;
                 }
             }
@@ -518,7 +539,8 @@
         return NOT_A_SUBTYPE_ID;
     }
 
-    private static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
+    @VisibleForTesting
+    public static ArrayList<InputMethodSubtype> getImplicitlyApplicableSubtypesLocked(
             Resources res, InputMethodInfo imi) {
         final List<InputMethodSubtype> subtypes = InputMethodUtils.getSubtypes(imi);
         final String systemLocale = res.getConfiguration().locale.toString();
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 20bb95e..d0c7f8c 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -94,7 +94,7 @@
     private static final int MAGIC = 0xBA757475; // 'BATSTATS'
 
     // Current on-disk Parcel version
-    private static final int VERSION = 116 + (USE_OLD_HISTORY ? 1000 : 0);
+    private static final int VERSION = 118 + (USE_OLD_HISTORY ? 1000 : 0);
 
     // Maximum number of items we will record in the history.
     private static final int MAX_HISTORY_ITEMS = 2000;
@@ -208,7 +208,7 @@
     final HistoryItem mHistoryLastLastWritten = new HistoryItem();
     final HistoryItem mHistoryReadTmp = new HistoryItem();
     final HistoryItem mHistoryAddTmp = new HistoryItem();
-    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap<HistoryTag, Integer>();
+    final HashMap<HistoryTag, Integer> mHistoryTagPool = new HashMap();
     String[] mReadHistoryStrings;
     int[] mReadHistoryUids;
     int mReadHistoryChars;
@@ -227,6 +227,38 @@
     HistoryItem mHistoryLastEnd;
     HistoryItem mHistoryCache;
 
+    // Used by computeHistoryStepDetails
+    HistoryStepDetails mLastHistoryStepDetails = null;
+    byte mLastHistoryStepLevel = 0;
+    final HistoryStepDetails mCurHistoryStepDetails = new HistoryStepDetails();
+    final HistoryStepDetails mReadHistoryStepDetails = new HistoryStepDetails();
+    final HistoryStepDetails mTmpHistoryStepDetails = new HistoryStepDetails();
+    /**
+     * Total time (in 1/100 sec) spent executing in user code.
+     */
+    long mLastStepCpuUserTime;
+    long mCurStepCpuUserTime;
+    /**
+     * Total time (in 1/100 sec) spent executing in kernel code.
+     */
+    long mLastStepCpuSystemTime;
+    long mCurStepCpuSystemTime;
+    /**
+     * Times from /proc/stat
+     */
+    long mLastStepStatUserTime;
+    long mLastStepStatSystemTime;
+    long mLastStepStatIOWaitTime;
+    long mLastStepStatIrqTime;
+    long mLastStepStatSoftIrqTime;
+    long mLastStepStatIdleTime;
+    long mCurStepStatUserTime;
+    long mCurStepStatSystemTime;
+    long mCurStepStatIOWaitTime;
+    long mCurStepStatIrqTime;
+    long mCurStepStatSoftIrqTime;
+    long mCurStepStatIdleTime;
+
     private HistoryItem mHistoryIterator;
     private boolean mReadOverflow;
     private boolean mIteratingHistory;
@@ -1938,6 +1970,10 @@
     static final int STATE_BATTERY_PLUG_MASK    = 0x00000003;
     static final int STATE_BATTERY_PLUG_SHIFT   = 24;
 
+    // We use the low bit of the battery state int to indicate that we have full details
+    // from a battery level change.
+    static final int BATTERY_DELTA_LEVEL_FLAG   = 0x00000001;
+
     public void writeHistoryDelta(Parcel dest, HistoryItem cur, HistoryItem last) {
         if (last == null || cur.cmd != HistoryItem.CMD_UPDATE) {
             dest.writeInt(DELTA_TIME_ABS);
@@ -1958,7 +1994,11 @@
             deltaTimeToken = (int)deltaTime;
         }
         int firstToken = deltaTimeToken | (cur.states&DELTA_STATE_MASK);
-        final int batteryLevelInt = buildBatteryLevelInt(cur);
+        final int includeStepDetails = mLastHistoryStepLevel > cur.batteryLevel
+                ? BATTERY_DELTA_LEVEL_FLAG : 0;
+        final boolean computeStepDetails = includeStepDetails != 0
+                || mLastHistoryStepDetails == null;
+        final int batteryLevelInt = buildBatteryLevelInt(cur) | includeStepDetails;
         final boolean batteryLevelIntChanged = batteryLevelInt != lastBatteryLevelInt;
         if (batteryLevelIntChanged) {
             firstToken |= DELTA_BATTERY_LEVEL_FLAG;
@@ -2040,12 +2080,26 @@
                     + cur.eventTag.poolIdx + " " + cur.eventTag.uid + ":"
                     + cur.eventTag.string);
         }
+        if (computeStepDetails) {
+            computeHistoryStepDetails(mCurHistoryStepDetails, mLastHistoryStepDetails);
+            if (includeStepDetails != 0) {
+                mCurHistoryStepDetails.writeToParcel(dest);
+            }
+            cur.stepDetails = mCurHistoryStepDetails;
+            mLastHistoryStepDetails = mCurHistoryStepDetails;
+        } else {
+            cur.stepDetails = null;
+        }
+        if (mLastHistoryStepLevel < cur.batteryLevel) {
+            mLastHistoryStepDetails = null;
+        }
+        mLastHistoryStepLevel = cur.batteryLevel;
     }
 
     private int buildBatteryLevelInt(HistoryItem h) {
         return ((((int)h.batteryLevel)<<25)&0xfe000000)
-                | ((((int)h.batteryTemperature)<<14)&0x01ffc000)
-                | (((int)h.batteryVoltage)&0x00003fff);
+                | ((((int)h.batteryTemperature)<<14)&0x01ff8000)
+                | ((((int)h.batteryVoltage)<<1)&0x00007fff);
     }
 
     private int buildStateInt(HistoryItem h) {
@@ -2063,6 +2117,98 @@
                 | (h.states&(~DELTA_STATE_MASK));
     }
 
+    private void computeHistoryStepDetails(final HistoryStepDetails out,
+            final HistoryStepDetails last) {
+        final HistoryStepDetails tmp = last != null ? mTmpHistoryStepDetails : out;
+
+        // Perform a CPU update right after we do this collection, so we have started
+        // collecting good data for the next step.
+        requestImmediateCpuUpdate();
+
+        if (last == null) {
+            // We are not generating a delta, so all we need to do is reset the stats
+            // we will later be doing a delta from.
+            final int NU = mUidStats.size();
+            for (int i=0; i<NU; i++) {
+                final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+                uid.mLastStepUserTime = uid.mCurStepUserTime;
+                uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+            }
+            mLastStepCpuUserTime = mCurStepCpuUserTime;
+            mLastStepCpuSystemTime = mCurStepCpuSystemTime;
+            mLastStepStatUserTime = mCurStepStatUserTime;
+            mLastStepStatSystemTime = mCurStepStatSystemTime;
+            mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
+            mLastStepStatIrqTime = mCurStepStatIrqTime;
+            mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
+            mLastStepStatIdleTime = mCurStepStatIdleTime;
+            tmp.clear();
+            return;
+        }
+        if (DEBUG) {
+            Slog.d(TAG, "Step stats last: user=" + mLastStepCpuUserTime + " sys="
+                    + mLastStepStatSystemTime + " io=" + mLastStepStatIOWaitTime
+                    + " irq=" + mLastStepStatIrqTime + " sirq="
+                    + mLastStepStatSoftIrqTime + " idle=" + mLastStepStatIdleTime);
+            Slog.d(TAG, "Step stats cur: user=" + mCurStepCpuUserTime + " sys="
+                    + mCurStepStatSystemTime + " io=" + mCurStepStatIOWaitTime
+                    + " irq=" + mCurStepStatIrqTime + " sirq="
+                    + mCurStepStatSoftIrqTime + " idle=" + mCurStepStatIdleTime);
+        }
+        out.userTime = (int)(mCurStepCpuUserTime - mLastStepCpuUserTime);
+        out.systemTime = (int)(mCurStepCpuSystemTime - mLastStepCpuSystemTime);
+        out.statUserTime = (int)(mCurStepStatUserTime - mLastStepStatUserTime);
+        out.statSystemTime = (int)(mCurStepStatSystemTime - mLastStepStatSystemTime);
+        out.statIOWaitTime = (int)(mCurStepStatIOWaitTime - mLastStepStatIOWaitTime);
+        out.statIrqTime = (int)(mCurStepStatIrqTime - mLastStepStatIrqTime);
+        out.statSoftIrqTime = (int)(mCurStepStatSoftIrqTime - mLastStepStatSoftIrqTime);
+        out.statIdlTime = (int)(mCurStepStatIdleTime - mLastStepStatIdleTime);
+        out.appCpuUid1 = out.appCpuUid2 = out.appCpuUid3 = -1;
+        out.appCpuUTime1 = out.appCpuUTime2 = out.appCpuUTime3 = 0;
+        out.appCpuSTime1 = out.appCpuSTime2 = out.appCpuSTime3 = 0;
+        final int NU = mUidStats.size();
+        for (int i=0; i<NU; i++) {
+            final BatteryStatsImpl.Uid uid = mUidStats.valueAt(i);
+            final int totalUTime = (int)(uid.mCurStepUserTime - uid.mLastStepUserTime);
+            final int totalSTime = (int)(uid.mCurStepSystemTime - uid.mLastStepSystemTime);
+            final int totalTime = totalUTime + totalSTime;
+            uid.mLastStepUserTime = uid.mCurStepUserTime;
+            uid.mLastStepSystemTime = uid.mCurStepSystemTime;
+            if (totalTime <= (out.appCpuUTime3+out.appCpuSTime3)) {
+                continue;
+            }
+            if (totalTime <= (out.appCpuUTime2+out.appCpuSTime2)) {
+                out.appCpuUid3 = uid.mUid;
+                out.appCpuUTime3 = totalUTime;
+                out.appCpuSTime3 = totalSTime;
+            } else {
+                out.appCpuUid3 = out.appCpuUid2;
+                out.appCpuUTime3 = out.appCpuUTime2;
+                out.appCpuSTime3 = out.appCpuSTime2;
+                if (totalTime <= (out.appCpuUTime1+out.appCpuSTime1)) {
+                    out.appCpuUid2 = uid.mUid;
+                    out.appCpuUTime2 = totalUTime;
+                    out.appCpuSTime2 = totalSTime;
+                } else {
+                    out.appCpuUid2 = out.appCpuUid1;
+                    out.appCpuUTime2 = out.appCpuUTime1;
+                    out.appCpuSTime2 = out.appCpuSTime1;
+                    out.appCpuUid1 = uid.mUid;
+                    out.appCpuUTime1 = totalUTime;
+                    out.appCpuSTime1 = totalSTime;
+                }
+            }
+        }
+        mLastStepCpuUserTime = mCurStepCpuUserTime;
+        mLastStepCpuSystemTime = mCurStepCpuSystemTime;
+        mLastStepStatUserTime = mCurStepStatUserTime;
+        mLastStepStatSystemTime = mCurStepStatSystemTime;
+        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime;
+        mLastStepStatIrqTime = mCurStepStatIrqTime;
+        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime;
+        mLastStepStatIdleTime = mCurStepStatIdleTime;
+    }
+
     public void readHistoryDelta(Parcel src, HistoryItem cur) {
         int firstToken = src.readInt();
         int deltaTimeToken = firstToken&DELTA_TIME_MASK;
@@ -2091,8 +2237,9 @@
             cur.numReadInts += 2;
         }
 
+        final int batteryLevelInt;
         if ((firstToken&DELTA_BATTERY_LEVEL_FLAG) != 0) {
-            int batteryLevelInt = src.readInt();
+            batteryLevelInt = src.readInt();
             cur.batteryLevel = (byte)((batteryLevelInt>>25)&0x7f);
             cur.batteryTemperature = (short)((batteryLevelInt<<7)>>21);
             cur.batteryVoltage = (char)(batteryLevelInt&0x3fff);
@@ -2102,6 +2249,8 @@
                     + " batteryLevel=" + cur.batteryLevel
                     + " batteryTemp=" + cur.batteryTemperature
                     + " batteryVolt=" + (int)cur.batteryVoltage);
+        } else {
+            batteryLevelInt = 0;
         }
 
         if ((firstToken&DELTA_STATE_FLAG) != 0) {
@@ -2180,6 +2329,13 @@
         } else {
             cur.eventCode = HistoryItem.EVENT_NONE;
         }
+
+        if ((batteryLevelInt&BATTERY_DELTA_LEVEL_FLAG) != 0) {
+            cur.stepDetails = mReadHistoryStepDetails;
+            cur.stepDetails.readFromParcel(src);
+        } else {
+            cur.stepDetails = null;
+        }
     }
 
     @Override
@@ -2207,6 +2363,7 @@
                 && (diffStates2&lastDiffStates2) == 0
                 && (mHistoryLastWritten.wakelockTag == null || cur.wakelockTag == null)
                 && (mHistoryLastWritten.wakeReasonTag == null || cur.wakeReasonTag == null)
+                && mHistoryLastWritten.stepDetails == null
                 && (mHistoryLastWritten.eventCode == HistoryItem.EVENT_NONE
                         || cur.eventCode == HistoryItem.EVENT_NONE)
                 && mHistoryLastWritten.batteryLevel == cur.batteryLevel
@@ -2632,6 +2789,11 @@
         }
     }
 
+    private void requestImmediateCpuUpdate() {
+        mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
+        mHandler.sendEmptyMessage(MSG_UPDATE_WAKELOCKS);
+    }
+
     public void setRecordAllHistoryLocked(boolean enabled) {
         mRecordAllHistory = enabled;
         if (!enabled) {
@@ -2823,6 +2985,10 @@
     public int startAddingCpuLocked() {
         mHandler.removeMessages(MSG_UPDATE_WAKELOCKS);
 
+        if (!mOnBatteryInternal) {
+            return -1;
+        }
+
         final int N = mPartialTimers.size();
         if (N == 0) {
             mLastPartialTimers.clear();
@@ -2853,7 +3019,23 @@
         return 0;
     }
 
-    public void finishAddingCpuLocked(int perc, int utime, int stime, long[] cpuSpeedTimes) {
+    public void finishAddingCpuLocked(int perc, int remainUTime, int remainSTtime,
+            int totalUTime, int totalSTime, int statUserTime, int statSystemTime,
+            int statIOWaitTime, int statIrqTime, int statSoftIrqTime, int statIdleTime,
+            long[] cpuSpeedTimes) {
+        if (DEBUG) Slog.d(TAG, "Adding cpu: tuser=" + totalUTime + " tsys=" + totalSTime
+                + " user=" + statUserTime + " sys=" + statSystemTime
+                + " io=" + statIOWaitTime + " irq=" + statIrqTime
+                + " sirq=" + statSoftIrqTime + " idle=" + statIdleTime);
+        mCurStepCpuUserTime += totalUTime;
+        mCurStepCpuSystemTime += totalSTime;
+        mCurStepStatUserTime += statUserTime;
+        mCurStepStatSystemTime += statSystemTime;
+        mCurStepStatIOWaitTime += statIOWaitTime;
+        mCurStepStatIrqTime += statIrqTime;
+        mCurStepStatSoftIrqTime += statSoftIrqTime;
+        mCurStepStatIdleTime += statIdleTime;
+
         final int N = mPartialTimers.size();
         if (perc != 0) {
             int num = 0;
@@ -2874,26 +3056,24 @@
                     if (st.mInList) {
                         Uid uid = st.mUid;
                         if (uid != null && uid.mUid != Process.SYSTEM_UID) {
-                            int myUTime = utime/num;
-                            int mySTime = stime/num;
-                            utime -= myUTime;
-                            stime -= mySTime;
+                            int myUTime = remainUTime/num;
+                            int mySTime = remainSTtime/num;
+                            remainUTime -= myUTime;
+                            remainSTtime -= mySTime;
                             num--;
                             Uid.Proc proc = uid.getProcessStatsLocked("*wakelock*");
-                            proc.addCpuTimeLocked(myUTime, mySTime);
-                            proc.addSpeedStepTimes(cpuSpeedTimes);
+                            proc.addCpuTimeLocked(myUTime, mySTime, cpuSpeedTimes);
                         }
                     }
                 }
             }
 
             // Just in case, collect any lost CPU time.
-            if (utime != 0 || stime != 0) {
+            if (remainUTime != 0 || remainSTtime != 0) {
                 Uid uid = getUidStatsLocked(Process.SYSTEM_UID);
                 if (uid != null) {
                     Uid.Proc proc = uid.getProcessStatsLocked("*lost*");
-                    proc.addCpuTimeLocked(utime, stime);
-                    proc.addSpeedStepTimes(cpuSpeedTimes);
+                    proc.addCpuTimeLocked(remainUTime, remainSTtime, cpuSpeedTimes);
                 }
             }
         }
@@ -4214,6 +4394,14 @@
         LongSamplingCounter mMobileRadioActiveCount;
 
         /**
+         * The CPU times we had at the last history details update.
+         */
+        long mLastStepUserTime;
+        long mLastStepSystemTime;
+        long mCurStepUserTime;
+        long mCurStepSystemTime;
+
+        /**
          * The statistics we have collected for this uid's wake locks.
          */
         final OverflowArrayMap<Wakelock> mWakelockStats = new OverflowArrayMap<Wakelock>() {
@@ -4876,6 +5064,9 @@
                 mPackageStats.clear();
             }
 
+            mLastStepUserTime = mLastStepSystemTime = 0;
+            mCurStepUserTime = mCurStepSystemTime = 0;
+
             if (!active) {
                 if (mWifiRunningTimer != null) {
                     mWifiRunningTimer.detach();
@@ -5678,9 +5869,22 @@
                 return BatteryStatsImpl.this;
             }
 
-            public void addCpuTimeLocked(int utime, int stime) {
+            public void addCpuTimeLocked(int utime, int stime, long[] speedStepBins) {
                 mUserTime += utime;
+                mCurStepUserTime += utime;
                 mSystemTime += stime;
+                mCurStepSystemTime += stime;
+
+                for (int i = 0; i < mSpeedBins.length && i < speedStepBins.length; i++) {
+                    long amt = speedStepBins[i];
+                    if (amt != 0) {
+                        SamplingCounter c = mSpeedBins[i];
+                        if (c == null) {
+                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
+                        }
+                        c.addCountAtomic(speedStepBins[i]);
+                    }
+                }
             }
 
             public void addForegroundTimeLocked(long ttime) {
@@ -5770,20 +5974,6 @@
                 return val;
             }
 
-            /* Called by ActivityManagerService when CPU times are updated. */
-            public void addSpeedStepTimes(long[] values) {
-                for (int i = 0; i < mSpeedBins.length && i < values.length; i++) {
-                    long amt = values[i];
-                    if (amt != 0) {
-                        SamplingCounter c = mSpeedBins[i];
-                        if (c == null) {
-                            mSpeedBins[i] = c = new SamplingCounter(mOnBatteryTimeBase);
-                        }
-                        c.addCountAtomic(values[i]);
-                    }
-                }
-            }
-
             @Override
             public long getTimeAtCpuSpeedStep(int speedStep, int which) {
                 if (speedStep < mSpeedBins.length) {
@@ -6756,6 +6946,18 @@
             mWakeupReasonStats.clear();
         }
 
+        mLastHistoryStepDetails = null;
+        mLastStepCpuUserTime = mLastStepCpuSystemTime = 0;
+        mCurStepCpuUserTime = mCurStepCpuSystemTime = 0;
+        mLastStepCpuUserTime = mCurStepCpuUserTime = 0;
+        mLastStepCpuSystemTime = mCurStepCpuSystemTime = 0;
+        mLastStepStatUserTime = mCurStepStatUserTime = 0;
+        mLastStepStatSystemTime = mCurStepStatSystemTime = 0;
+        mLastStepStatIOWaitTime = mCurStepStatIOWaitTime = 0;
+        mLastStepStatIrqTime = mCurStepStatIrqTime = 0;
+        mLastStepStatSoftIrqTime = mCurStepStatSoftIrqTime = 0;
+        mLastStepStatIdleTime = mCurStepStatIdleTime = 0;
+
         initDischarge();
 
         clearHistoryLocked();
@@ -6872,7 +7074,7 @@
                 reset = true;
                 mNumDischargeStepDurations = 0;
             }
-            mOnBattery = mOnBatteryInternal = onBattery;
+            mOnBattery = mOnBatteryInternal = true;
             mLastDischargeStepLevel = level;
             mMinDischargeStepLevel = level;
             mLastDischargeStepTime = -1;
@@ -6900,7 +7102,7 @@
             mDischargeAmountScreenOff = 0;
             updateTimeBasesLocked(true, !screenOn, uptime, realtime);
         } else {
-            mOnBattery = mOnBatteryInternal = onBattery;
+            mOnBattery = mOnBatteryInternal = false;
             pullPendingStateUpdatesLocked();
             mHistoryCur.batteryLevel = (byte)level;
             mHistoryCur.states |= HistoryItem.STATE_BATTERY_PLUGGED_FLAG;
diff --git a/core/java/com/android/internal/os/ProcessCpuTracker.java b/core/java/com/android/internal/os/ProcessCpuTracker.java
index b5338df..501e0ec 100644
--- a/core/java/com/android/internal/os/ProcessCpuTracker.java
+++ b/core/java/com/android/internal/os/ProcessCpuTracker.java
@@ -152,6 +152,7 @@
     private int mRelIrqTime;
     private int mRelSoftIrqTime;
     private int mRelIdleTime;
+    private boolean mRelStatsAreGood;
 
     private int[] mCurPids;
     private int[] mCurThreadPids;
@@ -285,10 +286,9 @@
 
     public void update() {
         if (DEBUG) Slog.v(TAG, "Update: " + this);
-        mLastSampleTime = mCurrentSampleTime;
-        mCurrentSampleTime = SystemClock.uptimeMillis();
-        mLastSampleRealTime = mCurrentSampleRealTime;
-        mCurrentSampleRealTime = SystemClock.elapsedRealtime();
+
+        final long nowUptime = SystemClock.uptimeMillis();
+        final long nowRealtime = SystemClock.elapsedRealtime();
 
         final long[] sysCpu = mSystemCpuData;
         if (Process.readProcFile("/proc/stat", SYSTEM_CPU_FORMAT,
@@ -304,30 +304,53 @@
             final long irqtime = sysCpu[5];
             final long softirqtime = sysCpu[6];
 
-            mRelUserTime = (int)(usertime - mBaseUserTime);
-            mRelSystemTime = (int)(systemtime - mBaseSystemTime);
-            mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
-            mRelIrqTime = (int)(irqtime - mBaseIrqTime);
-            mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
-            mRelIdleTime = (int)(idletime - mBaseIdleTime);
+            // This code is trying to avoid issues with idle time going backwards,
+            // but currently it gets into situations where it triggers most of the time. :(
+            if (true || (usertime >= mBaseUserTime && systemtime >= mBaseSystemTime
+                    && iowaittime >= mBaseIoWaitTime && irqtime >= mBaseIrqTime
+                    && softirqtime >= mBaseSoftIrqTime && idletime >= mBaseIdleTime)) {
+                mRelUserTime = (int)(usertime - mBaseUserTime);
+                mRelSystemTime = (int)(systemtime - mBaseSystemTime);
+                mRelIoWaitTime = (int)(iowaittime - mBaseIoWaitTime);
+                mRelIrqTime = (int)(irqtime - mBaseIrqTime);
+                mRelSoftIrqTime = (int)(softirqtime - mBaseSoftIrqTime);
+                mRelIdleTime = (int)(idletime - mBaseIdleTime);
+                mRelStatsAreGood = true;
 
-            if (DEBUG) {
-                Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
-                      + " S:" + sysCpu[2] + " I:" + sysCpu[3]
-                      + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
-                      + " O:" + sysCpu[6]);
-                Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
-                      + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+                if (DEBUG) {
+                    Slog.i("Load", "Total U:" + sysCpu[0] + " N:" + sysCpu[1]
+                          + " S:" + sysCpu[2] + " I:" + sysCpu[3]
+                          + " W:" + sysCpu[4] + " Q:" + sysCpu[5]
+                          + " O:" + sysCpu[6]);
+                    Slog.i("Load", "Rel U:" + mRelUserTime + " S:" + mRelSystemTime
+                          + " I:" + mRelIdleTime + " Q:" + mRelIrqTime);
+                }
+
+                mBaseUserTime = usertime;
+                mBaseSystemTime = systemtime;
+                mBaseIoWaitTime = iowaittime;
+                mBaseIrqTime = irqtime;
+                mBaseSoftIrqTime = softirqtime;
+                mBaseIdleTime = idletime;
+
+            } else {
+                mRelUserTime = 0;
+                mRelSystemTime = 0;
+                mRelIoWaitTime = 0;
+                mRelIrqTime = 0;
+                mRelSoftIrqTime = 0;
+                mRelIdleTime = 0;
+                mRelStatsAreGood = false;
+                Slog.w(TAG, "/proc/stats has gone backwards; skipping CPU update");
+                return;
             }
-
-            mBaseUserTime = usertime;
-            mBaseSystemTime = systemtime;
-            mBaseIoWaitTime = iowaittime;
-            mBaseIrqTime = irqtime;
-            mBaseSoftIrqTime = softirqtime;
-            mBaseIdleTime = idletime;
         }
 
+        mLastSampleTime = mCurrentSampleTime;
+        mCurrentSampleTime = nowUptime;
+        mLastSampleRealTime = mCurrentSampleRealTime;
+        mCurrentSampleRealTime = nowRealtime;
+
         final StrictMode.ThreadPolicy savedPolicy = StrictMode.allowThreadDiskReads();
         try {
             mCurPids = collectStats("/proc", -1, mFirst, mCurPids, mProcStats);
@@ -647,6 +670,10 @@
         return mRelIdleTime;
     }
 
+    final public boolean hasGoodLastStats() {
+        return mRelStatsAreGood;
+    }
+
     final public float getTotalCpuPercent() {
         int denom = mRelUserTime+mRelSystemTime+mRelIrqTime+mRelIdleTime;
         if (denom <= 0) {
diff --git a/core/java/com/android/internal/os/ZygoteConnection.java b/core/java/com/android/internal/os/ZygoteConnection.java
index c9b44be..a55fe9a 100644
--- a/core/java/com/android/internal/os/ZygoteConnection.java
+++ b/core/java/com/android/internal/os/ZygoteConnection.java
@@ -399,7 +399,7 @@
                 throws IllegalArgumentException {
             int curArg = 0;
 
-            boolean seenRuntimeArgs = true;
+            boolean seenRuntimeArgs = false;
 
             for ( /* curArg */ ; curArg < args.length; curArg++) {
                 String arg = args[curArg];
@@ -533,14 +533,18 @@
                 }
             }
 
-            if (!seenRuntimeArgs) {
-                throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+            if (abiListQuery) {
+                if (args.length - curArg > 0) {
+                    throw new IllegalArgumentException("Unexpected arguments after --query-abi-list.");
+                }
+            } else {
+                if (!seenRuntimeArgs) {
+                    throw new IllegalArgumentException("Unexpected argument : " + args[curArg]);
+                }
+
+                remainingArgs = new String[args.length - curArg];
+                System.arraycopy(args, curArg, remainingArgs, 0, remainingArgs.length);
             }
-
-            remainingArgs = new String[args.length - curArg];
-
-            System.arraycopy(args, curArg, remainingArgs, 0,
-                    remainingArgs.length);
         }
     }
 
diff --git a/core/java/com/android/internal/os/ZygoteInit.java b/core/java/com/android/internal/os/ZygoteInit.java
index 035b017..400ea37 100644
--- a/core/java/com/android/internal/os/ZygoteInit.java
+++ b/core/java/com/android/internal/os/ZygoteInit.java
@@ -504,8 +504,8 @@
             "--setgid=1000",
             "--setgroups=1001,1002,1003,1004,1005,1006,1007,1008,1009,1010,1018,1032,3001,3002,3003,3006,3007",
             "--capabilities=" + capabilities + "," + capabilities,
-            "--runtime-init",
             "--nice-name=system_server",
+            "--runtime-args",
             "com.android.server.SystemServer",
         };
         ZygoteConnection.Arguments parsedArgs = null;
diff --git a/core/java/com/android/internal/view/ActionModeWrapper.java b/core/java/com/android/internal/view/ActionModeWrapper.java
new file mode 100644
index 0000000..ef1981a
--- /dev/null
+++ b/core/java/com/android/internal/view/ActionModeWrapper.java
@@ -0,0 +1,200 @@
+/*
+ * 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.internal.view;
+
+import android.content.Context;
+import android.view.ActionMode;
+import android.view.Menu;
+import android.view.MenuInflater;
+import android.view.MenuItem;
+import android.view.View;
+
+import com.android.internal.view.menu.MenuBuilder;
+import com.android.internal.widget.ActionBarContextView;
+
+/**
+ * ActionMode implementation that wraps several actions modes and creates them on the fly depending
+ * on the ActionMode type chosen by the client.
+ */
+public class ActionModeWrapper extends ActionMode {
+
+    private ActionMode mActionMode;
+    private final Context mContext;
+    private MenuBuilder mMenu;
+    private final ActionMode.Callback mCallback;
+    private boolean mTypeLocked = false;
+
+    private CharSequence mTitle;
+    private CharSequence mSubtitle;
+    private View mCustomView;
+
+    // Fields for StandaloneActionMode
+    private ActionBarContextView mActionModeView;
+    private boolean mIsFocusable;
+
+    public ActionModeWrapper(Context context, ActionMode.Callback callback) {
+        mContext = context;
+        mMenu = new MenuBuilder(context).setDefaultShowAsAction(
+                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mCallback = callback;
+    }
+
+    @Override
+    public void setTitle(CharSequence title) {
+        if (mActionMode != null) {
+            mActionMode.setTitle(title);
+        } else {
+            mTitle = title;
+        }
+    }
+
+    @Override
+    public void setTitle(int resId) {
+        if (mActionMode != null) {
+            mActionMode.setTitle(resId);
+        } else {
+            mTitle = resId != 0 ? mContext.getString(resId) : null;
+        }
+    }
+
+    @Override
+    public void setSubtitle(CharSequence subtitle) {
+        if (mActionMode != null) {
+            mActionMode.setSubtitle(subtitle);
+        } else {
+            mSubtitle = subtitle;
+        }
+    }
+
+    @Override
+    public void setSubtitle(int resId) {
+        if (mActionMode != null) {
+            mActionMode.setSubtitle(resId);
+        } else {
+            mSubtitle = resId != 0 ? mContext.getString(resId) : null;
+        }
+    }
+
+    @Override
+    public void setCustomView(View view) {
+        if (mActionMode != null) {
+            mActionMode.setCustomView(view);
+        } else {
+            mCustomView = view;
+        }
+    }
+
+    /**
+     * Set the current type as final and create the necessary ActionMode. After this call, any
+     * changes to the ActionMode type will be ignored.
+     */
+    public void lockType() {
+        mTypeLocked = true;
+        switch (getType()) {
+            case ActionMode.TYPE_PRIMARY:
+            default:
+                mActionMode = new StandaloneActionMode(
+                        mActionModeView.getContext(),
+                        mActionModeView, mCallback, mIsFocusable, mMenu);
+                break;
+            case ActionMode.TYPE_FLOATING:
+                // Not implemented yet.
+                break;
+        }
+
+        if (mActionMode == null) {
+            return;
+        }
+
+        mActionMode.setTitle(mTitle);
+        mActionMode.setSubtitle(mSubtitle);
+        if (mCustomView != null) {
+            mActionMode.setCustomView(mCustomView);
+        }
+
+        mTitle = null;
+        mSubtitle = null;
+        mCustomView = null;
+    }
+
+    @Override
+    public void setType(int type) {
+        if (!mTypeLocked) {
+            super.setType(type);
+        } else {
+            throw new IllegalStateException(
+                    "You can't change the ActionMode's type after onCreateActionMode.");
+        }
+    }
+
+    @Override
+    public void invalidate() {
+        if (mActionMode != null) {
+            mActionMode.invalidate();
+        }
+    }
+
+    @Override
+    public void finish() {
+        if (mActionMode != null) {
+            mActionMode.finish();
+        }
+    }
+
+    @Override
+    public Menu getMenu() {
+        return mMenu;
+    }
+
+    @Override
+    public CharSequence getTitle() {
+        if (mActionMode != null) {
+            return mActionMode.getTitle();
+        }
+        return mTitle;
+    }
+
+    @Override
+    public CharSequence getSubtitle() {
+        if (mActionMode != null) {
+            return mActionMode.getSubtitle();
+        }
+        return mSubtitle;
+    }
+
+    @Override
+    public View getCustomView() {
+        if (mActionMode != null) {
+            return mActionMode.getCustomView();
+        }
+        return mCustomView;
+    }
+
+    @Override
+    public MenuInflater getMenuInflater() {
+        return new MenuInflater(mContext);
+    }
+
+    public void setActionModeView(ActionBarContextView actionModeView) {
+        mActionModeView = actionModeView;
+    }
+
+    public void setFocusable(boolean focusable) {
+        mIsFocusable = focusable;
+    }
+
+}
diff --git a/core/java/com/android/internal/view/StandaloneActionMode.java b/core/java/com/android/internal/view/StandaloneActionMode.java
index d5d3602..2812b77 100644
--- a/core/java/com/android/internal/view/StandaloneActionMode.java
+++ b/core/java/com/android/internal/view/StandaloneActionMode.java
@@ -20,6 +20,7 @@
 import com.android.internal.view.menu.SubMenuBuilder;
 import com.android.internal.widget.ActionBarContextView;
 
+import android.annotation.Nullable;
 import android.content.Context;
 import android.view.ActionMode;
 import android.view.Menu;
@@ -41,13 +42,15 @@
     private MenuBuilder mMenu;
 
     public StandaloneActionMode(Context context, ActionBarContextView view,
-            ActionMode.Callback callback, boolean isFocusable) {
+            ActionMode.Callback callback, boolean isFocusable, @Nullable MenuBuilder menuBuilder) {
         mContext = context;
         mContextView = view;
         mCallback = callback;
 
-        mMenu = new MenuBuilder(view.getContext()).setDefaultShowAsAction(
-                MenuItem.SHOW_AS_ACTION_IF_ROOM);
+        mMenu = (menuBuilder != null)
+                ? menuBuilder
+                : new MenuBuilder(view.getContext()).setDefaultShowAsAction(
+                        MenuItem.SHOW_AS_ACTION_IF_ROOM);
         mMenu.setCallback(this);
         mFocusable = isFocusable;
     }
@@ -64,12 +67,12 @@
 
     @Override
     public void setTitle(int resId) {
-        setTitle(mContext.getString(resId));
+        setTitle(resId != 0 ? mContext.getString(resId) : null);
     }
 
     @Override
     public void setSubtitle(int resId) {
-        setSubtitle(mContext.getString(resId));
+        setSubtitle(resId != 0 ? mContext.getString(resId) : null);
     }
 
     @Override
diff --git a/core/java/com/android/internal/widget/ActionBarContextView.java b/core/java/com/android/internal/widget/ActionBarContextView.java
index 5d3f464..ae5999a 100644
--- a/core/java/com/android/internal/widget/ActionBarContextView.java
+++ b/core/java/com/android/internal/widget/ActionBarContextView.java
@@ -158,7 +158,7 @@
             removeView(mCustomView);
         }
         mCustomView = view;
-        if (mTitleLayout != null) {
+        if (view != null && mTitleLayout != null) {
             removeView(mTitleLayout);
             mTitleLayout = null;
         }
diff --git a/core/jni/android_view_Surface.cpp b/core/jni/android_view_Surface.cpp
index 7f6c50f..bfa0534 100644
--- a/core/jni/android_view_Surface.cpp
+++ b/core/jni/android_view_Surface.cpp
@@ -49,6 +49,7 @@
 
 #include <AnimationContext.h>
 #include <DisplayListRenderer.h>
+#include <FrameInfo.h>
 #include <RenderNode.h>
 #include <renderthread/RenderProxy.h>
 
@@ -394,7 +395,7 @@
     proxy->initialize(surface);
     // Shadows can't be used via this interface, so just set the light source
     // to all 0s. (and width & height are unused, TODO remove them)
-    proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0);
+    proxy->setup(0, 0, (Vector3){0, 0, 0}, 0, 0, 0, 1.0f);
     return (jlong) proxy;
 }
 
@@ -406,8 +407,11 @@
 
 static void draw(JNIEnv* env, jclass clazz, jlong rendererPtr) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(rendererPtr);
-    nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-    proxy->syncAndDrawFrame(frameTimeNs, 0, 1.0f);
+    nsecs_t vsync = systemTime(CLOCK_MONOTONIC);
+    UiFrameInfoBuilder(proxy->frameInfo())
+            .setVsync(vsync, vsync)
+            .addFlag(FrameInfoFlags::kSurfaceCanvas);
+    proxy->syncAndDrawFrame();
 }
 
 static void destroy(JNIEnv* env, jclass clazz, jlong rendererPtr) {
diff --git a/core/jni/android_view_ThreadedRenderer.cpp b/core/jni/android_view_ThreadedRenderer.cpp
index 068b24e..ad93301 100644
--- a/core/jni/android_view_ThreadedRenderer.cpp
+++ b/core/jni/android_view_ThreadedRenderer.cpp
@@ -281,10 +281,10 @@
 static void android_view_ThreadedRenderer_setup(JNIEnv* env, jobject clazz, jlong proxyPtr,
         jint width, jint height,
         jfloat lightX, jfloat lightY, jfloat lightZ, jfloat lightRadius,
-        jint ambientShadowAlpha, jint spotShadowAlpha) {
+        jint ambientShadowAlpha, jint spotShadowAlpha, jfloat density) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     proxy->setup(width, height, (Vector3){lightX, lightY, lightZ}, lightRadius,
-            ambientShadowAlpha, spotShadowAlpha);
+            ambientShadowAlpha, spotShadowAlpha, density);
 }
 
 static void android_view_ThreadedRenderer_setOpaque(JNIEnv* env, jobject clazz,
@@ -294,9 +294,13 @@
 }
 
 static int android_view_ThreadedRenderer_syncAndDrawFrame(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jlong frameTimeNanos, jlong recordDuration, jfloat density) {
+        jlong proxyPtr, jlongArray frameInfo, jint frameInfoSize) {
+    LOG_ALWAYS_FATAL_IF(frameInfoSize != UI_THREAD_FRAME_INFO_SIZE,
+            "Mismatched size expectations, given %d expected %d",
+            frameInfoSize, UI_THREAD_FRAME_INFO_SIZE);
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
-    return proxy->syncAndDrawFrame(frameTimeNanos, recordDuration, density);
+    env->GetLongArrayRegion(frameInfo, 0, frameInfoSize, proxy->frameInfo());
+    return proxy->syncAndDrawFrame();
 }
 
 static void android_view_ThreadedRenderer_destroy(JNIEnv* env, jobject clazz,
@@ -391,10 +395,10 @@
 }
 
 static void android_view_ThreadedRenderer_dumpProfileInfo(JNIEnv* env, jobject clazz,
-        jlong proxyPtr, jobject javaFileDescriptor) {
+        jlong proxyPtr, jobject javaFileDescriptor, jint dumpFlags) {
     RenderProxy* proxy = reinterpret_cast<RenderProxy*>(proxyPtr);
     int fd = jniGetFDFromFileDescriptor(env, javaFileDescriptor);
-    proxy->dumpProfileInfo(fd);
+    proxy->dumpProfileInfo(fd, dumpFlags);
 }
 
 // ----------------------------------------------------------------------------
@@ -425,9 +429,9 @@
     { "nInitialize", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_initialize },
     { "nUpdateSurface", "(JLandroid/view/Surface;)V", (void*) android_view_ThreadedRenderer_updateSurface },
     { "nPauseSurface", "(JLandroid/view/Surface;)Z", (void*) android_view_ThreadedRenderer_pauseSurface },
-    { "nSetup", "(JIIFFFFII)V", (void*) android_view_ThreadedRenderer_setup },
+    { "nSetup", "(JIIFFFFIIF)V", (void*) android_view_ThreadedRenderer_setup },
     { "nSetOpaque", "(JZ)V", (void*) android_view_ThreadedRenderer_setOpaque },
-    { "nSyncAndDrawFrame", "(JJJF)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
+    { "nSyncAndDrawFrame", "(J[JI)I", (void*) android_view_ThreadedRenderer_syncAndDrawFrame },
     { "nDestroy", "(J)V", (void*) android_view_ThreadedRenderer_destroy },
     { "nRegisterAnimatingRenderNode", "(JJ)V", (void*) android_view_ThreadedRenderer_registerAnimatingRenderNode },
     { "nInvokeFunctor", "(JZ)V", (void*) android_view_ThreadedRenderer_invokeFunctor },
@@ -442,7 +446,7 @@
     { "nFence", "(J)V", (void*) android_view_ThreadedRenderer_fence },
     { "nStopDrawing", "(J)V", (void*) android_view_ThreadedRenderer_stopDrawing },
     { "nNotifyFramePending", "(J)V", (void*) android_view_ThreadedRenderer_notifyFramePending },
-    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
+    { "nDumpProfileInfo", "(JLjava/io/FileDescriptor;I)V", (void*) android_view_ThreadedRenderer_dumpProfileInfo },
     { "setupShadersDiskCache", "(Ljava/lang/String;)V",
                 (void*) android_view_ThreadedRenderer_setupShadersDiskCache },
 };
diff --git a/core/res/res/values-mcc259-mnc05/config.xml b/core/res/res/values-mcc259-mnc05/config.xml
new file mode 100644
index 0000000..065668c
--- /dev/null
+++ b/core/res/res/values-mcc259-mnc05/config.xml
@@ -0,0 +1,35 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+/*
+** Copyright 2013, 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.
+*/
+-->
+
+<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <!-- The list of ril radio technologies (see ServiceState.java) which only support
+         a single data connection at one time.  This may change by carrier via
+         overlays (some don't support multiple pdp on UMTS).  All unlisted radio
+         tech types support unlimited types (practically only 2-4 used). -->
+    <integer-array name="config_onlySingleDcAllowed">
+        <item>1</item>  <!-- GPRS -->
+        <item>2</item>  <!-- EDGE -->
+        <item>3</item>  <!-- UMTS -->
+        <item>9</item>  <!-- HSDPA -->
+        <item>10</item> <!-- HSUPA -->
+        <item>11</item> <!-- HSPA -->
+        <item>14</item> <!-- LTE -->
+        <item>15</item> <!-- HSPAP -->
+    </integer-array>
+</resources>
diff --git a/core/res/res/values-watch/config.xml b/core/res/res/values-watch/config.xml
index 307a1ea..745aa73 100644
--- a/core/res/res/values-watch/config.xml
+++ b/core/res/res/values-watch/config.xml
@@ -43,4 +43,12 @@
     <!-- Flags enabling default window features. See Window.java -->
     <bool name="config_defaultWindowFeatureOptionsPanel">false</bool>
     <bool name="config_defaultWindowFeatureContextMenu">false</bool>
+
+    <!-- Time adjustment, in milliseconds, applied to the default double tap threshold
+         used for gesture detection by the screen magnifier. -->
+    <integer name="config_screen_magnification_multi_tap_adjustment">25</integer>
+
+    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
+         panning to scaling the magnification viewport. -->
+    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.1</item>
 </resources>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 2041777..51c6a66 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -2060,4 +2060,12 @@
 
     <!-- Whether to start in touch mode -->
     <bool name="config_defaultInTouchMode">true</bool>
+
+    <!-- Time adjustment, in milliseconds, applied to the default double tap threshold
+         used for gesture detection by the screen magnifier. -->
+    <integer name="config_screen_magnification_multi_tap_adjustment">-50</integer>
+
+    <!-- Scale factor threshold used by the screen magnifier to determine when to switch from
+         panning to scaling the magnification viewport. -->
+    <item name="config_screen_magnification_scaling_threshold" format="float" type="dimen">0.3</item>
 </resources>
diff --git a/core/res/res/values/ids.xml b/core/res/res/values/ids.xml
index bd24f3e..1f4d37c 100644
--- a/core/res/res/values/ids.xml
+++ b/core/res/res/values/ids.xml
@@ -89,4 +89,6 @@
   <item type="id" name="parentMatrix" />
   <item type="id" name="statusBarBackground" />
   <item type="id" name="navigationBarBackground" />
+  <item type="id" name="undo" />
+  <item type="id" name="redo" />
 </resources>
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index cfff420..8814138 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -2634,4 +2634,9 @@
   <public type="style" name="Theme.Material.DayNight.Panel" />
   <public type="style" name="Theme.Material.Light.LightStatusBar" />
 
+  <!-- Context menu ID for the "Undo" menu item to undo the last text edit operation. -->
+  <public type="id" name="undo" />
+  <!-- Context menu ID for the "Redo" menu item to redo the last text edit operation. -->
+  <public type="id" name="redo" />
+
 </resources>
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index c43977da..b414634 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2157,4 +2157,7 @@
   <java-symbol type="xml" name="bookmarks" />
 
   <java-symbol type="integer" name="config_defaultNightMode" />
+
+  <java-symbol type="integer" name="config_screen_magnification_multi_tap_adjustment" />
+  <java-symbol type="dimen" name="config_screen_magnification_scaling_threshold" />
 </resources>
diff --git a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
index 1557918..a50fb54 100644
--- a/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
+++ b/core/tests/inputmethodtests/src/android/os/InputMethodTest.java
@@ -29,8 +29,6 @@
 import com.android.internal.inputmethod.InputMethodUtils;
 
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashSet;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -38,19 +36,33 @@
 public class InputMethodTest extends InstrumentationTestCase {
     private static final boolean IS_AUX = true;
     private static final boolean IS_DEFAULT = true;
-    private static final boolean IS_AUTO = true;
+    private static final boolean IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE = true;
     private static final boolean IS_ASCII_CAPABLE = true;
+    private static final boolean IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE = true;
     private static final boolean IS_SYSTEM_READY = true;
-    private static final ArrayList<InputMethodSubtype> NO_SUBTYPE = null;
+    private static final Locale LOCALE_EN = new Locale("en");
     private static final Locale LOCALE_EN_US = new Locale("en", "US");
     private static final Locale LOCALE_EN_GB = new Locale("en", "GB");
     private static final Locale LOCALE_EN_IN = new Locale("en", "IN");
+    private static final Locale LOCALE_FI = new Locale("fi");
+    private static final Locale LOCALE_FI_FI = new Locale("fi", "FI");
+    private static final Locale LOCALE_FIL = new Locale("fil");
+    private static final Locale LOCALE_FIL_PH = new Locale("fil", "PH");
+    private static final Locale LOCALE_FR = new Locale("fr");
+    private static final Locale LOCALE_FR_CA = new Locale("fr", "CA");
     private static final Locale LOCALE_HI = new Locale("hi");
     private static final Locale LOCALE_JA_JP = new Locale("ja", "JP");
     private static final Locale LOCALE_ZH_CN = new Locale("zh", "CN");
     private static final Locale LOCALE_ZH_TW = new Locale("zh", "TW");
+    private static final Locale LOCALE_IN = new Locale("in");
+    private static final Locale LOCALE_ID = new Locale("id");
     private static final String SUBTYPE_MODE_KEYBOARD = "keyboard";
     private static final String SUBTYPE_MODE_VOICE = "voice";
+    private static final String SUBTYPE_MODE_ANY = null;
+    private static final String EXTRA_VALUE_PAIR_SEPARATOR = ",";
+    private static final String EXTRA_VALUE_ASCII_CAPABLE = "AsciiCapable";
+    private static final String EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE =
+            "EnabledWhenDefaultIsNotAsciiCapable";
 
     @SmallTest
     public void testVoiceImes() throws Exception {
@@ -159,10 +171,415 @@
         }
     }
 
+    @SmallTest
+    public void testGetImplicitlyApplicableSubtypesLocked() throws Exception {
+        final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFrCA = createDummyInputMethodSubtype("fr_CA",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFr = createDummyInputMethodSubtype("fr_CA",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype autoSubtype = createDummyInputMethodSubtype("auto",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoJa = createDummyInputMethodSubtype("ja",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                !IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype =
+                createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                        !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                        IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2 =
+                createDummyInputMethodSubtype("zz", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
+                        !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                        IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+
+        // Make sure that an automatic subtype (overridesImplicitlyEnabledSubtype:true) is
+        // selected no matter what locale is specified.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(autoSubtype);  // overridesImplicitlyEnabledSubtype == true
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+            assertEquals(1, result.size());
+            verifyEquality(autoSubtype, result.get(0));
+        }
+
+        // Make sure that a subtype whose locale is exactly equal to the specified locale is
+        // selected as long as there is no no automatic subtype
+        // (overridesImplicitlyEnabledSubtype:true) in the given list.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);  // locale == "en_US"
+            subtypes.add(nonAutoEnGB);
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_US, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnUS, result.get(0));
+        }
+
+        // Make sure that a subtype whose locale is exactly equal to the specified locale is
+        // selected as long as there is no automatic subtype
+        // (overridesImplicitlyEnabledSubtype:true) in the given list.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoEnGB); // locale == "en_GB"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_EN_GB, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoEnGB, result.get(0));
+        }
+
+        // If there is no automatic subtype (overridesImplicitlyEnabledSubtype:true) and
+        // any subtype whose locale is exactly equal to the specified locale in the given list,
+        // try to find a subtype whose language is equal to the language part of the given locale.
+        // Here make sure that a subtype (locale: "fr_CA") can be found with locale: "fr".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFrCA);  // locale == "fr_CA"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFrCA, result.get(0));
+        }
+        // Then make sure that a subtype (locale: "fr") can be found with locale: "fr_CA".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFr);  // locale == "fr"
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoFil);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FR_CA, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFrCA, result.get(0));
+        }
+
+        // Make sure that subtypes which have "EnabledWhenDefaultIsNotAsciiCapable" in its
+        // extra value is selected if and only if all other selected IMEs are not AsciiCapable.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoJa);    // not ASCII capable
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype);
+            subtypes.add(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_JA_JP, imi);
+            assertEquals(3, result.size());
+            verifyEquality(nonAutoJa, result.get(0));
+            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype, result.get(1));
+            verifyEquality(nonAutoEnabledWhenDefaultIsNotAsciiCalableSubtype2, result.get(2));
+        }
+
+        // Make sure that 3-letter language code can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FIL_PH, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoFil, result.get(0));
+        }
+
+        // Make sure that we never end up matching "fi" (finnish) with "fil" (filipino).
+        // Also make sure that the first subtype will be used as the last-resort candidate.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoJa);
+            subtypes.add(nonAutoEnUS);
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_FI, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoJa, result.get(0));
+        }
+
+        // Make sure that "in" and "id" conversion is taken into account.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoIn, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoIn, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_IN, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoId, result.get(0));
+        }
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            final ArrayList<InputMethodSubtype> result =
+                    callGetImplicitlyApplicableSubtypesLockedWithLocale(LOCALE_ID, imi);
+            assertEquals(1, result.size());
+            verifyEquality(nonAutoId, result.get(0));
+        }
+    }
+
+    @SmallTest
+    public void testContainsSubtypeOf() throws Exception {
+        final InputMethodSubtype nonAutoEnUS = createDummyInputMethodSubtype("en_US",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoEnGB = createDummyInputMethodSubtype("en_GB",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFil = createDummyInputMethodSubtype("fil",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoFilPH = createDummyInputMethodSubtype("fil_PH",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoIn = createDummyInputMethodSubtype("in",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        final InputMethodSubtype nonAutoId = createDummyInputMethodSubtype("id",
+                SUBTYPE_MODE_KEYBOARD, !IS_AUX, !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE,
+                IS_ASCII_CAPABLE, IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+
+        final boolean CHECK_COUNTRY = true;
+
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_VOICE));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_VOICE));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_ANY));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_US, CHECK_COUNTRY,
+                    SUBTYPE_MODE_ANY));
+
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_EN_GB, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that 3-letter language code ("fil") can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFil);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that 3-letter language code ("fil_PH") can be handled.
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoFilPH);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FIL_PH, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertFalse(InputMethodUtils.containsSubtypeOf(imi, LOCALE_FI_FI, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that a subtype whose locale is "in" can be queried with "id".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoIn);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+
+        // Make sure that a subtype whose locale is "id" can be queried with "in".
+        {
+            final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
+            subtypes.add(nonAutoId);
+            subtypes.add(nonAutoEnUS);
+            final InputMethodInfo imi = createDummyInputMethodInfo(
+                    "com.android.apps.inputmethod.latin",
+                    "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, IS_DEFAULT,
+                    subtypes);
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_IN, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, !CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+            assertTrue(InputMethodUtils.containsSubtypeOf(imi, LOCALE_ID, CHECK_COUNTRY,
+                    SUBTYPE_MODE_KEYBOARD));
+        }
+    }
+
+    private ArrayList<InputMethodSubtype> callGetImplicitlyApplicableSubtypesLockedWithLocale(
+            final Locale locale, final InputMethodInfo imi) {
+        final Context context = getInstrumentation().getTargetContext();
+        final Locale initialLocale = context.getResources().getConfiguration().locale;
+        try {
+            context.getResources().getConfiguration().setLocale(locale);
+            return InputMethodUtils.getImplicitlyApplicableSubtypesLocked(context.getResources(),
+                    imi);
+        } finally {
+            context.getResources().getConfiguration().setLocale(initialLocale);
+        }
+    }
+
     private void assertDefaultEnabledImes(final ArrayList<InputMethodInfo> preinstalledImes,
             final Locale systemLocale, final boolean isSystemReady, String... expectedImeNames) {
         final Context context = getInstrumentation().getTargetContext();
-        final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesUnderWithLocale(
+        final String[] actualImeNames = getPackageNames(callGetDefaultEnabledImesWithLocale(
                 context, isSystemReady, preinstalledImes, systemLocale));
         assertEquals(expectedImeNames.length, actualImeNames.length);
         for (int i = 0; i < expectedImeNames.length; ++i) {
@@ -184,7 +601,7 @@
         }
     }
 
-    private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesUnderWithLocale(
+    private static ArrayList<InputMethodInfo> callGetDefaultEnabledImesWithLocale(
             final Context context, final boolean isSystemReady,
             final ArrayList<InputMethodInfo> imis, final Locale locale) {
         final Locale initialLocale = context.getResources().getConfiguration().locale;
@@ -210,11 +627,15 @@
         for (int subtypeIndex = 0; subtypeIndex < expected.getSubtypeCount(); ++subtypeIndex) {
             final InputMethodSubtype expectedSubtype = expected.getSubtypeAt(subtypeIndex);
             final InputMethodSubtype actualSubtype = actual.getSubtypeAt(subtypeIndex);
-            assertEquals(expectedSubtype, actualSubtype);
-            assertEquals(expectedSubtype.hashCode(), actualSubtype.hashCode());
+            verifyEquality(expectedSubtype, actualSubtype);
         }
     }
 
+    private static void verifyEquality(InputMethodSubtype expected, InputMethodSubtype actual) {
+        assertEquals(expected, actual);
+        assertEquals(expected.hashCode(), actual.hashCode());
+    }
+
     private static InputMethodInfo createDummyInputMethodInfo(String packageName, String name,
             CharSequence label, boolean isAuxIme, boolean isDefault,
             List<InputMethodSubtype> subtypes) {
@@ -236,13 +657,27 @@
 
     private static InputMethodSubtype createDummyInputMethodSubtype(String locale, String mode,
             boolean isAuxiliary, boolean overridesImplicitlyEnabledSubtype,
-            boolean isAsciiCapable) {
+            boolean isAsciiCapable, boolean isEnabledWhenDefaultIsNotAsciiCapable) {
+
+        final StringBuilder subtypeExtraValue = new StringBuilder();
+        if (isEnabledWhenDefaultIsNotAsciiCapable) {
+            subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
+            subtypeExtraValue.append(EXTRA_VALUE_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE);
+        }
+
+        // TODO: Remove following code. InputMethodSubtype#isAsciiCapable() has been publicly
+        // available since API level 19 (KitKat). We no longer need to rely on extra value.
+        if (isAsciiCapable) {
+            subtypeExtraValue.append(EXTRA_VALUE_PAIR_SEPARATOR);
+            subtypeExtraValue.append(EXTRA_VALUE_ASCII_CAPABLE);
+        }
+
         return new InputMethodSubtypeBuilder()
                 .setSubtypeNameResId(0)
                 .setSubtypeIconResId(0)
                 .setSubtypeLocale(locale)
                 .setSubtypeMode(mode)
-                .setSubtypeExtraValue("")
+                .setSubtypeExtraValue(subtypeExtraValue.toString())
                 .setIsAuxiliary(isAuxiliary)
                 .setOverridesImplicitlyEnabledSubtype(overridesImplicitlyEnabledSubtype)
                 .setIsAsciiCapable(isAsciiCapable)
@@ -253,10 +688,12 @@
         ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultAutoVoiceIme",
                     "dummy.voice0", "DummyVoice0", IS_AUX, IS_DEFAULT, subtypes));
         }
@@ -268,33 +705,39 @@
         ArrayList<InputMethodInfo> preinstalledImes = new ArrayList<>();
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme0",
                     "dummy.voice1", "DummyVoice1", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
-            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX, IS_AUTO,
-                    !IS_ASCII_CAPABLE));
+            subtypes.add(createDummyInputMethodSubtype("auto", SUBTYPE_MODE_VOICE, IS_AUX,
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultAutoVoiceIme1",
                     "dummy.voice2", "DummyVoice2", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_VOICE, IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyNonDefaultVoiceIme2",
                     "dummy.voice3", "DummyVoice3", IS_AUX, !IS_DEFAULT, subtypes));
         }
         {
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("DummyDefaultEnKeyboardIme",
                     "dummy.keyboard0", "DummyKeyboard0", !IS_AUX, IS_DEFAULT, subtypes));
         }
@@ -321,7 +764,8 @@
             final boolean isDefaultIme = false;
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("", SUBTYPE_MODE_VOICE, IS_AUX,
-                    IS_AUTO, !IS_ASCII_CAPABLE));
+                    IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.voice",
                     "com.android.inputmethod.voice", "DummyVoiceIme", IS_AUX, isDefaultIme,
                     subtypes));
@@ -332,9 +776,11 @@
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             // TODO: This subtype should be marked as IS_ASCII_CAPABLE
             subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.hindi",
                     "com.android.inputmethod.hindi", "DummyHindiIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -345,7 +791,8 @@
             final boolean isDefaultIme = contains(new String[]{ "zh-rCN" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("zh_CN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.pinyin",
                     "com.android.apps.inputmethod.pinyin", "DummyPinyinIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -356,7 +803,8 @@
             final boolean isDefaultIme = contains(new String[]{ "ko" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("ko", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.korean",
                     "com.android.apps.inputmethod.korean", "DummyKoreanIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -368,13 +816,17 @@
                     new String[]{ "en-rUS", "en-rGB", "en-rIN", "en", "hi" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("en_US", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_GB", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("en_IN", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("hi", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.latin",
                     "com.android.apps.inputmethod.latin", "DummyLatinIme", !IS_AUX, isDefaultIme,
                     subtypes));
@@ -385,9 +837,11 @@
             final boolean isDefaultIme = contains(new String[]{ "ja", "ja-rJP" }, localeString);
             final ArrayList<InputMethodSubtype> subtypes = new ArrayList<InputMethodSubtype>();
             subtypes.add(createDummyInputMethodSubtype("ja", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             subtypes.add(createDummyInputMethodSubtype("emoji", SUBTYPE_MODE_KEYBOARD, !IS_AUX,
-                    !IS_AUTO, !IS_ASCII_CAPABLE));
+                    !IS_OVERRIDES_IMPLICITLY_ENABLED_SUBTYPE, !IS_ASCII_CAPABLE,
+                    !IS_ENABLED_WHEN_DEFAULT_IS_NOT_ASCII_CAPABLE));
             preinstalledImes.add(createDummyInputMethodInfo("com.android.apps.inputmethod.japanese",
                     "com.android.apps.inputmethod.japanese", "DummyJapaneseIme", !IS_AUX,
                     isDefaultIme, subtypes));
diff --git a/docs/html/design/style/iconography.jd b/docs/html/design/style/iconography.jd
index 1a92753..75f541a 100644
--- a/docs/html/design/style/iconography.jd
+++ b/docs/html/design/style/iconography.jd
@@ -536,7 +536,7 @@
 </p>
 
 <p> For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.</p>
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.</p>
 
 <h3 id="xxxhdpi-launcher">Provide an xxx-high-density launcher icon</h3>
 
diff --git a/docs/html/google/gcm/c2dm.jd b/docs/html/google/gcm/c2dm.jd
index fc95c2b..6ae7c1a 100644
--- a/docs/html/google/gcm/c2dm.jd
+++ b/docs/html/google/gcm/c2dm.jd
@@ -75,7 +75,6 @@
 <dt><strong>Canonical registration ID</strong></dt>
 <dd>There may be situations where the server ends up with 2 registration IDs for the same device. If the GCM response contains a registration ID, simply replace the registration ID you have with the one provided. With this feature your application doesn't need to send the device ID to your server anymore. For more information, see <a href="adv.html#canonical">Advanced Topics</a>.</dd>
 </dl>
-<p>GCM also provides client and server <a href="{@docRoot}reference/com/google/android/gcm/package-summary.html">helper libraries</a> to make writing your code easier.</p>
 
 <h3 id="interop">Relationship between C2DM and GCM</h3>
 
diff --git a/docs/html/guide/practices/screens_support.jd b/docs/html/guide/practices/screens_support.jd
index 7c963dd..b6f1c49 100644
--- a/docs/html/guide/practices/screens_support.jd
+++ b/docs/html/guide/practices/screens_support.jd
@@ -368,7 +368,7 @@
 mipmap-xxxhdpi, regardless of the screen resolution of the device where your app is installed. This
 behavior allows launcher apps to pick the best resolution icon for your app to display on the home
 screen. For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.
 </p>
 
 
diff --git a/docs/html/guide/topics/resources/providing-resources.jd b/docs/html/guide/topics/resources/providing-resources.jd
index 98e7c96..fc79970 100644
--- a/docs/html/guide/topics/resources/providing-resources.jd
+++ b/docs/html/guide/topics/resources/providing-resources.jd
@@ -76,7 +76,7 @@
 directory names are important and are described in table 1.</p>
 
 <p class="note"><strong>Note:</strong> For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.</p>
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.</p>
 
 <p class="table-caption" id="table1"><strong>Table 1.</strong> Resource directories
 supported inside project {@code res/} directory.</p>
diff --git a/docs/html/images/tools/studio-inspections-config.png b/docs/html/images/tools/studio-inspections-config.png
new file mode 100644
index 0000000..e41afa1
--- /dev/null
+++ b/docs/html/images/tools/studio-inspections-config.png
Binary files differ
diff --git a/docs/html/sdk/index.jd b/docs/html/sdk/index.jd
index af6f6b8..a43ba3c 100644
--- a/docs/html/sdk/index.jd
+++ b/docs/html/sdk/index.jd
@@ -4,27 +4,27 @@
 header.hide=1
 page.metaDescription=Download the official Android IDE and developer tools to build apps for Android phones, tablets, wearables, TVs, and more.
 
-studio.version=1.0.1
+studio.version=1.1.0
 
-studio.linux_bundle_download=android-studio-ide-135.1641136-linux.zip
-studio.linux_bundle_bytes=243917559
-studio.linux_bundle_checksum=7c8f2d0cec21b98984cdba45ab5a25f26d67f23a
+studio.linux_bundle_download=android-studio-ide-135.1740770-linux.zip
+studio.linux_bundle_bytes=259336386
+studio.linux_bundle_checksum=e8d166559c50a484f83ebfec6731cc0e3f259208
 
-studio.mac_bundle_download=android-studio-ide-1641136.dmg
-studio.mac_bundle_bytes=245729073
-studio.mac_bundle_checksum=49506ba2cf6b56be4f7d07e6a00c4ec3ba2249d5
+studio.mac_bundle_download=android-studio-ide-135.1740770-mac.dmg
+studio.mac_bundle_bytes=261303345
+studio.mac_bundle_checksum=f9745d0fec1eefd498f6160a2d6a1b5247d4cda3
 
-studio.win_bundle_exe_download=android-studio-bundle-135.1641136.exe
-studio.win_bundle_exe_bytes=868344232
-studio.win_bundle_exe_checksum=9c1c8ea6aa17fb74e0593c62fd48ee62a8950be7
+studio.win_bundle_exe_download=android-studio-bundle-135.1740770-windows.exe
+studio.win_bundle_exe_bytes=856233768
+studio.win_bundle_exe_checksum=7484b9989d2914e1de30995fbaa97a271a514b3f
 
-studio.win_notools_exe_download=android-studio-ide-135.1641136.exe
-studio.win_notools_exe_bytes=260272840
-studio.win_notools_exe_checksum=464d1c5497ab3d1bdef441365791ab36c89cd5ae
+studio.win_notools_exe_download=android-studio-ide-135.1740770-windows.exe
+studio.win_notools_exe_bytes=242135128
+studio.win_notools_exe_checksum=5ea77661cd2300cea09e8e34f4a2219a0813911f
 
-studio.win_bundle_download=android-studio-ide-135.1641136-windows.zip
-studio.win_bundle_bytes=246249059
-studio.win_bundle_checksum=6d6856aca83f6ff747ca40b10f70edfbbcccd91c
+studio.win_bundle_download=android-studio-ide-135.1740770-windows.zip
+studio.win_bundle_bytes=261667054
+studio.win_bundle_checksum=e903f17cc6a57c7e3d460c4555386e3e65c6b4eb
 
 
 
diff --git a/docs/html/tools/debugging/debugging-ui.jd b/docs/html/tools/debugging/debugging-ui.jd
index f927d08..cf7e3ba 100644
--- a/docs/html/tools/debugging/debugging-ui.jd
+++ b/docs/html/tools/debugging/debugging-ui.jd
@@ -34,17 +34,17 @@
       <h2>Related videos</h2>
           <ol>
               <li>
-<iframe title="Hierarchyviewer" 
-    width="210" height="160" 
-    src="//www.youtube.com/embed/PAgE7saQUUY?rel=0&amp;hd=1" 
+<iframe title="Hierarchyviewer"
+    width="210" height="160"
+    src="//www.youtube.com/embed/PAgE7saQUUY?rel=0&amp;hd=1"
     frameborder="0" allowfullscreen>
 </iframe>
               </li>
               <li>
-<iframe title="Pixel Perfect" 
-    width="210" height="160" 
-    src="//www.youtube.com/embed/C45bMZGdN7Y?rel=0&amp;hd=1" 
-    frameborder="0" 
+<iframe title="Pixel Perfect"
+    width="210" height="160"
+    src="//www.youtube.com/embed/C45bMZGdN7Y?rel=0&amp;hd=1"
+    frameborder="0"
     allowfullscreen>
 </iframe>
               </li>
@@ -52,11 +52,10 @@
     </div>
   </div>
 
-  <p>
-Sometimes your application's layout can slow down your application.
-  To help debug issues in your layout, the Android SDK provides the Hierarchy Viewer and
-  <code>lint</code> tools.
-  </p>
+
+<p>Sometimes your application's layout can slow down your application.
+To help debug issues in your layout, the Android SDK provides the Hierarchy Viewer and
+<code><a href="{@docRoot}tools/help/lint.html">lint</a></code> tools. </p>
 
   <p>The Hierarchy Viewer application allows you to debug and optimize your user interface. It
   provides a visual representation of the layout's View hierarchy (the View Hierarchy window)
@@ -64,8 +63,10 @@
   and a magnified view of the display (the Pixel Perfect window) to closely examine the pixels
   in your layout.</p>
 
-  <p>Android <code>lint</code> is a static code scanning tool that helps you optimize the layouts and layout
-  hierarchies of your applications, as well as detect other common coding problems. You can run it against your layout files or resource
+  <p>Android <code><a href="{@docRoot}tools/help/lint.html">lint</a></code> is a static code
+  scanning tool that helps you optimize the layouts and layout
+  hierarchies of your applications, as well as detect other common coding problems. You can run it
+  against your layout files or resource
   directories to quickly check for inefficiencies or other types of problems that could be
   affecting the performance of your application.</p>
 
@@ -493,7 +494,10 @@
         alt=""
         height="600"/>
 <p class="img-caption"><strong>Figure 4.</strong> The Pixel Perfect window</p>
+
+
 <h2 id="lint">Using lint to Optimize Your UI</h2>
-<p>The Android {@code lint} tool lets you analyze the XML files that define your application's UI to find inefficiencies in the view hierarchy.</p>
-<p class="note"><strong>Note: </strong>The Android <code>layoutopt</code> tool has been replaced by the {@code lint} tool beginning in ADT and SDK Tools revision 16. The {@code lint} tool reports UI layout performance issues in a similar way as <code>layoutopt</code>, and detects additional problems.</p>
-<p>For more information about using {@code lint}, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a> and the <a  href="{@docRoot}tools/help/lint.html">lint reference documentation</a>.</p>
+<p>The Android <a href="{@docRoot}tools/help/lint.html">lint</a> tool lets you analyze the XML
+files that define your application's UI to find inefficiencies in the view hierarchy.</p>
+<p class="note"><strong>Note: </strong>The Android <code>layoutopt</code> tool has been replaced by the {@code lint} tool beginning in SDK Tools revision 16. The {@code lint} tool reports UI layout performance issues in a similar way as <code>layoutopt</code>, and detects additional problems.</p>
+<p>For more information about using {@code lint}, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a> and the <a  href="{@docRoot}tools/help/lint.html">lint tools help</a>.</p>
diff --git a/docs/html/tools/debugging/improving-w-lint.jd b/docs/html/tools/debugging/improving-w-lint.jd
index 7e238fa..ff94b7f 100644
--- a/docs/html/tools/debugging/improving-w-lint.jd
+++ b/docs/html/tools/debugging/improving-w-lint.jd
@@ -9,11 +9,11 @@
 
       <ol>
         <li><a href="#overview">Overview</a></li>
-        <li><a href=#eclipse">Running lint from Eclipse</a></li>
+        <li><a href=#studio">Running lint from Android Studio</a></li>
         <li><a href=#commandline">Running lint from the command-line</a></li>
          <li><a href=#config">Configuring lint</a>
             <ol>
-		<LI><a href="#eclipse_config">Configuring lint in Eclipse</a></LI>
+		<LI><a href="#studio_config">Configuring lint in Android Studio</a></LI>
                 <LI><a href="#pref">Configuring the lint file</a></LI>
                 <LI><a href="#src">Configuring lint checking in Java and XML source files</a></LI>
             </ol>
@@ -31,8 +31,15 @@
 In addition to testing that your Android application meets its functional requirements, it's important to ensure that your code has no structural problems. Poorly structured code can impact the reliability and efficiency of your Android apps and make your code harder to maintain. For example, if your XML resource files contain unused namespaces, this takes up space and incurs unnecessary processing. Other structural issues, such as use of deprecated elements or API calls that are not supported by the target API versions, might lead to code failing to run correctly.</p>
 
 <h2 id="overview">Overview</h2>
-<p>The Android SDK provides a code scanning tool called {@code lint} that can help you to easily identify and correct problems with the structural quality of your code, without having to execute the app or write any test cases. Each problem detected by the tool is reported with a description message and a severity level, so that you can quickly prioritize the critical improvements that need to be made.  You can also configure a problem's severity level to ignore issues that are not relevant for your project, or raise the severity level. The tool has a command-line interface, so you can easily integrate it into your automated testing process.</p>
-<p>The {@code lint} tool checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. You can run {@code lint} from the command-line or from the Eclipse environment.</p>
+<p>The Android SDK provides a code scanning tool called <a href="{@docRoot}tools/help/lint.html"><code>lint</code></a>
+that can help you to easily identify and correct problems with the structural quality of your code, without having to execute the app or write any test cases. Each problem detected by the tool is reported with a description message and a severity level, so that you can quickly prioritize the critical improvements that need to be made.  You can also configure a problem's severity level to ignore issues that are not relevant for your project, or raise the severity level. The tool has a command-line interface, so you can easily integrate it into your automated testing process.</p>
+<p>The {@code lint} tool checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. You can run {@code lint} from the command-line or from Android Studio.</p>
+
+<p class="note"><strong>Note:</strong> In Android Studio, additional
+<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
+target="_blank">IntelliJ code inspections</a> run when your code is compiled in Android Studio to
+streamline code review.</p>
+
 <p>Figure 1 shows how the {@code lint} tool processes the application source files.</p>
 <img id="Fig1" src="{@docRoot}images/tools/lint.png" alt="">
 <p class="img-caption"><strong>Figure 1.</strong> Code scanning workflow with the {@code lint} tool</p>
@@ -42,25 +49,51 @@
 <dt><b>The <code>lint.xml</code> file</b></dt>
 <dd>A configuration file that you can use to specify any {@code lint} checks that you want to exclude and to customize problem severity levels.</dd>
 <dt><b>The {@code lint} tool</b></dt>
-<dd>A static code scanning tool that you can run on your Android project from the command-line or from Eclipse.   The {@code lint} tool checks for structural code problems that could affect the quality and performance of your Android application. It is strongly recommended that you correct any errors that {@code lint} detects before publishing your application.</dd>
+<dd>A static code scanning tool that you can run on your Android project from the command-line or Android Studio.  The {@code lint} tool checks for structural code problems that could affect the quality and performance of your Android application. It is strongly recommended that you correct any errors that {@code lint} detects before publishing your application.</dd>
 <dt><b>Results of {@code lint} checking</b></dt>
-<dd>You can view the results from {@code lint} in the console or in the <strong>Lint Warnings</strong> view in Eclipse.  Each issue is identified by the location in the source files where it occurred and a description of the issue.</dd>
+<dd>You can view the results from {@code lint} in the console or in the <strong>Event Log</strong> in Android Studio.  Each issue is identified by the location in the source files where it occurred and a description of the issue.</dd>
 </dl>
-<p>The {@code lint} tool is automatically installed as part of the Android SDK Tools revision 16 or higher. If you want to use {@code lint} in the Eclipse environment, you must also install the Android Development Tools (ADT) Plugin for Eclipse revision 16 or higher. For more information about installing the SDK or the ADT Plugin for Eclipse, see <a href="http://developer.android.com/sdk/installing.html">Installing the SDK.</a></p>
+<p>The {@code lint} tool is automatically installed as part of the Android SDK Tools revision 16 or higher.</p>
 
-<h2 id="eclipse">Running lint from Eclipse</h2>
-<p>If the ADT Plugin is installed in your Eclipse environment, the {@code lint} tool runs automatically when you perform one of these actions:</p>
-<ul>
-<LI>Export an APK</LI>
-<LI>Edit and save an XML source file in your Android project (such as a manifest or layout file)</LI>
-<LI>Use the layout editor in Eclipse to make changes</LI>
-</ul>
-<p>Note that when you export an APK, {@code lint} only runs an automatic check for fatal errors and aborts the export if fatal errors are found. You can turn off this automatic checking from the <strong>Lint Error Checking</strong> page in Eclipse Preferences. </p>
-<p>The output is displayed in the <strong>Lint Warnings</strong> view. If the <strong>Lint Warnings</strong> view is not showing in the workbench, you can bring it up from the Eclipse menu by clicking <strong>Window &gt; Show View &gt; Other &gt;  Android &gt; Lint Warnings</strong>.</p>
-<p>Figure 2 shows an example of the output in the Lint Warnings view.</p>
-<img id="Fig2" src="{@docRoot}images/tools/lint_output.png" alt="">
-<p class="img-caption"><strong>Figure 2.</strong> Sample output in the <strong>Lint Warnings</strong> view</p>
-<p>You can also run a {@code lint} scan manually on your Android project in Eclipse by right-clicking on the project folder in the Package Explorer > <strong>Android Tools  &gt; Run Lint: Check for Common Errors</strong>.</p>
+
+<h2 id="studio">Running lint in Android Studio</h2>
+<p>In Android Studio, the configured <code>lint</code> and
+IDE inspections run automatically whenever you build your app. The IDE inspections are
+configured along with the {@code lint} checks to run
+<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
+target="_blank">IntelliJ code inspections</a> to streamline code review.</p>
+
+<p class="note"><strong>Note:</strong> To view and modify inspection severity
+levels, use the <strong>File &gt; Settings &gt; Project Settings</strong> menu to open the
+<em>Inspection Configuration</em> page with a list of the supported inspections.</p>
+
+
+<p>With Android Studio, you can also run {@code lint} inspections for a specific build variant,
+or for all build variants from the <code>build.gradle</code> file. Add the
+<code>lintOptions</code> property to the <code>android</code> settings in the build file.
+This code snippet from a Gradle build file shows how to set the <code>quiet</code> option to
+<code>true</code> and the <code>abortOnError</code> option to <code>false</code>. </p>
+
+<pre>
+android {
+    lintOptions {
+       // set to true to turn off analysis progress reporting by lint
+       quiet true
+       // if true, stop the gradle build if errors are found
+       abortOnError false
+       // if true, only report errors
+       ignoreWarnings true
+       }
+       ...
+    }
+</pre>
+
+
+<p>To manually run inspections in Android Studio, from the application or right-click menu,
+choose <strong>Analyze &gt; Inspect Code</strong>. The <em>Specify Inspections Scope</em> dialog
+appears so you can specify the desired inspection scope and profile.</p>
+
+
 
 
 <h2 id="commandline">Running lint from the Command-Line</h2>
@@ -96,38 +129,45 @@
 <p>By default, when you run a {@code lint} scan, the tool checks for all issues that are supported by {@code lint}.  You can also restrict the issues for {@code lint} to check and assign the severity level for those issues. For example, you can disable {@code lint} checking for specific issues that are not relevant to your project and configure {@code lint} to report non-critical issues at a lower severity level.</p>
 <p>You can configure {@code lint} checking at different levels:</p>
 <ul>
-<LI>Globally, for all projects</LI>
-<li>Per project</li>
-<li>Per file</li>
-<li>Per Java class or method (by using the <code>&#64;SuppressLint</code> annotation), or per XML element (by using the <code>tools:ignore</code> attribute.</li>
+<LI>Globally, for the entire project</LI>
+<li>Per project module</li>
+<li>Per production module</li>
+<li>Per test module</li>
+<li>Per open files</li>
+<li>Per class hierarchy</li>
+<li>Per Version Control System (VCS) scopes</li>
 </ul>
 
-<h3 id="eclipse_config">Configuring lint in Eclipse</h3>
-<p>You can configure global, project-specific, and file-specific settings for {@code lint} from the Eclipse user interface.</p>
+<h3 id="studio_config">Configuring lint in Android Studio</h3>
+<p>Android Studio allows you to enable or disable individual inspections and configure
+project-global, directory-specific, and file-specific settings for {@code lint}.</p>
+
+<p>You can manage inspection profiles and configure inspection severity within Android Studio using
+the <strong>File &gt; Settings &gt; Project Settings</strong> menu to open the <em>Inspections</em>
+page with a list of the supported profiles and inspections.</p>
+<p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
+<p class="img-caption"><strong>Figure 3.</strong> Inspection Configuration</p> 
 
 <h4>Global preferences</h4>
 <ol>
-<LI>Open <strong>Window  &gt; Preferences  &gt; Android  &gt; Lint Error Checking</strong>.</LI>
-<li>Specify your preferences and click <b>OK</b>.</li>
-</ol>
-<p>These settings are applied by default when you run {@code lint} on your Android projects in Eclipse.</p>
+<li>To specify global project settings, select the project folder in the Project View and choose
+<strong>Analyze &gt; Inspect Code</strong>.</li>
 
-<h4>Project and file-specific preferences</h4>
-<ol>
-<LI>Run the {@code lint} tool on your project by right-clicking on your project folder in the Package Explorer and selecting  <strong>Android Tools &gt; Run Lint: Check for Common Errors</strong>. This action brings up the <strong>Lint Warnings</strong> view which displays a list of issues that {@code lint} detected in your project.</LI>
-<li>From the <strong>Lint Warnings</strong> view, use the toolbar options to configure {@code lint} preferences for individual projects and files in Eclipse. The options you can select include:
-<ul>
-<LI><b>Suppress this error with an annotation/attribute</b> - If the issue appears in a Java class, the {@code lint} tool adds a <code>&#64;SuppressLint</code> annotation to the method where the issue was detected.  If the issue appears in an {@code .xml} file, {@code lint} inserts a <code>tools:ignore</code> attribute to disable checking for the {@code lint} issue in this file.</LI>
-<LI><b>Ignore in this file</b> - Disables checking for this {@code lint} issue in this file.</LI>
-<li><b>Ignore in this project</b>  - Disables checking for this {@code lint} issue in this project.</li>
-<li><b>Always ignore</b> - Disables checking for this {@code lint} issue globally for all projects.</li>
-</ul>
-</li>
+<li>Specify your inspection scope and profile, and click <b>OK</b>.</li>
 </ol>
-<p>If you select the second or third option, the {@code lint} tool automatically generates a <code>lint.xml</code> file with these configuration settings in your Android application project folder.  </p>
+<p>The configured settings run the specified {@code lint} inspections. The {@code lint}
+inspections are also run whenever you build and run your Android project and modules.</p>
+
+<h4>Module and file-specific preferences</h4>
+<ol>
+<LI>Run the {@code lint} tool on your module by right-clicking on your module folder or file in the Project View and selecting  <strong>Analyze &gt; Inspect Code</strong>. This displays the {@code lint} inspection results
+with a list of issues that {@code lint} detected in your module.</LI>
+<li>From the <strong>Lint Warnings</strong> view, use the toolbar options to configure {@code lint} preferences for individual modules and files, and set the issue display options.</li>
+</ol>
+
 
 <h3 id="pref">Configuring the lint file</h3>
-<p>You can specify your {@code lint} checking preferences in the <code>lint.xml</code> file.  If you are creating this file manually, place it in the root directory of your Android project.  If you are configuring {@code lint} preferences in Eclipse, the <code>lint.xml</code> file is automatically created and added to your Android project for you.</p>
+<p>You can specify your {@code lint} checking preferences in the <code>lint.xml</code> file.  If you are creating this file manually, place it in the root directory of your Android project.  If you are configuring {@code lint} preferences in Android Studio, the <code>lint.xml</code> file is automatically created and added to your Android project for you.</p>
 <p>The <code>lint.xml</code> file consists of an enclosing <code>&lt;lint&gt;</code> parent tag that contains one or more children <code>&lt;issue&gt;</code> elements.  Each <code>&lt;issue&gt;</code> is identified by a unique <code>id</code> attribute value, which is defined by {@code lint}.</p>
 <pre>
 &lt;?xml version="1.0" encoding="UTF-8"?&gt;
@@ -165,12 +205,9 @@
 <h3 id="src">Configuring lint checking in Java and XML source files</h3>
 <p>You can disable {@code lint} checking from your Java and XML source files.</p>
 
-<p class="note"><strong>Tip: </strong>If you are using Eclipse, you can use the <strong>Quick Fix</strong> feature to automatically add the annotation or attribute to disable {@code lint} checking to your Java or XML source files:
-<ol>
-<LI>Open the Java or XML file that has a {@code lint} warning or error in an Eclipse editor.</LI>
-<LI>Move your cursor to the location in the file where is {@code lint} issue is found, then press <code>Ctrl+1</code> to bring up the <strong>Quick Fix</strong> pop-up.</LI>
-<li>From the <strong>Quick Fix</strong> pop-up, select the action to add an annotation or attribute to ignore the {@code lint} issue.</li>
-</ol>
+<p class="note"><strong>Tip: </strong>If you are using Android Studio, you can use the
+<strong>File &gt; Settings &gt; Project Settings &gt; Inspections</strong> feature to manage the
+{@code lint} checking to your Java or XML source files.
 </p>
 
 <h4>Configuring lint checking in Java</h4>
diff --git a/docs/html/tools/help/lint.jd b/docs/html/tools/help/lint.jd
index ba31f6d..0f52689 100644
--- a/docs/html/tools/help/lint.jd
+++ b/docs/html/tools/help/lint.jd
@@ -14,14 +14,23 @@
   </div>
 </div>
 
-<p>The Android {@code lint} tool is a static code analysis tool that checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization. </p>
-<p>For more information on running {@code lint}, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+<p>The Android {@code lint} tool is a static code analysis tool that checks your Android project source files for potential bugs and optimization improvements for correctness, security, performance, usability, accessibility, and internationalization.</p>
 
-<h2 id="syntax">Syntax</h2>
+<p>In Android Studio, the configured <code>lint</code> and other IDE inspections run automatically
+whenever you compile your program. You can also manually run inspections in Android Studio
+by selecting <strong>Analyze &gt; Inspect Code</strong> from the application or right-click menu.
+The <em>Specify Inspections Scope</em> dialog appears so you can specify the desired inspection 
+profile and scope.</p>
+
+<p>For more information on enabling {@code lint} inspections and running {@code lint},
+see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+
+<h2 id="syntax">Command Line Syntax</h2>
 <p>
 <pre>lint [flags] &lt;project directory&gt;</pre>
 
-For example, you can issue the following command to scan the Java and XML files under the {@code myproject}  directory and its subdirectories. The result is displayed on the console.
+For example, you can issue the following command to scan the Java and XML files under the
+{@code myproject}  directory and its subdirectories. The result is displayed on the console.
 <pre>lint myproject</pre>
 
 You can also use {@code lint} to check for a specific issue. For example, you can run the following command to scan the files under the {@code myproject} directory and its subdirectories to check for XML attributes missing the Android namespace prefix. The issue ID {@code MissingPrefix} tells lint to only scan for this issue.
@@ -172,7 +181,11 @@
 <h2 id="config_keywords">Configuring Java and XML Source Files</h2>
 <p>To configure lint checking, you can apply the following annotation or attribute to the source files in your Android project. </p>
 <ul>
-<LI>To disable lint checking for a specific Java class or method, use the <code>@SuppressLint</code> annotation. </LI>
-<li>To disable lint checking for specific sections of your XML file, use the <code>tools:ignore</code> attribute. </li>
+<LI>To disable {@code lint} checking for a specific Java class or method, use the <code>@SuppressLint</code>
+annotation. </LI>
+<li>To disable {@code lint} checking for specific sections of your XML file, use the
+<code>tools:ignore</code> attribute. </li>
 </ul>
-<p>You can also specify your lint checking preferences for a specific Android project in the lint.xml file.  For more information on configuring lint, see <a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
+<p>You can also specify your {@code lint} checking preferences for a specific Android project in
+the <code>lint.xml</code> file.  For more information on configuring {@code lint}, see
+<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with lint</a>.</p>
diff --git a/docs/html/tools/studio/index.jd b/docs/html/tools/studio/index.jd
index 26fe3cd..9e7721b 100644
--- a/docs/html/tools/studio/index.jd
+++ b/docs/html/tools/studio/index.jd
@@ -36,7 +36,7 @@
   <li>Build variants and multiple <code>apk</code> file generation</li>
   <li>Code templates to help you build common app features</li>
   <li>Rich layout editor with support for drag and drop theme editing</li>
-  <li>Lint tools to catch performance, usability, version compatibility, and other problems</li>
+  <li>{@code lint} tools to catch performance, usability, version compatibility, and other problems</li>
   <li>ProGuard and app-signing capabilities</li>
   <li>Built-in support for <a
   href="http://developers.google.com/cloud/devtools/android_studio_templates/"
@@ -244,7 +244,7 @@
 
 
 
-<h3> Memory Monitor</h3>
+<h3>Memory Monitor</h3>
 <p>Android Studio provides a memory monitor view so you can more easily monitor your
 app's memory usage to find deallocated objects, locate memory leaks and track the amount of
 memory the connected device is using. With your app running on a device or emulator, click the
@@ -255,33 +255,81 @@
 
 
 
-<h3> Lint inspections</h3>
-<p>The Android {@code lint} tool is a static code analysis tool that checks your Android project
-source files for potential bugs and optimization improvements. Choose the <strong>Analyze &gt; 
-Inspect Code</strong> to manually run the inspections. The {@code lint} settings icon in the
-Inspection display provides a complete list of the current inspections.</p>
+<h3>Code Inspections</h3>
+<p>In Android Studio, the configured <a href="{@docRoot}tools/help/lint.html"><code>lint</code></a> and
+other IDE inspections run automatically whenever you compile your program. In addition to the
+configured {@code lint} checks, additional
+<a href="https://www.jetbrains.com/idea/help/inspection-basics.html?search=inspection" class="external-link"
+target="_blank">IntelliJ code inspections</a>
+run to streamline code review.</p>
 
-<p>Hovering over a Lint error displays the full issue explanation inline for easy error
+
+<p>Android Studio enables several <code>lint</code> checks
+to ensure:
+<ul>
+  <li><code> Cipher.getInstance()</code> is used with safe values</li>
+  <li>In custom Views, the associated declare-styleable for the custom view uses the same
+  base name as the class name.</li>
+  <li>Security check for fragment injection.</li>
+  <li>Where ever property assignment no longer works as expected.</li>
+  <li>Gradle plugin version is compatible with the SDK.</li>
+  <li>Right to left validation </li>
+  <li>Required API version</li>
+  <li>many others</li>
+</ul>
+
+
+<p>Hovering over an inspection error displays the full issue explanation inline for easy error
 resolution. There is also a helpful hyperlink at the end of the error message for additional
 error information.</p>
 
-<p>With Android Studio, you can run Lint for a specific build variant, or for all build variants.
-You can configure Lint by adding a <em>lintOptions</em> property to the Android settings in the
-build.gradle file.  </p>
+<p>With Android Studio, you can also run {@code lint} inspections for a specific build variant, or
+for all build variants. You can configure the {@code lint} inspections that run by adding a
+<code>lintOptions</code> property to the Android settings in the <code>build.gradle</code>
+file.  </p>
 
-    <pre>
-    android {
-        lintOptions {
-           // set to true to turn off analysis progress reporting by lint
-           quiet true
-           // if true, stop the gradle build if errors are found
-           abortOnError false
-           // if true, only report errors
-           ignoreWarnings true
-    </pre>
+<pre>
+android {
+    lintOptions {
+       // set to true to turn off analysis progress reporting by lint
+       quiet true
+       // if true, stop the gradle build if errors are found
+       abortOnError false
+       // if true, only report errors
+       ignoreWarnings true
+    }
+</pre>
+
+
+<p>You can also manage inspection profiles and configure inspections within Android Studio.
+Choose <strong>File &gt; Settings &gt; Project Settings</strong>. The
+<em>Inspection Configuration</em> page appears with the supported inspections.</p>
+<p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
+<p class="img-caption"><strong>Figure 5.</strong> Inspection Configuration</p> 
+
+<p class="note"><strong>Note:</strong> If you wish to change the behavior of specific
+inspection notifications, you can change the inspection severity, for example from <em>warning</em>
+to <em>error</em>. </p>
+
+
+<p>To manually run inspections in Android Studio, choose <strong>Analyze &gt; Inspect Code</strong>.
+The <em>Inspections Scope</em> dialog appears so you can specify the desired inspection profile and scope.</p>
+
+
+
+<h4>Running Inspections from the command line</h4>
+<p>You can also run {@code lint} inspections from the command line in your SDK directory. </p>
+<pre>
+sdk$ lint [flags] <project directories>
+</pre>
+
+<p class="note"><strong>Note:</strong> The {@code lint} <strong>--show</strong> and <strong>--list</strong>
+flags can be used to display the available issues and explanations. </p>
+
 
 <p>For more information, see
-<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with Lint</a>.</p>
+<a href="{@docRoot}tools/debugging/improving-w-lint.html">Improving Your Code with {@code lint}</a> and
+<a href="{@docRoot}tools/help/lint.html">lint tool</a>.</p>
 
 
 <h3>Dynamic layout preview</h3>
@@ -346,6 +394,7 @@
     <p>For easy cross-platform development, the Project Wizard provides new templates for
     creating your apps for Android Wear and TV. </p>
     <p><img src="{@docRoot}images/tools/studio-tvwearsupport.png"  />
+
       <p class="img-caption"><strong>Figure 10.</strong> Supported Form Factors</p>
     <p>During app creation, the Project Wizard also displays an API Level dialog to help you choose
     the best <em>minSdkVersion</em> for your project.</p>
@@ -519,7 +568,8 @@
 
 
 <h3 id="git-samples"> Easy access to Android code samples on GitHub</h3>
-<p>Clicking <strong>Import Samples</strong> from the <strong>File</strong> menu or Welcome page
+<p>Clicking <strong>Import Samples</strong> from the <strong>File</strong> menu or <em>Welcome</em> page
+
 provides seamless access to Google code samples on GitHub.</p>
     <p><img src="{@docRoot}images/tools/studio-samples-githubaccess.png" /></p>
     <p class="img-caption"><strong>Figure 13.</strong> Code Sample Access</p>
diff --git a/docs/html/training/improving-layouts/optimizing-layout.jd b/docs/html/training/improving-layouts/optimizing-layout.jd
index 520ce56..003e7a2 100644
--- a/docs/html/training/improving-layouts/optimizing-layout.jd
+++ b/docs/html/training/improving-layouts/optimizing-layout.jd
@@ -126,13 +126,15 @@
 
 <p>Most of this time difference is due to the use of {@code layout_weight} in the {@link
 android.widget.LinearLayout} design, which can slow down the speed of measurement. It is just one
-example of how each layout has appropriate uses and you should carefully consider whether using 
+example of how each layout has appropriate uses and you should carefully consider whether using
 layout weight is necessary.</p>
 
 
 <h2 id="Lint">Use Lint</h2>
 
-<p>It is always good practice to run the <a href="http://tools.android.com/tips/lint">Lint</a> tool on your layout files to search for possible view hierarchy optimizations. Lint has replaced the Layoutopt tool and has much greater functionality. Some examples of Lint <a
+<p>It is always good practice to run the <a href="{@docRoot}tools/help/lint.html">lint</a>
+tool on your layout files to search for possible view hierarchy optimizations. Lint has replaced
+the Layoutopt tool and has much greater functionality. Some examples of lint <a
 href="http://tools.android.com/tips/lint-checks">rules</a> are:</p>
 
 <ul>
@@ -143,11 +145,18 @@
 <li>Deep layouts - Layouts with too much nesting are bad for performance. Consider using flatter layouts such as {@link android.widget.RelativeLayout} or {@link android.widget.GridLayout} to improve performance. The default maximum depth is 10.</li>
 </ul>
 
-<p>Another benefit of Lint is that it is integrated into the Android Development Tools for Eclipse (ADT 16+). Lint automatically runs whenever you export an APK, edit and save an XML file or use the Layout Editor. To manually force Lint to run press the Lint button in the Eclipse toolbar.</p>
+<p>Another benefit of Lint is that it is integrated into Android Studio. Lint automatically runs 
+whenever you compile your program. With Android Studio, you can also run lint inspections for a
+specific build variant, or for all build variants. </p>
 
-<img src="{@docRoot}images/training/lint_icon.png" alt="" />
+<p>You can also manage inspection profiles and configure inspections within Android Studio with the
+<strong>File&gt;Settings&gt;Project Settings</strong> option. The Inspection Configuration page
+appears with the supported inspections.</p>
+<p><img src="{@docRoot}images/tools/studio-inspections-config.png" alt="" /> </p>
+<p class="img-caption"><strong>Figure 5.</strong> Inspection Configuration</p> 
 
-<p>When used inside Eclipse, Lint has the ability to automatically fix some issues, provide suggestions for others and jump directly to the offending code for review. If you don’t use Eclipse for your development, Lint can also be run from the command line. More information about Lint is available at <a href="http://tools.android.com/tips/lint">tools.android.com</a>.</p>
+<p>Lint has the ability to automatically fix some issues, provide suggestions for others and jump
+directly to the offending code for review.</p>
 
 
 
diff --git a/docs/html/training/multiscreen/screendensities.jd b/docs/html/training/multiscreen/screendensities.jd
index 1fc5904..64e70fd 100644
--- a/docs/html/training/multiscreen/screendensities.jd
+++ b/docs/html/training/multiscreen/screendensities.jd
@@ -154,7 +154,7 @@
 <p class="note"><strong>Note:</strong> You should place all launcher icons in the
 <code>res/mipmap-[density]/</code> folders, rather than <code>drawable/</code> folders to ensure
 launcher apps use the best resolution icon. For more information about using the mipmap folders, see
-<a href="{@docRoot}tools/project/index.html#mipmap">Managing Projects Overview</a>.</p>
+<a href="{@docRoot}tools/projects/index.html#mipmap">Managing Projects Overview</a>.</p>
 
 <p>For more tips and guidelines for creating icon assets for your application, see the <a
 href="{@docRoot}guide/practices/ui_guidelines/icon_design.html">Icon Design
diff --git a/docs/html/training/volley/request.jd b/docs/html/training/volley/request.jd
index d8ccab2..8a7dc62 100644
--- a/docs/html/training/volley/request.jd
+++ b/docs/html/training/volley/request.jd
@@ -85,7 +85,7 @@
 
 // Retrieves an image specified by the URL, displays it in the UI.
 ImageRequest request = new ImageRequest(url,
-    new Response.Listener<Bitmap>() {
+    new Response.Listener&lt;Bitmap&gt;() {
         &#64;Override
         public void onResponse(Bitmap bitmap) {
             mImageView.setImageBitmap(bitmap);
@@ -257,7 +257,7 @@
 String url = "http://my-json-feed";
 
 JsonObjectRequest jsObjRequest = new JsonObjectRequest
-        (Request.Method.GET, url, null, new Response.Listener<JSONObject>() {
+        (Request.Method.GET, url, null, new Response.Listener&lt;JSONObject&gt;() {
 
     &#64;Override
     public void onResponse(JSONObject response) {
diff --git a/docs/html/training/volley/simple.jd b/docs/html/training/volley/simple.jd
index 942c57f..ecb5fde 100644
--- a/docs/html/training/volley/simple.jd
+++ b/docs/html/training/volley/simple.jd
@@ -63,7 +63,7 @@
 
 // Request a string response from the provided URL.
 StringRequest stringRequest = new StringRequest(Request.Method.GET, url,
-            new Response.Listener<String>() {
+            new Response.Listener&lt;String&gt;() {
     &#64;Override
     public void onResponse(String response) {
         // Display the first 500 characters of the response string.
diff --git a/libs/hwui/Android.common.mk b/libs/hwui/Android.common.mk
index e05dd55..5dacbb5 100644
--- a/libs/hwui/Android.common.mk
+++ b/libs/hwui/Android.common.mk
@@ -43,11 +43,13 @@
     Extensions.cpp \
     FboCache.cpp \
     FontRenderer.cpp \
+    FrameInfo.cpp \
     GammaFontRenderer.cpp \
     GlopBuilder.cpp \
     GradientCache.cpp \
     Image.cpp \
     Interpolator.cpp \
+    JankTracker.cpp \
     Layer.cpp \
     LayerCache.cpp \
     LayerRenderer.cpp \
diff --git a/libs/hwui/FrameInfo.cpp b/libs/hwui/FrameInfo.cpp
new file mode 100644
index 0000000..6da1fa8
--- /dev/null
+++ b/libs/hwui/FrameInfo.cpp
@@ -0,0 +1,28 @@
+/*
+ * 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.
+ */
+#include "FrameInfo.h"
+
+#include <cstring>
+
+namespace android {
+namespace uirenderer {
+
+void FrameInfo::importUiThreadInfo(int64_t* info) {
+    memcpy(mFrameInfo, info, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/FrameInfo.h b/libs/hwui/FrameInfo.h
new file mode 100644
index 0000000..3c31677
--- /dev/null
+++ b/libs/hwui/FrameInfo.h
@@ -0,0 +1,116 @@
+/*
+ * 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.
+ */
+#ifndef FRAMEINFO_H_
+#define FRAMEINFO_H_
+
+#include "utils/Macros.h"
+
+#include <cutils/compiler.h>
+#include <utils/Timers.h>
+
+#include <memory.h>
+
+namespace android {
+namespace uirenderer {
+
+#define UI_THREAD_FRAME_INFO_SIZE 9
+
+HWUI_ENUM(FrameInfoIndex,
+    kFlags = 0,
+    kIntendedVsync,
+    kVsync,
+    kOldestInputEvent,
+    kNewestInputEvent,
+    kHandleInputStart,
+    kAnimationStart,
+    kPerformTraversalsStart,
+    kDrawStart,
+    // End of UI frame info
+
+    kSyncStart,
+    kIssueDrawCommandsStart,
+    kSwapBuffers,
+    kFrameCompleted,
+
+    // Must be the last value!
+    kNumIndexes
+);
+
+HWUI_ENUM(FrameInfoFlags,
+    kWindowLayoutChanged = 1 << 0,
+    kRTAnimation = 1 << 1,
+    kSurfaceCanvas = 1 << 2,
+);
+
+class ANDROID_API UiFrameInfoBuilder {
+public:
+    UiFrameInfoBuilder(int64_t* buffer) : mBuffer(buffer) {
+        memset(mBuffer, 0, UI_THREAD_FRAME_INFO_SIZE * sizeof(int64_t));
+    }
+
+    UiFrameInfoBuilder& setVsync(nsecs_t vsyncTime, nsecs_t intendedVsync) {
+        mBuffer[FrameInfoIndex::kVsync] = vsyncTime;
+        mBuffer[FrameInfoIndex::kIntendedVsync] = intendedVsync;
+        return *this;
+    }
+
+    UiFrameInfoBuilder& addFlag(FrameInfoFlagsEnum flag) {
+        mBuffer[FrameInfoIndex::kFlags] |= static_cast<uint64_t>(flag);
+        return *this;
+    }
+
+private:
+    int64_t* mBuffer;
+};
+
+class FrameInfo {
+public:
+    void importUiThreadInfo(int64_t* info);
+
+    void markSyncStart() {
+        mFrameInfo[FrameInfoIndex::kSyncStart] = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markIssueDrawCommandsStart() {
+        mFrameInfo[FrameInfoIndex::kIssueDrawCommandsStart] = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markSwapBuffers() {
+        mFrameInfo[FrameInfoIndex::kSwapBuffers] = systemTime(CLOCK_MONOTONIC);
+    }
+
+    void markFrameCompleted() {
+        mFrameInfo[FrameInfoIndex::kFrameCompleted] = systemTime(CLOCK_MONOTONIC);
+    }
+
+    int64_t operator[](FrameInfoIndexEnum index) const {
+        if (index == FrameInfoIndex::kNumIndexes) return 0;
+        return mFrameInfo[static_cast<int>(index)];
+    }
+
+    int64_t operator[](int index) const {
+        if (index < 0 || index >= FrameInfoIndex::kNumIndexes) return 0;
+        return mFrameInfo[static_cast<int>(index)];
+    }
+
+private:
+    int64_t mFrameInfo[FrameInfoIndex::kNumIndexes];
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* FRAMEINFO_H_ */
diff --git a/libs/hwui/JankTracker.cpp b/libs/hwui/JankTracker.cpp
new file mode 100644
index 0000000..62cb97c
--- /dev/null
+++ b/libs/hwui/JankTracker.cpp
@@ -0,0 +1,136 @@
+/*
+ * 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.
+ */
+#include "JankTracker.h"
+
+#include <cstdio>
+#include <inttypes.h>
+
+namespace android {
+namespace uirenderer {
+
+static const char* JANK_TYPE_NAMES[] = {
+        "Missed Vsync",
+        "High input latency",
+        "Slow UI thread",
+        "Slow bitmap uploads",
+        "Slow draw",
+};
+
+struct Comparison {
+    FrameInfoIndexEnum start;
+    FrameInfoIndexEnum end;
+};
+
+static const Comparison COMPARISONS[] = {
+        {FrameInfoIndex::kIntendedVsync, FrameInfoIndex::kVsync},
+        {FrameInfoIndex::kOldestInputEvent, FrameInfoIndex::kVsync},
+        {FrameInfoIndex::kVsync, FrameInfoIndex::kSyncStart},
+        {FrameInfoIndex::kSyncStart, FrameInfoIndex::kIssueDrawCommandsStart},
+        {FrameInfoIndex::kIssueDrawCommandsStart, FrameInfoIndex::kFrameCompleted},
+};
+
+// If the event exceeds 10 seconds throw it away, this isn't a jank event
+// it's an ANR and will be handled as such
+static const int64_t IGNORE_EXCEEDING = seconds_to_nanoseconds(10);
+
+/*
+ * Frames that are exempt from jank metrics.
+ * First-draw frames, for example, are expected to
+ * be slow, this is hidden from the user with window animations and
+ * other tricks
+ *
+ * Similarly, we don't track direct-drawing via Surface:lockHardwareCanvas()
+ * for now
+ *
+ * TODO: kSurfaceCanvas can negatively impact other drawing by using up
+ * time on the RenderThread, figure out how to attribute that as a jank-causer
+ */
+static const int64_t EXEMPT_FRAMES_FLAGS
+        = FrameInfoFlags::kWindowLayoutChanged
+        | FrameInfoFlags::kSurfaceCanvas;
+
+JankTracker::JankTracker(nsecs_t frameIntervalNanos) {
+    reset();
+    setFrameInterval(frameIntervalNanos);
+}
+
+void JankTracker::setFrameInterval(nsecs_t frameInterval) {
+    mFrameInterval = frameInterval;
+    mThresholds[kMissedVsync] = 1;
+    /*
+     * Due to interpolation and sample rate differences between the touch
+     * panel and the display (example, 85hz touch panel driving a 60hz display)
+     * we call high latency 1.5 * frameinterval
+     *
+     * NOTE: Be careful when tuning this! A theoretical 1,000hz touch panel
+     * on a 60hz display will show kOldestInputEvent - kIntendedVsync of being 15ms
+     * Thus this must always be larger than frameInterval, or it will fail
+     */
+    mThresholds[kHighInputLatency] = static_cast<int64_t>(1.5 * frameInterval);
+
+    // Note that these do not add up to 1. This is intentional. It's to deal
+    // with variance in values, and should be sort of an upper-bound on what
+    // is reasonable to expect.
+    mThresholds[kSlowUI] = static_cast<int64_t>(.5 * frameInterval);
+    mThresholds[kSlowSync] = static_cast<int64_t>(.2 * frameInterval);
+    mThresholds[kSlowRT] = static_cast<int64_t>(.75 * frameInterval);
+
+}
+
+void JankTracker::addFrame(const FrameInfo& frame) {
+    using namespace FrameInfoIndex;
+    mTotalFrameCount++;
+    // Fast-path for jank-free frames
+    int64_t totalDuration = frame[kFrameCompleted] - frame[kIntendedVsync];
+    if (CC_LIKELY(totalDuration < mFrameInterval)) {
+        return;
+    }
+
+    if (frame[kFlags] & EXEMPT_FRAMES_FLAGS) {
+        return;
+    }
+
+    mJankFrameCount++;
+
+    for (int i = 0; i < NUM_BUCKETS; i++) {
+        int64_t delta = frame[COMPARISONS[i].end] - frame[COMPARISONS[i].start];
+        if (delta >= mThresholds[i] && delta < IGNORE_EXCEEDING) {
+            mBuckets[i].count++;
+        }
+    }
+}
+
+void JankTracker::dump(int fd) {
+    FILE* file = fdopen(fd, "a");
+    fprintf(file, "\nFrame stats:");
+    fprintf(file, "\n  Total frames rendered: %u", mTotalFrameCount);
+    fprintf(file, "\n  Janky frames: %u (%.2f%%)", mJankFrameCount,
+            (float) mJankFrameCount / (float) mTotalFrameCount * 100.0f);
+    for (int i = 0; i < NUM_BUCKETS; i++) {
+        fprintf(file, "\n   Number %s: %u", JANK_TYPE_NAMES[i], mBuckets[i].count);
+    }
+    fprintf(file, "\n");
+    fflush(file);
+}
+
+void JankTracker::reset() {
+    memset(mBuckets, 0, sizeof(JankBucket) * NUM_BUCKETS);
+    mTotalFrameCount = 0;
+    mJankFrameCount = 0;
+}
+
+} /* namespace uirenderer */
+} /* namespace android */
diff --git a/libs/hwui/JankTracker.h b/libs/hwui/JankTracker.h
new file mode 100644
index 0000000..aa554cd
--- /dev/null
+++ b/libs/hwui/JankTracker.h
@@ -0,0 +1,68 @@
+/*
+ * 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.
+ */
+#ifndef JANKTRACKER_H_
+#define JANKTRACKER_H_
+
+#include "FrameInfo.h"
+#include "renderthread/TimeLord.h"
+#include "utils/RingBuffer.h"
+
+#include <memory>
+
+namespace android {
+namespace uirenderer {
+
+enum JankType {
+    kMissedVsync = 0,
+    kHighInputLatency,
+    kSlowUI,
+    kSlowSync,
+    kSlowRT,
+
+    // must be last
+    NUM_BUCKETS,
+};
+
+struct JankBucket {
+    // Number of frames that hit this bucket
+    uint32_t count;
+};
+
+// TODO: Replace DrawProfiler with this
+class JankTracker {
+public:
+    JankTracker(nsecs_t frameIntervalNanos);
+
+    void setFrameInterval(nsecs_t frameIntervalNanos);
+
+    void addFrame(const FrameInfo& frame);
+
+    void dump(int fd);
+    void reset();
+
+private:
+    JankBucket mBuckets[NUM_BUCKETS];
+    int64_t mThresholds[NUM_BUCKETS];
+
+    int64_t mFrameInterval;
+    uint32_t mTotalFrameCount;
+    uint32_t mJankFrameCount;
+};
+
+} /* namespace uirenderer */
+} /* namespace android */
+
+#endif /* JANKTRACKER_H_ */
diff --git a/libs/hwui/SkiaCanvasProxy.cpp b/libs/hwui/SkiaCanvasProxy.cpp
index de5f91c..3c65705 100644
--- a/libs/hwui/SkiaCanvasProxy.cpp
+++ b/libs/hwui/SkiaCanvasProxy.cpp
@@ -228,21 +228,23 @@
     }
 
     // setup the first glyph position and adjust bounds if needed
+    int xBaseline = 0;
+    int yBaseline = 0;
     if (mCanvas->drawTextAbsolutePos()) {
         bounds.offset(x,y);
-        pointStorage[0].set(x, y);
-    } else {
-        pointStorage[0].set(0, 0);
+        xBaseline = x;
+        yBaseline = y;
     }
+    pointStorage[0].set(xBaseline, yBaseline);
 
     // setup the remaining glyph positions
     if (glyphs.paint.isVerticalText()) {
         for (int i = 1; i < glyphs.count; i++) {
-            pointStorage[i].set(x, glyphWidths[i-1] + pointStorage[i-1].fY);
+            pointStorage[i].set(xBaseline, glyphWidths[i-1] + pointStorage[i-1].fY);
         }
     } else {
         for (int i = 1; i < glyphs.count; i++) {
-            pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, y);
+            pointStorage[i].set(glyphWidths[i-1] + pointStorage[i-1].fX, yBaseline);
         }
     }
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index 6346479..80c60d9 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -48,7 +48,8 @@
         , mCanvas(nullptr)
         , mHaveNewSurface(false)
         , mAnimationContext(contextFactory->createAnimationContext(mRenderThread.timeLord()))
-        , mRootRenderNode(rootRenderNode) {
+        , mRootRenderNode(rootRenderNode)
+        , mCurrentFrameInfo(nullptr) {
     mRenderThread.renderState().registerCanvasContext(this);
 }
 
@@ -151,9 +152,13 @@
     }
 }
 
-void CanvasContext::prepareTree(TreeInfo& info) {
+void CanvasContext::prepareTree(TreeInfo& info, int64_t* uiFrameInfo) {
     mRenderThread.removeFrameCallback(this);
 
+    mCurrentFrameInfo = &mFrames.next();
+    mCurrentFrameInfo->importUiThreadInfo(uiFrameInfo);
+    mCurrentFrameInfo->markSyncStart();
+
     info.damageAccumulator = &mDamageAccumulator;
     info.renderer = mCanvas;
     if (mPrefetechedLayers.size() && info.mode == TreeInfo::MODE_FULL) {
@@ -203,6 +208,7 @@
             "drawRenderNode called on a context with no canvas or surface!");
 
     profiler().markPlaybackStart();
+    mCurrentFrameInfo->markIssueDrawCommandsStart();
 
     SkRect dirty;
     mDamageAccumulator.finish(&dirty);
@@ -239,12 +245,19 @@
 
     profiler().markPlaybackEnd();
 
+    // Even if we decided to cancel the frame, from the perspective of jank
+    // metrics the frame was swapped at this point
+    mCurrentFrameInfo->markSwapBuffers();
+
     if (drew) {
         swapBuffers();
     } else {
         mEglManager.cancelFrame();
     }
 
+    // TODO: Use a fence for real completion?
+    mCurrentFrameInfo->markFrameCompleted();
+    mRenderThread.jankTracker().addFrame(*mCurrentFrameInfo);
     profiler().finishFrame();
 }
 
@@ -257,9 +270,14 @@
     ATRACE_CALL();
 
     profiler().startFrame();
+    int64_t frameInfo[UI_THREAD_FRAME_INFO_SIZE];
+    UiFrameInfoBuilder(frameInfo)
+        .addFlag(FrameInfoFlags::kRTAnimation)
+        .setVsync(mRenderThread.timeLord().computeFrameTimeNanos(),
+                mRenderThread.timeLord().latestVsync());
 
     TreeInfo info(TreeInfo::MODE_RT_ONLY, mRenderThread.renderState());
-    prepareTree(info);
+    prepareTree(info, frameInfo);
     if (info.out.canDrawThisFrame) {
         draw();
     }
@@ -372,6 +390,28 @@
     thread.eglManager().setTextureAtlas(buffer, map, mapSize);
 }
 
+void CanvasContext::dumpFrames(int fd) {
+    FILE* file = fdopen(fd, "a");
+    fprintf(file, "\n\n---PROFILEDATA---");
+    for (size_t i = 0; i < mFrames.size(); i++) {
+        FrameInfo& frame = mFrames[i];
+        if (frame[FrameInfoIndex::kSyncStart] == 0) {
+            continue;
+        }
+        fprintf(file, "\n");
+        for (int i = 0; i < FrameInfoIndex::kNumIndexes; i++) {
+            fprintf(file, "%" PRId64 ",", frame[i]);
+        }
+    }
+    fprintf(file, "\n---PROFILEDATA---\n\n");
+    fflush(file);
+}
+
+void CanvasContext::resetFrameStats() {
+    mFrames.clear();
+    mRenderThread.jankTracker().reset();
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/CanvasContext.h b/libs/hwui/renderthread/CanvasContext.h
index d3fbde8..9a60dc7 100644
--- a/libs/hwui/renderthread/CanvasContext.h
+++ b/libs/hwui/renderthread/CanvasContext.h
@@ -17,7 +17,14 @@
 #ifndef CANVASCONTEXT_H_
 #define CANVASCONTEXT_H_
 
-#include <set>
+#include "DamageAccumulator.h"
+#include "DrawProfiler.h"
+#include "IContextFactory.h"
+#include "FrameInfo.h"
+#include "RenderNode.h"
+#include "utils/RingBuffer.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
 
 #include <cutils/compiler.h>
 #include <EGL/egl.h>
@@ -25,14 +32,7 @@
 #include <utils/Functor.h>
 #include <utils/Vector.h>
 
-#include "../DamageAccumulator.h"
-#include "../DrawProfiler.h"
-#include "../IContextFactory.h"
-#include "../RenderNode.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#define FUNCTOR_PROCESS_DELAY 4
+#include <set>
 
 namespace android {
 namespace uirenderer {
@@ -75,7 +75,7 @@
     void setOpaque(bool opaque);
     void makeCurrent();
     void processLayerUpdate(DeferredLayerUpdater* layerUpdater);
-    void prepareTree(TreeInfo& info);
+    void prepareTree(TreeInfo& info, int64_t* uiFrameInfo);
     void draw();
     void destroy();
 
@@ -103,6 +103,9 @@
 
     DrawProfiler& profiler() { return mProfiler; }
 
+    void dumpFrames(int fd);
+    void resetFrameStats();
+
 private:
     friend class RegisterFrameCallbackTask;
     // TODO: Replace with something better for layer & other GL object
@@ -133,6 +136,9 @@
     const sp<RenderNode> mRootRenderNode;
 
     DrawProfiler mProfiler;
+    FrameInfo* mCurrentFrameInfo;
+    // Ring buffer large enough for 1 second worth of frames
+    RingBuffer<FrameInfo, 60> mFrames;
 
     std::set<RenderNode*> mPrefetechedLayers;
 };
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 4d8a469..679a00f 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -34,8 +34,6 @@
 DrawFrameTask::DrawFrameTask()
         : mRenderThread(nullptr)
         , mContext(nullptr)
-        , mFrameTimeNanos(0)
-        , mRecordDurationNanos(0)
         , mDensity(1.0f) // safe enough default
         , mSyncResult(kSync_OK) {
 }
@@ -68,18 +66,12 @@
     }
 }
 
-int DrawFrameTask::drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos) {
+int DrawFrameTask::drawFrame() {
     LOG_ALWAYS_FATAL_IF(!mContext, "Cannot drawFrame with no CanvasContext!");
 
     mSyncResult = kSync_OK;
-    mFrameTimeNanos = frameTimeNanos;
-    mRecordDurationNanos = recordDurationNanos;
     postAndWait();
 
-    // Reset the single-frame data
-    mFrameTimeNanos = 0;
-    mRecordDurationNanos = 0;
-
     return mSyncResult;
 }
 
@@ -93,7 +85,7 @@
     ATRACE_NAME("DrawFrame");
 
     mContext->profiler().setDensity(mDensity);
-    mContext->profiler().startFrame(mRecordDurationNanos);
+    mContext->profiler().startFrame();
 
     bool canUnblockUiThread;
     bool canDrawThisFrame;
@@ -122,7 +114,7 @@
 
 bool DrawFrameTask::syncFrameState(TreeInfo& info) {
     ATRACE_CALL();
-    mRenderThread->timeLord().vsyncReceived(mFrameTimeNanos);
+    mRenderThread->timeLord().vsyncReceived(mFrameInfo[FrameInfoIndex::kVsync]);
     mContext->makeCurrent();
     Caches::getInstance().textureCache.resetMarkInUse();
 
@@ -130,7 +122,7 @@
         mContext->processLayerUpdate(mLayers[i].get());
     }
     mLayers.clear();
-    mContext->prepareTree(info);
+    mContext->prepareTree(info, mFrameInfo);
 
     // This is after the prepareTree so that any pending operations
     // (RenderNode tree state, prefetched layers, etc...) will be flushed.
diff --git a/libs/hwui/renderthread/DrawFrameTask.h b/libs/hwui/renderthread/DrawFrameTask.h
index 953f012..0e56bea 100644
--- a/libs/hwui/renderthread/DrawFrameTask.h
+++ b/libs/hwui/renderthread/DrawFrameTask.h
@@ -25,6 +25,7 @@
 #include "RenderTask.h"
 
 #include "../Rect.h"
+#include "../FrameInfo.h"
 #include "../TreeInfo.h"
 
 namespace android {
@@ -62,7 +63,9 @@
     void removeLayerUpdate(DeferredLayerUpdater* layer);
 
     void setDensity(float density) { mDensity = density; }
-    int drawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos);
+    int drawFrame();
+
+    int64_t* frameInfo() { return mFrameInfo; }
 
     virtual void run() override;
 
@@ -80,12 +83,12 @@
     /*********************************************
      *  Single frame data
      *********************************************/
-    nsecs_t mFrameTimeNanos;
-    nsecs_t mRecordDurationNanos;
     float mDensity;
     std::vector< sp<DeferredLayerUpdater> > mLayers;
 
     int mSyncResult;
+
+    int64_t mFrameInfo[UI_THREAD_FRAME_INFO_SIZE];
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 4dc4248..3a31db0 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,14 +16,14 @@
 
 #include "RenderProxy.h"
 
-#include "CanvasContext.h"
-#include "RenderTask.h"
-#include "RenderThread.h"
-
-#include "../DeferredLayerUpdater.h"
-#include "../DisplayList.h"
-#include "../LayerRenderer.h"
-#include "../Rect.h"
+#include "DeferredLayerUpdater.h"
+#include "DisplayList.h"
+#include "LayerRenderer.h"
+#include "Rect.h"
+#include "renderthread/CanvasContext.h"
+#include "renderthread/RenderTask.h"
+#include "renderthread/RenderThread.h"
+#include "utils/Macros.h"
 
 namespace android {
 namespace uirenderer {
@@ -52,6 +52,11 @@
     MethodInvokeRenderTask* task = new MethodInvokeRenderTask((RunnableMethod) Bridge_ ## method); \
     ARGS(method) *args = (ARGS(method) *) task->payload()
 
+HWUI_ENUM(DumpFlags,
+        kFrameStats = 1 << 0,
+        kReset      = 1 << 1,
+);
+
 CREATE_BRIDGE4(createContext, RenderThread* thread, bool translucent,
         RenderNode* rootRenderNode, IContextFactory* contextFactory) {
     return new CanvasContext(*args->thread, args->translucent,
@@ -92,7 +97,7 @@
 }
 
 CREATE_BRIDGE2(setFrameInterval, RenderThread* thread, nsecs_t frameIntervalNanos) {
-    args->thread->timeLord().setFrameInterval(args->frameIntervalNanos);
+    args->thread->setFrameInterval(args->frameIntervalNanos);
     return nullptr;
 }
 
@@ -175,7 +180,8 @@
 }
 
 void RenderProxy::setup(int width, int height, const Vector3& lightCenter, float lightRadius,
-        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha) {
+        uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha, float density) {
+    mDrawFrameTask.setDensity(density);
     SETUP_TASK(setup);
     args->context = mContext;
     args->width = width;
@@ -199,10 +205,12 @@
     post(task);
 }
 
-int RenderProxy::syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
-        float density) {
-    mDrawFrameTask.setDensity(density);
-    return mDrawFrameTask.drawFrame(frameTimeNanos, recordDurationNanos);
+int64_t* RenderProxy::frameInfo() {
+    return mDrawFrameTask.frameInfo();
+}
+
+int RenderProxy::syncAndDrawFrame() {
+    return mDrawFrameTask.drawFrame();
 }
 
 CREATE_BRIDGE1(destroy, CanvasContext* context) {
@@ -375,19 +383,28 @@
     mRenderThread.queueAtFront(task);
 }
 
-CREATE_BRIDGE2(dumpProfileInfo, CanvasContext* context, int fd) {
+CREATE_BRIDGE3(dumpProfileInfo, CanvasContext* context, int fd, int dumpFlags) {
     args->context->profiler().dumpData(args->fd);
+    if (args->dumpFlags & DumpFlags::kFrameStats) {
+        args->context->dumpFrames(args->fd);
+    }
+    if (args->dumpFlags & DumpFlags::kReset) {
+        args->context->resetFrameStats();
+    }
     return nullptr;
 }
 
-void RenderProxy::dumpProfileInfo(int fd) {
+void RenderProxy::dumpProfileInfo(int fd, int dumpFlags) {
     SETUP_TASK(dumpProfileInfo);
     args->context = mContext;
     args->fd = fd;
+    args->dumpFlags = dumpFlags;
     postAndWait(task);
 }
 
-CREATE_BRIDGE1(dumpGraphicsMemory, int fd) {
+CREATE_BRIDGE2(dumpGraphicsMemory, int fd, RenderThread* thread) {
+    args->thread->jankTracker().dump(args->fd);
+
     FILE *file = fdopen(args->fd, "a");
     if (Caches::hasInstance()) {
         String8 cachesLog;
@@ -403,6 +420,7 @@
 void RenderProxy::dumpGraphicsMemory(int fd) {
     SETUP_TASK(dumpGraphicsMemory);
     args->fd = fd;
+    args->thread = &RenderThread::getInstance();
     staticPostAndWait(task);
 }
 
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index d87e777..19e73e5 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -71,10 +71,10 @@
     ANDROID_API void updateSurface(const sp<ANativeWindow>& window);
     ANDROID_API bool pauseSurface(const sp<ANativeWindow>& window);
     ANDROID_API void setup(int width, int height, const Vector3& lightCenter, float lightRadius,
-            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha);
+            uint8_t ambientShadowAlpha, uint8_t spotShadowAlpha, float density);
     ANDROID_API void setOpaque(bool opaque);
-    ANDROID_API int syncAndDrawFrame(nsecs_t frameTimeNanos, nsecs_t recordDurationNanos,
-            float density);
+    ANDROID_API int64_t* frameInfo();
+    ANDROID_API int syncAndDrawFrame();
     ANDROID_API void destroy();
 
     ANDROID_API static void invokeFunctor(Functor* functor, bool waitForCompletion);
@@ -95,7 +95,7 @@
     ANDROID_API void stopDrawing();
     ANDROID_API void notifyFramePending();
 
-    ANDROID_API void dumpProfileInfo(int fd);
+    ANDROID_API void dumpProfileInfo(int fd, int dumpFlags);
     ANDROID_API static void dumpGraphicsMemory(int fd);
 
     ANDROID_API void setTextureAtlas(const sp<GraphicBuffer>& buffer, int64_t* map, size_t size);
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 9a0fbad..2a8baa7 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -151,6 +151,11 @@
     LOG_ALWAYS_FATAL("Can't destroy the render thread");
 }
 
+void RenderThread::setFrameInterval(nsecs_t frameInterval) {
+    mTimeLord.setFrameInterval(frameInterval);
+    mJankTracker->setFrameInterval(frameInterval);
+}
+
 void RenderThread::initializeDisplayEventReceiver() {
     LOG_ALWAYS_FATAL_IF(mDisplayEventReceiver, "Initializing a second DisplayEventReceiver?");
     mDisplayEventReceiver = new DisplayEventReceiver();
@@ -167,6 +172,7 @@
     initializeDisplayEventReceiver();
     mEglManager = new EglManager(*this);
     mRenderState = new RenderState(*this);
+    mJankTracker = new JankTracker(mTimeLord.frameIntervalNanos());
 }
 
 int RenderThread::displayEventReceiverCallback(int fd, int events, void* data) {
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 8fc8ca5..f169424 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -19,8 +19,8 @@
 
 #include "RenderTask.h"
 
-#include <memory>
-#include <set>
+#include "../JankTracker.h"
+#include "TimeLord.h"
 
 #include <cutils/compiler.h>
 #include <utils/Looper.h>
@@ -28,7 +28,8 @@
 #include <utils/Singleton.h>
 #include <utils/Thread.h>
 
-#include "TimeLord.h"
+#include <memory>
+#include <set>
 
 namespace android {
 
@@ -85,9 +86,12 @@
     // the next vsync. If it is not currently registered this does nothing.
     void pushBackFrameCallback(IFrameCallback* callback);
 
+    void setFrameInterval(nsecs_t frameInterval);
+
     TimeLord& timeLord() { return mTimeLord; }
     RenderState& renderState() { return *mRenderState; }
     EglManager& eglManager() { return *mEglManager; }
+    JankTracker& jankTracker() { return *mJankTracker; }
 
 protected:
     virtual bool threadLoop() override;
@@ -132,6 +136,8 @@
     TimeLord mTimeLord;
     RenderState* mRenderState;
     EglManager* mEglManager;
+
+    JankTracker* mJankTracker = nullptr;
 };
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.cpp b/libs/hwui/renderthread/TimeLord.cpp
index f187493..f846d6a 100644
--- a/libs/hwui/renderthread/TimeLord.cpp
+++ b/libs/hwui/renderthread/TimeLord.cpp
@@ -32,7 +32,7 @@
     return false;
 }
 
-nsecs_t TimeLord::computeFrameTimeMs() {
+nsecs_t TimeLord::computeFrameTimeNanos() {
     // Logic copied from Choreographer.java
     nsecs_t now = systemTime(CLOCK_MONOTONIC);
     nsecs_t jitterNanos = now - mFrameTimeNanos;
@@ -40,7 +40,11 @@
         nsecs_t lastFrameOffset = jitterNanos % mFrameIntervalNanos;
         mFrameTimeNanos = now - lastFrameOffset;
     }
-    return nanoseconds_to_milliseconds(mFrameTimeNanos);
+    return mFrameTimeNanos;
+}
+
+nsecs_t TimeLord::computeFrameTimeMs() {
+    return nanoseconds_to_milliseconds(computeFrameTimeNanos());
 }
 
 } /* namespace renderthread */
diff --git a/libs/hwui/renderthread/TimeLord.h b/libs/hwui/renderthread/TimeLord.h
index 7c155d2..5464399 100644
--- a/libs/hwui/renderthread/TimeLord.h
+++ b/libs/hwui/renderthread/TimeLord.h
@@ -29,9 +29,13 @@
 class TimeLord {
 public:
     void setFrameInterval(nsecs_t intervalNanos) { mFrameIntervalNanos = intervalNanos; }
+    nsecs_t frameIntervalNanos() const { return mFrameIntervalNanos; }
+
     // returns true if the vsync is newer, false if it was rejected for staleness
     bool vsyncReceived(nsecs_t vsync);
+    nsecs_t latestVsync() { return mFrameTimeNanos; }
     nsecs_t computeFrameTimeMs();
+    nsecs_t computeFrameTimeNanos();
 
 private:
     friend class RenderThread;
diff --git a/libs/hwui/tests/main.cpp b/libs/hwui/tests/main.cpp
index b6d2c4d..0431e22 100644
--- a/libs/hwui/tests/main.cpp
+++ b/libs/hwui/tests/main.cpp
@@ -85,7 +85,7 @@
         proxy->initialize(surface);
         float lightX = width / 2.0;
         proxy->setup(width, height, (Vector3){lightX, dp(-200.0f), dp(800.0f)},
-                dp(800.0f), 255 * 0.075, 255 * 0.15);
+                dp(800.0f), 255 * 0.075, 255 * 0.15, gDisplay.density);
 
         android::uirenderer::Rect DUMMY;
 
@@ -100,8 +100,7 @@
 
             ATRACE_NAME("UI-Draw Frame");
             animation.doFrame(i);
-            nsecs_t frameTimeNs = systemTime(CLOCK_MONOTONIC);
-            proxy->syncAndDrawFrame(frameTimeNs, 0, gDisplay.density);
+            proxy->syncAndDrawFrame();
         }
 
         sleep(5);
diff --git a/libs/hwui/utils/Macros.h b/libs/hwui/utils/Macros.h
index 5ca9083..b93f720 100644
--- a/libs/hwui/utils/Macros.h
+++ b/libs/hwui/utils/Macros.h
@@ -35,4 +35,12 @@
         static_assert(std::is_standard_layout<Type>::value, \
         #Type " must have standard layout")
 
+#define HWUI_ENUM(name, ...) \
+    namespace name { \
+        enum _##name { \
+            __VA_ARGS__ \
+        }; \
+    } \
+    typedef enum name::_##name name##Enum
+
 #endif /* MACROS_H */
diff --git a/libs/hwui/utils/RingBuffer.h b/libs/hwui/utils/RingBuffer.h
new file mode 100644
index 0000000..fc9aec0
--- /dev/null
+++ b/libs/hwui/utils/RingBuffer.h
@@ -0,0 +1,71 @@
+/*
+ * 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.
+ */
+#ifndef RINGBUFFER_H_
+#define RINGBUFFER_H_
+
+#include "utils/Macros.h"
+
+#include <stddef.h>
+
+namespace android {
+namespace uirenderer {
+
+template<class T, size_t SIZE>
+class RingBuffer {
+    PREVENT_COPY_AND_ASSIGN(RingBuffer);
+
+public:
+    RingBuffer() {}
+    ~RingBuffer() {}
+
+    size_t capacity() { return SIZE; }
+    size_t size() { return mCount; }
+
+    T& next() {
+        mHead = (mHead + 1) % SIZE;
+        if (mCount < SIZE) {
+            mCount++;
+        }
+        return mBuffer[mHead];
+    }
+
+    T& front() {
+        return this[0];
+    }
+
+    T& back() {
+        return this[size() - 1];
+    }
+
+    T& operator[](size_t index) {
+        return mBuffer[(mHead + index + 1) % mCount];
+    }
+
+    void clear() {
+        mCount = 0;
+        mHead = -1;
+    }
+
+private:
+    T mBuffer[SIZE];
+    int mHead = -1;
+    size_t mCount = 0;
+};
+
+}; // namespace uirenderer
+}; // namespace android
+
+#endif /* RINGBUFFER_H_ */
diff --git a/media/java/android/media/AudioAttributes.java b/media/java/android/media/AudioAttributes.java
index ca242e4..97919a9 100644
--- a/media/java/android/media/AudioAttributes.java
+++ b/media/java/android/media/AudioAttributes.java
@@ -209,8 +209,23 @@
     @SystemApi
     public final static int FLAG_HW_HOTWORD = 0x1 << 5;
 
+    /**
+     * @hide
+     * Flag requesting audible playback even under limited interruptions.
+     */
+    @SystemApi
+    public final static int FLAG_BYPASS_INTERRUPTION_POLICY = 0x1 << 6;
+
+    /**
+     * @hide
+     * Flag requesting audible playback even when the underlying stream is muted.
+     */
+    @SystemApi
+    public final static int FLAG_BYPASS_MUTE = 0x1 << 7;
+
     private final static int FLAG_ALL = FLAG_AUDIBILITY_ENFORCED | FLAG_SECURE | FLAG_SCO |
-            FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD;
+            FLAG_BEACON | FLAG_HW_AV_SYNC | FLAG_HW_HOTWORD | FLAG_BYPASS_INTERRUPTION_POLICY |
+            FLAG_BYPASS_MUTE;
     private final static int FLAG_ALL_PUBLIC = FLAG_AUDIBILITY_ENFORCED | FLAG_HW_AV_SYNC;
 
     private int mUsage = USAGE_UNKNOWN;
diff --git a/media/java/android/media/AudioDevicesManager.java b/media/java/android/media/AudioDevicesManager.java
new file mode 100644
index 0000000..bce2100
--- /dev/null
+++ b/media/java/android/media/AudioDevicesManager.java
@@ -0,0 +1,271 @@
+/*
+ * 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 android.media;
+
+import android.content.Context;
+import android.util.Slog;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.Iterator;
+import android.content.Context;
+
+/** @hide
+ * API candidate
+ */
+public class AudioDevicesManager {
+    private static String TAG = "AudioDevicesManager";
+    private static boolean DEBUG = true;
+
+    private AudioManager mAudioManager = null;
+    private OnAmPortUpdateListener mPortListener = null;
+
+    /*
+     * Enum/Selection API
+     */
+    public AudioDevicesManager(Context context) {
+        mAudioManager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
+        mPortListener = new OnAmPortUpdateListener();
+        mAudioManager.registerAudioPortUpdateListener(mPortListener);
+    }
+
+    /** @hide
+     * API candidate
+     */
+    //TODO Merge this class into android.media.AudioDevice
+    public class AudioDeviceInfo {
+        private AudioDevicePort mPort = null;
+
+        /** @hide */
+        /* package */ AudioDeviceInfo(AudioDevicePort port) {
+            mPort = port;
+        }
+
+        public int getId() { return mPort.handle().id(); }
+
+        public String getName() { return mPort.name(); }
+
+        public int getType() {
+            return mPort.type();
+        }
+
+        public String getAddress() {
+            return mPort.address();
+        }
+
+        public int getRole() { return mPort.role(); }
+
+        public int[] getSampleRates() { return mPort.samplingRates(); }
+
+        public int[] getChannelMasks() { return mPort.channelMasks(); }
+
+        public int[] getChannelCounts() {
+            int[] masks = getChannelMasks();
+            int[] counts = new int[masks.length];
+            for (int mask_index = 0; mask_index < masks.length; mask_index++) {
+                counts[mask_index] = getRole() == AudioPort.ROLE_SINK
+                        ? AudioFormat.channelCountFromOutChannelMask(masks[mask_index])
+                        : AudioFormat.channelCountFromInChannelMask(masks[mask_index]);
+            }
+            return counts;
+        }
+
+        /* The format IDs are in AudioFormat.java */
+        public int[] getFormats() { return mPort.formats(); }
+
+        public String toString() { return "" + getId() + " - " + getName(); }
+    }
+
+    /** @hide */
+    public static final int LIST_DEVICES_OUTPUTS   = 0x0001;
+    /** @hide */
+    public static final int LIST_DEVICES_INPUTS    = 0x0002;
+    /** @hide */
+    public static final int LIST_DEVICES_BUILTIN   = 0x0004;
+    /** @hide */
+    public static final int LIST_DEVICES_USB       = 0x0008;
+    // TODO implement the semantics for these.
+    /** @hide */
+    public static final int LIST_DEVICES_WIRED     = 0x0010;
+    /** @hide */
+    public static final int LIST_DEVICES_UNWIRED   = 0x0020;
+
+    /** @hide */
+    public static final int LIST_DEVICES_ALL = LIST_DEVICES_OUTPUTS | LIST_DEVICES_INPUTS;
+
+    private boolean checkFlags(AudioDevicePort port, int flags) {
+        // Inputs / Outputs
+        boolean passed =
+                port.role() == AudioPort.ROLE_SINK && (flags & LIST_DEVICES_OUTPUTS) != 0 ||
+                port.role() == AudioPort.ROLE_SOURCE && (flags & LIST_DEVICES_INPUTS) != 0;
+
+        // USB
+        if (passed && (flags & LIST_DEVICES_USB) != 0) {
+            int role = port.role();
+            int type = port.type();
+            Slog.i(TAG, "  role:" + role + " type:0x" + Integer.toHexString(type));
+            passed =
+                (role == AudioPort.ROLE_SINK && (type & AudioSystem.DEVICE_OUT_ALL_USB) != 0) ||
+                (role == AudioPort.ROLE_SOURCE && (type & AudioSystem.DEVICE_IN_ALL_USB) != 0);
+        }
+
+        return passed;
+    }
+
+    /** @hide */
+    public ArrayList<AudioDeviceInfo> listDevices(int flags) {
+        Slog.i(TAG, "AudioManager.listDevices(" + Integer.toHexString(flags) + ")");
+
+        ArrayList<AudioDevicePort> ports = new ArrayList<AudioDevicePort>();
+        int status = mAudioManager.listAudioDevicePorts(ports);
+
+        Slog.i(TAG, "  status:" + status + " numPorts:" + ports.size());
+
+        ArrayList<AudioDeviceInfo> deviceList = new ArrayList<AudioDeviceInfo>();
+
+        if (status == AudioManager.SUCCESS) {
+            deviceList = new ArrayList<AudioDeviceInfo>();
+             for (AudioDevicePort port : ports) {
+                if (checkFlags(port, flags)) {
+                    deviceList.add(new AudioDeviceInfo(port));
+                }
+            }
+        }
+        return deviceList;
+    }
+
+    private ArrayList<OnAudioDeviceConnectionListener> mDeviceConnectionListeners =
+            new ArrayList<OnAudioDeviceConnectionListener>();
+
+    private HashMap<Integer, AudioPort> mCurrentPortlist =
+            new HashMap<Integer, AudioPort>();
+
+    private ArrayList<AudioDeviceInfo> calcAddedDevices(AudioPort[] portList) {
+        ArrayList<AudioDeviceInfo> addedDevices = new  ArrayList<AudioDeviceInfo>();
+        synchronized(mCurrentPortlist) {
+            for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+                if (portList[portIndex] instanceof AudioDevicePort) {
+                    if (!mCurrentPortlist.containsKey(portList[portIndex].handle().id())) {
+                        addedDevices.add(new AudioDeviceInfo((AudioDevicePort)portList[portIndex]));
+                    }
+                }
+            }
+        }
+        return addedDevices;
+    }
+
+    private boolean hasPortId(AudioPort[] portList, int id) {
+        for(int portIndex = 0; portIndex < portList.length; portIndex++) {
+            if (portList[portIndex].handle().id() == id) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private ArrayList<AudioDeviceInfo> calcRemovedDevices(AudioPort[] portList) {
+        ArrayList<AudioDeviceInfo> removedDevices = new  ArrayList<AudioDeviceInfo>();
+
+        synchronized (mCurrentPortlist) {
+            Iterator it = mCurrentPortlist.entrySet().iterator();
+            while (it.hasNext()) {
+                HashMap.Entry pairs = (HashMap.Entry)it.next();
+                if (pairs.getValue() instanceof AudioDevicePort) {
+                    if (!hasPortId(portList, ((Integer)pairs.getKey()).intValue())) {
+                        removedDevices.add(new AudioDeviceInfo((AudioDevicePort)pairs.getValue()));
+                    }
+                }
+            }
+        }
+        return removedDevices;
+    }
+
+    private void buildCurrentDevicesList(AudioPort[] portList) {
+        synchronized (mCurrentPortlist) {
+            mCurrentPortlist.clear();
+            for (int portIndex = 0; portIndex < portList.length; portIndex++) {
+                if (portList[portIndex] instanceof AudioDevicePort) {
+                    mCurrentPortlist.put(portList[portIndex].handle().id(),
+                                         (AudioDevicePort)portList[portIndex]);
+                }
+            }
+        }
+    }
+
+    /** @hide */
+    public void addDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+        synchronized (mDeviceConnectionListeners) {
+            mDeviceConnectionListeners.add(listener);
+        }
+    }
+
+    /** @hide */
+    public void removeDeviceConnectionListener(OnAudioDeviceConnectionListener listener) {
+        synchronized (mDeviceConnectionListeners) {
+            mDeviceConnectionListeners.remove(listener);
+        }
+    }
+
+    /**
+     * @hide
+     */
+    private class OnAmPortUpdateListener implements AudioManager.OnAudioPortUpdateListener {
+        static final String TAG = "OnAmPortUpdateListener";
+        public void onAudioPortListUpdate(AudioPort[] portList) {
+            Slog.i(TAG, "onAudioPortListUpdate() " + portList.length + " ports.");
+            ArrayList<AudioDeviceInfo> addedDevices = calcAddedDevices(portList);
+            ArrayList<AudioDeviceInfo> removedDevices = calcRemovedDevices(portList);
+
+            ArrayList<OnAudioDeviceConnectionListener> listeners = null;
+            synchronized (mDeviceConnectionListeners) {
+                listeners =
+                        new ArrayList<OnAudioDeviceConnectionListener>(mDeviceConnectionListeners);
+            }
+
+            // Connect
+            if (addedDevices.size() != 0) {
+                for (OnAudioDeviceConnectionListener listener : listeners) {
+                    listener.onConnect(addedDevices);
+                }
+            }
+
+            // Disconnect?
+            if (removedDevices.size() != 0) {
+                for (OnAudioDeviceConnectionListener listener : listeners) {
+                    listener.onDisconnect(removedDevices);
+                }
+            }
+
+            buildCurrentDevicesList(portList);
+        }
+
+        /**
+         * Callback method called upon audio patch list update.
+         * @param patchList the updated list of audio patches
+         */
+        public void onAudioPatchListUpdate(AudioPatch[] patchList) {
+            Slog.i(TAG, "onAudioPatchListUpdate() " + patchList.length + " patches.");
+        }
+
+        /**
+         * Callback method called when the mediaserver dies
+         */
+        public void onServiceDied() {
+            Slog.i(TAG, "onServiceDied()");
+        }
+    }
+}
diff --git a/media/java/android/media/AudioManager.java b/media/java/android/media/AudioManager.java
index da89cf4..9876995 100644
--- a/media/java/android/media/AudioManager.java
+++ b/media/java/android/media/AudioManager.java
@@ -3459,14 +3459,14 @@
      * @see listAudioPorts(ArrayList<AudioPort>)
      * @hide
      */
-    public int listAudioDevicePorts(ArrayList<AudioPort> devices) {
+    public int listAudioDevicePorts(ArrayList<AudioDevicePort> devices) {
         ArrayList<AudioPort> ports = new ArrayList<AudioPort>();
         int status = updateAudioPortCache(ports, null);
         if (status == SUCCESS) {
             devices.clear();
             for (int i = 0; i < ports.size(); i++) {
                 if (ports.get(i) instanceof AudioDevicePort) {
-                    devices.add(ports.get(i));
+                    devices.add((AudioDevicePort)ports.get(i));
                 }
             }
         }
diff --git a/media/java/android/media/AudioTrack.java b/media/java/android/media/AudioTrack.java
index caccb6e..cd78234 100644
--- a/media/java/android/media/AudioTrack.java
+++ b/media/java/android/media/AudioTrack.java
@@ -1178,6 +1178,9 @@
     }
 
     private boolean isRestricted() {
+        if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+            return false;
+        }
         try {
             final int usage = AudioAttributes.usageForLegacyStreamType(mStreamType);
             final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO, usage,
diff --git a/media/java/android/media/MediaPlayer.java b/media/java/android/media/MediaPlayer.java
index 615dac2..fc372eb 100644
--- a/media/java/android/media/MediaPlayer.java
+++ b/media/java/android/media/MediaPlayer.java
@@ -604,6 +604,7 @@
     private final IAppOpsService mAppOps;
     private int mStreamType = AudioManager.USE_DEFAULT_STREAM_TYPE;
     private int mUsage = -1;
+    private boolean mBypassInterruptionPolicy;
 
     /**
      * Default constructor. Consider using one of the create() methods for
@@ -1169,6 +1170,9 @@
     private native void _start() throws IllegalStateException;
 
     private boolean isRestricted() {
+        if (mBypassInterruptionPolicy) {
+            return false;
+        }
         try {
             final int usage = mUsage != -1 ? mUsage
                     : AudioAttributes.usageForLegacyStreamType(getAudioStreamType());
@@ -1560,6 +1564,8 @@
             throw new IllegalArgumentException(msg);
         }
         mUsage = attributes.getUsage();
+        mBypassInterruptionPolicy = (attributes.getFlags()
+                & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0;
         Parcel pattributes = Parcel.obtain();
         attributes.writeToParcel(pattributes, AudioAttributes.FLATTEN_TAGS);
         setParameter(KEY_PARAMETER_AUDIO_ATTRIBUTES, pattributes);
diff --git a/media/java/android/media/OnAudioDeviceConnectionListener.java b/media/java/android/media/OnAudioDeviceConnectionListener.java
new file mode 100644
index 0000000..4bdd4d0
--- /dev/null
+++ b/media/java/android/media/OnAudioDeviceConnectionListener.java
@@ -0,0 +1,28 @@
+/*
+ * 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 android.media;
+
+import java.util.ArrayList;
+
+/**
+ * @hide
+ * API candidate
+ */
+public abstract class OnAudioDeviceConnectionListener {
+    public void onConnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+    public void onDisconnect(ArrayList<AudioDevicesManager.AudioDeviceInfo> devices) {}
+}
diff --git a/media/java/android/media/SoundPool.java b/media/java/android/media/SoundPool.java
index 32d5b82..db6b38b 100644
--- a/media/java/android/media/SoundPool.java
+++ b/media/java/android/media/SoundPool.java
@@ -608,6 +608,9 @@
                 int priority, int loop, float rate);
 
         private boolean isRestricted() {
+            if ((mAttributes.getFlags() & AudioAttributes.FLAG_BYPASS_INTERRUPTION_POLICY) != 0) {
+                return false;
+            }
             try {
                 final int mode = mAppOps.checkAudioOperation(AppOpsManager.OP_PLAY_AUDIO,
                         mAttributes.getUsage(),
diff --git a/media/jni/android_media_ImageReader.cpp b/media/jni/android_media_ImageReader.cpp
index 5406130..cf69b8f 100644
--- a/media/jni/android_media_ImageReader.cpp
+++ b/media/jni/android_media_ImageReader.cpp
@@ -430,7 +430,7 @@
             pData = buffer->data;
             dataSize = Image_getJpegSize(buffer, usingRGBAOverride);
             break;
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             // Single plane 16bpp bayer data.
             bytesPerPixel = 2;
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -517,7 +517,7 @@
             pixelStride = 0;
             break;
         case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
         case HAL_PIXEL_FORMAT_RGB_565:
             // Single plane 16bpp data.
             ALOG_ASSERT(idx == 0, "Wrong index: %d", idx);
@@ -584,7 +584,7 @@
             rowStride = buffer->stride;
             break;
         case HAL_PIXEL_FORMAT_Y16:
-        case HAL_PIXEL_FORMAT_RAW_SENSOR:
+        case HAL_PIXEL_FORMAT_RAW16:
             // In native side, strides are specified in pixels, not in bytes.
             // Single plane 16bpp bayer data. even width/height,
             // row stride multiple of 16 pixels (32 bytes)
diff --git a/packages/Keyguard/res/layout/keyguard_password_view.xml b/packages/Keyguard/res/layout/keyguard_password_view.xml
index cff2fc7..7dcaf6d 100644
--- a/packages/Keyguard/res/layout/keyguard_password_view.xml
+++ b/packages/Keyguard/res/layout/keyguard_password_view.xml
@@ -64,6 +64,7 @@
              android:layout_height="wrap_content"
              android:layout_marginBottom="12dp"
              android:src="@drawable/ic_lockscreen_ime"
+             android:contentDescription="@string/accessibility_ime_switch_button"
              android:clickable="true"
              android:padding="8dip"
              android:layout_gravity="end|center_vertical"
diff --git a/packages/Keyguard/res/values/strings.xml b/packages/Keyguard/res/values/strings.xml
index 8b18b2ed..5047330 100644
--- a/packages/Keyguard/res/values/strings.xml
+++ b/packages/Keyguard/res/values/strings.xml
@@ -297,4 +297,7 @@
         This is displayed if the phone is not connected to a carrier.-->
     <string name="keyguard_carrier_default">No service.</string>
 
+    <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
+    <string name="accessibility_ime_switch_button" msgid="5032926134740456424">Switch input method button.</string>
+
 </resources>
diff --git a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
index 78f6ace..eac83d8 100644
--- a/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
+++ b/packages/SettingsProvider/src/com/android/providers/settings/SettingsBackupAgent.java
@@ -32,14 +32,18 @@
 import android.os.Handler;
 import android.os.ParcelFileDescriptor;
 import android.os.Process;
+import android.os.UserHandle;
 import android.provider.Settings;
 import android.util.Log;
 
+import com.android.internal.widget.LockPatternUtils;
+
 import libcore.io.IoUtils;
 
 import java.io.BufferedOutputStream;
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
+import java.io.ByteArrayInputStream;
 import java.io.ByteArrayOutputStream;
 import java.io.CharArrayReader;
 import java.io.DataInputStream;
@@ -76,10 +80,11 @@
     private static final String KEY_SECURE = "secure";
     private static final String KEY_GLOBAL = "global";
     private static final String KEY_LOCALE = "locale";
+    private static final String KEY_LOCK_SETTINGS = "lock_settings";
 
     // Versioning of the state file.  Increment this version
     // number any time the set of state items is altered.
-    private static final int STATE_VERSION = 3;
+    private static final int STATE_VERSION = 4;
 
     // Slots in the checksum array.  Never insert new items in the middle
     // of this array; new slots must be appended.
@@ -89,20 +94,23 @@
     private static final int STATE_WIFI_SUPPLICANT = 3;
     private static final int STATE_WIFI_CONFIG     = 4;
     private static final int STATE_GLOBAL          = 5;
+    private static final int STATE_LOCK_SETTINGS   = 6;
 
-    private static final int STATE_SIZE            = 6; // The current number of state items
+    private static final int STATE_SIZE            = 7; // The current number of state items
 
     // Number of entries in the checksum array at various version numbers
     private static final int STATE_SIZES[] = {
         0,
         4,              // version 1
         5,              // version 2 added STATE_WIFI_CONFIG
-        STATE_SIZE      // version 3 added STATE_GLOBAL
+        6,              // version 3 added STATE_GLOBAL
+        STATE_SIZE      // version 4 added STATE_LOCK_SETTINGS
     };
 
     // Versioning of the 'full backup' format
-    private static final int FULL_BACKUP_VERSION = 2;
+    private static final int FULL_BACKUP_VERSION = 3;
     private static final int FULL_BACKUP_ADDED_GLOBAL = 2;  // added the "global" entry
+    private static final int FULL_BACKUP_ADDED_LOCK_SETTINGS = 3; // added the "lock_settings" entry
 
     private static final int INTEGER_BYTE_COUNT = Integer.SIZE / Byte.SIZE;
 
@@ -124,6 +132,10 @@
     private static final String KEY_WIFI_SUPPLICANT = "\uffedWIFI";
     private static final String KEY_WIFI_CONFIG = "\uffedCONFIG_WIFI";
 
+    // Keys within the lock settings section
+    private static final String KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED = "owner_info_enabled";
+    private static final String KEY_LOCK_SETTINGS_OWNER_INFO = "owner_info";
+
     // Name of the temporary file we use during full backup/restore.  This is
     // stored in the full-backup tarfile as well, so should not be changed.
     private static final String STAGE_FILE = "flattened-data";
@@ -367,6 +379,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] globalSettingsData = getGlobalSettings();
+        byte[] lockSettingsData   = getLockSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -387,6 +400,9 @@
         stateChecksums[STATE_WIFI_CONFIG] =
             writeIfChanged(stateChecksums[STATE_WIFI_CONFIG], KEY_WIFI_CONFIG, wifiConfigData,
                     data);
+        stateChecksums[STATE_LOCK_SETTINGS] =
+            writeIfChanged(stateChecksums[STATE_LOCK_SETTINGS], KEY_LOCK_SETTINGS,
+                    lockSettingsData, data);
 
         writeNewChecksums(stateChecksums, newState);
     }
@@ -492,6 +508,8 @@
             } else if (KEY_WIFI_CONFIG.equals(key)) {
                 initWifiRestoreIfNecessary();
                 mWifiRestore.incorporateWifiConfigFile(data);
+            } else if (KEY_LOCK_SETTINGS.equals(key)) {
+                restoreLockSettings(data);
              } else {
                 data.skipEntityData();
             }
@@ -513,6 +531,7 @@
         byte[] systemSettingsData = getSystemSettings();
         byte[] secureSettingsData = getSecureSettings();
         byte[] globalSettingsData = getGlobalSettings();
+        byte[] lockSettingsData   = getLockSettings();
         byte[] locale = mSettingsHelper.getLocaleData();
         byte[] wifiSupplicantData = getWifiSupplicant(FILE_WIFI_SUPPLICANT);
         byte[] wifiConfigData = getFileData(mWifiConfigFile);
@@ -547,6 +566,9 @@
             if (DEBUG_BACKUP) Log.d(TAG, wifiConfigData.length + " bytes of wifi config data");
             out.writeInt(wifiConfigData.length);
             out.write(wifiConfigData);
+            if (DEBUG_BACKUP) Log.d(TAG, lockSettingsData.length + " bytes of lock settings data");
+            out.writeInt(lockSettingsData.length);
+            out.write(lockSettingsData);
 
             out.flush();    // also flushes downstream
 
@@ -629,6 +651,16 @@
             in.readFully(buffer, 0, nBytes);
             restoreFileData(mWifiConfigFile, buffer, nBytes);
 
+            if (version >= FULL_BACKUP_ADDED_LOCK_SETTINGS) {
+                nBytes = in.readInt();
+                if (DEBUG_BACKUP) Log.d(TAG, nBytes + " bytes of lock settings data");
+                if (nBytes > buffer.length) buffer = new byte[nBytes];
+                if (nBytes > 0) {
+                    in.readFully(buffer, 0, nBytes);
+                    restoreLockSettings(buffer, nBytes);
+                }
+            }
+
             if (DEBUG_BACKUP) Log.d(TAG, "Full restore complete.");
         } else {
             data.close();
@@ -676,6 +708,9 @@
             return oldChecksum;
         }
         try {
+            if (DEBUG_BACKUP) {
+                Log.v(TAG, "Writing entity " + key + " of size " + data.length);
+            }
             output.writeEntityHeader(key, data.length);
             output.writeEntityData(data, data.length);
         } catch (IOException ioe) {
@@ -714,6 +749,31 @@
         }
     }
 
+    /**
+     * Serialize the owner info settings
+     */
+    private byte[] getLockSettings() {
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+        final boolean ownerInfoEnabled = lockPatternUtils.isOwnerInfoEnabled();
+        final String ownerInfo = lockPatternUtils.getOwnerInfo(UserHandle.myUserId());
+
+        ByteArrayOutputStream baos = new ByteArrayOutputStream();
+        DataOutputStream out = new DataOutputStream(baos);
+        try {
+            out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED);
+            out.writeUTF(ownerInfoEnabled ? "1" : "0");
+            if (ownerInfo != null) {
+                out.writeUTF(KEY_LOCK_SETTINGS_OWNER_INFO);
+                out.writeUTF(ownerInfo != null ? ownerInfo : "");
+            }
+            // End marker
+            out.writeUTF("");
+            out.flush();
+        } catch (IOException ioe) {
+        }
+        return baos.toByteArray();
+    }
+
     private void restoreSettings(BackupDataInput data, Uri contentUri,
             HashSet<String> movedToGlobal) {
         byte[] settings = new byte[data.getDataSize()];
@@ -797,6 +857,50 @@
     }
 
     /**
+     * Restores the owner info enabled and owner info settings in LockSettings.
+     *
+     * @param buffer
+     * @param nBytes
+     */
+    private void restoreLockSettings(byte[] buffer, int nBytes) {
+        final LockPatternUtils lockPatternUtils = new LockPatternUtils(this);
+
+        ByteArrayInputStream bais = new ByteArrayInputStream(buffer, 0, nBytes);
+        DataInputStream in = new DataInputStream(bais);
+        try {
+            String key;
+            // Read until empty string marker
+            while ((key = in.readUTF()).length() > 0) {
+                final String value = in.readUTF();
+                if (DEBUG_BACKUP) {
+                    Log.v(TAG, "Restoring lock_settings " + key + " = " + value);
+                }
+                switch (key) {
+                    case KEY_LOCK_SETTINGS_OWNER_INFO_ENABLED:
+                        lockPatternUtils.setOwnerInfoEnabled("1".equals(value));
+                        break;
+                    case KEY_LOCK_SETTINGS_OWNER_INFO:
+                        lockPatternUtils.setOwnerInfo(value, UserHandle.myUserId());
+                        break;
+                }
+            }
+            in.close();
+        } catch (IOException ioe) {
+        }
+    }
+
+    private void restoreLockSettings(BackupDataInput data) {
+        final byte[] settings = new byte[data.getDataSize()];
+        try {
+            data.readEntityData(settings, 0, settings.length);
+        } catch (IOException ioe) {
+            Log.e(TAG, "Couldn't read entity data");
+            return;
+        }
+        restoreLockSettings(settings, settings.length);
+    }
+
+    /**
      * Given a cursor and a set of keys, extract the required keys and
      * values and write them to a byte array.
      *
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 1d8cb46..f7bbce0 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -79,7 +79,8 @@
             android:layout_width="@dimen/notification_panel_width"
             android:layout_height="match_parent"
             android:layout_gravity="@integer/notification_panel_layout_gravity"
-            android:layout_marginBottom="@dimen/close_handle_underlap" />
+            android:layout_marginBottom="@dimen/close_handle_underlap"
+            android:importantForAccessibility="no" />
 
         <ViewStub
             android:id="@+id/keyguard_user_switcher"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 808ded5..d8b6a82 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -217,8 +217,6 @@
     <!-- Click action label for accessibility for the phone button. [CHAR LIMIT=NONE] -->
     <string name="camera_label">open camera</string>
 
-    <!-- Content description of the switch input method button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
-    <string name="accessibility_ime_switch_button">Switch input method button.</string>
     <!-- Content description of the compatibility zoom button for accessibility (not shown on the screen). [CHAR LIMIT=NONE] -->
     <string name="accessibility_compatibility_zoom_button">Compatibility zoom button.</string>
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index b1ac733..e0b4c2f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -193,8 +193,7 @@
         }
 
         // Start loading tasks according to the load plan
-        ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
-        if (stacks.size() == 0) {
+        if (!plan.hasTasks()) {
             loader.preloadTasks(plan, mConfig.launchedFromHome);
         }
         RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
@@ -203,11 +202,11 @@
         loadOpts.numVisibleTaskThumbnails = mConfig.launchedNumVisibleThumbnails;
         loader.loadTasks(this, plan, loadOpts);
 
-        boolean hasTasks = plan.hasTasks();
-        if (hasTasks) {
+        ArrayList<TaskStack> stacks = plan.getAllTaskStacks();
+        mConfig.launchedWithNoRecentTasks = !plan.hasTasks();
+        if (!mConfig.launchedWithNoRecentTasks) {
             mRecentsView.setTaskStacks(stacks);
         }
-        mConfig.launchedWithNoRecentTasks = !hasTasks;
 
         // Create the home intent runnable
         Intent homeIntent = new Intent(Intent.ACTION_MAIN, null);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
index 2318319..21975b0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java
@@ -879,7 +879,7 @@
 
                     // Start the focus animation when alt-tabbing
                     if (mConfig.launchedWithAltTab && !mConfig.launchedHasConfigurationChanged) {
-                        TaskView tv = taskViews.get(mFocusedTaskIndex);
+                        TaskView tv = getChildViewForTask(mStack.getTasks().get(mFocusedTaskIndex));
                         if (tv != null) {
                             tv.setFocusedTask(true);
                         }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
index b827acc..81e960a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewHeader.java
@@ -32,12 +32,10 @@
 import android.graphics.PorterDuff;
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.PorterDuffXfermode;
-import android.graphics.drawable.ColorDrawable;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.GradientDrawable;
 import android.graphics.drawable.RippleDrawable;
 import android.util.AttributeSet;
-import android.view.MotionEvent;
 import android.view.View;
 import android.view.ViewOutlineProvider;
 import android.widget.FrameLayout;
@@ -104,11 +102,10 @@
         });
 
         // Load the dismiss resources
-        Resources res = context.getResources();
-        mLightDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_light);
-        mDarkDismissDrawable = res.getDrawable(R.drawable.recents_dismiss_dark);
+        mLightDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_light);
+        mDarkDismissDrawable = context.getDrawable(R.drawable.recents_dismiss_dark);
         mDismissContentDescription =
-                res.getString(R.string.accessibility_recents_item_will_be_dismissed);
+                context.getString(R.string.accessibility_recents_item_will_be_dismissed);
 
         // Configure the highlight paint
         if (sHighlightPaint == null) {
@@ -283,23 +280,26 @@
         }
 
         if (focused) {
+            int currentColor = mBackgroundColor;
             int secondaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             int[][] states = new int[][] {
+                    new int[] {},
                     new int[] { android.R.attr.state_enabled },
                     new int[] { android.R.attr.state_pressed }
             };
             int[] newStates = new int[]{
+                    0,
                     android.R.attr.state_enabled,
                     android.R.attr.state_pressed
             };
             int[] colors = new int[] {
+                    currentColor,
                     secondaryColor,
                     secondaryColor
             };
             mBackground.setColor(new ColorStateList(states, colors));
             mBackground.setState(newStates);
             // Pulse the background color
-            int currentColor = mBackgroundColor;
             int lightPrimaryColor = getSecondaryColor(mCurrentPrimaryColor, mCurrentPrimaryColorIsDark);
             ValueAnimator backgroundColor = ValueAnimator.ofObject(new ArgbEvaluator(),
                     currentColor, lightPrimaryColor);
@@ -326,7 +326,7 @@
 
             mFocusAnimator = new AnimatorSet();
             mFocusAnimator.playTogether(backgroundColor, translation);
-            mFocusAnimator.setStartDelay(750);
+            mFocusAnimator.setStartDelay(150);
             mFocusAnimator.setDuration(750);
             mFocusAnimator.start();
         } else {
diff --git a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
index c8b080e..b4613d6 100644
--- a/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
+++ b/services/accessibility/java/com/android/server/accessibility/ScreenMagnifier.java
@@ -34,6 +34,7 @@
 import android.text.TextUtils;
 import android.util.Property;
 import android.util.Slog;
+import android.util.TypedValue;
 import android.view.GestureDetector;
 import android.view.GestureDetector.SimpleOnGestureListener;
 import android.view.MagnificationSpec;
@@ -110,7 +111,6 @@
     private static final int STATE_MAGNIFIED_INTERACTION = 4;
 
     private static final float DEFAULT_MAGNIFICATION_SCALE = 2.0f;
-    private static final int MULTI_TAP_TIME_SLOP_ADJUSTMENT = 50;
 
     private static final int MESSAGE_ON_MAGNIFIED_BOUNDS_CHANGED = 1;
     private static final int MESSAGE_ON_RECTANGLE_ON_SCREEN_REQUESTED = 2;
@@ -135,9 +135,8 @@
 
     private final AccessibilityManagerService mAms;
 
-    private final int mTapTimeSlop = ViewConfiguration.getTapTimeout();
-    private final int mMultiTapTimeSlop =
-            ViewConfiguration.getDoubleTapTimeout() - MULTI_TAP_TIME_SLOP_ADJUSTMENT;
+    private final int mTapTimeSlop = ViewConfiguration.getJumpTapTimeout();
+    private final int mMultiTapTimeSlop;
     private final int mTapDistanceSlop;
     private final int mMultiTapDistanceSlop;
 
@@ -192,6 +191,9 @@
         mWindowManager = LocalServices.getService(WindowManagerInternal.class);
         mAms = service;
 
+        mMultiTapTimeSlop = ViewConfiguration.getDoubleTapTimeout()
+                + mContext.getResources().getInteger(
+                com.android.internal.R.integer.config_screen_magnification_multi_tap_adjustment);
         mLongAnimationDuration = context.getResources().getInteger(
                 com.android.internal.R.integer.config_longAnimTime);
         mTapDistanceSlop = ViewConfiguration.get(context).getScaledTouchSlop();
@@ -481,15 +483,20 @@
         private static final float MIN_SCALE = 1.3f;
         private static final float MAX_SCALE = 5.0f;
 
-        private static final float SCALING_THRESHOLD = 0.3f;
-
         private final ScaleGestureDetector mScaleGestureDetector;
         private final GestureDetector mGestureDetector;
 
+        private final float mScalingThreshold;
+
         private float mInitialScaleFactor = -1;
         private boolean mScaling;
 
         public MagnifiedContentInteractonStateHandler(Context context) {
+            final TypedValue scaleValue = new TypedValue();
+            context.getResources().getValue(
+                    com.android.internal.R.dimen.config_screen_magnification_scaling_threshold,
+                    scaleValue, false);
+            mScalingThreshold = scaleValue.getFloat();
             mScaleGestureDetector = new ScaleGestureDetector(context, this);
             mScaleGestureDetector.setQuickScaleEnabled(false);
             mGestureDetector = new GestureDetector(context, this);
@@ -537,7 +544,7 @@
                     mInitialScaleFactor = detector.getScaleFactor();
                 } else {
                     final float deltaScale = detector.getScaleFactor() - mInitialScaleFactor;
-                    if (Math.abs(deltaScale) > SCALING_THRESHOLD) {
+                    if (Math.abs(deltaScale) > mScalingThreshold) {
                         mScaling = true;
                         return true;
                     }
diff --git a/services/core/java/com/android/server/BatteryService.java b/services/core/java/com/android/server/BatteryService.java
index 912a181..b3b4651 100644
--- a/services/core/java/com/android/server/BatteryService.java
+++ b/services/core/java/com/android/server/BatteryService.java
@@ -626,6 +626,22 @@
                 pw.println("  voltage: " + mBatteryProps.batteryVoltage);
                 pw.println("  temperature: " + mBatteryProps.batteryTemperature);
                 pw.println("  technology: " + mBatteryProps.batteryTechnology);
+
+            } else if ("unplug".equals(args[0])) {
+                if (!mUpdatesStopped) {
+                    mLastBatteryProps.set(mBatteryProps);
+                }
+                mBatteryProps.chargerAcOnline = false;
+                mBatteryProps.chargerUsbOnline = false;
+                mBatteryProps.chargerWirelessOnline = false;
+                long ident = Binder.clearCallingIdentity();
+                try {
+                    mUpdatesStopped = true;
+                    processValuesLocked(false);
+                } finally {
+                    Binder.restoreCallingIdentity(ident);
+                }
+
             } else if (args.length == 3 && "set".equals(args[0])) {
                 String key = args[1];
                 String value = args[2];
@@ -662,6 +678,7 @@
                 } catch (NumberFormatException ex) {
                     pw.println("Bad value: " + value);
                 }
+
             } else if (args.length == 1 && "reset".equals(args[0])) {
                 long ident = Binder.clearCallingIdentity();
                 try {
@@ -676,6 +693,7 @@
             } else {
                 pw.println("Dump current battery state, or:");
                 pw.println("  set [ac|usb|wireless|status|level|invalid] <value>");
+                pw.println("  unplug");
                 pw.println("  reset");
             }
         }
diff --git a/services/core/java/com/android/server/LockSettingsService.java b/services/core/java/com/android/server/LockSettingsService.java
index 77b8b31..895a5c3 100644
--- a/services/core/java/com/android/server/LockSettingsService.java
+++ b/services/core/java/com/android/server/LockSettingsService.java
@@ -17,6 +17,7 @@
 package com.android.server;
 
 import android.app.admin.DevicePolicyManager;
+import android.app.backup.BackupManager;
 import android.content.BroadcastReceiver;
 import android.content.ContentResolver;
 import android.content.Context;
@@ -46,6 +47,7 @@
 import android.text.TextUtils;
 import android.util.Slog;
 
+import com.android.internal.util.ArrayUtils;
 import com.android.internal.widget.ILockSettings;
 import com.android.internal.widget.LockPatternUtils;
 
@@ -257,6 +259,9 @@
 
     private void setStringUnchecked(String key, int userId, String value) {
         mStorage.writeKeyValue(key, value, userId);
+        if (ArrayUtils.contains(SETTINGS_TO_BACKUP, key)) {
+            BackupManager.dataChanged("com.android.providers.settings");
+        }
     }
 
     @Override
@@ -463,6 +468,11 @@
         Secure.LOCK_SCREEN_OWNER_INFO
     };
 
+    private static final String[] SETTINGS_TO_BACKUP = new String[] {
+        Secure.LOCK_SCREEN_OWNER_INFO_ENABLED,
+        Secure.LOCK_SCREEN_OWNER_INFO
+    };
+
     private IMountService getMountService() {
         final IBinder service = ServiceManager.getService("mount");
         if (service != null) {
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index 50820ff..6229778 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -2256,31 +2256,33 @@
             if (MONITOR_CPU_USAGE &&
                     mLastCpuTime.get() < (now-MONITOR_CPU_MIN_TIME)) {
                 mLastCpuTime.set(now);
-                haveNewCpuStats = true;
                 mProcessCpuTracker.update();
-                //Slog.i(TAG, mProcessCpu.printCurrentState());
-                //Slog.i(TAG, "Total CPU usage: "
-                //        + mProcessCpu.getTotalCpuPercent() + "%");
+                if (mProcessCpuTracker.hasGoodLastStats()) {
+                    haveNewCpuStats = true;
+                    //Slog.i(TAG, mProcessCpu.printCurrentState());
+                    //Slog.i(TAG, "Total CPU usage: "
+                    //        + mProcessCpu.getTotalCpuPercent() + "%");
 
-                // Slog the cpu usage if the property is set.
-                if ("true".equals(SystemProperties.get("events.cpu"))) {
-                    int user = mProcessCpuTracker.getLastUserTime();
-                    int system = mProcessCpuTracker.getLastSystemTime();
-                    int iowait = mProcessCpuTracker.getLastIoWaitTime();
-                    int irq = mProcessCpuTracker.getLastIrqTime();
-                    int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
-                    int idle = mProcessCpuTracker.getLastIdleTime();
+                    // Slog the cpu usage if the property is set.
+                    if ("true".equals(SystemProperties.get("events.cpu"))) {
+                        int user = mProcessCpuTracker.getLastUserTime();
+                        int system = mProcessCpuTracker.getLastSystemTime();
+                        int iowait = mProcessCpuTracker.getLastIoWaitTime();
+                        int irq = mProcessCpuTracker.getLastIrqTime();
+                        int softIrq = mProcessCpuTracker.getLastSoftIrqTime();
+                        int idle = mProcessCpuTracker.getLastIdleTime();
 
-                    int total = user + system + iowait + irq + softIrq + idle;
-                    if (total == 0) total = 1;
+                        int total = user + system + iowait + irq + softIrq + idle;
+                        if (total == 0) total = 1;
 
-                    EventLog.writeEvent(EventLogTags.CPU,
-                            ((user+system+iowait+irq+softIrq) * 100) / total,
-                            (user * 100) / total,
-                            (system * 100) / total,
-                            (iowait * 100) / total,
-                            (irq * 100) / total,
-                            (softIrq * 100) / total);
+                        EventLog.writeEvent(EventLogTags.CPU,
+                                ((user+system+iowait+irq+softIrq) * 100) / total,
+                                (user * 100) / total,
+                                (system * 100) / total,
+                                (iowait * 100) / total,
+                                (irq * 100) / total,
+                                (softIrq * 100) / total);
+                    }
                 }
             }
 
@@ -2289,8 +2291,10 @@
             synchronized(bstats) {
                 synchronized(mPidsSelfLocked) {
                     if (haveNewCpuStats) {
-                        if (mOnBattery) {
-                            int perc = bstats.startAddingCpuLocked();
+                        final int perc = bstats.startAddingCpuLocked();
+                        if (perc >= 0) {
+                            int remainUTime = 0;
+                            int remainSTime = 0;
                             int totalUTime = 0;
                             int totalSTime = 0;
                             final int N = mProcessCpuTracker.countStats();
@@ -2302,17 +2306,18 @@
                                 ProcessRecord pr = mPidsSelfLocked.get(st.pid);
                                 int otherUTime = (st.rel_utime*perc)/100;
                                 int otherSTime = (st.rel_stime*perc)/100;
-                                totalUTime += otherUTime;
-                                totalSTime += otherSTime;
+                                remainUTime += otherUTime;
+                                remainSTime += otherSTime;
+                                totalUTime += st.rel_utime;
+                                totalSTime += st.rel_stime;
                                 if (pr != null) {
                                     BatteryStatsImpl.Uid.Proc ps = pr.curProcBatteryStats;
                                     if (ps == null || !ps.isActive()) {
                                         pr.curProcBatteryStats = ps = bstats.getProcessStatsLocked(
                                                 pr.info.uid, pr.processName);
                                     }
-                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                            st.rel_stime-otherSTime);
-                                    ps.addSpeedStepTimes(cpuSpeedTimes);
+                                    ps.addCpuTimeLocked(st.rel_utime - otherUTime,
+                                            st.rel_stime - otherSTime, cpuSpeedTimes);
                                     pr.curCpuTime += (st.rel_utime+st.rel_stime) * 10;
                                 } else {
                                     BatteryStatsImpl.Uid.Proc ps = st.batteryStats;
@@ -2320,13 +2325,19 @@
                                         st.batteryStats = ps = bstats.getProcessStatsLocked(
                                                 bstats.mapUid(st.uid), st.name);
                                     }
-                                    ps.addCpuTimeLocked(st.rel_utime-otherUTime,
-                                            st.rel_stime-otherSTime);
-                                    ps.addSpeedStepTimes(cpuSpeedTimes);
+                                    ps.addCpuTimeLocked(st.rel_utime - otherUTime,
+                                            st.rel_stime - otherSTime, cpuSpeedTimes);
                                 }
                             }
-                            bstats.finishAddingCpuLocked(perc, totalUTime,
-                                    totalSTime, cpuSpeedTimes);
+                            final int userTime = mProcessCpuTracker.getLastUserTime();
+                            final int systemTime = mProcessCpuTracker.getLastSystemTime();
+                            final int iowaitTime = mProcessCpuTracker.getLastIoWaitTime();
+                            final int irqTime = mProcessCpuTracker.getLastIrqTime();
+                            final int softIrqTime = mProcessCpuTracker.getLastSoftIrqTime();
+                            final int idleTime = mProcessCpuTracker.getLastIdleTime();
+                            bstats.finishAddingCpuLocked(perc, remainUTime,
+                                    remainSTime, totalUTime, totalSTime, userTime, systemTime,
+                                    iowaitTime, irqTime, softIrqTime, idleTime, cpuSpeedTimes);
                         }
                     }
                 }
@@ -7771,7 +7782,7 @@
         synchronized (this) {
             enforceCallingPermission(android.Manifest.permission.READ_FRAME_BUFFER,
                     "getTaskThumbnail()");
-            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id);
+            TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(id, false);
             if (tr != null) {
                 return tr.getTaskThumbnailLocked();
             }
@@ -7884,7 +7895,7 @@
     @Override
     public void setTaskResizeable(int taskId, boolean resizeable) {
         synchronized (this) {
-            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId);
+            TaskRecord task = mStackSupervisor.anyTaskForIdLocked(taskId, false);
             if (task == null) {
                 Slog.w(TAG, "setTaskResizeable: taskId=" + taskId + " not found");
                 return;
@@ -8032,7 +8043,7 @@
      * @return Returns true if the given task was found and removed.
      */
     private boolean removeTaskByIdLocked(int taskId, boolean killProcess) {
-        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
+        TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
         if (tr != null) {
             tr.removeTaskActivitiesLocked();
             cleanUpRemovedTaskLocked(tr, killProcess);
@@ -8285,7 +8296,7 @@
         long ident = Binder.clearCallingIdentity();
         try {
             synchronized (this) {
-                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId);
+                TaskRecord tr = mStackSupervisor.anyTaskForIdLocked(taskId, false);
                 return tr != null && tr.stack != null && tr.stack.isHomeStack();
             }
         } finally {
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index 4d7305d..7afe23a 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -4171,6 +4171,8 @@
             }
             mActivityContainer.onTaskListEmptyLocked();
         }
+
+        task.stack = null;
     }
 
     TaskRecord createTaskRecord(int taskId, ActivityInfo info, Intent intent,
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index 1aa2a10..9fe3c48 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -462,6 +462,16 @@
     }
 
     TaskRecord anyTaskForIdLocked(int id) {
+        return anyTaskForIdLocked(id, true);
+    }
+
+    /**
+     * Returns a {@link TaskRecord} for the input id if available. Null otherwise.
+     * @param id Id of the task we would like returned.
+     * @param restoreFromRecents If the id was not in the active list, but was found in recents,
+     *                           restore the task from recents to the active list.
+     */
+    TaskRecord anyTaskForIdLocked(int id, boolean restoreFromRecents) {
         int numDisplays = mActivityDisplays.size();
         for (int displayNdx = 0; displayNdx < numDisplays; ++displayNdx) {
             ArrayList<ActivityStack> stacks = mActivityDisplays.valueAt(displayNdx).mStacks;
@@ -482,6 +492,10 @@
             return null;
         }
 
+        if (!restoreFromRecents) {
+            return task;
+        }
+
         if (!restoreRecentTaskLocked(task)) {
             if (DEBUG_RECENTS) Slog.w(TAG, "Couldn't restore task id=" + id + " found in recents");
             return null;
@@ -516,7 +530,7 @@
             if (mCurTaskId <= 0) {
                 mCurTaskId = 1;
             }
-        } while (anyTaskForIdLocked(mCurTaskId) != null);
+        } while (anyTaskForIdLocked(mCurTaskId, false) != null);
         return mCurTaskId;
     }
 
@@ -2661,7 +2675,7 @@
             final ArrayList<ActivityStack> homeDisplayStacks = mHomeStack.mStacks;
             for (int stackNdx = homeDisplayStacks.size() - 1; stackNdx >= 0; --stackNdx) {
                 final ActivityStack tmpStack = homeDisplayStacks.get(stackNdx);
-                if (!tmpStack.isHomeStack()) {
+                if (!tmpStack.isHomeStack() && tmpStack.mFullscreen) {
                     stack = tmpStack;
                     break;
                 }
@@ -3928,6 +3942,10 @@
         }
 
         void onTaskListEmptyLocked() {
+            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
+            detachLocked();
+            deleteActivityContainer(this);
+            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
         }
 
         @Override
@@ -4016,13 +4034,6 @@
             return false;
         }
 
-        void onTaskListEmptyLocked() {
-            mHandler.removeMessages(CONTAINER_TASK_LIST_EMPTY_TIMEOUT, this);
-            detachLocked();
-            deleteActivityContainer(this);
-            mHandler.obtainMessage(CONTAINER_CALLBACK_TASK_LIST_EMPTY, this).sendToTarget();
-        }
-
         private void setSurfaceIfReadyLocked() {
             if (DEBUG_STACK) Slog.v(TAG, "setSurfaceIfReadyLocked: mDrawn=" + mDrawn +
                     " mContainerState=" + mContainerState + " mSurface=" + mSurface);
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 4ea62ec..02c8cce 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -581,8 +581,7 @@
 
         AudioSystem.setErrorCallback(mAudioSystemCallback);
 
-        boolean cameraSoundForced = mContext.getResources().getBoolean(
-                com.android.internal.R.bool.config_camera_sound_forced);
+        boolean cameraSoundForced = readCameraSoundForced();
         mCameraSoundForced = new Boolean(cameraSoundForced);
         sendMsg(mAudioHandler,
                 MSG_SET_FORCE_USE,
@@ -1107,11 +1106,6 @@
                 for (int stream = 0; stream < mStreamStates.length; stream++) {
                     if (streamTypeAlias == mStreamVolumeAlias[stream]) {
                         mStreamStates[stream].mute(state);
-
-                        Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
-                        intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, stream);
-                        intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
-                        sendBroadcastToAll(intent);
                     }
                 }
             } else if ((direction == AudioManager.ADJUST_RAISE) &&
@@ -1459,16 +1453,6 @@
             flags = updateFlagsForSystemAudio(flags);
         }
         mVolumeController.postVolumeChanged(streamType, flags);
-
-        if ((flags & AudioManager.FLAG_FIXED_VOLUME) == 0) {
-            oldIndex = (oldIndex + 5) / 10;
-            index = (index + 5) / 10;
-            Intent intent = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
-            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, streamType);
-            intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
-            intent.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
-            sendBroadcastToAll(intent);
-        }
     }
 
     // If Hdmi-CEC system audio mode is on, we show volume bar only when TV
@@ -3506,6 +3490,7 @@
         private int mIndexMax;
         private final ConcurrentHashMap<Integer, Integer> mIndex =
                                             new ConcurrentHashMap<Integer, Integer>(8, 0.75f, 4);
+        private final Intent mVolumeChanged;
 
         private VolumeStreamState(String settingName, int streamType) {
 
@@ -3517,6 +3502,8 @@
             mIndexMax *= 10;
 
             readSettings();
+            mVolumeChanged = new Intent(AudioManager.VOLUME_CHANGED_ACTION);
+            mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
         }
 
         public String getSettingNameForDevice(int device) {
@@ -3631,8 +3618,10 @@
         }
 
         public boolean setIndex(int index, int device) {
+            boolean changed = false;
+            int oldIndex;
             synchronized (VolumeStreamState.class) {
-                int oldIndex = getIndex(device);
+                oldIndex = getIndex(device);
                 index = getValidIndex(index);
                 synchronized (mCameraSoundForced) {
                     if ((mStreamType == AudioSystem.STREAM_SYSTEM_ENFORCED) && mCameraSoundForced) {
@@ -3641,7 +3630,8 @@
                 }
                 mIndex.put(device, index);
 
-                if (oldIndex != index) {
+                changed = oldIndex != index;
+                if (changed) {
                     // Apply change to all streams using this one as alias
                     // if changing volume of current device, also change volume of current
                     // device on aliased stream
@@ -3659,11 +3649,16 @@
                             }
                         }
                     }
-                    return true;
-                } else {
-                    return false;
                 }
             }
+            if (changed) {
+                oldIndex = (oldIndex + 5) / 10;
+                index = (index + 5) / 10;
+                mVolumeChanged.putExtra(AudioManager.EXTRA_VOLUME_STREAM_VALUE, index);
+                mVolumeChanged.putExtra(AudioManager.EXTRA_PREV_VOLUME_STREAM_VALUE, oldIndex);
+                sendBroadcastToAll(mVolumeChanged);
+            }
+            return changed;
         }
 
         public int getIndex(int device) {
@@ -3720,9 +3715,12 @@
         }
 
         public void mute(boolean state) {
+            boolean changed = false;
             synchronized (VolumeStreamState.class) {
                 if (state != mIsMuted) {
+                    changed = true;
                     mIsMuted = state;
+
                     // Set the new mute volume. This propagates the values to
                     // the audio system, otherwise the volume won't be changed
                     // at the lower level.
@@ -3734,6 +3732,13 @@
                             this, 0);
                 }
             }
+            if (changed) {
+                // Stream mute changed, fire the intent.
+                Intent intent = new Intent(AudioManager.STREAM_MUTE_CHANGED_ACTION);
+                intent.putExtra(AudioManager.EXTRA_VOLUME_STREAM_TYPE, mStreamType);
+                intent.putExtra(AudioManager.EXTRA_STREAM_VOLUME_MUTED, state);
+                sendBroadcastToAll(intent);
+            }
         }
 
         public int getStreamType() {
@@ -5071,6 +5076,12 @@
         return mMediaFocusControl.getCurrentAudioFocus();
     }
 
+    private boolean readCameraSoundForced() {
+        return SystemProperties.getBoolean("audio.camerasound.force", false) ||
+                mContext.getResources().getBoolean(
+                        com.android.internal.R.bool.config_camera_sound_forced);
+    }
+
     //==========================================================================================
     // Device orientation
     //==========================================================================================
@@ -5101,8 +5112,7 @@
                     null,
                     0);
 
-            boolean cameraSoundForced = mContext.getResources().getBoolean(
-                    com.android.internal.R.bool.config_camera_sound_forced);
+            boolean cameraSoundForced = readCameraSoundForced();
             synchronized (mSettingsLock) {
                 boolean cameraSoundForcedChanged = false;
                 synchronized (mCameraSoundForced) {
@@ -5517,6 +5527,7 @@
         pw.print("  mPendingVolumeCommand="); pw.println(mPendingVolumeCommand);
         pw.print("  mMusicActiveMs="); pw.println(mMusicActiveMs);
         pw.print("  mMcc="); pw.println(mMcc);
+        pw.print("  mCameraSoundForced="); pw.println(mCameraSoundForced);
         pw.print("  mHasVibrator="); pw.println(mHasVibrator);
         pw.print("  mControllerService="); pw.println(mControllerService);
 
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index 271ec75..b90d263 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -457,6 +457,7 @@
     static final Rect mTmpNavigationFrame = new Rect();
 
     WindowState mTopFullscreenOpaqueWindowState;
+    WindowState mTopFullscreenOpaqueOrDimmingWindowState;
     HashSet<IApplicationToken> mAppsToBeHidden = new HashSet<IApplicationToken>();
     HashSet<IApplicationToken> mAppsThatDismissKeyguard = new HashSet<IApplicationToken>();
     boolean mTopIsFullscreen;
@@ -3972,6 +3973,7 @@
     @Override
     public void beginPostLayoutPolicyLw(int displayWidth, int displayHeight) {
         mTopFullscreenOpaqueWindowState = null;
+        mTopFullscreenOpaqueOrDimmingWindowState = null;
         mAppsToBeHidden.clear();
         mAppsThatDismissKeyguard.clear();
         mForceStatusBar = false;
@@ -4060,6 +4062,9 @@
                         && attrs.height == WindowManager.LayoutParams.MATCH_PARENT) {
                     if (DEBUG_LAYOUT) Slog.v(TAG, "Fullscreen window: " + win);
                     mTopFullscreenOpaqueWindowState = win;
+                    if (mTopFullscreenOpaqueOrDimmingWindowState == null) {
+                        mTopFullscreenOpaqueOrDimmingWindowState = win;
+                    }
                     if (!mAppsThatDismissKeyguard.isEmpty() &&
                             mDismissKeyguard == DISMISS_KEYGUARD_NONE) {
                         if (DEBUG_LAYOUT) Slog.v(TAG,
@@ -4085,6 +4090,11 @@
                 }
             }
         }
+        if (mTopFullscreenOpaqueOrDimmingWindowState == null
+                && win.isVisibleOrBehindKeyguardLw() && !win.isGoneForLayoutLw()
+                && win.isDimming()) {
+            mTopFullscreenOpaqueOrDimmingWindowState = win;
+        }
     }
 
     /** {@inheritDoc} */
@@ -6051,6 +6061,7 @@
         if (mForcingShowNavBar && win.getSurfaceLayer() < mForcingShowNavBarLayer) {
             tmpVisibility &= ~PolicyControl.adjustClearableFlags(win, View.SYSTEM_UI_CLEARABLE_FLAGS);
         }
+        tmpVisibility = updateLightStatusBarLw(tmpVisibility);
         final int visibility = updateSystemBarsLw(win, mLastSystemUiFlags, tmpVisibility);
         final int diff = visibility ^ mLastSystemUiFlags;
         final boolean needsMenu = win.getNeedsMenuLw(mTopFullscreenOpaqueWindowState);
@@ -6079,6 +6090,26 @@
         return diff;
     }
 
+    private int updateLightStatusBarLw(int vis) {
+        WindowState statusColorWin = isStatusBarKeyguard() && !mHideLockScreen
+                ? mStatusBar
+                : mTopFullscreenOpaqueOrDimmingWindowState;
+
+        if (statusColorWin != null) {
+            if (statusColorWin == mTopFullscreenOpaqueWindowState) {
+                // If the top fullscreen-or-dimming window is also the top fullscreen, respect
+                // its light flag.
+                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+                vis |= PolicyControl.getSystemUiVisibility(statusColorWin, null)
+                        & View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            } else if (statusColorWin != null && statusColorWin.isDimming()) {
+                // Otherwise if it's dimming, clear the light flag.
+                vis &= ~View.SYSTEM_UI_FLAG_LIGHT_STATUS_BAR;
+            }
+        }
+        return vis;
+    }
+
     private int updateSystemBarsLw(WindowState win, int oldVis, int vis) {
         // apply translucent bar vis flags
         WindowState transWin = isStatusBarKeyguard() && !mHideLockScreen
@@ -6383,6 +6414,10 @@
             pw.print(prefix); pw.print("mTopFullscreenOpaqueWindowState=");
                     pw.println(mTopFullscreenOpaqueWindowState);
         }
+        if (mTopFullscreenOpaqueOrDimmingWindowState != null) {
+            pw.print(prefix); pw.print("mTopFullscreenOpaqueOrDimmingWindowState=");
+                    pw.println(mTopFullscreenOpaqueOrDimmingWindowState);
+        }
         if (mForcingShowNavBar) {
             pw.print(prefix); pw.print("mForcingShowNavBar=");
                     pw.println(mForcingShowNavBar); pw.print( "mForcingShowNavBarLayer=");
diff --git a/services/core/java/com/android/server/tv/TvInputHardwareManager.java b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
index 50b2262..c5f4161 100644
--- a/services/core/java/com/android/server/tv/TvInputHardwareManager.java
+++ b/services/core/java/com/android/server/tv/TvInputHardwareManager.java
@@ -699,15 +699,14 @@
 
         private void findAudioSinkFromAudioPolicy(List<AudioDevicePort> sinks) {
             sinks.clear();
-            ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+            ArrayList<AudioDevicePort> devicePorts = new ArrayList<AudioDevicePort>();
             if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
                 return;
             }
             int sinkDevice = mAudioManager.getDevicesForStream(AudioManager.STREAM_MUSIC);
-            for (AudioPort port : devicePorts) {
-                AudioDevicePort devicePort = (AudioDevicePort) port;
-                if ((devicePort.type() & sinkDevice) != 0) {
-                    sinks.add(devicePort);
+            for (AudioDevicePort port : devicePorts) {
+                if ((port.type() & sinkDevice) != 0) {
+                    sinks.add(port);
                 }
             }
         }
@@ -716,14 +715,13 @@
             if (type == AudioManager.DEVICE_NONE) {
                 return null;
             }
-            ArrayList<AudioPort> devicePorts = new ArrayList<AudioPort>();
+            ArrayList<AudioDevicePort> devicePorts = new ArrayList<AudioDevicePort>();
             if (mAudioManager.listAudioDevicePorts(devicePorts) != AudioManager.SUCCESS) {
                 return null;
             }
-            for (AudioPort port : devicePorts) {
-                AudioDevicePort devicePort = (AudioDevicePort) port;
-                if (devicePort.type() == type && devicePort.address().equals(address)) {
-                    return devicePort;
+            for (AudioDevicePort port : devicePorts) {
+                if (port.type() == type && port.address().equals(address)) {
+                    return port;
                 }
             }
             return null;
diff --git a/services/core/java/com/android/server/wm/FocusedStackFrame.java b/services/core/java/com/android/server/wm/FocusedStackFrame.java
index f1f5fe8..826fe97 100644
--- a/services/core/java/com/android/server/wm/FocusedStackFrame.java
+++ b/services/core/java/com/android/server/wm/FocusedStackFrame.java
@@ -16,14 +16,14 @@
 
 package com.android.server.wm;
 
-import static com.android.server.wm.WindowManagerService.DEBUG_STACK;
 import static com.android.server.wm.WindowManagerService.DEBUG_SURFACE_TRACE;
+import static com.android.server.wm.WindowManagerService.SHOW_LIGHT_TRANSACTIONS;
 
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.Paint;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
-import android.graphics.Region;
 import android.util.Slog;
 import android.view.Display;
 import android.view.Surface.OutOfResourcesException;
@@ -35,14 +35,17 @@
 
 class FocusedStackFrame {
     private static final String TAG = "FocusedStackFrame";
-    private static final int THICKNESS = 10;
+    private static final boolean DEBUG = false;
+    private static final int THICKNESS = 2;
     private static final float ALPHA = 0.3f;
 
     private final SurfaceControl mSurfaceControl;
     private final Surface mSurface = new Surface();
+    private final Paint mInnerPaint = new Paint();
+    private final Paint mOuterPaint = new Paint();
+    private final Rect mBounds = new Rect();
     private final Rect mLastBounds = new Rect();
-    final Rect mBounds = new Rect();
-    private final Rect mTmpDrawRect = new Rect();
+    private int mLayer = -1;
 
     public FocusedStackFrame(Display display, SurfaceSession session) {
         SurfaceControl ctrl = null;
@@ -60,83 +63,84 @@
         } catch (OutOfResourcesException e) {
         }
         mSurfaceControl = ctrl;
+
+        mInnerPaint.setStyle(Paint.Style.STROKE);
+        mInnerPaint.setStrokeWidth(THICKNESS);
+        mInnerPaint.setColor(Color.WHITE);
+        mOuterPaint.setStyle(Paint.Style.STROKE);
+        mOuterPaint.setStrokeWidth(THICKNESS);
+        mOuterPaint.setColor(Color.BLACK);
     }
 
-    private void draw(Rect bounds, int color) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "draw: bounds=" + bounds.toShortString() +
-                " color=" + Integer.toHexString(color));
-        mTmpDrawRect.set(bounds);
+    private void draw() {
+        if (mLastBounds.isEmpty()) {
+            // Currently unset. Set it.
+            mLastBounds.set(mBounds);
+        }
+
+        if (DEBUG) Slog.i(TAG, "draw: mBounds=" + mBounds + " mLastBounds=" + mLastBounds);
+
         Canvas c = null;
         try {
-            c = mSurface.lockCanvas(mTmpDrawRect);
+            c = mSurface.lockCanvas(mLastBounds);
         } catch (IllegalArgumentException e) {
+            Slog.e(TAG, "Unable to lock canvas", e);
         } catch (Surface.OutOfResourcesException e) {
+            Slog.e(TAG, "Unable to lock canvas", e);
         }
         if (c == null) {
+            if (DEBUG) Slog.w(TAG, "Canvas is null...");
             return;
         }
 
-        final int w = bounds.width();
-        final int h = bounds.height();
-
-        // Top
-        mTmpDrawRect.set(0, 0, w, THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Left (not including Top or Bottom stripe).
-        mTmpDrawRect.set(0, THICKNESS, THICKNESS, h - THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Right (not including Top or Bottom stripe).
-        mTmpDrawRect.set(w - THICKNESS, THICKNESS, w, h - THICKNESS);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-        // Bottom
-        mTmpDrawRect.set(0, h - THICKNESS, w, h);
-        c.clipRect(mTmpDrawRect, Region.Op.REPLACE);
-        c.drawColor(color);
-
+        c.drawRect(0, 0, mBounds.width(), mBounds.height(), mOuterPaint);
+        c.drawRect(THICKNESS, THICKNESS, mBounds.width() - THICKNESS, mBounds.height() - THICKNESS,
+                mInnerPaint);
+        if (DEBUG) Slog.w(TAG, "c.width=" + c.getWidth() + " c.height=" + c.getHeight()
+                + " c.clip=" + c .getClipBounds());
         mSurface.unlockCanvasAndPost(c);
+        mLastBounds.set(mBounds);
     }
 
-    private void positionSurface(Rect bounds) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "positionSurface: bounds=" + bounds.toShortString());
-        mSurfaceControl.setSize(bounds.width(), bounds.height());
-        mSurfaceControl.setPosition(bounds.left, bounds.top);
+    private void setupSurface(boolean visible) {
+        if (mSurfaceControl == null) {
+            return;
+        }
+        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setupSurface");
+        SurfaceControl.openTransaction();
+        try {
+            if (visible) {
+                mSurfaceControl.setPosition(mBounds.left, mBounds.top);
+                mSurfaceControl.setSize(mBounds.width(), mBounds.height());
+                mSurfaceControl.show();
+            } else {
+                mSurfaceControl.hide();
+            }
+        } finally {
+            SurfaceControl.closeTransaction();
+            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setupSurface");
+        }
+    }
+
+    void setVisibility(TaskStack stack) {
+        if (stack == null || stack.isFullscreen()) {
+            setupSurface(false);
+        } else {
+            stack.getBounds(mBounds);
+            setupSurface(true);
+            if (!mBounds.equals(mLastBounds)) {
+                draw();
+            }
+        }
     }
 
     // Note: caller responsible for being inside
     // Surface.openTransaction() / closeTransaction()
-    public void setVisibility(boolean on) {
-        if (false && DEBUG_STACK) Slog.i(TAG, "setVisibility: on=" + on +
-                " mLastBounds=" + mLastBounds.toShortString() +
-                " mBounds=" + mBounds.toShortString());
-        if (mSurfaceControl == null) {
+    void setLayer(int layer) {
+        if (mLayer == layer) {
             return;
         }
-        if (on) {
-            if (!mLastBounds.equals(mBounds)) {
-                // Erase the previous rectangle.
-                positionSurface(mLastBounds);
-                draw(mLastBounds, Color.TRANSPARENT);
-                // Draw the latest rectangle.
-                positionSurface(mBounds);
-                draw(mBounds, Color.WHITE);
-                // Update the history.
-                mLastBounds.set(mBounds);
-            }
-            mSurfaceControl.show();
-        } else {
-            mSurfaceControl.hide();
-        }
-    }
-
-    public void setBounds(TaskStack stack) {
-        stack.getBounds(mBounds);
-        if (false && DEBUG_STACK) Slog.i(TAG, "setBounds: bounds=" + mBounds);
-    }
-
-    public void setLayer(int layer) {
-        mSurfaceControl.setLayer(layer);
+        mLayer = layer;
+        mSurfaceControl.setLayer(mLayer);
     }
 }
diff --git a/services/core/java/com/android/server/wm/TaskStack.java b/services/core/java/com/android/server/wm/TaskStack.java
index 94fecc9..3e1c5ff 100644
--- a/services/core/java/com/android/server/wm/TaskStack.java
+++ b/services/core/java/com/android/server/wm/TaskStack.java
@@ -26,7 +26,6 @@
 import android.util.EventLog;
 import android.util.Slog;
 import android.util.TypedValue;
-import android.view.Display;
 import android.view.Surface;
 
 import com.android.server.EventLogTags;
@@ -371,7 +370,7 @@
             for (int appNdx = appWindowTokens.size() - 1; appNdx >= 0; --appNdx) {
                 final WindowList appWindows = appWindowTokens.get(appNdx).allAppWindows;
                 for (int winNdx = appWindows.size() - 1; winNdx >= 0; --winNdx) {
-                    mService.removeWindowInnerLocked(null, appWindows.get(winNdx));
+                    mService.removeWindowInnerLocked(appWindows.get(winNdx));
                     doAnotherLayoutPass = true;
                 }
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index dd4bbb7..e238d30 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -64,11 +64,9 @@
 import android.graphics.Bitmap;
 import android.graphics.Bitmap.Config;
 import android.graphics.Canvas;
-import android.graphics.Matrix;
 import android.graphics.PixelFormat;
 import android.graphics.Point;
 import android.graphics.Rect;
-import android.graphics.RectF;
 import android.graphics.Region;
 import android.hardware.display.DisplayManager;
 import android.hardware.display.DisplayManagerInternal;
@@ -127,7 +125,6 @@
 import android.view.SurfaceControl;
 import android.view.SurfaceSession;
 import android.view.View;
-import android.view.ViewTreeObserver;
 import android.view.WindowManager;
 import android.view.WindowManagerGlobal;
 import android.view.WindowManagerPolicy;
@@ -136,7 +133,6 @@
 import android.view.WindowManagerPolicy.PointerEventListener;
 import android.view.animation.Animation;
 import android.view.animation.AnimationUtils;
-import android.view.animation.Transformation;
 
 import java.io.BufferedWriter;
 import java.io.DataInputStream;
@@ -181,7 +177,6 @@
     static final boolean DEBUG_CONFIGURATION = false;
     static final boolean DEBUG_APP_TRANSITIONS = false;
     static final boolean DEBUG_STARTING_WINDOW = false;
-    static final boolean DEBUG_REORDER = false;
     static final boolean DEBUG_WALLPAPER = false;
     static final boolean DEBUG_WALLPAPER_LIGHT = false || DEBUG_WALLPAPER;
     static final boolean DEBUG_DRAG = false;
@@ -413,7 +408,7 @@
      * This is set when we have run out of memory, and will either be an empty
      * list or contain windows that need to be force removed.
      */
-    ArrayList<WindowState> mForceRemoves;
+    final ArrayList<WindowState> mForceRemoves = new ArrayList<>();
 
     /**
      * Windows that clients are waiting to have drawn.
@@ -1736,10 +1731,7 @@
         }
     }
 
-    static final int ADJUST_WALLPAPER_LAYERS_CHANGED = 1<<1;
-    static final int ADJUST_WALLPAPER_VISIBILITY_CHANGED = 1<<2;
-
-    int adjustWallpaperWindowsLocked() {
+    boolean adjustWallpaperWindowsLocked() {
         mInnerFields.mWallpaperMayChange = false;
         boolean targetChanged = false;
 
@@ -1966,13 +1958,12 @@
 
         // Start stepping backwards from here, ensuring that our wallpaper windows
         // are correctly placed.
-        int changed = 0;
+        boolean changed = false;
         for (int curTokenNdx = mWallpaperTokens.size() - 1; curTokenNdx >= 0; curTokenNdx--) {
             WindowToken token = mWallpaperTokens.get(curTokenNdx);
             if (token.hidden == visible) {
                 if (DEBUG_WALLPAPER_LIGHT) Slog.d(TAG,
                         "Wallpaper token " + token + " hidden=" + !visible);
-                changed |= ADJUST_WALLPAPER_VISIBILITY_CHANGED;
                 token.hidden = !visible;
                 // Need to do a layout to ensure the wallpaper now has the correct size.
                 getDefaultDisplayContentLocked().layoutNeeded = true;
@@ -2033,7 +2024,7 @@
 
                 windows.add(insertionIndex, wallpaper);
                 mWindowsChanged = true;
-                changed |= ADJUST_WALLPAPER_LAYERS_CHANGED;
+                changed = true;
             }
         }
 
@@ -2654,7 +2645,7 @@
             }
         }
 
-        removeWindowInnerLocked(session, win);
+        removeWindowInnerLocked(win);
         // Removing a visible window will effect the computed orientation
         // So just update orientation if needed.
         if (wasVisible && updateOrientationFromAppTokensLocked(false)) {
@@ -2664,7 +2655,7 @@
         Binder.restoreCallingIdentity(origId);
     }
 
-    void removeWindowInnerLocked(Session session, WindowState win) {
+    void removeWindowInnerLocked(WindowState win) {
         if (win.mRemoved) {
             // Nothing to do.
             return;
@@ -2674,7 +2665,7 @@
             WindowState cwin = win.mChildWindows.get(i);
             Slog.w(TAG, "Force-removing child win " + cwin + " from container "
                     + win);
-            removeWindowInnerLocked(cwin.mSession, cwin);
+            removeWindowInnerLocked(cwin);
         }
 
         win.mRemoved = true;
@@ -3781,6 +3772,9 @@
 
     private Configuration updateOrientationFromAppTokensLocked(
             Configuration currentConfig, IBinder freezeThisOneIfNeeded) {
+        if (!mDisplayReady) {
+            return null;
+        }
         Configuration config = null;
 
         if (updateOrientationFromAppTokensLocked(false)) {
@@ -3799,20 +3793,19 @@
             // the value of the previous configuration.
             mTempConfiguration.setToDefaults();
             mTempConfiguration.fontScale = currentConfig.fontScale;
-            if (computeScreenConfigurationLocked(mTempConfiguration)) {
-                if (currentConfig.diff(mTempConfiguration) != 0) {
-                    mWaitingForConfig = true;
-                    final DisplayContent displayContent = getDefaultDisplayContentLocked();
-                    displayContent.layoutNeeded = true;
-                    int anim[] = new int[2];
-                    if (displayContent.isDimming()) {
-                        anim[0] = anim[1] = 0;
-                    } else {
-                        mPolicy.selectRotationAnimationLw(anim);
-                    }
-                    startFreezingDisplayLocked(false, anim[0], anim[1]);
-                    config = new Configuration(mTempConfiguration);
+            computeScreenConfigurationLocked(mTempConfiguration);
+            if (currentConfig.diff(mTempConfiguration) != 0) {
+                mWaitingForConfig = true;
+                final DisplayContent displayContent = getDefaultDisplayContentLocked();
+                displayContent.layoutNeeded = true;
+                int anim[] = new int[2];
+                if (displayContent.isDimming()) {
+                    anim[0] = anim[1] = 0;
+                } else {
+                    mPolicy.selectRotationAnimationLw(anim);
                 }
+                startFreezingDisplayLocked(false, anim[0], anim[1]);
+                config = new Configuration(mTempConfiguration);
             }
         }
 
@@ -3936,20 +3929,7 @@
         } else {
             stack = null;
         }
-        if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> OPEN TRANSACTION setFocusedStackFrame");
-        SurfaceControl.openTransaction();
-        try {
-            if (stack == null) {
-                mFocusedStackFrame.setVisibility(false);
-            } else {
-                mFocusedStackFrame.setBounds(stack);
-                final boolean multipleStacks = !stack.isFullscreen();
-                mFocusedStackFrame.setVisibility(multipleStacks);
-            }
-        } finally {
-            SurfaceControl.closeTransaction();
-            if (SHOW_LIGHT_TRANSACTIONS) Slog.i(TAG, ">>> CLOSE TRANSACTION setFocusedStackFrame");
-        }
+        mFocusedStackFrame.setVisibility(stack);
     }
 
     @Override
@@ -6917,9 +6897,11 @@
 
     public Configuration computeNewConfiguration() {
         synchronized (mWindowMap) {
+            if (!mDisplayReady) {
+                return null;
+            }
             Configuration config = computeNewConfigurationLocked();
-            if (config == null && mWaitingForConfig) {
-                // Nothing changed but we are waiting for something... stop that!
+            if (mWaitingForConfig) {
                 mWaitingForConfig = false;
                 mLastFinishedFreezeSource = "new-config";
                 performLayoutAndPlaceSurfacesLocked();
@@ -6931,9 +6913,7 @@
     Configuration computeNewConfigurationLocked() {
         Configuration config = new Configuration();
         config.fontScale = 0;
-        if (!computeScreenConfigurationLocked(config)) {
-            return null;
-        }
+        computeScreenConfigurationLocked(config);
         return config;
     }
 
@@ -7040,11 +7020,8 @@
         return sw;
     }
 
+    /** Do not call if mDisplayReady == false */
     DisplayInfo updateDisplayAndOrientationLocked() {
-        if (!mDisplayReady) {
-            return null;
-        }
-
         // TODO(multidisplay): For now, apply Configuration to main screen only.
         final DisplayContent displayContent = getDefaultDisplayContentLocked();
 
@@ -7101,11 +7078,9 @@
         return displayInfo;
     }
 
-    boolean computeScreenConfigurationLocked(Configuration config) {
+    /** Do not call if mDisplayReady == false */
+    void computeScreenConfigurationLocked(Configuration config) {
         final DisplayInfo displayInfo = updateDisplayAndOrientationLocked();
-        if (displayInfo == null) {
-            return false;
-        }
 
         final int dw = displayInfo.logicalWidth;
         final int dh = displayInfo.logicalHeight;
@@ -7190,8 +7165,6 @@
         config.hardKeyboardHidden = Configuration.HARDKEYBOARDHIDDEN_NO;
         config.navigationHidden = Configuration.NAVIGATIONHIDDEN_NO;
         mPolicy.adjustConfigurationLw(config, keyboardPresence, navigationPresence);
-
-        return true;
     }
 
     public boolean isHardKeyboardAvailable() {
@@ -8320,17 +8293,17 @@
     // displayContent must not be null
     private void reconfigureDisplayLocked(DisplayContent displayContent) {
         // TODO: Multidisplay: for now only use with default display.
+        if (!mDisplayReady) {
+            return;
+        }
         configureDisplayPolicyLocked(displayContent);
         displayContent.layoutNeeded = true;
 
         boolean configChanged = updateOrientationFromAppTokensLocked(false);
         mTempConfiguration.setToDefaults();
         mTempConfiguration.fontScale = mCurConfiguration.fontScale;
-        if (computeScreenConfigurationLocked(mTempConfiguration)) {
-            if (mCurConfiguration.diff(mTempConfiguration) != 0) {
-                configChanged = true;
-            }
-        }
+        computeScreenConfigurationLocked(mTempConfiguration);
+        configChanged |= mCurConfiguration.diff(mTempConfiguration) != 0;
 
         if (configChanged) {
             mWaitingForConfig = true;
@@ -8631,29 +8604,24 @@
 
         Trace.traceBegin(Trace.TRACE_TAG_WINDOW_MANAGER, "wmLayout");
         mInLayout = true;
-        boolean recoveringMemory = false;
 
-        try {
-            if (mForceRemoves != null) {
-                recoveringMemory = true;
-                // Wait a little bit for things to settle down, and off we go.
-                for (int i=0; i<mForceRemoves.size(); i++) {
-                    WindowState ws = mForceRemoves.get(i);
-                    Slog.i(TAG, "Force removing: " + ws);
-                    removeWindowInnerLocked(ws.mSession, ws);
-                }
-                mForceRemoves = null;
-                Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
-                Object tmp = new Object();
-                synchronized (tmp) {
-                    try {
-                        tmp.wait(250);
-                    } catch (InterruptedException e) {
-                    }
+        boolean recoveringMemory = false;
+        if (!mForceRemoves.isEmpty()) {
+            recoveringMemory = true;
+            // Wait a little bit for things to settle down, and off we go.
+            while (!mForceRemoves.isEmpty()) {
+                WindowState ws = mForceRemoves.remove(0);
+                Slog.i(TAG, "Force removing: " + ws);
+                removeWindowInnerLocked(ws);
+            }
+            Slog.w(TAG, "Due to memory failure, waiting a bit for next layout");
+            Object tmp = new Object();
+            synchronized (tmp) {
+                try {
+                    tmp.wait(250);
+                } catch (InterruptedException e) {
                 }
             }
-        } catch (RuntimeException e) {
-            Slog.wtf(TAG, "Unhandled exception while force removing for memory", e);
         }
 
         try {
@@ -9329,14 +9297,12 @@
 
     /**
      * Extracted from {@link #performLayoutAndPlaceSurfacesLockedInner} to reduce size of method.
-     *
-     * @param w WindowState this method is applied to.
-     * @param currentTime The time which animations use for calculating transitions.
+     *  @param w WindowState this method is applied to.
      * @param innerDw Width of app window.
      * @param innerDh Height of app window.
      */
-    private void handleNotObscuredLocked(final WindowState w, final long currentTime,
-                                         final int innerDw, final int innerDh) {
+    private void handleNotObscuredLocked(final WindowState w,
+            final int innerDw, final int innerDh) {
         final WindowManager.LayoutParams attrs = w.mAttrs;
         final int attrFlags = attrs.flags;
         final boolean canBeSeen = w.isDisplayedLw();
@@ -9455,8 +9421,6 @@
                     + Debug.getCallers(3));
         }
 
-        final long currentTime = SystemClock.uptimeMillis();
-
         int i;
         boolean updateInputWindowsNeeded = false;
 
@@ -9547,8 +9511,7 @@
 
                     if ((displayContent.pendingLayoutChanges &
                             WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER) != 0 &&
-                            (adjustWallpaperWindowsLocked() &
-                                    ADJUST_WALLPAPER_LAYERS_CHANGED) != 0) {
+                            adjustWallpaperWindowsLocked()) {
                         assignLayersLocked(windows);
                         displayContent.layoutNeeded = true;
                     }
@@ -9613,7 +9576,7 @@
                     // Update effect.
                     w.mObscured = mInnerFields.mObscured;
                     if (!mInnerFields.mObscured) {
-                        handleNotObscuredLocked(w, currentTime, innerDw, innerDh);
+                        handleNotObscuredLocked(w, innerDw, innerDh);
                     }
 
                     if (stack != null && !stack.testDimmingTag()) {
@@ -9992,7 +9955,7 @@
             DisplayContentList displayList = new DisplayContentList();
             for (i = 0; i < N; i++) {
                 WindowState w = mPendingRemoveTmp[i];
-                removeWindowInnerLocked(w.mSession, w);
+                removeWindowInnerLocked(w);
                 final DisplayContent displayContent = w.getDisplayContent();
                 if (displayContent != null && !displayList.contains(displayContent)) {
                     displayList.add(displayContent);
@@ -10168,10 +10131,6 @@
         EventLog.writeEvent(EventLogTags.WM_NO_SURFACE_MEMORY, winAnimator.mWin.toString(),
                 winAnimator.mSession.mPid, operation);
 
-        if (mForceRemoves == null) {
-            mForceRemoves = new ArrayList<WindowState>();
-        }
-
         long callingIdentity = Binder.clearCallingIdentity();
         try {
             // There was some problem...   first, do a sanity check of the
@@ -10353,6 +10312,10 @@
                 + ", flags=" + win.mAttrs.flags
                 + ", canReceive=" + win.canReceiveKeys());
 
+            if (!win.canReceiveKeys()) {
+                continue;
+            }
+
             AppWindowToken wtoken = win.mAppToken;
 
             // If this window's application has been removed, just skip it.
@@ -10362,10 +10325,6 @@
                 continue;
             }
 
-            if (!win.canReceiveKeys()) {
-                continue;
-            }
-
             // Descend through all of the app tokens and find the first that either matches
             // win.mAppToken (return win) or mFocusedApp (return null).
             if (wtoken != null && win.mAttrs.type != TYPE_APPLICATION_STARTING &&
diff --git a/services/core/java/com/android/server/wm/WindowState.java b/services/core/java/com/android/server/wm/WindowState.java
index 99cc03e..d58b2b0 100644
--- a/services/core/java/com/android/server/wm/WindowState.java
+++ b/services/core/java/com/android/server/wm/WindowState.java
@@ -1288,6 +1288,15 @@
         return displayContent.isDefaultDisplay;
     }
 
+    @Override
+    public boolean isDimming() {
+        TaskStack stack = getStack();
+        if (stack == null) {
+            return false;
+        }
+        return stack.isDimming(mWinAnimator);
+    }
+
     public void setShowToOwnerOnlyLocked(boolean showToOwnerOnly) {
         mShowToOwnerOnly = showToOwnerOnly;
     }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
index f0e02bc..57ed876 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DeviceOwner.java
@@ -39,7 +39,9 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.OutputStream;
+import java.io.PrintWriter;
 import java.util.HashMap;
+import java.util.Map;
 import java.util.Set;
 
 /**
@@ -320,5 +322,23 @@
             this.admin = admin;
             this.packageName = admin.getPackageName();
         }
+        public void dump(String prefix, PrintWriter pw) {
+            pw.println(prefix + "admin=" + admin);
+            pw.println(prefix + "name=" + name);
+            pw.println();
+        }
+    }
+
+    public void dump(String prefix, PrintWriter pw) {
+        if (mDeviceOwner != null) {
+            pw.println(prefix + "Device Owner: ");
+            mDeviceOwner.dump(prefix + "  ", pw);
+        }
+        if (mProfileOwners != null) {
+            for (Map.Entry<Integer, OwnerInfo> entry : mProfileOwners.entrySet()) {
+                pw.println(prefix + "Profile Owner (User " + entry.getKey() + "): ");
+                entry.getValue().dump(prefix + "  ", pw);
+            }
+        }
     }
 }
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 7ff7827..770da5b 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -100,6 +100,7 @@
 import com.android.internal.os.storage.ExternalStorageFormatter;
 import com.android.internal.util.FastXmlSerializer;
 import com.android.internal.util.JournaledFile;
+import com.android.internal.util.Preconditions;
 import com.android.internal.util.XmlUtils;
 import com.android.internal.widget.LockPatternUtils;
 import com.android.server.LocalServices;
@@ -1920,13 +1921,11 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         validateQualityConstant(quality);
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordQuality != quality) {
@@ -1969,11 +1968,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLength != length) {
@@ -2016,11 +2013,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.passwordHistoryLength != length) {
@@ -2063,14 +2058,10 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
+        Preconditions.checkArgumentNonnegative(timeout, "Timeout must be >= 0 ms");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-            if (timeout < 0) {
-                throw new IllegalArgumentException("Timeout must be >= 0 ms");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_EXPIRE_PASSWORD);
             // Calling this API automatically bumps the expiration date
@@ -2232,11 +2223,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordUpperCase != length) {
@@ -2276,11 +2265,9 @@
     }
 
     public void setPasswordMinimumLowerCase(ComponentName who, int length) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLowerCase != length) {
@@ -2323,11 +2310,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordLetters != length) {
@@ -2370,11 +2355,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNumeric != length) {
@@ -2417,11 +2400,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordSymbols != length) {
@@ -2464,11 +2445,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_LIMIT_PASSWORD);
             if (ap.minimumPasswordNonLetter != length) {
@@ -2561,11 +2540,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who,
@@ -2772,11 +2749,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_FORCE_LOCK);
             if (ap.maximumTimeToUnlock != timeMs) {
@@ -2955,9 +2930,7 @@
 
     @Override
     public boolean installKeyPair(ComponentName who, byte[] privKey, byte[] cert, String alias) {
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
         }
@@ -3297,9 +3270,7 @@
             return null;
         }
         synchronized(this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
+            Preconditions.checkNotNull(who, "ComponentName is null");
 
             // Only check if owner has set global proxy. We don't allow other users to set it.
             DevicePolicyData policy = getUserData(UserHandle.USER_OWNER);
@@ -3435,12 +3406,10 @@
         if (!mHasFeature) {
             return DevicePolicyManager.ENCRYPTION_STATUS_UNSUPPORTED;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
             // Check for permissions
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // Only owner can set storage encryption
             if (userHandle != UserHandle.USER_OWNER
                     || UserHandle.getCallingUserId() != UserHandle.USER_OWNER) {
@@ -3571,11 +3540,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (ap.disableScreenCapture != disabled) {
@@ -3630,11 +3597,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
             if (admin.requireAutoTime != required) {
@@ -3682,11 +3647,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_CAMERA);
             if (ap.disableCamera != disabled) {
@@ -3731,12 +3694,10 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "disable keyguard features");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             if (ap.disabledKeyguardFeatures != which) {
@@ -3880,9 +3841,7 @@
 
     @Override
     public void clearDeviceOwner(String packageName) {
-        if (packageName == null) {
-            throw new NullPointerException("packageName is null");
-        }
+        Preconditions.checkNotNull(packageName, "packageName is null");
         try {
             int uid = mContext.getPackageManager().getPackageUid(packageName, 0);
             if (uid != Binder.getCallingUid()) {
@@ -4007,12 +3966,9 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
         synchronized (this) {
-            // Check for permissions
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             // Check if this is the profile owner who is calling
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             int userId = UserHandle.getCallingUserId();
@@ -4034,12 +3990,8 @@
 
     @Override
     public void setProfileName(ComponentName who, String profileName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int userId = UserHandle.getCallingUserId();
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
-
         // Check if this is the profile owner (includes device owner).
         getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -4187,7 +4139,9 @@
 
         synchronized (this) {
             p.println("Current Device Policy Manager state:");
-
+            if (mDeviceOwner != null) {
+                mDeviceOwner.dump("  ", pw);
+            }
             int userCount = mUserData.size();
             for (int u = 0; u < userCount; u++) {
                 DevicePolicyData policy = getUserData(mUserData.keyAt(u));
@@ -4215,12 +4169,9 @@
     @Override
     public void addPersistentPreferredActivity(ComponentName who, IntentFilter filter,
             ComponentName activity) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4237,12 +4188,9 @@
 
     @Override
     public void clearPackagePersistentPreferredActivities(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userHandle = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4259,12 +4207,9 @@
 
     @Override
     public void setApplicationRestrictions(ComponentName who, String packageName, Bundle settings) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4281,15 +4226,11 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(admin, "admin is null");
+        Preconditions.checkNotNull(agent, "agent is null");
         final int userHandle = UserHandle.getCallingUserId();
         enforceNotManagedProfile(userHandle, "set trust agent configuration");
         synchronized (this) {
-            if (admin == null) {
-                throw new NullPointerException("admin is null");
-            }
-            if (agent == null) {
-                throw new NullPointerException("agent is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(admin,
                     DeviceAdminInfo.USES_POLICY_DISABLE_KEYGUARD_FEATURES);
             ap.trustAgentInfos.put(agent.flattenToString(), new TrustAgentInfo(args));
@@ -4303,10 +4244,8 @@
         if (!mHasFeature) {
             return null;
         }
+        Preconditions.checkNotNull(agent, "agent null");
         enforceCrossUserPermission(userHandle);
-        if (agent == null) {
-            throw new NullPointerException("agent is null");
-        }
 
         synchronized (this) {
             final String componentName = agent.flattenToString();
@@ -4359,10 +4298,8 @@
 
     @Override
     public void setRestrictionsProvider(ComponentName who, ComponentName permissionProvider) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             int userHandle = UserHandle.getCallingUserId();
@@ -4384,11 +4321,9 @@
     }
 
     public void addCrossProfileIntentFilter(ComponentName who, IntentFilter filter, int flags) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IPackageManager pm = AppGlobals.getPackageManager();
@@ -4411,11 +4346,9 @@
     }
 
     public void clearCrossProfileIntentFilters(ComponentName who) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             IPackageManager pm = AppGlobals.getPackageManager();
             long id = Binder.clearCallingIdentity();
@@ -4485,9 +4418,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         if (packageList != null) {
             int userId = UserHandle.getCallingUserId();
@@ -4532,10 +4463,7 @@
         if (!mHasFeature) {
             return null;
         }
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -4640,9 +4568,7 @@
         if (!mHasFeature) {
             return false;
         }
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         // TODO When InputMethodManager supports per user calls remove
         //      this restriction.
@@ -4685,10 +4611,7 @@
         if (!mHasFeature) {
             return null;
         }
-
-        if (who == null) {
-            throw new NullPointerException("ComponentName is null");
-        }
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
@@ -4761,10 +4684,8 @@
 
     @Override
     public UserHandle createUser(ComponentName who, String name) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4815,10 +4736,8 @@
 
     @Override
     public boolean removeUser(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4832,10 +4751,8 @@
 
     @Override
     public boolean switchUser(ComponentName who, UserHandle userHandle) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4856,12 +4773,10 @@
 
     @Override
     public Bundle getApplicationRestrictions(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle userHandle = new UserHandle(UserHandle.getCallingUserId());
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -4875,12 +4790,10 @@
 
     @Override
     public void setUserRestriction(ComponentName who, String key, boolean enabled) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final UserHandle user = new UserHandle(UserHandle.getCallingUserId());
         final int userHandle = user.getIdentifier();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             boolean isDeviceOwner = isDeviceOwner(activeAdmin.info.getPackageName());
@@ -4982,11 +4895,9 @@
     @Override
     public boolean setApplicationHidden(ComponentName who, String packageName,
             boolean hidden) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5005,11 +4916,9 @@
 
     @Override
     public boolean isApplicationHidden(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5028,11 +4937,8 @@
 
     @Override
     public void enableSystemApp(ComponentName who, String packageName) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5073,11 +4979,8 @@
 
     @Override
     public int enableSystemAppWithIntent(ComponentName who, Intent intent) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             // This API can only be called by an active device admin,
             // so try to retrieve it to check that the caller is one.
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
@@ -5144,10 +5047,8 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin ap = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (disabled) {
@@ -5185,12 +5086,9 @@
     @Override
     public void setUninstallBlocked(ComponentName who, String packageName,
             boolean uninstallBlocked) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         final int userId = UserHandle.getCallingUserId();
-
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             long id = Binder.clearCallingIdentity();
@@ -5237,10 +5135,8 @@
         if (!mHasFeature) {
             return;
         }
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             if (admin.disableCallerId != disabled) {
@@ -5255,12 +5151,8 @@
         if (!mHasFeature) {
             return false;
         }
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
-
             ActiveAdmin admin = getActiveAdminForCallerLocked(who,
                     DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
             return admin.disableCallerId;
@@ -5281,13 +5173,11 @@
      * Sets which packages may enter lock task mode.
      *
      * This function can only be called by the device owner.
-     * @param components The list of components allowed to enter lock task mode.
+     * @param packages The list of packages allowed to enter lock task mode.
      */
     public void setLockTaskPackages(ComponentName who, String[] packages) throws SecurityException {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             int userHandle = Binder.getCallingUserHandle().getIdentifier();
@@ -5309,15 +5199,13 @@
      * This function returns the list of components allowed to start the task lock mode.
      */
     public String[] getLockTaskPackages(ComponentName who) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             int userHandle = Binder.getCallingUserHandle().getIdentifier();
             DevicePolicyData policy = getUserData(userHandle);
-            return policy.mLockTaskPackages.toArray(new String[0]);
+            return policy.mLockTaskPackages.toArray(new String[policy.mLockTaskPackages.size()]);
         }
     }
 
@@ -5373,11 +5261,9 @@
     @Override
     public void setGlobalSetting(ComponentName who, String setting, String value) {
         final ContentResolver contentResolver = mContext.getContentResolver();
+        Preconditions.checkNotNull(who, "ComponentName is null");
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_DEVICE_OWNER);
 
             if (!GLOBAL_SETTINGS_WHITELIST.contains(setting)) {
@@ -5396,13 +5282,11 @@
 
     @Override
     public void setSecureSetting(ComponentName who, String setting, String value) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         int callingUserId = UserHandle.getCallingUserId();
         final ContentResolver contentResolver = mContext.getContentResolver();
 
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             ActiveAdmin activeAdmin =
                     getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
@@ -5427,10 +5311,8 @@
 
     @Override
     public void setMasterVolumeMuted(ComponentName who, boolean on) {
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             IAudioService iAudioService = IAudioService.Stub.asInterface(
@@ -5447,12 +5329,8 @@
 
     @Override
     public boolean isMasterVolumeMuted(ComponentName who) {
-        final ContentResolver contentResolver = mContext.getContentResolver();
-
+        Preconditions.checkNotNull(who, "ComponentName is null");
         synchronized (this) {
-            if (who == null) {
-                throw new NullPointerException("ComponentName is null");
-            }
             getActiveAdminForCallerLocked(who, DeviceAdminInfo.USES_POLICY_PROFILE_OWNER);
 
             AudioManager audioManager =
diff --git a/services/usb/java/com/android/server/usb/UsbAlsaManager.java b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
index c6f6b85..009d25d 100644
--- a/services/usb/java/com/android/server/usb/UsbAlsaManager.java
+++ b/services/usb/java/com/android/server/usb/UsbAlsaManager.java
@@ -153,7 +153,7 @@
     // audioDevice - the AudioDevice that was added or removed
     // enabled - if true, we're connecting a device (it's arrived), else disconnecting
     private void notifyDeviceState(UsbAudioDevice audioDevice, boolean enabled) {
-       if (DEBUG) {
+        if (DEBUG) {
             Slog.d(TAG, "notifyDeviceState " + enabled + " " + audioDevice);
         }
 
@@ -422,7 +422,7 @@
     }
 
     /* package */ void usbDeviceRemoved(UsbDevice usbDevice) {
-       if (DEBUG) {
+        if (DEBUG) {
           Slog.d(TAG, "deviceRemoved(): " + usbDevice);
         }
 
diff --git a/telecomm/java/android/telecom/PhoneAccountHandle.java b/telecomm/java/android/telecom/PhoneAccountHandle.java
index 570f5fd..4600b72 100644
--- a/telecomm/java/android/telecom/PhoneAccountHandle.java
+++ b/telecomm/java/android/telecom/PhoneAccountHandle.java
@@ -80,6 +80,9 @@
      * ({@code 0}, {@code 1}, {@code 2}, ...) that are generated locally on each phone and could
      * collide with values generated on other phones or after a data wipe of a given phone.
      *
+     * Important: A non-unique identifier could cause non-deterministic call-log backup/restore
+     * behavior.
+     *
      * @return A service-specific unique identifier for this {@code PhoneAccountHandle}.
      */
     public String getId() {
diff --git a/telecomm/java/android/telecom/TelecomManager.java b/telecomm/java/android/telecom/TelecomManager.java
index 6c5f1c6..bcc1ccc4 100644
--- a/telecomm/java/android/telecom/TelecomManager.java
+++ b/telecomm/java/android/telecom/TelecomManager.java
@@ -83,6 +83,12 @@
             "android.telecom.action.SHOW_CALL_SETTINGS";
 
     /**
+     * The {@link android.content.Intent} action used to show the respond via SMS settings page.
+     */
+    public static final String ACTION_SHOW_RESPOND_VIA_SMS_SETTINGS =
+            "android.telecom.action.SHOW_RESPOND_VIA_SMS_SETTINGS";
+
+    /**
      * The {@link android.content.Intent} action used to show the settings page used to configure
      * {@link PhoneAccount} preferences.
      * @hide
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 94691c0..dda9626 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.os.ServiceManager;
 import android.os.SystemProperties;
+import android.telecom.PhoneAccount;
 import android.util.Log;
 
 import com.android.internal.telecom.ITelecomService;
@@ -3765,7 +3766,7 @@
 
    /**
     * Returns the IMS Registration Status
-    *@hide
+    * @hide
     */
    public boolean isImsRegistered() {
        try {
@@ -4116,4 +4117,21 @@
                     ServiceState.rilRadioTechnologyToString(type));
         }
     }
+
+    /**
+     * Returns the subscription ID for the given phone account.
+     * @hide
+     */
+    public int getSubIdForPhoneAccount(PhoneAccount phoneAccount) {
+        int retval = SubscriptionManager.INVALID_SUBSCRIPTION_ID;
+        try {
+            ITelephony service = getITelephony();
+            if (service != null) {
+                retval = service.getSubIdForPhoneAccount(phoneAccount);
+            }
+        } catch (RemoteException e) {
+        }
+
+        return retval;
+    }
 }
diff --git a/telephony/java/com/android/internal/telephony/ITelephony.aidl b/telephony/java/com/android/internal/telephony/ITelephony.aidl
index bf3ee09..62c8746 100644
--- a/telephony/java/com/android/internal/telephony/ITelephony.aidl
+++ b/telephony/java/com/android/internal/telephony/ITelephony.aidl
@@ -18,6 +18,7 @@
 
 import android.content.Intent;
 import android.os.Bundle;
+import android.telecom.PhoneAccount;
 import android.telephony.CellInfo;
 import android.telephony.IccOpenLogicalChannelResponse;
 import android.telephony.NeighboringCellInfo;
@@ -879,4 +880,9 @@
       *   {@link android.Manifest.permission#READ_PHONE_STATE READ_PHONE_STATE}
       */
     String getDeviceId();
+
+    /**
+     * Returns the subscription ID associated with the specified PhoneAccount.
+     */
+    int getSubIdForPhoneAccount(in PhoneAccount phoneAccount);
 }
diff --git a/tools/apilint/apilint.py b/tools/apilint/apilint.py
index b8eaa2d..54525ad 100644
--- a/tools/apilint/apilint.py
+++ b/tools/apilint/apilint.py
@@ -253,7 +253,7 @@
     for f in clazz.fields:
         if "static" in f.split and "final" in f.split:
             if re.match("[A-Z0-9_]+", f.name) is None:
-                error(clazz, f, "C2", "Constant field names should be FOO_NAME")
+                error(clazz, f, "C2", "Constant field names must be FOO_NAME")
 
 
 def verify_enums(clazz):
@@ -269,7 +269,7 @@
     if re.match("android\.R\.[a-z]+", clazz.fullname): return
 
     if re.search("[A-Z]{2,}", clazz.name) is not None:
-        warn(clazz, None, "S1", "Class name style should be Mtp not MTP")
+        warn(clazz, None, "S1", "Class names with acronyms should be Mtp not MTP")
     if re.match("[^A-Z]", clazz.name):
         error(clazz, None, "S1", "Class must start with uppercase char")
 
@@ -282,7 +282,7 @@
 
     for m in clazz.methods:
         if re.search("[A-Z]{2,}", m.name) is not None:
-            warn(clazz, m, "S1", "Method name style should be getMtu() instead of getMTU()")
+            warn(clazz, m, "S1", "Method names with acronyms should be getMtu() instead of getMTU()")
         if re.match("[^a-z]", m.name):
             error(clazz, m, "S1", "Method name must start with lowercase char")
 
@@ -294,13 +294,13 @@
     if clazz.fullname == "android.speech.tts.SynthesisCallback": return
 
     if clazz.name.endswith("Callbacks"):
-        error(clazz, None, "L1", "Class name must not be plural")
+        error(clazz, None, "L1", "Callback class names should be singular")
     if clazz.name.endswith("Observer"):
         warn(clazz, None, "L1", "Class should be named FooCallback")
 
     if clazz.name.endswith("Callback"):
         if "interface" in clazz.split:
-            error(clazz, None, "CL3", "Callback must be abstract class to enable extension in future API levels")
+            error(clazz, None, "CL3", "Callbacks must be abstract class to enable extension in future API levels")
 
         for m in clazz.methods:
             if not re.match("on[A-Z][a-z]*", m.name):
@@ -316,7 +316,7 @@
 
     if clazz.name.endswith("Listener"):
         if " abstract class " in clazz.raw:
-            error(clazz, None, "L1", "Listener should be an interface, otherwise renamed Callback")
+            error(clazz, None, "L1", "Listeners should be an interface, or otherwise renamed Callback")
 
         for m in clazz.methods:
             if not re.match("on[A-Z][a-z]*", m.name):
@@ -325,7 +325,7 @@
         if len(clazz.methods) == 1 and clazz.name.startswith("On"):
             m = clazz.methods[0]
             if (m.name + "Listener").lower() != clazz.name.lower():
-                error(clazz, m, "L1", "Single listener method name should match class name")
+                error(clazz, m, "L1", "Single listener method name must match class name")
 
 
 def verify_actions(clazz):
@@ -412,10 +412,10 @@
     """Verify that no protected methods or fields are allowed."""
     for m in clazz.methods:
         if "protected" in m.split:
-            error(clazz, m, "M7", "No protected methods; must be public")
+            error(clazz, m, "M7", "Protected methods not allowed; must be public")
     for f in clazz.fields:
         if "protected" in f.split:
-            error(clazz, f, "M7", "No protected fields; must be public")
+            error(clazz, f, "M7", "Protected fields not allowed; must be public")
 
 
 def verify_fields(clazz):
@@ -449,10 +449,10 @@
 
         if not "static" in f.split:
             if not re.match("[a-z]([a-zA-Z]+)?", f.name):
-                error(clazz, f, "S1", "Non-static fields must be named with myField style")
+                error(clazz, f, "S1", "Non-static fields must be named using myField style")
 
         if re.match("[ms][A-Z]", f.name):
-            error(clazz, f, "F1", "Don't expose your internal objects")
+            error(clazz, f, "F1", "Internal objects must not be exposed")
 
         if re.match("[A-Z_]+", f.name):
             if "static" not in f.split or "final" not in f.split:
@@ -496,7 +496,7 @@
     """Verify synchronized methods aren't exposed."""
     for m in clazz.methods:
         if "synchronized" in m.split:
-            error(clazz, m, "M5", "Internal lock exposed")
+            error(clazz, m, "M5", "Internal locks must not be exposed")
 
 
 def verify_intent_builder(clazz):
@@ -508,7 +508,7 @@
             if m.name.startswith("create") and m.name.endswith("Intent"):
                 pass
             else:
-                error(clazz, m, "FW1", "Methods creating an Intent should be named createFooIntent()")
+                error(clazz, m, "FW1", "Methods creating an Intent must be named createFooIntent()")
 
 
 def verify_helper_classes(clazz):
@@ -537,7 +537,7 @@
             if f.name == "PROVIDER_INTERFACE":
                 found = True
                 if f.value != clazz.fullname:
-                    error(clazz, f, "C4", "Inconsistent interface name; expected %s" % (clazz.fullname))
+                    error(clazz, f, "C4", "Inconsistent interface constant; expected %s" % (clazz.fullname))
 
     if "extends android.content.BroadcastReceiver" in clazz.raw:
         test_methods = True
@@ -578,11 +578,11 @@
         if m.name.startswith("clear"): continue
 
         if m.name.startswith("with"):
-            warn(clazz, m, None, "Builder methods names should follow setFoo() style")
+            warn(clazz, m, None, "Builder methods names should use setFoo() style")
 
         if m.name.startswith("set"):
             if not m.typ.endswith(clazz.fullname):
-                warn(clazz, m, "M4", "Methods should return the builder")
+                warn(clazz, m, "M4", "Methods must return the builder object")
 
     if not has_build:
         warn(clazz, None, None, "Missing build() method")
@@ -591,13 +591,13 @@
 def verify_aidl(clazz):
     """Catch people exposing raw AIDL."""
     if "extends android.os.Binder" in clazz.raw or "implements android.os.IInterface" in clazz.raw:
-        error(clazz, None, None, "Exposing raw AIDL interface")
+        error(clazz, None, None, "Raw AIDL interfaces must not be exposed")
 
 
 def verify_internal(clazz):
     """Catch people exposing internal classes."""
     if clazz.pkg.name.startswith("com.android"):
-        error(clazz, None, None, "Exposing internal class")
+        error(clazz, None, None, "Internal classes must not be exposed")
 
 
 def verify_layering(clazz):
@@ -645,25 +645,43 @@
 
 
 def verify_boolean(clazz, api):
-    """Catches people returning boolean from getFoo() style methods.
-    Ignores when matching setFoo() is present."""
+    """Verifies that boolean accessors are named correctly.
+    For example, hasFoo() and setHasFoo()."""
 
-    methods = [ m.name for m in clazz.methods ]
+    def is_get(m): return len(m.args) == 0 and m.typ == "boolean"
+    def is_set(m): return len(m.args) == 1 and m.args[0] == "boolean"
 
-    builder = clazz.fullname + ".Builder"
-    builder_methods = []
-    if builder in api:
-        builder_methods = [ m.name for m in api[builder].methods ]
+    gets = [ m for m in clazz.methods if is_get(m) ]
+    sets = [ m for m in clazz.methods if is_set(m) ]
+
+    def error_if_exists(methods, trigger, expected, actual):
+        for m in methods:
+            if m.name == actual:
+                error(clazz, m, "M6", "Symmetric method for %s must be named %s" % (trigger, expected))
 
     for m in clazz.methods:
-        if m.typ == "boolean" and m.name.startswith("get") and m.name != "get" and len(m.args) == 0:
-            setter = "set" + m.name[3:]
-            if setter in methods:
-                pass
-            elif builder is not None and setter in builder_methods:
-                pass
-            else:
-                warn(clazz, m, None, "Methods returning boolean should be named isFoo, hasFoo, areFoo")
+        if is_get(m):
+            if re.match("is[A-Z]", m.name):
+                target = m.name[2:]
+                expected = "setIs" + target
+                error_if_exists(sets, m.name, expected, "setHas" + target)
+            elif re.match("has[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "setHas" + target
+                error_if_exists(sets, m.name, expected, "setIs" + target)
+                error_if_exists(sets, m.name, expected, "set" + target)
+            elif re.match("get[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "set" + target
+                error_if_exists(sets, m.name, expected, "setIs" + target)
+                error_if_exists(sets, m.name, expected, "setHas" + target)
+
+        if is_set(m):
+            if re.match("set[A-Z]", m.name):
+                target = m.name[3:]
+                expected = "get" + target
+                error_if_exists(sets, m.name, expected, "is" + target)
+                error_if_exists(sets, m.name, expected, "has" + target)
 
 
 def verify_collections(clazz):
@@ -674,10 +692,10 @@
            "java.util.HashMap", "java.util.HashSet", "android.util.ArraySet", "android.util.ArrayMap"]
     for m in clazz.methods:
         if m.typ in bad:
-            error(clazz, m, "CL2", "Return type is concrete collection; should be interface")
+            error(clazz, m, "CL2", "Return type is concrete collection; must be higher-level interface")
         for arg in m.args:
             if arg in bad:
-                error(clazz, m, "CL2", "Argument is concrete collection; should be interface")
+                error(clazz, m, "CL2", "Argument is concrete collection; must be higher-level interface")
 
 
 def verify_flags(clazz):
@@ -740,7 +758,7 @@
     if not clazz.name.endswith("Manager"): return
 
     for c in clazz.ctors:
-        error(clazz, c, None, "Managers should always be obtained from Context")
+        error(clazz, c, None, "Managers must always be obtained from Context")
 
 
 def verify_boxed(clazz):
@@ -751,18 +769,18 @@
     for c in clazz.ctors:
         for arg in c.args:
             if arg in boxed:
-                error(clazz, c, None, "Must avoid boxed primitives")
+                error(clazz, c, "M11", "Must avoid boxed primitives")
 
     for f in clazz.fields:
         if f.typ in boxed:
-            error(clazz, f, None, "Must avoid boxed primitives")
+            error(clazz, f, "M11", "Must avoid boxed primitives")
 
     for m in clazz.methods:
         if m.typ in boxed:
-            error(clazz, m, None, "Must avoid boxed primitives")
+            error(clazz, m, "M11", "Must avoid boxed primitives")
         for arg in m.args:
             if arg in boxed:
-                error(clazz, m, None, "Must avoid boxed primitives")
+                error(clazz, m, "M11", "Must avoid boxed primitives")
 
 
 def verify_static_utils(clazz):
@@ -875,20 +893,56 @@
             if "android.os.Handler" in m.args:
                 takes_handler = True
         if not takes_handler:
-            error(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
+            warn(clazz, f, "L1", "Registration methods should have overload that accepts delivery Handler")
 
 
 def verify_context_first(clazz):
     """Verifies that methods accepting a Context keep it the first argument."""
-    for m in clazz.ctors:
-        if len(m.args) > 1:
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        if len(m.args) > 1 and m.args[0] != "android.content.Context":
             if "android.content.Context" in m.args[1:]:
                 error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
 
-    for m in clazz.methods:
-        if len(m.args) > 1:
-            if "android.content.Context" in m.args[1:]:
-                error(clazz, m, "M3", "Context is distinct, so it must be the first argument")
+
+def verify_listener_last(clazz):
+    """Verifies that methods accepting a Listener or Callback keep them as last arguments."""
+    examine = clazz.ctors + clazz.methods
+    for m in examine:
+        if "Listener" in m.name or "Callback" in m.name: continue
+        found = False
+        for a in m.args:
+            if a.endswith("Callback") or a.endswith("Callbacks") or a.endswith("Listener"):
+                found = True
+            elif found and a != "android.os.Handler":
+                warn(clazz, m, "M3", "Listeners should always be at end of argument list")
+
+
+def verify_resource_names(clazz):
+    """Verifies that resource names have consistent case."""
+    if not re.match("android\.R\.[a-z]+", clazz.fullname): return
+
+    # Resources defined by files are foo_bar_baz
+    if clazz.name in ["anim","animator","color","dimen","drawable","interpolator","layout","transition","menu","mipmap","string","plurals","raw","xml"]:
+        for f in clazz.fields:
+            if re.match("[a-z1-9_]+$", f.name): continue
+            error(clazz, f, None, "Expected resource name in this class to be foo_bar_baz style")
+
+    # Resources defined inside files are fooBarBaz
+    if clazz.name in ["array","attr","id","bool","fraction","integer"]:
+        for f in clazz.fields:
+            if re.match("config_[a-z][a-zA-Z1-9]*$", f.name): continue
+            if re.match("layout_[a-z][a-zA-Z1-9]*$", f.name): continue
+            if re.match("state_[a-z_]*$", f.name): continue
+
+            if re.match("[a-z][a-zA-Z1-9]*$", f.name): continue
+            error(clazz, f, "C7", "Expected resource name in this class to be fooBarBaz style")
+
+    # Styles are FooBar_Baz
+    if clazz.name in ["style"]:
+        for f in clazz.fields:
+            if re.match("[A-Z][A-Za-z1-9]+(_[A-Z][A-Za-z1-9]+?)*$", f.name): continue
+            error(clazz, f, "C7", "Expected resource name in this class to be FooBar_Baz style")
 
 
 def verify_style(api):
@@ -938,6 +992,8 @@
         verify_overload_args(clazz)
         verify_callback_handlers(clazz)
         verify_context_first(clazz)
+        verify_listener_last(clazz)
+        verify_resource_names(clazz)
 
     return failures