Merge "Ignore the active network scorer when checking for idleness" into mnc-dev
diff --git a/api/current.txt b/api/current.txt
index a129a63..462ca0a 100644
--- a/api/current.txt
+++ b/api/current.txt
@@ -66,6 +66,7 @@
     field public static final java.lang.String FACTORY_TEST = "android.permission.FACTORY_TEST";
     field public static final java.lang.String FLASHLIGHT = "android.permission.FLASHLIGHT";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
     field public static final deprecated java.lang.String GET_TASKS = "android.permission.GET_TASKS";
     field public static final java.lang.String GLOBAL_SEARCH = "android.permission.GLOBAL_SEARCH";
@@ -9445,6 +9446,7 @@
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
     field public static final int FLAG_COSTS_MONEY = 1; // 0x1
+    field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
     field public static final int PROTECTION_DANGEROUS = 1; // 0x1
     field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
     field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20
diff --git a/api/system-current.txt b/api/system-current.txt
index c2fd0d1f..d6e3c03 100644
--- a/api/system-current.txt
+++ b/api/system-current.txt
@@ -95,6 +95,7 @@
     field public static final java.lang.String FORCE_BACK = "android.permission.FORCE_BACK";
     field public static final java.lang.String FORCE_STOP_PACKAGES = "android.permission.FORCE_STOP_PACKAGES";
     field public static final java.lang.String GET_ACCOUNTS = "android.permission.GET_ACCOUNTS";
+    field public static final java.lang.String GET_ACCOUNTS_PRIVILEGED = "android.permission.GET_ACCOUNTS_PRIVILEGED";
     field public static final java.lang.String GET_APP_OPS_STATS = "android.permission.GET_APP_OPS_STATS";
     field public static final java.lang.String GET_PACKAGE_IMPORTANCE = "android.permission.GET_PACKAGE_IMPORTANCE";
     field public static final java.lang.String GET_PACKAGE_SIZE = "android.permission.GET_PACKAGE_SIZE";
@@ -9783,6 +9784,7 @@
     method public java.lang.CharSequence loadDescription(android.content.pm.PackageManager);
     field public static final android.os.Parcelable.Creator<android.content.pm.PermissionInfo> CREATOR;
     field public static final int FLAG_COSTS_MONEY = 1; // 0x1
+    field public static final int FLAG_INSTALLED = 1073741824; // 0x40000000
     field public static final int PROTECTION_DANGEROUS = 1; // 0x1
     field public static final int PROTECTION_FLAG_APPOP = 64; // 0x40
     field public static final int PROTECTION_FLAG_DEVELOPMENT = 32; // 0x20
diff --git a/cmds/am/src/com/android/commands/am/Am.java b/cmds/am/src/com/android/commands/am/Am.java
index 9f4bc52..d952dfc 100644
--- a/cmds/am/src/com/android/commands/am/Am.java
+++ b/cmds/am/src/com/android/commands/am/Am.java
@@ -26,6 +26,7 @@
 import android.app.IActivityManager;
 import android.app.IInstrumentationWatcher;
 import android.app.Instrumentation;
+import android.app.IStopUserCallback;
 import android.app.ProfilerInfo;
 import android.app.UiAutomationConnection;
 import android.app.usage.ConfigurationStats;
@@ -133,7 +134,7 @@
                 "       am to-app-uri [INTENT]\n" +
                 "       am switch-user <USER_ID>\n" +
                 "       am start-user <USER_ID>\n" +
-                "       am stop-user <USER_ID>\n" +
+                "       am stop-user [-w] <USER_ID>\n" +
                 "       am stack start <DISPLAY_ID> <INTENT>\n" +
                 "       am stack movetask <TASK_ID> <STACK_ID> [true|false]\n" +
                 "       am stack resize <STACK_ID> <LEFT,TOP,RIGHT,BOTTOM>\n" +
@@ -257,6 +258,7 @@
                 "\n" +
                 "am stop-user: stop execution of USER_ID, not allowing it to run any\n" +
                 "  code until a later explicit start or switch to it.\n" +
+                "  -w: wait for stop-user to complete.\n" +
                 "\n" +
                 "am stack start: start a new activity on <DISPLAY_ID> using <INTENT>.\n" +
                 "\n" +
@@ -1303,9 +1305,45 @@
         }
     }
 
+    private static class StopUserCallback extends IStopUserCallback.Stub {
+        private boolean mFinished = false;
+
+        public synchronized void waitForFinish() {
+            try {
+                while (!mFinished) wait();
+            } catch (InterruptedException e) {
+                throw new IllegalStateException(e);
+            }
+        }
+
+        @Override
+        public synchronized void userStopped(int userId) {
+            mFinished = true;
+            notifyAll();
+        }
+
+        @Override
+        public synchronized void userStopAborted(int userId) {
+            mFinished = true;
+            notifyAll();
+        }
+    }
+
     private void runStopUser() throws Exception {
-        String user = nextArgRequired();
-        int res = mAm.stopUser(Integer.parseInt(user), null);
+        boolean wait = false;
+        String opt = null;
+        while ((opt = nextOption()) != null) {
+            if ("-w".equals(opt)) {
+                wait = true;
+            } else {
+                System.err.println("Error: unknown option: " + opt);
+                return;
+            }
+        }
+        int user = Integer.parseInt(nextArgRequired());
+        StopUserCallback callback = wait ? new StopUserCallback() : null;
+
+        int res = mAm.stopUser(user, callback);
         if (res != ActivityManager.USER_OP_SUCCESS) {
             String txt = "";
             switch (res) {
@@ -1317,6 +1355,8 @@
                     break;
             }
             System.err.println("Switch failed: " + res + txt);
+        } else if (callback != null) {
+            callback.waitForFinish();
         }
     }
 
diff --git a/cmds/sm/src/com/android/commands/sm/Sm.java b/cmds/sm/src/com/android/commands/sm/Sm.java
index 0dad4dc..0a1ba4d1 100644
--- a/cmds/sm/src/com/android/commands/sm/Sm.java
+++ b/cmds/sm/src/com/android/commands/sm/Sm.java
@@ -81,6 +81,8 @@
             runUnmount();
         } else if ("format".equals(op)) {
             runFormat();
+        } else if ("benchmark".equals(op)) {
+            runBenchmark();
         } else if ("forget".equals(op)) {
             runForget();
         } else {
@@ -89,9 +91,12 @@
     }
 
     public void runListDisks() throws RemoteException {
+        final boolean onlyAdoptable = "adoptable".equals(nextArg());
         final DiskInfo[] disks = mSm.getDisks();
         for (DiskInfo disk : disks) {
-            System.out.println(disk.getId());
+            if (!onlyAdoptable || disk.isAdoptable()) {
+                System.out.println(disk.getId());
+            }
         }
     }
 
@@ -161,6 +166,11 @@
         mSm.format(volId);
     }
 
+    public void runBenchmark() throws RemoteException {
+        final String volId = nextArg();
+        mSm.benchmark(volId);
+    }
+
     public void runForget() throws RemoteException{
         final String fsUuid = nextArg();
         if ("all".equals(fsUuid)) {
@@ -180,7 +190,7 @@
     }
 
     private static int showUsage() {
-        System.err.println("usage: sm list-disks");
+        System.err.println("usage: sm list-disks [adoptable]");
         System.err.println("       sm list-volumes [public|private|emulated|all]");
         System.err.println("       sm has-adoptable");
         System.err.println("       sm get-primary-storage-uuid");
@@ -190,6 +200,7 @@
         System.err.println("       sm mount VOLUME");
         System.err.println("       sm unmount VOLUME");
         System.err.println("       sm format VOLUME");
+        System.err.println("       sm benchmark VOLUME");
         System.err.println("");
         System.err.println("       sm forget [UUID|all]");
         System.err.println("");
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index 40126d6..ee0fc91 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -4,6 +4,7 @@
 import android.content.ComponentName;
 import android.graphics.Matrix;
 import android.graphics.Rect;
+import android.os.BadParcelableException;
 import android.os.Binder;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -31,8 +32,12 @@
     static final String TAG = "AssistStructure";
 
     static final boolean DEBUG_PARCEL = false;
+    static final boolean DEBUG_PARCEL_CHILDREN = false;
     static final boolean DEBUG_PARCEL_TREE = false;
 
+    static final int VALIDATE_WINDOW_TOKEN = 0x11111111;
+    static final int VALIDATE_VIEW_TOKEN = 0x22222222;
+
     boolean mHaveData;
 
     ComponentName mActivityComponent;
@@ -173,6 +178,26 @@
             mCurViewStackEntry = entry;
         }
 
+        void writeView(ViewNode child, Parcel out, PooledStringWriter pwriter, int levelAdj) {
+            if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
+                    + ", windows=" + mNumWrittenWindows
+                    + ", views=" + mNumWrittenViews
+                    + ", level=" + (mCurViewStackPos+levelAdj));
+            out.writeInt(VALIDATE_VIEW_TOKEN);
+            int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
+            mNumWrittenViews++;
+            // If the child has children, push it on the stack to write them next.
+            if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
+                if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
+                        "Preparing to write " + child.mChildren.length
+                                + " children: @ #" + mNumWrittenViews
+                                + ", level " + (mCurViewStackPos+levelAdj));
+                out.writeInt(child.mChildren.length);
+                int pos = ++mCurViewStackPos;
+                pushViewStackEntry(child, pos);
+            }
+        }
+
         boolean writeNextEntryToParcel(AssistStructure as, Parcel out, PooledStringWriter pwriter) {
             // Write next view node if appropriate.
             if (mCurViewStackEntry != null) {
@@ -182,20 +207,7 @@
                             + mCurViewStackEntry.curChild + " in " + mCurViewStackEntry.node);
                     ViewNode child = mCurViewStackEntry.node.mChildren[mCurViewStackEntry.curChild];
                     mCurViewStackEntry.curChild++;
-                    if (DEBUG_PARCEL) Log.d(TAG, "write view: at " + out.dataPosition()
-                            + ", windows=" + mNumWrittenWindows
-                            + ", views=" + mNumWrittenViews);
-                    out.writeInt(1);
-                    int flags = child.writeSelfToParcel(out, pwriter, mTmpMatrix);
-                    mNumWrittenViews++;
-                    // If the child has children, push it on the stack to write them next.
-                    if ((flags&ViewNode.FLAGS_HAS_CHILDREN) != 0) {
-                        if (DEBUG_PARCEL_TREE) Log.d(TAG, "Preparing to write "
-                                + child.mChildren.length + " children under " + child);
-                        out.writeInt(child.mChildren.length);
-                        int pos = ++mCurViewStackPos;
-                        pushViewStackEntry(child, pos);
-                    }
+                    writeView(child, out, pwriter, 1);
                     return true;
                 }
 
@@ -223,13 +235,13 @@
                 if (DEBUG_PARCEL) Log.d(TAG, "write window #" + pos + ": at " + out.dataPosition()
                         + ", windows=" + mNumWrittenWindows
                         + ", views=" + mNumWrittenViews);
-                out.writeInt(1);
+                out.writeInt(VALIDATE_WINDOW_TOKEN);
                 win.writeSelfToParcel(out, pwriter, mTmpMatrix);
                 mNumWrittenWindows++;
                 ViewNode root = win.mRoot;
                 mCurViewStackPos = 0;
-                if (DEBUG_PARCEL_TREE) Log.d(TAG, "Pushing initial root view " + root);
-                pushViewStackEntry(root, 0);
+                if (DEBUG_PARCEL_TREE) Log.d(TAG, "Writing initial root view " + root);
+                writeView(root, out, pwriter, 0);
                 return true;
             }
 
@@ -271,11 +283,16 @@
                     + ", views=" + mNumReadViews);
         }
 
-        Parcel readParcel() {
+        Parcel readParcel(int validateToken, int level) {
             if (DEBUG_PARCEL) Log.d(TAG, "readParcel: at " + mCurParcel.dataPosition()
                     + ", avail=" + mCurParcel.dataAvail() + ", windows=" + mNumReadWindows
-                    + ", views=" + mNumReadViews);
-            if (mCurParcel.readInt() != 0) {
+                    + ", views=" + mNumReadViews + ", level=" + level);
+            int token = mCurParcel.readInt();
+            if (token != 0) {
+                if (token != validateToken) {
+                    throw new BadParcelableException("Got token " + Integer.toHexString(token)
+                            + ", expected token " + Integer.toHexString(validateToken));
+                }
                 return mCurParcel;
             }
             // We have run out of partial data, need to read another batch.
@@ -406,7 +423,7 @@
         }
 
         WindowNode(ParcelTransferReader reader) {
-            Parcel in = reader.readParcel();
+            Parcel in = reader.readParcel(VALIDATE_WINDOW_TOKEN, 0);
             reader.mNumReadWindows++;
             mX = in.readInt();
             mY = in.readInt();
@@ -414,7 +431,7 @@
             mHeight = in.readInt();
             mTitle = TextUtils.CHAR_SEQUENCE_CREATOR.createFromParcel(in);
             mDisplayId = in.readInt();
-            mRoot = new ViewNode(reader);
+            mRoot = new ViewNode(reader, 0);
         }
 
         void writeSelfToParcel(Parcel out, PooledStringWriter pwriter, float[] tmpMatrix) {
@@ -548,8 +565,8 @@
         ViewNode() {
         }
 
-        ViewNode(ParcelTransferReader reader) {
-            final Parcel in = reader.readParcel();
+        ViewNode(ParcelTransferReader reader, int nestingLevel) {
+            final Parcel in = reader.readParcel(VALIDATE_VIEW_TOKEN, nestingLevel);
             reader.mNumReadViews++;
             final PooledStringReader preader = reader.mStringReader;
             mClassName = preader.readString();
@@ -604,9 +621,13 @@
             }
             if ((flags&FLAGS_HAS_CHILDREN) != 0) {
                 final int NCHILDREN = in.readInt();
+                if (DEBUG_PARCEL_TREE || DEBUG_PARCEL_CHILDREN) Log.d(TAG,
+                        "Preparing to read " + NCHILDREN
+                                + " children: @ #" + reader.mNumReadViews
+                                + ", level " + nestingLevel);
                 mChildren = new ViewNode[NCHILDREN];
                 for (int i=0; i<NCHILDREN; i++) {
-                    mChildren[i] = new ViewNode(reader);
+                    mChildren[i] = new ViewNode(reader, nestingLevel + 1);
                 }
             }
         }
diff --git a/core/java/android/bluetooth/le/BluetoothLeScanner.java b/core/java/android/bluetooth/le/BluetoothLeScanner.java
index e09ab56..2ba87744 100644
--- a/core/java/android/bluetooth/le/BluetoothLeScanner.java
+++ b/core/java/android/bluetooth/le/BluetoothLeScanner.java
@@ -79,6 +79,10 @@
      * delivered through {@code callback}.
      * <p>
      * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+     * An app must hold
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
+     * in order to get results.
      *
      * @param callback Callback used to deliver scan results.
      * @throws IllegalArgumentException If {@code callback} is null.
@@ -95,6 +99,10 @@
      * Start Bluetooth LE scan. The scan results will be delivered through {@code callback}.
      * <p>
      * Requires {@link android.Manifest.permission#BLUETOOTH_ADMIN} permission.
+     * An app must hold
+     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
+     * in order to get results.
      *
      * @param filters {@link ScanFilter}s for finding exact BLE devices.
      * @param settings Settings for the scan.
diff --git a/core/java/android/content/pm/PermissionInfo.java b/core/java/android/content/pm/PermissionInfo.java
index 2828d83..d514513 100644
--- a/core/java/android/content/pm/PermissionInfo.java
+++ b/core/java/android/content/pm/PermissionInfo.java
@@ -145,12 +145,10 @@
     public static final int FLAG_COSTS_MONEY = 1<<0;
 
     /**
-     * Flag for {@link #protectionLevel}, corresponding
-     * to the <code>hide</code> value of
-     * {@link android.R.attr#permissionFlags}.
-     * @hide
+     * Flag for {@link #flags}, indicating that this permission has been
+     * installed into the system's globally defined permissions.
      */
-    public static final int PROTECTION_FLAG_HIDE = 1<<1;
+    public static final int FLAG_INSTALLED = 1<<30;
 
     /**
      * Additional flags about this permission as given by
@@ -210,6 +208,15 @@
         if ((level&PermissionInfo.PROTECTION_FLAG_PRE23) != 0) {
             protLevel += "|pre23";
         }
+        if ((level&PermissionInfo.PROTECTION_FLAG_INSTALLER) != 0) {
+            protLevel += "|installer";
+        }
+        if ((level&PermissionInfo.PROTECTION_FLAG_VERIFIER) != 0) {
+            protLevel += "|verifier";
+        }
+        if ((level&PermissionInfo.PROTECTION_FLAG_PREINSTALLED) != 0) {
+            protLevel += "|preinstalled";
+        }
         return protLevel;
     }
 
diff --git a/core/java/android/os/FileUtils.java b/core/java/android/os/FileUtils.java
index 864225a..af4c2bc 100644
--- a/core/java/android/os/FileUtils.java
+++ b/core/java/android/os/FileUtils.java
@@ -16,6 +16,7 @@
 
 package android.os;
 
+import android.annotation.NonNull;
 import android.provider.DocumentsContract.Document;
 import android.system.ErrnoException;
 import android.system.Os;
@@ -69,6 +70,8 @@
     /** Regular expression for safe filenames: no spaces or metacharacters */
     private static final Pattern SAFE_FILENAME_PATTERN = Pattern.compile("[\\w%+,./=_-]+");
 
+    private static final File[] EMPTY = new File[0];
+
     /**
      * Set owner and mode of of given {@link File}.
      *
@@ -634,4 +637,13 @@
             return new File(parent, name + "." + ext);
         }
     }
+
+    public static @NonNull File[] listFilesOrEmpty(File dir) {
+        File[] res = dir.listFiles();
+        if (res != null) {
+            return res;
+        } else {
+            return EMPTY;
+        }
+    }
 }
diff --git a/core/java/android/os/IDeviceIdleController.aidl b/core/java/android/os/IDeviceIdleController.aidl
index b768852..d3eec1e 100644
--- a/core/java/android/os/IDeviceIdleController.aidl
+++ b/core/java/android/os/IDeviceIdleController.aidl
@@ -29,5 +29,6 @@
     boolean isPowerSaveWhitelistApp(String name);
     void addPowerSaveTempWhitelistApp(String name, long duration, int userId, String reason);
     long addPowerSaveTempWhitelistAppForMms(String name, int userId, String reason);
+    long addPowerSaveTempWhitelistAppForSms(String name, int userId, String reason);
     void exitIdle(String reason);
 }
diff --git a/core/java/android/provider/Settings.java b/core/java/android/provider/Settings.java
index fff355b..a79970c 100644
--- a/core/java/android/provider/Settings.java
+++ b/core/java/android/provider/Settings.java
@@ -7578,14 +7578,6 @@
         public static final String WFC_IMS_ROAMING_ENABLED = "wfc_ims_roaming_enabled";
 
         /**
-         * Global override to disable VoLTE (independent of user setting)
-         * <p>
-         * Type: int (1 for disable VoLTE, 0 to use user configuration)
-         * @hide
-         */
-        public static final String VOLTE_FEATURE_DISABLED = "volte_feature_disabled";
-
-        /**
          * Whether user can enable/disable LTE as a preferred network. A carrier might control
          * this via gservices, OMA-DM, carrier app, etc.
          * <p>
diff --git a/core/java/android/security/keymaster/KeymasterDefs.java b/core/java/android/security/keymaster/KeymasterDefs.java
index bae5455..04d5952 100644
--- a/core/java/android/security/keymaster/KeymasterDefs.java
+++ b/core/java/android/security/keymaster/KeymasterDefs.java
@@ -51,6 +51,7 @@
     public static final int KM_TAG_DIGEST = KM_ENUM_REP | 5;
     public static final int KM_TAG_PADDING = KM_ENUM_REP | 6;
     public static final int KM_TAG_CALLER_NONCE = KM_BOOL | 7;
+    public static final int KM_TAG_MIN_MAC_LENGTH = KM_UINT | 8;
 
     public static final int KM_TAG_RESCOPING_ADD = KM_ENUM_REP | 101;
     public static final int KM_TAG_RESCOPING_DEL = KM_ENUM_REP | 102;
@@ -194,6 +195,9 @@
     public static final int KM_ERROR_KEY_RATE_LIMIT_EXCEEDED = -54;
     public static final int KM_ERROR_CALLER_NONCE_PROHIBITED = -55;
     public static final int KM_ERROR_KEY_MAX_OPS_EXCEEDED = -56;
+    public static final int KM_ERROR_INVALID_MAC_LENGTH = -57;
+    public static final int KM_ERROR_MISSING_MIN_MAC_LENGTH = -58;
+    public static final int KM_ERROR_UNSUPPORTED_MIN_MAC_LENGTH = -59;
     public static final int KM_ERROR_UNIMPLEMENTED = -100;
     public static final int KM_ERROR_VERSION_MISMATCH = -101;
     public static final int KM_ERROR_UNKNOWN_ERROR = -1000;
@@ -237,6 +241,8 @@
         sErrorCodeToString.put(KM_ERROR_INVALID_NONCE, "Invalid IV");
         sErrorCodeToString.put(KM_ERROR_CALLER_NONCE_PROHIBITED,
                 "Caller-provided IV not permitted");
+        sErrorCodeToString.put(KM_ERROR_INVALID_MAC_LENGTH,
+                "Invalid MAC or authentication tag length");
         sErrorCodeToString.put(KM_ERROR_UNIMPLEMENTED, "Not implemented");
         sErrorCodeToString.put(KM_ERROR_UNKNOWN_ERROR, "Unknown error");
     }
diff --git a/core/java/android/widget/AppSecurityPermissions.java b/core/java/android/widget/AppSecurityPermissions.java
index e3ce6f2..a12b15e 100644
--- a/core/java/android/widget/AppSecurityPermissions.java
+++ b/core/java/android/widget/AppSecurityPermissions.java
@@ -533,6 +533,12 @@
             int existingReqFlags) {
         final int base = pInfo.protectionLevel & PermissionInfo.PROTECTION_MASK_BASE;
         final boolean isNormal = (base == PermissionInfo.PROTECTION_NORMAL);
+
+        // We do not show normal permissions in the UI.
+        if (isNormal) {
+            return false;
+        }
+
         final boolean isDangerous = (base == PermissionInfo.PROTECTION_DANGEROUS)
                 || ((pInfo.protectionLevel&PermissionInfo.PROTECTION_FLAG_PRE23) != 0);
         final boolean isRequired =
@@ -546,7 +552,7 @@
 
         // Dangerous and normal permissions are always shown to the user if the permission
         // is required, or it was previously granted
-        if ((isNormal || isDangerous) && (isRequired || wasGranted || isGranted)) {
+        if (isDangerous && (isRequired || wasGranted || isGranted)) {
             return true;
         }
 
diff --git a/core/java/android/widget/RelativeLayout.java b/core/java/android/widget/RelativeLayout.java
index dac02fa..6a561e6 100644
--- a/core/java/android/widget/RelativeLayout.java
+++ b/core/java/android/widget/RelativeLayout.java
@@ -731,7 +731,8 @@
         // Negative values in a mySize value in RelativeLayout
         // measurement is code for, "we got an unspecified mode in the
         // RelativeLayout's measure spec."
-        if (mySize < 0 && !mAllowBrokenMeasureSpecs) {
+        final boolean isUnspecified = mySize < 0;
+        if (isUnspecified && !mAllowBrokenMeasureSpecs) {
             if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
                 // Constraints fixed both edges, so child has an exact size.
                 childSpecSize = Math.max(0, childEnd - childStart);
@@ -767,7 +768,7 @@
 
         if (childStart != VALUE_NOT_SET && childEnd != VALUE_NOT_SET) {
             // Constraints fixed both edges, so child must be an exact size.
-            childSpecMode = MeasureSpec.EXACTLY;
+            childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
             childSpecSize = Math.max(0, maxAvailable);
         } else {
             if (childSize >= 0) {
@@ -784,7 +785,7 @@
             } else if (childSize == LayoutParams.MATCH_PARENT) {
                 // Child wanted to be as big as possible. Give all available
                 // space.
-                childSpecMode = MeasureSpec.EXACTLY;
+                childSpecMode = isUnspecified ? MeasureSpec.UNSPECIFIED : MeasureSpec.EXACTLY;
                 childSpecSize = Math.max(0, maxAvailable);
             } else if (childSize == LayoutParams.WRAP_CONTENT) {
                 // Child wants to wrap content. Use AT_MOST to communicate
diff --git a/core/java/com/android/internal/logging/MetricsLogger.java b/core/java/com/android/internal/logging/MetricsLogger.java
index cbe535f..91ae27b 100644
--- a/core/java/com/android/internal/logging/MetricsLogger.java
+++ b/core/java/com/android/internal/logging/MetricsLogger.java
@@ -27,7 +27,20 @@
  */
 public class MetricsLogger implements MetricsConstants {
     // Temporary constants go here, to await migration to MetricsConstants.
-    // next value is 227;
+    // next value is 238;
+
+    public static final int TUNER = 227;
+    public static final int TUNER_QS = 228;
+    public static final int TUNER_DEMO_MODE = 229;
+
+    public static final int TUNER_QS_REORDER = 230;
+    public static final int TUNER_QS_ADD = 231;
+    public static final int TUNER_QS_REMOVE = 232;
+    public static final int TUNER_STATUS_BAR_ENABLE = 233;
+    public static final int TUNER_STATUS_BAR_DISABLE = 234;
+    public static final int TUNER_DEMO_MODE_ENABLED = 235;
+    public static final int TUNER_DEMO_MODE_ON = 236;
+    public static final int TUNER_BATTERY_PERCENTAGE = 237;
 
     public static void visible(Context context, int category) throws IllegalArgumentException {
         if (Build.IS_DEBUGGABLE && category == VIEW_UNKNOWN) {
diff --git a/core/java/com/android/internal/os/BatteryStatsHelper.java b/core/java/com/android/internal/os/BatteryStatsHelper.java
index 264b8c1..9caf78a 100644
--- a/core/java/com/android/internal/os/BatteryStatsHelper.java
+++ b/core/java/com/android/internal/os/BatteryStatsHelper.java
@@ -47,6 +47,7 @@
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.List;
+import java.util.Locale;
 
 /**
  * A helper class for retrieving the power usage information for all applications and services.
@@ -267,15 +268,20 @@
 
     public static String makemAh(double power) {
         if (power == 0) return "0";
-        else if (power < .00001) return String.format("%.8f", power);
-        else if (power < .0001) return String.format("%.7f", power);
-        else if (power < .001) return String.format("%.6f", power);
-        else if (power < .01) return String.format("%.5f", power);
-        else if (power < .1) return String.format("%.4f", power);
-        else if (power < 1) return String.format("%.3f", power);
-        else if (power < 10) return String.format("%.2f", power);
-        else if (power < 100) return String.format("%.1f", power);
-        else return String.format("%.0f", power);
+
+        final String format;
+        if (power < .00001) format = "%.8f";
+        else if (power < .0001) format = "%.7f";
+        else if (power < .001) format = "%.6f";
+        else if (power < .01) format = "%.5f";
+        else if (power < .1) format = "%.4f";
+        else if (power < 1) format = "%.3f";
+        else if (power < 10) format = "%.2f";
+        else if (power < 100) format = "%.1f";
+        else format = "%.0f";
+
+        // Use English locale because this is never used in UI (only in checkin and dump).
+        return String.format(Locale.ENGLISH, format, power);
     }
 
     /**
diff --git a/core/java/com/android/internal/os/BatteryStatsImpl.java b/core/java/com/android/internal/os/BatteryStatsImpl.java
index 60f47d6..e7c58f4 100644
--- a/core/java/com/android/internal/os/BatteryStatsImpl.java
+++ b/core/java/com/android/internal/os/BatteryStatsImpl.java
@@ -2560,14 +2560,24 @@
         addHistoryEventLocked(elapsedRealtime, uptime, code, name, uid);
     }
 
+    boolean ensureStartClockTime(final long currentTime) {
+        final long ABOUT_ONE_YEAR = 365*24*60*60*1000L;
+        if (currentTime > ABOUT_ONE_YEAR && mStartClockTime < (currentTime-ABOUT_ONE_YEAR)) {
+            // If the start clock time has changed by more than a year, then presumably
+            // the previous time was completely bogus.  So we are going to figure out a
+            // new time based on how much time has elapsed since we started counting.
+            mStartClockTime = currentTime - (SystemClock.elapsedRealtime()-(mRealtimeStart/1000));
+            return true;
+        }
+        return false;
+    }
+
     public void noteCurrentTimeChangedLocked() {
         final long currentTime = System.currentTimeMillis();
         final long elapsedRealtime = SystemClock.elapsedRealtime();
         final long uptime = SystemClock.uptimeMillis();
         recordCurrentTimeChangeLocked(currentTime, elapsedRealtime, uptime);
-        if (isStartClockTimeValid()) {
-            mStartClockTime = currentTime;
-        }
+        ensureStartClockTime(currentTime);
     }
 
     public void noteProcessStartLocked(String name, int uid) {
@@ -4306,19 +4316,11 @@
         }
     }
 
-    boolean isStartClockTimeValid() {
-        return mStartClockTime > 365*24*60*60*1000L;
-    }
-
     @Override public long getStartClockTime() {
-        if (!isStartClockTimeValid()) {
-            // If the last clock time we got was very small, then we hadn't had a real
-            // time yet, so try to get it again.
-            mStartClockTime = System.currentTimeMillis();
-            if (isStartClockTimeValid()) {
-                recordCurrentTimeChangeLocked(mStartClockTime, SystemClock.elapsedRealtime(),
-                        SystemClock.uptimeMillis());
-            }
+        final long currentTime = System.currentTimeMillis();
+        if (ensureStartClockTime(currentTime)) {
+            recordCurrentTimeChangeLocked(currentTime, SystemClock.elapsedRealtime(),
+                    SystemClock.uptimeMillis());
         }
         return mStartClockTime;
     }
diff --git a/core/res/AndroidManifest.xml b/core/res/AndroidManifest.xml
index 92862f5..3e22e09 100644
--- a/core/res/AndroidManifest.xml
+++ b/core/res/AndroidManifest.xml
@@ -1749,6 +1749,10 @@
     <!-- ==================================== -->
     <eat-comment />
 
+    <!-- @SystemApi Allows access to the list of accounts in the Accounts Service. -->
+    <permission android:name="android.permission.GET_ACCOUNTS_PRIVILEGED"
+        android:protectionLevel="signature|privileged" />
+
     <!-- @SystemApi Allows applications to RW to diagnostic resources.
     <p>Not for use by third-party applications. -->
     <permission android:name="android.permission.DIAGNOSTIC"
diff --git a/core/res/res/values-es/strings.xml b/core/res/res/values-es/strings.xml
index be2b962..0533317 100644
--- a/core/res/res/values-es/strings.xml
+++ b/core/res/res/values-es/strings.xml
@@ -1001,7 +1001,7 @@
     <string name="sms_short_code_remember_undo_instruction" msgid="4960944133052287484">"Puedes cambiar esta opción más tarde en Ajustes &gt; Aplicaciones."</string>
     <string name="sms_short_code_confirm_always_allow" msgid="3241181154869493368">"Permitir siempre"</string>
     <string name="sms_short_code_confirm_never_allow" msgid="446992765774269673">"No permitir nunca"</string>
-    <string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM eliminada"</string>
+    <string name="sim_removed_title" msgid="6227712319223226185">"Tarjeta SIM retirada"</string>
     <string name="sim_removed_message" msgid="5450336489923274918">"La red móvil no estará disponible hasta que reinicies el dispositivo con una tarjeta SIM válida insertada."</string>
     <string name="sim_done_button" msgid="827949989369963775">"Listo"</string>
     <string name="sim_added_title" msgid="3719670512889674693">"Tarjeta SIM añadida"</string>
diff --git a/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml b/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml
new file mode 100644
index 0000000..bad49c3
--- /dev/null
+++ b/core/res/res/values-mcc310-mnc260-pt-rBR/strings.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/*
+** Copyright 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 my 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.
+*/
+ -->
+
+<!--  These resources are around just to allow their values to be customized
+     for different hardware and product builds.  -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+  <string-array name="wfcOperatorErrorAlertMessages">
+    <item msgid="7239039348648848288">"Para fazer chamadas e enviar mensagens por Wi-Fi, primeiro peça à sua operadora para configurar esse serviço. Depois ative novamente as chamadas por Wi-Fi nas configurações."</item>
+  </string-array>
+  <string-array name="wfcOperatorErrorNotificationMessages">
+    <item msgid="483847327467331298">"Faça registro na sua operadora"</item>
+  </string-array>
+    <string name="wfcSpnFormat" msgid="4982938551498609442">"%s chamada Wi-Fi"</string>
+</resources>
diff --git a/core/res/res/values-mn-rMN/strings.xml b/core/res/res/values-mn-rMN/strings.xml
index be72354..df9f2805 100644
--- a/core/res/res/values-mn-rMN/strings.xml
+++ b/core/res/res/values-mn-rMN/strings.xml
@@ -1042,7 +1042,7 @@
     <string name="usb_accessory_notification_title" msgid="7848236974087653666">"USB төхөөрөмжид холбогдов"</string>
     <string name="usb_notification_message" msgid="7347368030849048437">"Нэмэлт сонголтыг харахын тулд дарна."</string>
     <string name="adb_active_notification_title" msgid="6729044778949189918">"USB дебаг холбогдсон"</string>
-    <string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебаг хийхийг идэвхгүй болгох бол хүрнэ үү."</string>
+    <string name="adb_active_notification_message" msgid="1016654627626476142">"USB дебагийг идэвхгүй болгох бол хүрнэ үү."</string>
     <string name="select_input_method" msgid="8547250819326693584">"Гарыг өөрчлөх"</string>
     <string name="configure_input_methods" msgid="4769971288371946846">"Гар сонгох"</string>
     <string name="show_ime" msgid="9157568568695230830">"Оруулах аргыг харуулах"</string>
diff --git a/core/res/res/values-pt-rBR-watch/strings.xml b/core/res/res/values-pt-rBR-watch/strings.xml
new file mode 100644
index 0000000..120e4a5
--- /dev/null
+++ b/core/res/res/values-pt-rBR-watch/strings.xml
@@ -0,0 +1,24 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!-- 
+/* //device/apps/common/assets/res/any/strings.xml
+**
+** Copyright 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.
+*/
+ -->
+
+<resources xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
+    <string name="android_upgrading_apk" msgid="1090732262010398759">"App <xliff:g id="NUMBER_0">%1$d</xliff:g> de <xliff:g id="NUMBER_1">%2$d</xliff:g>."</string>
+</resources>
diff --git a/core/res/res/values-sq-rAL/strings.xml b/core/res/res/values-sq-rAL/strings.xml
index 549c5ef7..2bde626 100644
--- a/core/res/res/values-sq-rAL/strings.xml
+++ b/core/res/res/values-sq-rAL/strings.xml
@@ -21,7 +21,7 @@
 <resources xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
     <string name="byteShort" msgid="8340973892742019101">"B"</string>
-    <string name="kilobyteShort" msgid="5973789783504771878">"kilobajt"</string>
+    <string name="kilobyteShort" msgid="5973789783504771878">"KB"</string>
     <string name="megabyteShort" msgid="6355851576770428922">"MB"</string>
     <string name="gigabyteShort" msgid="3259882455212193214">"GB"</string>
     <string name="terabyteShort" msgid="231613018159186962">"terabajt"</string>
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 06b6389..54848e9 100755
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -408,6 +408,7 @@
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_24">24</integer>
     <integer translatable="false" name="config_wifi_framework_wifi_score_good_link_speed_5">36</integer>
     <string  translatable="false" name="config_wifi_random_mac_oui">DA-A1-19</string>
+    <string  translatable="false" name="config_wifi_framework_sap_2G_channel_list">1,6,11</string>
 
     <bool translatable="false" name="config_wifi_framework_cellular_handover_enable_user_triggered_adjustment">true</bool>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index fe82b8c..8070986 100755
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -337,6 +337,7 @@
   <java-symbol type="integer"  name="config_wifi_active_rx_cur_ma" />
   <java-symbol type="integer"  name="config_wifi_tx_cur_ma" />
   <java-symbol type="integer"  name="config_wifi_operating_voltage_mv" />
+  <java-symbol type="string"  name="config_wifi_framework_sap_2G_channel_list" />
 
   <java-symbol type="bool" name="editable_voicemailnumber" />
 
diff --git a/docs/html/design/wear/structure.jd b/docs/html/design/wear/structure.jd
index c1d9ef9..768aa7f 100644
--- a/docs/html/design/wear/structure.jd
+++ b/docs/html/design/wear/structure.jd
@@ -166,8 +166,11 @@
   <li>A map that asks the user to drop a pin should exit when the pin is dropped.</li>
   <li>A short game can exit when the game finishes.</li>
   <li>A drawing app can finish after 5 seconds of inactivity.</li>
+
+  <p class="note">An app generally should not exit in {@link android.app.Activity#onPause onPause()}.  This is because events such as <a href="{@docRoot}guide/topics/ui/notifiers/notifications.html#Heads-up">Heads-up Notifications</a> can trigger the {@link android.app.Activity#onPause() onPause()} callback.</p>
 </ul>
 
+
 <h3>Manually exiting</h3>
 
 <p>Even with logical exit points like these, some cases may exist where the user may want to
diff --git a/docs/html/training/articles/keystore.jd b/docs/html/training/articles/keystore.jd
index 52cb13e..aa1ed0a 100644
--- a/docs/html/training/articles/keystore.jd
+++ b/docs/html/training/articles/keystore.jd
@@ -7,14 +7,15 @@
     <ol>
       <li><a href="#SecurityFeatures">Security Features</a></li>
       <li><a href="#WhichShouldIUse">Choosing Between a Keychain or the Android Keystore Provider</a></li>
-      <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider
-      </a></li>
+      <li><a href="#UsingAndroidKeyStore">Using Android Keystore Provider</a>
       <ol>
         <li><a href="#GeneratingANewPrivateKey">Generating a New Private Key</a></li>
         <li><a href="#WorkingWithKeyStoreEntries">Working with Keystore Entries</a></li>
         <li><a href="#ListingEntries">Listing Entries</a></li>
         <li><a href="#SigningAndVerifyingData">Signing and Verifying Data</a></li>
       </ol>
+      </li>
+      <li><a href="#SupportedAlgorithms">Supported Algorithms</a></li>
     </ol>
 
     <h2>Blog articles</h2>
@@ -27,6 +28,14 @@
   </div>
 </div>
 
+<style type="text/css">
+  tr.deprecated {
+    background-color: #ccc;
+    color: #999;
+    font-style: italic;
+  }
+</style>
+
 <p>The Android Keystore system lets you store cryptographic keys in a container
   to make it more difficult to extract from the device. Once keys are in the
   keystore, they can be used for cryptographic operations with the key material
@@ -213,4 +222,456 @@
   {@link android.hardware.fingerprint.FingerprintManager#hasEnrolledFingerprints() FingerprintManager.hasEnrolledFingerprints}).
   These keys become permanently invalidated once a new fingerprint is enrolled or all fingerprints
   are unenrolled.</li>
-</ul>
\ No newline at end of file
+</ul>
+
+<h2 id="SupportedAlgorithms">Supported Algorithms</h2>
+
+<ul>
+  <li><a href="#SupportedCiphers">{@code Cipher}</a></li>
+  <li><a href="#SupportedKeyGenerators">{@code KeyGenerator}</a></li>
+  <li><a href="#SupportedKeyFactories">{@code KeyFactory}</a></li>
+  <li><a href="#SupportedKeyPairGenerators">{@code KeyPairGenerator}</a></li>
+  <li><a href="#SupportedMacs">{@code Mac}</a></li>
+  <li><a href="#SupportedSignatures">{@code Signature}</a></li>
+  <li><a href="#SupportedSecretKeyFactories">{@code SecretKeyFactory}</a></li>
+</ul>
+
+<h3 id="SupportedCiphers">Cipher</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>AES/CBC/NoPadding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>AES/CBC/PKCS7Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>AES/CTR/NoPadding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>AES/ECB/NoPadding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>AES/ECB/PKCS7Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>AES/GCM/NoPadding</td>
+      <td>23+</td>
+      <td>Only 12-byte long IVs supported.</td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/NoPadding</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/PKCS1Padding</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/OAEPWithSHA-1AndMGF1Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/OAEPWithSHA-224AndMGF1Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/OAEPWithSHA-256AndMGF1Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/OAEPWithSHA-384AndMGF1Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/OAEPWithSHA-512AndMGF1Padding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>RSA/ECB/OAEPPadding</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+  </tbody>
+</table>
+
+<h3 id="SupportedKeyGenerators">KeyGenerator</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>AES</td>
+      <td>23+</td>
+      <td>Supported sizes: 128, 192, 256</td>
+    </tr>
+    <tr>
+      <td>HmacSHA1</td>
+      <td>23+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li>
+          <li>Default size: 160</li>
+        <ul>
+      </td>
+    </tr>
+    <tr>
+      <td>HmacSHA224</td>
+      <td>23+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li>
+          <li>Default size: 224</li>
+        <ul>
+      </td>
+    </tr>
+    <tr>
+      <td>HmacSHA256</td>
+      <td>23+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li>
+          <li>Default size: 256</li>
+        <ul>
+      </td>
+    </tr>
+    <tr>
+      <td>HmacSHA384</td>
+      <td>23+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li>
+          <li>Default size: 384</li>
+        <ul>
+      </td>
+    </tr>
+    <tr>
+      <td>HmacSHA512</td>
+      <td>23+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 8--1024 (inclusive), must be multiple of 8</li>
+          <li>Default size: 512</li>
+        <ul>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+<h3 id="SupportedKeyFactories">KeyFactory</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>EC</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo} (private key only),
+        {@link java.security.spec.ECPublicKeySpec} (public key only),
+        {@link java.security.spec.X509EncodedKeySpec} (public key only)
+      </td>
+    </tr>
+    <tr>
+      <td>RSA</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo} (private key only),
+        {@link java.security.spec.RSAPublicKeySpec} (public key only),
+        {@link java.security.spec.X509EncodedKeySpec} (public key only)
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+<h3 id="SupportedKeyStoreKeys">KeyStore</h3>
+KeyStore supports the same key types as
+<a href="#SupportedKeyPairGenerators">{@code KeyPairGenerator}</a> and
+<a href="#SupportedKeyGenerators">{@code KeyGenerator}</a>.
+
+<h3 id="SupportedKeyPairGenerators">KeyPairGenerator</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr class="deprecated">
+      <td>DSA</td>
+      <td>19&ndash;22</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>EC</td>
+      <td>23+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 224, 256, 384, 521</li>
+          <li>Supported named curves: P-224 (secp256r1), P-256 (aka secp256r1 and prime256v1), P-384
+            (aka secp384r1), P-521 (aka secp521r1)</li>
+        </ul>
+
+        <p>Prior to API Level 23, EC keys can be generated using KeyPairGenerator of algorithm "RSA"
+        initialized {@link android.security.KeyPairGeneratorSpec} whose key type is set to "EC"
+        using {@link android.security.KeyPairGeneratorSpec.Builder#setKeyType(String)}. EC curve
+        name cannot be specified using this method -- a NIST P-curve is automatically chosen based
+        on the requested key size.
+      </td>
+    </tr>
+    <tr>
+      <td>RSA</td>
+      <td>18+</td>
+      <td>
+        <ul>
+          <li>Supported sizes: 512, 768, 1024, 2048, 3072, 4096</li>
+          <li>Supported public exponents: 3, 65537</li>
+          <li>Default public exponent: 65537</li>
+        </ul>
+      </td>
+    </tr>
+  </tbody>
+</table>
+
+<h3 id="SupportedMacs">Mac</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>HmacSHA1</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>HmacSHA224</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>HmacSHA256</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>HmacSHA384</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>HmacSHA512</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+  </tbody>
+</table>
+
+<h3 id="SupportedSignatures">Signature</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>MD5withRSA</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>NONEwithECDSA</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>NONEwithRSA</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr class="deprecated">
+      <td>SHA1withDSA</td>
+      <td>19&ndash;22</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA1withECDSA</td>
+      <td>19+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA1withRSA</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA1withRSA/PSS</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr class="deprecated">
+      <td>SHA224withDSA</td>
+      <td>20&ndash;22</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA224withECDSA</td>
+      <td>20+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA224withRSA</td>
+      <td>20+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA224withRSA/PSS</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr class="deprecated">
+      <td>SHA256withDSA</td>
+      <td>19&ndash;22</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA256withECDSA</td>
+      <td>19+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA256withRSA</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA256withRSA/PSS</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr class="deprecated">
+      <td>SHA384withDSA</td>
+      <td>19&ndash;22</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA384withECDSA</td>
+      <td>19+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA384withRSA</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA384withRSA/PSS</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+    <tr class="deprecated">
+      <td>SHA512withDSA</td>
+      <td>19&ndash;22</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA512withECDSA</td>
+      <td>19+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA512withRSA</td>
+      <td>18+</td>
+      <td></td>
+    </tr>
+    <tr>
+      <td>SHA512withRSA/PSS</td>
+      <td>23+</td>
+      <td></td>
+    </tr>
+  </tbody>
+</table>
+
+<h3 id="SupportedSecretKeyFactories">SecretKeyFactory</h3>
+<table>
+  <thead>
+    <tr>
+      <th>Algorithm</th>
+      <th>Supported (API Levels)</th>
+      <th>Notes</th>
+    </tr>
+  </thead>
+  <tbody>
+    <tr>
+      <td>AES</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td>
+    </tr>
+    <tr>
+      <td>HmacSHA1</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td>
+    </tr>
+    <tr>
+      <td>HmacSHA224</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td>
+    </tr>
+    <tr>
+      <td>HmacSHA256</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td>
+    </tr>
+    <tr>
+      <td>HmacSHA384</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td>
+    </tr>
+    <tr>
+      <td>HmacSHA512</td>
+      <td>23+</td>
+      <td>Supported key specs: {@link android.security.keystore.KeyInfo}</td>
+    </tr>
+  </tbody>
+</table>
\ No newline at end of file
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
index 5459bea..441ee66 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreAuthenticatedAESCipherSpi.java
@@ -51,7 +51,7 @@
 abstract class AndroidKeyStoreAuthenticatedAESCipherSpi extends AndroidKeyStoreCipherSpiBase {
 
     abstract static class GCM extends AndroidKeyStoreAuthenticatedAESCipherSpi {
-        private static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
+        static final int MIN_SUPPORTED_TAG_LENGTH_BITS = 96;
         private static final int MAX_SUPPORTED_TAG_LENGTH_BITS = 128;
         private static final int DEFAULT_TAG_LENGTH_BITS = 128;
         private static final int IV_LENGTH_BYTES = 12;
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
index fd014eb..4c174f1 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreKeyGeneratorSpi.java
@@ -171,7 +171,7 @@
                         "Key size must be positive: " + mKeySizeBits);
             } else if ((mKeySizeBits % 8) != 0) {
                 throw new InvalidAlgorithmParameterException(
-                        "Key size in must be a multiple of 8: " + mKeySizeBits);
+                        "Key size must be a multiple of 8: " + mKeySizeBits);
             }
 
             try {
@@ -272,6 +272,11 @@
         KeymasterUtils.addUserAuthArgs(args,
                 spec.isUserAuthenticationRequired(),
                 spec.getUserAuthenticationValidityDurationSeconds());
+        KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
+                args,
+                mKeymasterAlgorithm,
+                mKeymasterBlockModes,
+                mKeymasterDigests);
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME, spec.getKeyValidityStart());
         args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
                 spec.getKeyValidityForOriginationEnd());
diff --git a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
index 88858de..915d86f 100644
--- a/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
+++ b/keystore/java/android/security/keystore/AndroidKeyStoreSpi.java
@@ -672,6 +672,11 @@
             KeymasterUtils.addUserAuthArgs(args,
                     params.isUserAuthenticationRequired(),
                     params.getUserAuthenticationValidityDurationSeconds());
+            KeymasterUtils.addMinMacLengthAuthorizationIfNecessary(
+                    args,
+                    keymasterAlgorithm,
+                    keymasterBlockModes,
+                    keymasterDigests);
             args.addDateIfNotNull(KeymasterDefs.KM_TAG_ACTIVE_DATETIME,
                     params.getKeyValidityStart());
             args.addDateIfNotNull(KeymasterDefs.KM_TAG_ORIGINATION_EXPIRE_DATETIME,
diff --git a/keystore/java/android/security/keystore/KeymasterUtils.java b/keystore/java/android/security/keystore/KeymasterUtils.java
index 92d636c..feafbfa 100644
--- a/keystore/java/android/security/keystore/KeymasterUtils.java
+++ b/keystore/java/android/security/keystore/KeymasterUtils.java
@@ -22,6 +22,8 @@
 import android.security.keymaster.KeymasterArguments;
 import android.security.keymaster.KeymasterDefs;
 
+import java.security.ProviderException;
+
 /**
  * @hide
  */
@@ -133,4 +135,45 @@
                     userAuthenticationValidityDurationSeconds);
         }
     }
+
+    /**
+     * Adds {@code KM_TAG_MIN_MAC_LENGTH} tag, if necessary, to the keymaster arguments for
+     * generating or importing a key. This tag may only be needed for symmetric keys (e.g., HMAC,
+     * AES-GCM).
+     */
+    public static void addMinMacLengthAuthorizationIfNecessary(KeymasterArguments args,
+            int keymasterAlgorithm,
+            int[] keymasterBlockModes,
+            int[] keymasterDigests) {
+        switch (keymasterAlgorithm) {
+            case KeymasterDefs.KM_ALGORITHM_AES:
+                if (com.android.internal.util.ArrayUtils.contains(
+                        keymasterBlockModes, KeymasterDefs.KM_MODE_GCM)) {
+                    // AES GCM key needs the minimum length of AEAD tag specified.
+                    args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH,
+                            AndroidKeyStoreAuthenticatedAESCipherSpi.GCM
+                                    .MIN_SUPPORTED_TAG_LENGTH_BITS);
+                }
+                break;
+            case KeymasterDefs.KM_ALGORITHM_HMAC:
+                // HMAC key needs the minimum length of MAC set to the output size of the associated
+                // digest. This is because we do not offer a way to generate shorter MACs and
+                // don't offer a way to verify MACs (other than by generating them).
+                if (keymasterDigests.length != 1) {
+                    throw new ProviderException(
+                            "Unsupported number of authorized digests for HMAC key: "
+                                    + keymasterDigests.length
+                                    + ". Exactly one digest must be authorized");
+                }
+                int keymasterDigest = keymasterDigests[0];
+                int digestOutputSizeBits = getDigestOutputSizeBits(keymasterDigest);
+                if (digestOutputSizeBits == -1) {
+                    throw new ProviderException(
+                            "HMAC key authorized for unsupported digest: "
+                                    + KeyProperties.Digest.fromKeymaster(keymasterDigest));
+                }
+                args.addUnsignedInt(KeymasterDefs.KM_TAG_MIN_MAC_LENGTH, digestOutputSizeBits);
+                break;
+        }
+    }
 }
diff --git a/libs/hwui/Caches.cpp b/libs/hwui/Caches.cpp
index 1030451..aa73d44 100644
--- a/libs/hwui/Caches.cpp
+++ b/libs/hwui/Caches.cpp
@@ -248,11 +248,6 @@
 void Caches::flush(FlushMode mode) {
     FLUSH_LOGD("Flushing caches (mode %d)", mode);
 
-    // We must stop tasks before clearing caches
-    if (mode > kFlushMode_Layers) {
-        tasks.stop();
-    }
-
     switch (mode) {
         case kFlushMode_Full:
             textureCache.clear();
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index a1b8a3b..025029e 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -23,9 +23,11 @@
 import android.app.Activity;
 import android.content.ContentUris;
 import android.content.Context;
+import android.content.pm.PackageManager;
 import android.database.Cursor;
 import android.net.Uri;
 import android.os.Environment;
+import android.os.Process;
 import android.provider.MediaStore;
 import android.provider.Settings;
 import android.provider.Settings.System;
@@ -359,7 +361,10 @@
      * If {@link RingtoneManager#RingtoneManager(Activity)} was not used, the
      * caller should manage the returned cursor through its activity's life
      * cycle to prevent leaking the cursor.
-     * 
+     * <p>
+     * Note that the list of ringtones available will differ depending on whether the caller
+     * has the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission.
+     *
      * @return A {@link Cursor} of all the ringtones available.
      * @see #ID_COLUMN_INDEX
      * @see #TITLE_COLUMN_INDEX
@@ -455,8 +460,10 @@
 
     /**
      * Returns a valid ringtone URI. No guarantees on which it returns. If it
-     * cannot find one, returns null.
-     * 
+     * cannot find one, returns null. If it can only find one on external storage and the caller
+     * doesn't have the {@link android.Manifest.permission#READ_EXTERNAL_STORAGE} permission,
+     * returns null.
+     *
      * @param context The context to use for querying.
      * @return A ringtone URI, or null if one cannot be found.
      */
@@ -495,6 +502,12 @@
     }
 
     private Cursor getMediaRingtones() {
+        if (PackageManager.PERMISSION_GRANTED != mContext.checkPermission(
+                android.Manifest.permission.READ_EXTERNAL_STORAGE,
+                Process.myPid(), Process.myUid())) {
+            Log.w(TAG, "No READ_EXTERNAL_STORAGE permission, ignoring ringtones on ext storage");
+            return null;
+        }
          // Get the external media cursor. First check to see if it is mounted.
         final String status = Environment.getExternalStorageState();
         
diff --git a/media/java/android/media/tv/TvInputService.java b/media/java/android/media/tv/TvInputService.java
index 86e8560..053d43b6 100644
--- a/media/java/android/media/tv/TvInputService.java
+++ b/media/java/android/media/tv/TvInputService.java
@@ -20,6 +20,7 @@
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
+import android.app.ActivityManager;
 import android.app.Service;
 import android.content.Context;
 import android.content.Intent;
@@ -1200,12 +1201,15 @@
             // We make the overlay view non-focusable and non-touchable so that
             // the application that owns the window token can decide whether to consume or
             // dispatch the input events.
-            int flag = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
-                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS
-                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE;
+            int flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
+                    | WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE
+                    | WindowManager.LayoutParams.FLAG_LAYOUT_NO_LIMITS;
+            if (ActivityManager.isHighEndGfx()) {
+                flags |= WindowManager.LayoutParams.FLAG_HARDWARE_ACCELERATED;
+            }
             mWindowParams = new WindowManager.LayoutParams(
                     frame.right - frame.left, frame.bottom - frame.top,
-                    frame.left, frame.top, type, flag, PixelFormat.TRANSPARENT);
+                    frame.left, frame.top, type, flags, PixelFormat.TRANSPARENT);
             mWindowParams.privateFlags |=
                     WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
             mWindowParams.gravity = Gravity.START | Gravity.TOP;
diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml
index 6e5dc3f..fea7f94 100644
--- a/packages/SystemUI/AndroidManifest.xml
+++ b/packages/SystemUI/AndroidManifest.xml
@@ -405,5 +405,13 @@
             android:exported="true"
             android:singleUser="true"
             android:permission="android.permission.BIND_DREAM_SERVICE" />
+
+        <receiver
+            android:name=".tuner.TunerService$ClearReceiver"
+            android:exported="false">
+            <intent-filter>
+                <action android:name="com.android.systemui.action.CLEAR_TUNER" />
+            </intent-filter>
+        </receiver>
     </application>
 </manifest>
diff --git a/packages/SystemUI/res/drawable-nodpi/tuner.xml b/packages/SystemUI/res/drawable-nodpi/tuner.xml
index e27423f..0596aa4 100644
--- a/packages/SystemUI/res/drawable-nodpi/tuner.xml
+++ b/packages/SystemUI/res/drawable-nodpi/tuner.xml
@@ -1,7 +1,7 @@
 <!--
-   Copyright (C) 2015 The Android Open Source Project
+    Copyright (C) 2015 The Android Open Source Project
 
-   Licensed under the Apache License, Version 2.0 (the "License");
+    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
 
@@ -14,14 +14,11 @@
     limitations under the License.
 -->
 <vector xmlns:android="http://schemas.android.com/apk/res/android"
-        android:width="48.0dp"
-        android:height="48.0dp"
-        android:viewportWidth="48.0"
-        android:viewportHeight="48.0">
+        android:width="24.0dp"
+        android:height="24.0dp"
+        android:viewportWidth="24.0"
+        android:viewportHeight="24.0">
     <path
-        android:fillColor="#FF000000"
-        android:pathData="M29.9,24.8c0.0,-0.3 0.1,-0.5 0.1,-0.8s0.0,-0.5 -0.1,-0.8l1.7,-1.3c0.2,-0.1 0.2,-0.3 0.1,-0.5l-1.6,-2.8c-0.1,-0.2 -0.3,-0.2 -0.5,-0.2l-2.0,0.8c-0.4,-0.3 -0.9,-0.6 -1.4,-0.8L26.0,16.3c0.0,-0.2 -0.2,-0.3 -0.4,-0.3l-3.2,0.0c-0.2,0.0 -0.4,0.1 -0.4,0.3l-0.3,2.1c-0.5,0.2 -0.9,0.5 -1.4,0.8l-2.0,-0.8c-0.2,-0.1 -0.4,0.0 -0.5,0.2l-1.6,2.8c-0.1,0.2 -0.1,0.4 0.1,0.5l1.7,1.3c0.0,0.3 -0.1,0.5 -0.1,0.8s0.0,0.5 0.1,0.8l-1.7,1.3c-0.2,0.1 -0.2,0.3 -0.1,0.5l1.6,2.8c0.1,0.2 0.3,0.2 0.5,0.2l2.0,-0.8c0.4,0.3 0.9,0.6 1.4,0.8l0.3,2.1c0.0,0.2 0.2,0.3 0.4,0.3l3.2,0.0c0.2,0.0 0.4,-0.1 0.4,-0.3l0.3,-2.1c0.5,-0.2 0.9,-0.5 1.4,-0.8l2.0,0.8c0.2,0.1 0.4,0.0 0.5,-0.2l1.6,-2.8c0.1,-0.2 0.1,-0.4 -0.1,-0.5L29.9,24.8zM24.0,26.8c-1.5,0.0 -2.8,-1.3 -2.8,-2.8s1.3,-2.8 2.8,-2.8s2.8,1.3 2.8,2.8S25.5,26.8 24.0,26.8z"/>
-    <path
-        android:fillColor="#FF000000"
-        android:pathData="M18.0,38.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0s0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0S18.6,38.0 18.0,38.0zM24.0,38.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0s0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0S24.6,38.0 24.0,38.0zM30.0,38.0c-0.6,0.0 -1.0,-0.4 -1.0,-1.0s0.4,-1.0 1.0,-1.0s1.0,0.4 1.0,1.0S30.6,38.0 30.0,38.0zM42.0,6.0L6.0,6.0c-2.2,0.0 -4.0,1.8 -4.0,4.0l0.0,28.0c0.0,2.2 1.8,4.0 4.0,4.0l36.0,0.0c2.2,0.0 4.0,-1.8 4.0,-4.0L46.0,10.0C46.0,7.8 44.2,6.0 42.0,6.0zM42.0,34.0L6.0,34.0L6.0,14.0l36.0,0.0L42.0,34.0zM9.0,12.0L7.0,12.0l0.0,-2.0l2.0,0.0L9.0,12.0zM13.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0L13.0,12.0zM17.0,12.0l-2.0,0.0l0.0,-2.0l2.0,0.0L17.0,12.0z"/>
+        android:fillColor="#FFFFFFFF"
+        android:pathData="M22.7,19.0l-9.1,-9.1c0.9,-2.0 0.4,-5.0 -1.5,-6.9 -2.0,-2.0 -5.0,-2.4 -7.4,-1.3L9.0,6.0 6.0,9.0 1.6,4.7C0.4,7.0 0.9,10.1 2.9,12.1c1.9,1.9 4.6,2.4 6.9,1.5l9.1,9.1c0.4,0.4 1.0,0.4 1.4,0.0l2.3,-2.3c0.5,-0.4 0.5,-1.0 0.1,-1.4z"/>
 </vector>
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 1488ad6..444f0f0 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -26,7 +26,7 @@
 
     <com.android.systemui.statusbar.phone.KeyguardIndicationTextView
         android:id="@+id/keyguard_indication_text"
-        android:layout_width="wrap_content"
+        android:layout_width="match_parent"
         android:layout_height="wrap_content"
         android:layout_marginBottom="@dimen/keyguard_indication_margin_bottom"
         android:layout_gravity="bottom|center_horizontal"
diff --git a/packages/SystemUI/res/layout/status_bar_expanded_header.xml b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
index 7262ed2..8c8a3dd 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded_header.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded_header.xml
@@ -44,14 +44,31 @@
             android:scaleType="centerInside"/>
     </com.android.systemui.statusbar.phone.MultiUserSwitch>
 
-    <com.android.keyguard.AlphaOptimizedImageButton android:id="@+id/settings_button"
-        style="@android:style/Widget.Material.Button.Borderless"
-        android:layout_toStartOf="@id/multi_user_switch"
+    <com.android.keyguard.AlphaOptimizedLinearLayout
+        android:id="@+id/settings_button_container"
         android:layout_width="48dp"
         android:layout_height="@dimen/status_bar_header_height"
-        android:background="@drawable/ripple_drawable"
-        android:src="@drawable/ic_settings"
-        android:contentDescription="@string/accessibility_desc_settings" />
+        android:paddingStart="12dp"
+        android:clipChildren="false"
+        android:clipToPadding="false"
+        android:layout_toStartOf="@id/multi_user_switch">
+
+        <com.android.systemui.statusbar.phone.SettingsButton android:id="@+id/settings_button"
+            style="@android:style/Widget.Material.Button.Borderless"
+            android:layout_width="24dp"
+            android:layout_height="@dimen/status_bar_header_height"
+            android:background="@drawable/ripple_drawable"
+            android:src="@drawable/ic_settings"
+            android:contentDescription="@string/accessibility_desc_settings" />
+        <com.android.systemui.statusbar.AlphaOptimizedImageView android:id="@+id/tuner_icon"
+            android:layout_width="12dp"
+            android:layout_height="@dimen/status_bar_header_height"
+            android:tint="#4DFFFFFF"
+            android:tintMode="src_in"
+            android:visibility="invisible"
+            android:src="@drawable/tuner" />
+
+    </com.android.keyguard.AlphaOptimizedLinearLayout>
 
     <LinearLayout android:id="@+id/system_icons_super_container"
         android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index fcf7e3e..3eac84f 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -1032,7 +1032,7 @@
     <string name="volume_stream_vibrate_dnd" translatable="false">%s vibrate — Priority only</string>
 
     <!-- Name of special SystemUI debug settings -->
-    <string name="system_ui_tuner">System UI tuner</string>
+    <string name="system_ui_tuner">System UI Tuner</string>
 
     <!-- Preference to show/hide embedded battery percentage [CHAR LIMIT=50] -->
     <string name="show_battery_percentage">Show embedded battery percentage</string>
@@ -1099,4 +1099,25 @@
     <!-- Accessibility label for managed profile icon (not shown on screen) [CHAR LIMIT=NONE] -->
     <string name="accessibility_managed_profile">Work profile</string>
 
+    <!-- Title of warning when entering System UI tuner for first time [CHAR LIMIT=NONE] -->
+    <string name="tuner_warning_title">Fun for some but not for all</string>
+
+    <!-- Warning for users entering the System UI tuner for the first time [CHAR LIMIT=NONE]-->
+    <string name="tuner_warning">System UI Tuner gives you extra ways to tweak and customize the Android user interface. These experimental features may change, break, or disappear in future releases. Proceed with caution.</string>
+
+    <!-- Warning for users entering the System UI tuner [CHAR LIMIT=NONE]-->
+    <string name="tuner_persistent_warning">These experimental features may change, break, or disappear in future releases. Proceed with caution.</string>
+
+    <!-- Generic "got it" acceptance of dialog or cling [CHAR LIMIT=NONE] -->
+    <string name="got_it">Got it</string>
+
+    <!-- Toast describing tuner has been enabled [CHAR LIMIT=NONE] -->
+    <string name="tuner_toast">Congrats! System UI Tuner has been added to Settings</string>
+
+    <!-- Option to remove the tuner from settings [CHAR LIMIT=NONE] -->
+    <string name="remove_from_settings">Remove from Settings</string>
+
+    <!-- Dialog asking if the tuner should really be removed from settings [CHAR LIMIT=NONE]-->
+    <string name="remove_from_settings_prompt">Remove System UI Tuner from Settings and stop using all of its features?"</string>
+
 </resources>
diff --git a/packages/SystemUI/res/xml/tuner_prefs.xml b/packages/SystemUI/res/xml/tuner_prefs.xml
index 8c1acc3..3a41c3c 100644
--- a/packages/SystemUI/res/xml/tuner_prefs.xml
+++ b/packages/SystemUI/res/xml/tuner_prefs.xml
@@ -76,4 +76,8 @@
         android:key="demo_mode"
         android:title="@string/demo_mode" />
 
+    <Preference
+        android:summary="@string/tuner_persistent_warning"
+        android:selectable="false" />
+
 </PreferenceScreen>
diff --git a/packages/SystemUI/src/com/android/systemui/DemoMode.java b/packages/SystemUI/src/com/android/systemui/DemoMode.java
index d406f5b..11996d0 100644
--- a/packages/SystemUI/src/com/android/systemui/DemoMode.java
+++ b/packages/SystemUI/src/com/android/systemui/DemoMode.java
@@ -20,6 +20,8 @@
 
 public interface DemoMode {
 
+    public static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed";
+
     void dispatchDemoCommand(String command, Bundle args);
 
     public static final String ACTION_DEMO = "com.android.systemui.demo";
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
index 07406b9..f3ad9d8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/CellularTile.java
@@ -45,6 +45,8 @@
     private final MobileDataController mDataController;
     private final CellularDetailAdapter mDetailAdapter;
 
+    private final CellSignalCallback mSignalCallback = new CellSignalCallback();
+
     public CellularTile(Host host) {
         super(host);
         mController = host.getNetworkController();
@@ -90,8 +92,10 @@
     protected void handleUpdateState(SignalState state, Object arg) {
         state.visible = mController.hasMobileDataFeature();
         if (!state.visible) return;
-        final CallbackInfo cb = (CallbackInfo) arg;
-        if (cb == null) return;
+        CallbackInfo cb = (CallbackInfo) arg;
+        if (cb == null) {
+            cb = mSignalCallback.mInfo;
+        }
 
         final Resources r = mContext.getResources();
         final int iconId = cb.noSim ? R.drawable.ic_qs_no_sim
@@ -152,7 +156,7 @@
         boolean isDataTypeIconWide;
     }
 
-    private final SignalCallback mSignalCallback = new SignalCallbackAdapter() {
+    private final class CellSignalCallback extends SignalCallbackAdapter {
         private final CallbackInfo mInfo = new CallbackInfo();
         @Override
         public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
index f7f7acb..3d0dc7b 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/IntentTile.java
@@ -45,6 +45,8 @@
     private int mCurrentUserId;
     private String mIntentPackage;
 
+    private Intent mLastIntent;
+
     private IntentTile(Host host, String action) {
         super(host);
         mContext.registerReceiver(mReceiver, new IntentFilter(action));
@@ -112,8 +114,16 @@
 
     @Override
     protected void handleUpdateState(State state, Object arg) {
-        if (!(arg instanceof Intent)) return;
-        final Intent intent = (Intent) arg;
+        Intent intent = (Intent) arg;
+        if (intent == null) {
+            if (mLastIntent == null) {
+                return;
+            }
+            // No intent but need to refresh state, just use the last one.
+            intent = mLastIntent;
+        }
+        // Save the last one in case we need it later.
+        mLastIntent = intent;
         state.visible = intent.getBooleanExtra("visible", true);
         state.contentDescription = intent.getStringExtra("contentDescription");
         state.label = intent.getStringExtra("label");
diff --git a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
index 3bfff2f..e654efd 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/tiles/WifiTile.java
@@ -35,7 +35,6 @@
 import com.android.systemui.statusbar.policy.NetworkController;
 import com.android.systemui.statusbar.policy.NetworkController.AccessPointController;
 import com.android.systemui.statusbar.policy.NetworkController.IconState;
-import com.android.systemui.statusbar.policy.NetworkController.SignalCallback;
 import com.android.systemui.statusbar.policy.SignalCallbackAdapter;
 
 import java.util.List;
@@ -49,6 +48,8 @@
     private final WifiDetailAdapter mDetailAdapter;
     private final QSTile.SignalState mStateBeforeClick = newTileState();
 
+    private final WifiSignalCallback mSignalCallback = new WifiSignalCallback();
+
     public WifiTile(Host host) {
         super(host);
         mController = host.getNetworkController();
@@ -118,8 +119,10 @@
     protected void handleUpdateState(SignalState state, Object arg) {
         state.visible = true;
         if (DEBUG) Log.d(TAG, "handleUpdateState arg=" + arg);
-        if (arg == null) return;
         CallbackInfo cb = (CallbackInfo) arg;
+        if (cb == null) {
+            cb = mSignalCallback.mInfo;
+        }
 
         boolean wifiConnected = cb.enabled && (cb.wifiSignalIconId > 0) && (cb.enabledDesc != null);
         boolean wifiNotConnected = (cb.wifiSignalIconId > 0) && (cb.enabledDesc == null);
@@ -213,20 +216,21 @@
         }
     }
 
-    private final SignalCallback mSignalCallback = new SignalCallbackAdapter() {
+    private final class WifiSignalCallback extends SignalCallbackAdapter {
+        final CallbackInfo mInfo = new CallbackInfo();
+
         @Override
         public void setWifiIndicators(boolean enabled, IconState statusIcon, IconState qsIcon,
                 boolean activityIn, boolean activityOut, String description) {
             if (DEBUG) Log.d(TAG, "onWifiSignalChanged enabled=" + enabled);
-            final CallbackInfo info = new CallbackInfo();
-            info.enabled = enabled;
-            info.connected = qsIcon.visible;
-            info.wifiSignalIconId = qsIcon.icon;
-            info.enabledDesc = description;
-            info.activityIn = activityIn;
-            info.activityOut = activityOut;
-            info.wifiSignalContentDescription = qsIcon.contentDescription;
-            refreshState(info);
+            mInfo.enabled = enabled;
+            mInfo.connected = qsIcon.visible;
+            mInfo.wifiSignalIconId = qsIcon.icon;
+            mInfo.enabledDesc = description;
+            mInfo.activityIn = activityIn;
+            mInfo.activityOut = activityOut;
+            mInfo.wifiSignalContentDescription = qsIcon.contentDescription;
+            refreshState(mInfo);
         }
     };
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
index f62dc59..a2e6632 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/BaseStatusBar.java
@@ -729,11 +729,15 @@
     }
 
     protected void setNotificationShown(StatusBarNotification n) {
-        mNotificationListener.setNotificationsShown(new String[] { n.getKey() });
+        setNotificationsShown(new String[]{n.getKey()});
     }
 
     protected void setNotificationsShown(String[] keys) {
-        mNotificationListener.setNotificationsShown(keys);
+        try {
+            mNotificationListener.setNotificationsShown(keys);
+        } catch (RuntimeException e) {
+            Log.d(TAG, "failed setNotificationsShown: ", e);
+        }
     }
 
     protected boolean isCurrentProfile(int userId) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
index 46beed7..e1ba2d5 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/PhoneStatusBar.java
@@ -198,6 +198,8 @@
 
     public static final boolean SHOW_LOCKSCREEN_MEDIA_ARTWORK = true;
 
+    public static final String ACTION_FAKE_ARTWORK = "fake_artwork";
+
     private static final int MSG_OPEN_NOTIFICATION_PANEL = 1000;
     private static final int MSG_CLOSE_PANELS = 1001;
     private static final int MSG_OPEN_SETTINGS_PANEL = 1002;
@@ -890,12 +892,16 @@
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
         filter.addAction(Intent.ACTION_SCREEN_OFF);
         filter.addAction(Intent.ACTION_SCREEN_ON);
-        if (DEBUG_MEDIA_FAKE_ARTWORK) {
-            filter.addAction("fake_artwork");
-        }
-        filter.addAction(ACTION_DEMO);
         context.registerReceiverAsUser(mBroadcastReceiver, UserHandle.ALL, filter, null, null);
 
+        IntentFilter demoFilter = new IntentFilter();
+        if (DEBUG_MEDIA_FAKE_ARTWORK) {
+            demoFilter.addAction(ACTION_FAKE_ARTWORK);
+        }
+        demoFilter.addAction(ACTION_DEMO);
+        context.registerReceiverAsUser(mDemoReceiver, UserHandle.ALL, demoFilter,
+                android.Manifest.permission.DUMP, null);
+
         // listen for USER_SETUP_COMPLETE setting (per-user)
         resetUserSetupObserver();
 
@@ -2852,7 +2858,14 @@
                 mScreenOn = true;
                 notifyNavigationBarScreenOn(true);
             }
-            else if (ACTION_DEMO.equals(action)) {
+        }
+    };
+
+    private BroadcastReceiver mDemoReceiver = new BroadcastReceiver() {
+        public void onReceive(Context context, Intent intent) {
+            if (DEBUG) Log.v(TAG, "onReceive: " + intent);
+            String action = intent.getAction();
+            if (ACTION_DEMO.equals(action)) {
                 Bundle bundle = intent.getExtras();
                 if (bundle != null) {
                     String command = bundle.getString("command", "").trim().toLowerCase();
@@ -2864,7 +2877,7 @@
                         }
                     }
                 }
-            } else if ("fake_artwork".equals(action)) {
+            } else if (ACTION_FAKE_ARTWORK.equals(action)) {
                 if (DEBUG_MEDIA_FAKE_ARTWORK) {
                     updateMediaMetaData(true);
                 }
@@ -2913,7 +2926,7 @@
         updateRowStates();
         mIconController.updateResources();
         mScreenPinningRequest.onConfigurationChanged();
-        mNetworkController.handleConfigurationChanged();
+        mNetworkController.onConfigurationChanged();
     }
 
     @Override
@@ -3188,6 +3201,7 @@
             mHandlerThread = null;
         }
         mContext.unregisterReceiver(mBroadcastReceiver);
+        mContext.unregisterReceiver(mDemoReceiver);
         mAssistManager.destroy();
 
         final SignalClusterView signalCluster =
@@ -3211,7 +3225,7 @@
     public void dispatchDemoCommand(String command, Bundle args) {
         if (!mDemoModeAllowed) {
             mDemoModeAllowed = Settings.Global.getInt(mContext.getContentResolver(),
-                    "sysui_demo_allowed", 0) != 0;
+                    DEMO_MODE_ALLOWED, 0) != 0;
         }
         if (!mDemoModeAllowed) return;
         if (command.equals(COMMAND_ENTER)) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
new file mode 100644
index 0000000..a1e9ece
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/SettingsButton.java
@@ -0,0 +1,174 @@
+/*
+ * 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.systemui.statusbar.phone;
+
+import android.animation.Animator;
+import android.animation.Animator.AnimatorListener;
+import android.animation.ObjectAnimator;
+import android.content.Context;
+import android.os.Handler;
+import android.os.Message;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewConfiguration;
+import android.view.animation.Animation;
+import android.view.animation.AnimationUtils;
+
+import com.android.keyguard.AlphaOptimizedImageButton;
+
+public class SettingsButton extends AlphaOptimizedImageButton {
+
+    private static final long LONG_PRESS_LENGTH = 1000;
+    private static final long ACCEL_LENGTH = 750;
+    private static final long FULL_SPEED_LENGTH = 375;
+    private static final long RUN_DURATION = 350;
+
+    private boolean mUpToSpeed;
+    private ObjectAnimator mAnimator;
+
+    private float mSlop;
+
+    public SettingsButton(Context context, AttributeSet attrs) {
+        super(context, attrs);
+        mSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
+    }
+
+    public boolean isAnimating() {
+        return mAnimator != null && mAnimator.isRunning();
+    }
+
+    public boolean isTunerClick() {
+        return mUpToSpeed;
+    }
+
+    @Override
+    public boolean onTouchEvent(MotionEvent event) {
+        switch (event.getActionMasked()) {
+            case MotionEvent.ACTION_DOWN:
+                postDelayed(mLongPressCallback, LONG_PRESS_LENGTH);
+                break;
+            case MotionEvent.ACTION_UP:
+                if (mUpToSpeed) {
+                    startExitAnimation();
+                } else {
+                    cancelLongClick();
+                }
+                break;
+            case MotionEvent.ACTION_CANCEL:
+                cancelLongClick();
+                break;
+            case MotionEvent.ACTION_MOVE:
+                float x = event.getX();
+                float y = event.getY();
+                if ((x < -mSlop) || (y < -mSlop) || (x > getWidth() + mSlop)
+                        || (y > getHeight() + mSlop)) {
+                    cancelLongClick();
+                }
+                break;
+        }
+        return super.onTouchEvent(event);
+    }
+
+    private void cancelLongClick() {
+        cancelAnimation();
+        mUpToSpeed = false;
+        removeCallbacks(mLongPressCallback);
+    }
+
+    private void cancelAnimation() {
+        if (mAnimator != null) {
+            mAnimator.removeAllListeners();
+            mAnimator.cancel();
+            mAnimator = null;
+        }
+    }
+
+    private void startExitAnimation() {
+        animate()
+                .translationX(((View) getParent().getParent()).getWidth() - getX())
+                .alpha(0)
+                .setDuration(RUN_DURATION)
+                .setInterpolator(AnimationUtils.loadInterpolator(mContext,
+                        android.R.interpolator.accelerate_cubic))
+                .setListener(new AnimatorListener() {
+                    @Override
+                    public void onAnimationStart(Animator animation) {
+                    }
+
+                    @Override
+                    public void onAnimationRepeat(Animator animation) {
+                    }
+
+                    @Override
+                    public void onAnimationEnd(Animator animation) {
+                        setAlpha(1f);
+                        setTranslationX(0);
+                        cancelLongClick();
+                    }
+
+                    @Override
+                    public void onAnimationCancel(Animator animation) {
+                    }
+                })
+                .start();
+    }
+
+    protected void startAccelSpin() {
+        cancelAnimation();
+        mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360);
+        mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.accelerate_quad));
+        mAnimator.setDuration(ACCEL_LENGTH);
+        mAnimator.addListener(new AnimatorListener() {
+            @Override
+            public void onAnimationStart(Animator animation) {
+            }
+
+            @Override
+            public void onAnimationRepeat(Animator animation) {
+            }
+
+            @Override
+            public void onAnimationEnd(Animator animation) {
+                startContinuousSpin();
+            }
+
+            @Override
+            public void onAnimationCancel(Animator animation) {
+            }
+        });
+        mAnimator.start();
+    }
+
+    protected void startContinuousSpin() {
+        cancelAnimation();
+        mUpToSpeed = true;
+        mAnimator = ObjectAnimator.ofFloat(this, View.ROTATION, 0, 360);
+        mAnimator.setInterpolator(AnimationUtils.loadInterpolator(mContext,
+                android.R.interpolator.linear));
+        mAnimator.setDuration(FULL_SPEED_LENGTH);
+        mAnimator.setRepeatCount(Animation.INFINITE);
+        mAnimator.start();
+    }
+
+    private final Runnable mLongPressCallback = new Runnable() {
+        @Override
+        public void run() {
+            startAccelSpin();
+        }
+    };
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
index a81f06e2..5d58cd0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarHeaderView.java
@@ -37,6 +37,7 @@
 import android.widget.RelativeLayout;
 import android.widget.Switch;
 import android.widget.TextView;
+import android.widget.Toast;
 
 import com.android.keyguard.KeyguardStatusView;
 import com.android.systemui.BatteryMeterView;
@@ -48,6 +49,7 @@
 import com.android.systemui.statusbar.policy.NetworkControllerImpl.EmergencyListener;
 import com.android.systemui.statusbar.policy.NextAlarmController;
 import com.android.systemui.statusbar.policy.UserInfoController;
+import com.android.systemui.tuner.TunerService;
 
 import java.text.NumberFormat;
 
@@ -73,7 +75,8 @@
     private TextView mDateExpanded;
     private LinearLayout mSystemIcons;
     private View mSignalCluster;
-    private View mSettingsButton;
+    private SettingsButton mSettingsButton;
+    private View mSettingsContainer;
     private View mQsDetailHeader;
     private TextView mQsDetailHeaderTitle;
     private Switch mQsDetailHeaderSwitch;
@@ -142,7 +145,8 @@
         mMultiUserAvatar = (ImageView) findViewById(R.id.multi_user_avatar);
         mDateCollapsed = (TextView) findViewById(R.id.date_collapsed);
         mDateExpanded = (TextView) findViewById(R.id.date_expanded);
-        mSettingsButton = findViewById(R.id.settings_button);
+        mSettingsButton = (SettingsButton) findViewById(R.id.settings_button);
+        mSettingsContainer = findViewById(R.id.settings_button_container);
         mSettingsButton.setOnClickListener(this);
         mQsDetailHeader = findViewById(R.id.qs_detail_header);
         mQsDetailHeader.setAlpha(0);
@@ -323,13 +327,15 @@
         mDateCollapsed.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
         mDateExpanded.setVisibility(mExpanded && mAlarmShowing ? View.INVISIBLE : View.VISIBLE);
         mAlarmStatus.setVisibility(mExpanded && mAlarmShowing ? View.VISIBLE : View.INVISIBLE);
-        mSettingsButton.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE);
+        mSettingsContainer.setVisibility(mExpanded ? View.VISIBLE : View.INVISIBLE);
         mQsDetailHeader.setVisibility(mExpanded && mShowingDetail? View.VISIBLE : View.INVISIBLE);
         if (mSignalCluster != null) {
             updateSignalClusterDetachment();
         }
         mEmergencyCallsOnly.setVisibility(mExpanded && mShowEmergencyCallsOnly ? VISIBLE : GONE);
         mBatteryLevel.setVisibility(mExpanded ? View.VISIBLE : View.GONE);
+        mSettingsContainer.findViewById(R.id.tuner_icon).setVisibility(
+                TunerService.isTunerEnabled(mContext) ? View.VISIBLE : View.INVISIBLE);
     }
 
     private void updateSignalClusterDetachment() {
@@ -352,7 +358,7 @@
     private void updateSystemIconsLayoutParams() {
         RelativeLayout.LayoutParams lp = (LayoutParams) mSystemIconsSuperContainer.getLayoutParams();
         int rule = mExpanded
-                ? mSettingsButton.getId()
+                ? mSettingsContainer.getId()
                 : mMultiUserSwitch.getId();
         if (rule != lp.getRules()[RelativeLayout.START_OF]) {
             lp.addRule(RelativeLayout.START_OF, rule);
@@ -495,6 +501,20 @@
     @Override
     public void onClick(View v) {
         if (v == mSettingsButton) {
+            if (mSettingsButton.isTunerClick()) {
+                if (TunerService.isTunerEnabled(mContext)) {
+                    TunerService.showResetRequest(mContext, new Runnable() {
+                        @Override
+                        public void run() {
+                            // Relaunch settings so that the tuner disappears.
+                            startSettingsActivity();
+                        }
+                    });
+                } else {
+                    Toast.makeText(getContext(), R.string.tuner_toast, Toast.LENGTH_LONG).show();
+                    TunerService.setTunerEnabled(mContext, true);
+                }
+            }
             startSettingsActivity();
         } else if (v == mSystemIconsSuperContainer) {
             startBatteryActivity();
@@ -567,10 +587,10 @@
         }
         target.batteryY = mSystemIconsSuperContainer.getTop() + mSystemIconsContainer.getTop();
         target.batteryLevelAlpha = getAlphaForVisibility(mBatteryLevel);
-        target.settingsAlpha = getAlphaForVisibility(mSettingsButton);
+        target.settingsAlpha = getAlphaForVisibility(mSettingsContainer);
         target.settingsTranslation = mExpanded
                 ? 0
-                : mMultiUserSwitch.getLeft() - mSettingsButton.getLeft();
+                : mMultiUserSwitch.getLeft() - mSettingsContainer.getLeft();
         target.signalClusterAlpha = mSignalClusterDetached ? 0f : 1f;
         target.settingsRotation = !mExpanded ? 90f : 0f;
     }
@@ -622,9 +642,11 @@
             mSignalCluster.setTranslationX(0f);
             mSignalCluster.setTranslationY(0f);
         }
-        mSettingsButton.setTranslationY(mSystemIconsSuperContainer.getTranslationY());
-        mSettingsButton.setTranslationX(values.settingsTranslation);
-        mSettingsButton.setRotation(values.settingsRotation);
+        if (!mSettingsButton.isAnimating()) {
+            mSettingsContainer.setTranslationY(mSystemIconsSuperContainer.getTranslationY());
+            mSettingsContainer.setTranslationX(values.settingsTranslation);
+            mSettingsButton.setRotation(values.settingsRotation);
+        }
         applyAlpha(mEmergencyCallsOnly, values.emergencyCallsOnlyAlpha);
         if (!mShowingDetail && !mDetailTransitioning) {
             // Otherwise it needs to stay invisible
@@ -633,7 +655,7 @@
         applyAlpha(mDateCollapsed, values.dateCollapsedAlpha);
         applyAlpha(mDateExpanded, values.dateExpandedAlpha);
         applyAlpha(mBatteryLevel, values.batteryLevelAlpha);
-        applyAlpha(mSettingsButton, values.settingsAlpha);
+        applyAlpha(mSettingsContainer, values.settingsAlpha);
         applyAlpha(mSignalCluster, values.signalClusterAlpha);
         if (!mExpanded) {
             mTime.setScaleX(1f);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
index 81f2d53..7cd94d7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/NetworkControllerImpl.java
@@ -197,7 +197,6 @@
         filter.addAction(TelephonyIntents.SPN_STRINGS_UPDATED_ACTION);
         filter.addAction(ConnectivityManager.CONNECTIVITY_ACTION);
         filter.addAction(ConnectivityManager.INET_CONDITION_ACTION);
-        filter.addAction(Intent.ACTION_CONFIGURATION_CHANGED);
         filter.addAction(Intent.ACTION_AIRPLANE_MODE_CHANGED);
         mContext.registerReceiver(this, filter, null, mReceiverHandler);
         mListening = true;
@@ -339,8 +338,6 @@
         if (action.equals(ConnectivityManager.CONNECTIVITY_ACTION) ||
                 action.equals(ConnectivityManager.INET_CONDITION_ACTION)) {
             updateConnectivity();
-        } else if (action.equals(Intent.ACTION_CONFIGURATION_CHANGED)) {
-            handleConfigurationChanged();
         } else if (action.equals(Intent.ACTION_AIRPLANE_MODE_CHANGED)) {
             refreshLocale();
             updateAirplaneMode(false);
@@ -373,8 +370,18 @@
         }
     }
 
-    public void handleConfigurationChanged() {
+    public void onConfigurationChanged() {
         mConfig = Config.readConfig(mContext);
+        mReceiverHandler.post(new Runnable() {
+            @Override
+            public void run() {
+                handleConfigurationChanged();
+            }
+        });
+    }
+
+    @VisibleForTesting
+    void handleConfigurationChanged() {
         for (MobileSignalController mobileSignalController : mMobileSignalControllers.values()) {
             mobileSignalController.setConfiguration(mConfig);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
index 3f5ca58..a2b062c 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/DemoModeFragment.java
@@ -28,13 +28,14 @@
 import android.preference.PreferenceScreen;
 import android.preference.SwitchPreference;
 import android.provider.Settings;
+import android.view.MenuItem;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.DemoMode;
 import com.android.systemui.R;
 
 public class DemoModeFragment extends PreferenceFragment implements OnPreferenceChangeListener {
 
-    private static final String DEMO_MODE_ALLOWED = "sysui_demo_allowed";
     private static final String DEMO_MODE_ON = "sysui_tuner_demo_on";
 
     private static final String[] STATUS_ICONS = {
@@ -75,10 +76,33 @@
         updateDemoModeEnabled();
         updateDemoModeOn();
         ContentResolver contentResolver = getContext().getContentResolver();
-        contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ALLOWED), false,
-                mDemoModeObserver);
+        contentResolver.registerContentObserver(Settings.Global.getUriFor(
+                DemoMode.DEMO_MODE_ALLOWED), false, mDemoModeObserver);
         contentResolver.registerContentObserver(Settings.Global.getUriFor(DEMO_MODE_ON), false,
                 mDemoModeObserver);
+        setHasOptionsMenu(true);
+    }
+
+    @Override
+    public boolean onOptionsItemSelected(MenuItem item) {
+        switch (item.getItemId()) {
+            case android.R.id.home:
+                getFragmentManager().popBackStack();
+                break;
+        }
+        return super.onOptionsItemSelected(item);
+    }
+
+    @Override
+    public void onResume() {
+        super.onResume();
+        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, true);
+    }
+
+    @Override
+    public void onPause() {
+        super.onPause();
+        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_DEMO_MODE, false);
     }
 
     @Override
@@ -89,7 +113,7 @@
 
     private void updateDemoModeEnabled() {
         boolean enabled = Settings.Global.getInt(getContext().getContentResolver(),
-                DEMO_MODE_ALLOWED, 0) != 0;
+                DemoMode.DEMO_MODE_ALLOWED, 0) != 0;
         mEnabledSwitch.setChecked(enabled);
         mOnSwitch.setEnabled(enabled);
     }
@@ -102,15 +126,18 @@
 
     @Override
     public boolean onPreferenceChange(Preference preference, Object newValue) {
+        boolean enabled = newValue == Boolean.TRUE;
         if (preference == mEnabledSwitch) {
-            if (newValue != Boolean.TRUE) {
+            if (!enabled) {
                 // Make sure we aren't in demo mode when disabling it.
                 mOnSwitch.setChecked(false);
                 stopDemoMode();
             }
-            setGlobal(DEMO_MODE_ALLOWED, newValue == Boolean.TRUE ? 1 : 0);
+            MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ENABLED, enabled);
+            setGlobal(DemoMode.DEMO_MODE_ALLOWED, enabled ? 1 : 0);
         } else if (preference == mOnSwitch) {
-            if (newValue == Boolean.TRUE) {
+            MetricsLogger.action(getContext(), MetricsLogger.TUNER_DEMO_MODE_ON, enabled);
+            if (enabled) {
                 startDemoMode();
             } else {
                 stopDemoMode();
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
index a5b244e..37ac098 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/QsTuner.java
@@ -40,6 +40,7 @@
 import android.widget.FrameLayout;
 import android.widget.ScrollView;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.qs.QSPanel;
 import com.android.systemui.qs.QSTile;
@@ -79,12 +80,25 @@
         menu.add(0, MENU_RESET, 0, com.android.internal.R.string.reset);
     }
 
+    public void onResume() {
+        super.onResume();
+        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_QS, true);
+    }
+
+    public void onPause() {
+        super.onPause();
+        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER_QS, false);
+    }
+
     @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case MENU_RESET:
                 mTileHost.reset();
                 break;
+            case android.R.id.home:
+                getFragmentManager().popBackStack();
+                break;
         }
         return super.onOptionsItemSelected(item);
     }
@@ -205,6 +219,8 @@
             if (oldTile.equals(newTile)) {
                 return;
             }
+            MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REORDER, oldTile + ","
+                    + newTile);
             List<String> order = new ArrayList<>(mTileSpecs);
             int index = order.indexOf(oldTile);
             if (index < 0) {
@@ -217,12 +233,14 @@
         }
 
         public void remove(String tile) {
+            MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_REMOVE, tile);
             List<String> tiles = new ArrayList<>(mTileSpecs);
             tiles.remove(tile);
             setTiles(tiles);
         }
 
         public void add(String tile) {
+            MetricsLogger.action(getContext(), MetricsLogger.TUNER_QS_ADD, tile);
             List<String> tiles = new ArrayList<>(mTileSpecs);
             tiles.add(tile);
             setTiles(tiles);
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
index d4cc56d..e5b550e 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/StatusBarSwitch.java
@@ -23,6 +23,7 @@
 import android.text.TextUtils;
 import android.util.AttributeSet;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService.Tunable;
 
@@ -50,11 +51,14 @@
         if (!value) {
             // If not enabled add to blacklist.
             if (!mBlacklist.contains(getKey())) {
+                MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_DISABLE,
+                        getKey());
                 mBlacklist.add(getKey());
                 setList(mBlacklist);
             }
         } else {
             if (mBlacklist.remove(getKey())) {
+                MetricsLogger.action(getContext(), MetricsLogger.TUNER_STATUS_BAR_ENABLE, getKey());
                 setList(mBlacklist);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
index 4a8c2e4..71b5de5 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerFragment.java
@@ -17,7 +17,10 @@
 
 import static com.android.systemui.BatteryMeterView.SHOW_PERCENT_SETTING;
 
+import android.app.AlertDialog;
 import android.app.FragmentTransaction;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Bundle;
@@ -28,19 +31,29 @@
 import android.preference.PreferenceFragment;
 import android.preference.PreferenceGroup;
 import android.preference.SwitchPreference;
+import android.provider.Settings;
 import android.provider.Settings.System;
+import android.view.Menu;
+import android.view.MenuInflater;
 import android.view.MenuItem;
 
+import com.android.internal.logging.MetricsLogger;
 import com.android.systemui.R;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.tuner.TunerService.Tunable;
 
 public class TunerFragment extends PreferenceFragment {
 
+    private static final String TAG = "TunerFragment";
+
     private static final String KEY_QS_TUNER = "qs_tuner";
     private static final String KEY_DEMO_MODE = "demo_mode";
     private static final String KEY_BATTERY_PCT = "battery_pct";
 
+    public static final String SETTING_SEEN_TUNER_WARNING = "seen_tuner_warning";
+
+    private static final int MENU_REMOVE = Menu.FIRST + 1;
+
     private final SettingObserver mSettingObserver = new SettingObserver();
 
     private SwitchPreference mBatteryPct;
@@ -73,6 +86,19 @@
             }
         });
         mBatteryPct = (SwitchPreference) findPreference(KEY_BATTERY_PCT);
+        if (Settings.Secure.getInt(getContext().getContentResolver(), SETTING_SEEN_TUNER_WARNING,
+                0) == 0) {
+            new AlertDialog.Builder(getContext())
+                    .setTitle(R.string.tuner_warning_title)
+                    .setMessage(R.string.tuner_warning)
+                    .setPositiveButton(R.string.got_it, new OnClickListener() {
+                        @Override
+                        public void onClick(DialogInterface dialog, int which) {
+                            Settings.Secure.putInt(getContext().getContentResolver(),
+                                    SETTING_SEEN_TUNER_WARNING, 1);
+                        }
+                    }).show();
+        }
     }
 
     @Override
@@ -83,6 +109,7 @@
                 System.getUriFor(SHOW_PERCENT_SETTING), false, mSettingObserver);
 
         registerPrefs(getPreferenceScreen());
+        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, true);
     }
 
     @Override
@@ -91,6 +118,7 @@
         getContext().getContentResolver().unregisterContentObserver(mSettingObserver);
 
         unregisterPrefs(getPreferenceScreen());
+        MetricsLogger.visibility(getContext(), MetricsLogger.TUNER, false);
     }
 
     private void registerPrefs(PreferenceGroup group) {
@@ -120,11 +148,24 @@
     }
 
     @Override
+    public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
+        menu.add(Menu.NONE, MENU_REMOVE, Menu.NONE, R.string.remove_from_settings);
+    }
+
+    @Override
     public boolean onOptionsItemSelected(MenuItem item) {
         switch (item.getItemId()) {
             case android.R.id.home:
                 getActivity().finish();
                 return true;
+            case MENU_REMOVE:
+                TunerService.showResetRequest(getContext(), new Runnable() {
+                    @Override
+                    public void run() {
+                        getActivity().finish();
+                    }
+                });
+                return true;
         }
         return super.onOptionsItemSelected(item);
     }
@@ -152,6 +193,7 @@
         @Override
         public boolean onPreferenceChange(Preference preference, Object newValue) {
             final boolean v = (Boolean) newValue;
+            MetricsLogger.action(getContext(), MetricsLogger.TUNER_BATTERY_PERCENTAGE, v);
             System.putInt(getContext().getContentResolver(), SHOW_PERCENT_SETTING, v ? 1 : 0);
             return true;
         }
diff --git a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
index de5aaf6..d3f33ab 100644
--- a/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
+++ b/packages/SystemUI/src/com/android/systemui/tuner/TunerService.java
@@ -16,8 +16,15 @@
 package com.android.systemui.tuner;
 
 import android.app.ActivityManager;
+import android.app.AlertDialog;
+import android.content.BroadcastReceiver;
+import android.content.ComponentName;
 import android.content.ContentResolver;
 import android.content.Context;
+import android.content.DialogInterface;
+import android.content.DialogInterface.OnClickListener;
+import android.content.Intent;
+import android.content.pm.PackageManager;
 import android.database.ContentObserver;
 import android.net.Uri;
 import android.os.Handler;
@@ -25,9 +32,13 @@
 import android.provider.Settings;
 import android.util.ArrayMap;
 
+import com.android.systemui.BatteryMeterView;
+import com.android.systemui.DemoMode;
+import com.android.systemui.R;
 import com.android.systemui.SystemUI;
 import com.android.systemui.SystemUIApplication;
 import com.android.systemui.settings.CurrentUserTracker;
+import com.android.systemui.statusbar.phone.SystemUIDialog;
 
 import java.util.ArrayList;
 import java.util.HashMap;
@@ -36,6 +47,8 @@
 
 public class TunerService extends SystemUI {
 
+    public static final String ACTION_CLEAR = "com.android.systemui.action.CLEAR_TUNER";
+
     private final Observer mObserver = new Observer();
     // Map of Uris we listen on to their settings keys.
     private final ArrayMap<Uri, String> mListeningUris = new ArrayMap<>();
@@ -118,6 +131,19 @@
         }
     }
 
+    public void clearAll() {
+        // A couple special cases.
+        Settings.Global.putString(mContentResolver, DemoMode.DEMO_MODE_ALLOWED, null);
+        Settings.System.putString(mContentResolver, BatteryMeterView.SHOW_PERCENT_SETTING, null);
+        Intent intent = new Intent(DemoMode.ACTION_DEMO);
+        intent.putExtra(DemoMode.EXTRA_COMMAND, DemoMode.COMMAND_EXIT);
+        mContext.sendBroadcast(intent);
+
+        for (String key : mTunableLookup.keySet()) {
+            Settings.Secure.putString(mContentResolver, key, null);
+        }
+    }
+
     // Only used in other processes, such as the tuner.
     private static TunerService sInstance;
 
@@ -141,6 +167,44 @@
         return sInstance;
     }
 
+    public static final void showResetRequest(final Context context, final Runnable onDisabled) {
+        SystemUIDialog dialog = new SystemUIDialog(context);
+        dialog.setMessage(R.string.remove_from_settings_prompt);
+        dialog.setButton(DialogInterface.BUTTON_NEGATIVE, context.getString(R.string.cancel),
+                (OnClickListener) null);
+        dialog.setButton(DialogInterface.BUTTON_POSITIVE,
+                context.getString(R.string.guest_exit_guest_dialog_remove), new OnClickListener() {
+            @Override
+            public void onClick(DialogInterface dialog, int which) {
+                // Tell the tuner (in main SysUI process) to clear all its settings.
+                context.sendBroadcast(new Intent(TunerService.ACTION_CLEAR));
+                // Disable access to tuner.
+                TunerService.setTunerEnabled(context, false);
+                // Make them sit through the warning dialog again.
+                Settings.Secure.putInt(context.getContentResolver(),
+                        TunerFragment.SETTING_SEEN_TUNER_WARNING, 0);
+                if (onDisabled != null) {
+                    onDisabled.run();
+                }
+            }
+        });
+        dialog.show();
+    }
+
+    public static final void setTunerEnabled(Context context, boolean enabled) {
+        context.getPackageManager().setComponentEnabledSetting(
+                new ComponentName(context, TunerActivity.class),
+                enabled ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
+                        : PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
+                        PackageManager.DONT_KILL_APP);
+    }
+
+    public static final boolean isTunerEnabled(Context context) {
+        return context.getPackageManager().getComponentEnabledSetting(
+                new ComponentName(context, TunerActivity.class))
+                == PackageManager.COMPONENT_ENABLED_STATE_ENABLED;
+    }
+
     private class Observer extends ContentObserver {
         public Observer() {
             super(new Handler(Looper.getMainLooper()));
@@ -157,4 +221,13 @@
     public interface Tunable {
         void onTuningChanged(String key, String newValue);
     }
+
+    public static class ClearReceiver extends BroadcastReceiver {
+        @Override
+        public void onReceive(Context context, Intent intent) {
+            if (ACTION_CLEAR.equals(intent.getAction())) {
+                get(context).clearAll();
+            }
+        }
+    }
 }
diff --git a/services/core/java/com/android/server/AssetAtlasService.java b/services/core/java/com/android/server/AssetAtlasService.java
index ebc810f..4569dae 100644
--- a/services/core/java/com/android/server/AssetAtlasService.java
+++ b/services/core/java/com/android/server/AssetAtlasService.java
@@ -93,7 +93,7 @@
     // Defines the number of int fields used to represent a single entry
     // in the atlas map. This number defines the size of the array returned
     // by the getMap(). See the mAtlasMap field for more information
-    private static final int ATLAS_MAP_ENTRY_FIELD_COUNT = 4;
+    private static final int ATLAS_MAP_ENTRY_FIELD_COUNT = 3;
 
     // Specifies how our GraphicBuffer will be used. To get proper swizzling
     // the buffer will be written to using OpenGL (from JNI) so we can leave
diff --git a/services/core/java/com/android/server/DeviceIdleController.java b/services/core/java/com/android/server/DeviceIdleController.java
index c7c9d29..7561c7d 100644
--- a/services/core/java/com/android/server/DeviceIdleController.java
+++ b/services/core/java/com/android/server/DeviceIdleController.java
@@ -253,6 +253,8 @@
                 "max_temp_app_whitelist_duration";
         private static final String KEY_MMS_TEMP_APP_WHITELIST_DURATION =
                 "mms_temp_app_whitelist_duration";
+        private static final String KEY_SMS_TEMP_APP_WHITELIST_DURATION =
+                "sms_temp_app_whitelist_duration";
 
         /**
          * This is the time, after becoming inactive, at which we start looking at the
@@ -357,6 +359,13 @@
          */
         public long MMS_TEMP_APP_WHITELIST_DURATION;
 
+        /**
+         * Amount of time we would like to whitelist an app that is receiving an SMS.
+         * @see Settings.Global#DEVICE_IDLE_CONSTANTS
+         * @see #KEY_SMS_TEMP_APP_WHITELIST_DURATION
+         */
+        public long SMS_TEMP_APP_WHITELIST_DURATION;
+
         private final ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
 
@@ -410,6 +419,8 @@
                         KEY_MAX_TEMP_APP_WHITELIST_DURATION, 5 * 60 * 1000L);
                 MMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
                         KEY_MMS_TEMP_APP_WHITELIST_DURATION, 60 * 1000L);
+                SMS_TEMP_APP_WHITELIST_DURATION = mParser.getLong(
+                        KEY_SMS_TEMP_APP_WHITELIST_DURATION, 20 * 1000L);
             }
         }
 
@@ -465,6 +476,10 @@
             pw.print("    "); pw.print(KEY_MMS_TEMP_APP_WHITELIST_DURATION); pw.print("=");
             TimeUtils.formatDuration(MMS_TEMP_APP_WHITELIST_DURATION, pw);
             pw.println();
+
+            pw.print("    "); pw.print(KEY_SMS_TEMP_APP_WHITELIST_DURATION); pw.print("=");
+            TimeUtils.formatDuration(SMS_TEMP_APP_WHITELIST_DURATION, pw);
+            pw.println();
         }
     }
 
@@ -617,6 +632,13 @@
             return duration;
         }
 
+        @Override public long addPowerSaveTempWhitelistAppForSms(String packageName,
+                int userId, String reason) throws RemoteException {
+            long duration = mConstants.SMS_TEMP_APP_WHITELIST_DURATION;
+            addPowerSaveTempWhitelistApp(packageName, duration, userId, reason);
+            return duration;
+        }
+
         @Override public void exitIdle(String reason) {
             getContext().enforceCallingOrSelfPermission(android.Manifest.permission.DEVICE_POWER,
                     null);
diff --git a/services/core/java/com/android/server/MountService.java b/services/core/java/com/android/server/MountService.java
index 92b98a7..ed136e9 100644
--- a/services/core/java/com/android/server/MountService.java
+++ b/services/core/java/com/android/server/MountService.java
@@ -3431,6 +3431,11 @@
         }
 
         public boolean hasExternalStorage(int uid, String packageName) {
+            // No need to check for system uid. This avoids a deadlock between
+            // PackageManagerService and AppOpsService.
+            if (uid == Process.SYSTEM_UID) {
+                return true;
+            }
             // No locking - CopyOnWriteArrayList
             for (ExternalStorageMountPolicy policy : mPolicies) {
                 final boolean policyHasStorage = policy.hasExternalStorage(uid, packageName);
diff --git a/services/core/java/com/android/server/accounts/AccountManagerService.java b/services/core/java/com/android/server/accounts/AccountManagerService.java
index cb294fd..32fd56a 100644
--- a/services/core/java/com/android/server/accounts/AccountManagerService.java
+++ b/services/core/java/com/android/server/accounts/AccountManagerService.java
@@ -3799,7 +3799,8 @@
          * access accounts of the specified account.
          */
         boolean isPermitted =
-                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS);
+                isPermitted(callingUid, Manifest.permission.GET_ACCOUNTS,
+                        Manifest.permission.GET_ACCOUNTS_PRIVILEGED);
         boolean isAccountManagedByCaller = isAccountManagedByCaller(accountType, callingUid);
         Log.w(TAG, String.format(
                 "isReadAccountPermitted: isPermitted: %s, isAM: %s",
diff --git a/services/core/java/com/android/server/am/ActivityStack.java b/services/core/java/com/android/server/am/ActivityStack.java
index e57e3ff..a75cc48 100644
--- a/services/core/java/com/android/server/am/ActivityStack.java
+++ b/services/core/java/com/android/server/am/ActivityStack.java
@@ -617,12 +617,9 @@
             for (int activityNdx = activities.size() - 1; activityNdx >= 0; --activityNdx) {
                 ActivityRecord r = activities.get(activityNdx);
                 if (notCurrentUserTask && (r.info.flags & FLAG_SHOW_FOR_ALL_USERS) == 0) {
-                    return null;
+                    continue;
                 }
                 if (!r.finishing && r.intent.getComponent().equals(cls) && r.userId == userId) {
-                    //Slog.i(TAG, "Found matching class!");
-                    //dump();
-                    //Slog.i(TAG, "For Intent " + intent + " bringing to top: " + r.intent);
                     return r;
                 }
             }
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index f34fff7..c705fbf 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -123,20 +123,29 @@
     public void binderDied() {
         Slog.v(TAG, "fingerprintd died");
         mDaemon = null;
+        dispatchError(mHalDeviceId, FingerprintManager.FINGERPRINT_ERROR_HW_UNAVAILABLE);
     }
 
     public IFingerprintDaemon getFingerprintDaemon() {
         if (mDaemon == null) {
             mDaemon = IFingerprintDaemon.Stub.asInterface(ServiceManager.getService(FINGERPRINTD));
-            if (mDaemon == null) {
-                Slog.w(TAG, "fingerprind service not available");
-            } else {
+            if (mDaemon != null) {
                 try {
                     mDaemon.asBinder().linkToDeath(this, 0);
-                }   catch (RemoteException e) {
-                    Slog.w(TAG, "caught remote exception in linkToDeath: ", e);
-                    mDaemon = null; // try again!
+                    mDaemon.init(mDaemonCallback);
+                    mHalDeviceId = mDaemon.openHal();
+                    if (mHalDeviceId != 0) {
+                        updateActiveGroup(ActivityManager.getCurrentUser());
+                    } else {
+                        Slog.w(TAG, "Failed to open Fingerprint HAL!");
+                        mDaemon = null;
+                    }
+                } catch (RemoteException e) {
+                    Slog.e(TAG, "Failed to open fingeprintd HAL", e);
+                    mDaemon = null; // try again later!
                 }
+            } else {
+                Slog.w(TAG, "fingerprint service not available");
             }
         }
         return mDaemon;
@@ -155,7 +164,6 @@
     protected void dispatchRemoved(long deviceId, int fingerId, int groupId) {
         final ClientMonitor client = mRemoveClient;
         if (fingerId != 0) {
-            ContentResolver res = mContext.getContentResolver();
             removeTemplateForUser(mRemoveClient, fingerId);
         }
         if (client != null && client.sendRemoved(fingerId, groupId)) {
@@ -813,15 +821,6 @@
     public void onStart() {
         publishBinderService(Context.FINGERPRINT_SERVICE, new FingerprintServiceWrapper());
         IFingerprintDaemon daemon = getFingerprintDaemon();
-        if (daemon != null) {
-            try {
-                daemon.init(mDaemonCallback);
-                mHalDeviceId = daemon.openHal();
-            	updateActiveGroup(ActivityManager.getCurrentUser());
-            } catch (RemoteException e) {
-                Slog.e(TAG, "Failed to open fingeprintd HAL", e);
-            }
-        }
         if (DEBUG) Slog.v(TAG, "Fingerprint HAL id: " + mHalDeviceId);
         listenForUserSwitches();
     }
diff --git a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
index f04790e..0d1d1ea 100644
--- a/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
+++ b/services/core/java/com/android/server/pm/DefaultPermissionGrantPolicy.java
@@ -495,6 +495,16 @@
                 }
             }
 
+            // Voice recognition
+            Intent voiceRecoIntent = new Intent("android.speech.RecognitionService");
+            voiceRecoIntent.addCategory(Intent.CATEGORY_DEFAULT);
+            PackageParser.Package voiceRecoPackage = getDefaultSystemHandlerServicePackageLPr(
+                    voiceRecoIntent, userId);
+            if (voiceRecoPackage != null
+                    && doesPackageSupportRuntimePermissions(voiceRecoPackage)) {
+                grantRuntimePermissionsLPw(voiceRecoPackage, MICROPHONE_PERMISSIONS, userId);
+            }
+
             // Location
             if (locationPackageNames != null) {
                 for (String packageName : locationPackageNames) {
@@ -627,6 +637,26 @@
         return null;
     }
 
+    private PackageParser.Package getDefaultSystemHandlerServicePackageLPr(
+            Intent intent, int userId) {
+        List<ResolveInfo> handlers = mService.queryIntentServices(intent,
+                intent.resolveType(mService.mContext.getContentResolver()),
+                PackageManager.GET_DISABLED_COMPONENTS, userId);
+        if (handlers == null) {
+            return null;
+        }
+        final int handlerCount = handlers.size();
+        for (int i = 0; i < handlerCount; i++) {
+            ResolveInfo handler = handlers.get(i);
+            PackageParser.Package handlerPackage = getSystemPackageLPr(
+                    handler.serviceInfo.packageName);
+            if (handlerPackage != null) {
+                return handlerPackage;
+            }
+        }
+        return null;
+    }
+
     private List<PackageParser.Package> getHeadlessSyncAdapterPackagesLPr(
             String[] syncAdapterPackageNames, int userId) {
         List<PackageParser.Package> syncAdapterPackages = new ArrayList<>();
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c139389..0b74996 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -7321,6 +7321,9 @@
             for (i=0; i<N; i++) {
                 PackageParser.Permission p = pkg.permissions.get(i);
 
+                // Assume by default that we did not install this permission into the system.
+                p.info.flags &= ~PermissionInfo.FLAG_INSTALLED;
+
                 // Now that permission groups have a special meaning, we ignore permission
                 // groups for legacy apps to prevent unexpected behavior. In particular,
                 // permissions for one app being granted to someone just becuase they happen
@@ -7350,6 +7353,7 @@
                             bp.perm = p;
                             bp.uid = pkg.applicationInfo.uid;
                             bp.sourcePackage = p.info.packageName;
+                            p.info.flags |= PermissionInfo.FLAG_INSTALLED;
                         } else if (!currentOwnerIsSystem) {
                             String msg = "New decl " + p.owner + " of permission  "
                                     + p.info.name + " is system; overriding " + bp.sourcePackage;
@@ -7375,6 +7379,7 @@
                             bp.perm = p;
                             bp.uid = pkg.applicationInfo.uid;
                             bp.sourcePackage = p.info.packageName;
+                            p.info.flags |= PermissionInfo.FLAG_INSTALLED;
                             if ((parseFlags&PackageParser.PARSE_CHATTY) != 0) {
                                 if (r == null) {
                                     r = new StringBuilder(256);
@@ -14688,12 +14693,12 @@
                 pw.println("    s[hared-users]: dump shared user IDs");
                 pw.println("    m[essages]: print collected runtime messages");
                 pw.println("    v[erifiers]: print package verifier info");
-                pw.println("    version: print database version info");
-                pw.println("    write: write current settings now");
-                pw.println("    <package.name>: info about given package");
-                pw.println("    installs: details about install sessions");
                 pw.println("    d[omain-preferred-apps]: print domains preferred apps");
                 pw.println("    i[ntent-filter-verifiers]|ifv: print intent filter verifier info");
+                pw.println("    version: print database version info");
+                pw.println("    write: write current settings now");
+                pw.println("    installs: details about install sessions");
+                pw.println("    <package.name>: info about given package");
                 return;
             } else if ("--checkin".equals(opt)) {
                 checkin = true;
@@ -15600,12 +15605,8 @@
      * recycled.
      */
     private void reconcileUsers(String volumeUuid) {
-        final File[] files = Environment.getDataUserDirectory(volumeUuid).listFiles();
-        if (ArrayUtils.isEmpty(files)) {
-            Slog.d(TAG, "No users found on " + volumeUuid);
-            return;
-        }
-
+        final File[] files = FileUtils
+                .listFilesOrEmpty(Environment.getDataUserDirectory(volumeUuid));
         for (File file : files) {
             if (!file.isDirectory()) continue;
 
@@ -15661,12 +15662,8 @@
      * another volume.
      */
     private void reconcileApps(String volumeUuid) {
-        final File[] files = Environment.getDataAppDirectory(volumeUuid).listFiles();
-        if (ArrayUtils.isEmpty(files)) {
-            Slog.d(TAG, "No apps found on " + volumeUuid);
-            return;
-        }
-
+        final File[] files = FileUtils
+                .listFilesOrEmpty(Environment.getDataAppDirectory(volumeUuid));
         for (File file : files) {
             final boolean isPackage = (isApkFile(file) || file.isDirectory())
                     && !PackageInstallerService.isStageName(file.getName());
@@ -15797,7 +15794,12 @@
         }
 
         // Now that we're guarded by frozen state, kill app during move
-        killApplication(packageName, appId, "move pkg");
+        final long token = Binder.clearCallingIdentity();
+        try {
+            killApplication(packageName, appId, "move pkg");
+        } finally {
+            Binder.restoreCallingIdentity(token);
+        }
 
         final Bundle extras = new Bundle();
         extras.putString(Intent.EXTRA_PACKAGE_NAME, packageName);
diff --git a/services/core/java/com/android/server/pm/Settings.java b/services/core/java/com/android/server/pm/Settings.java
index 92b9da6..736b153 100644
--- a/services/core/java/com/android/server/pm/Settings.java
+++ b/services/core/java/com/android/server/pm/Settings.java
@@ -4120,6 +4120,28 @@
         pw.print(prefix); pw.print("  pkgFlags="); printFlags(pw, ps.pkgFlags, FLAG_DUMP_SPEC);
                 pw.println();
 
+        if (ps.pkg != null && ps.pkg.permissions != null && ps.pkg.permissions.size() > 0) {
+            final ArrayList<PackageParser.Permission> perms = ps.pkg.permissions;
+            pw.print(prefix); pw.println("  declared permissions:");
+            for (int i=0; i<perms.size(); i++) {
+                PackageParser.Permission perm = perms.get(i);
+                if (permissionNames != null
+                        && !permissionNames.contains(perm.info.name)) {
+                    continue;
+                }
+                pw.print(prefix); pw.print("    "); pw.print(perm.info.name);
+                pw.print(": prot=");
+                pw.print(PermissionInfo.protectionToString(perm.info.protectionLevel));
+                if ((perm.info.flags&PermissionInfo.FLAG_COSTS_MONEY) != 0) {
+                    pw.print(", COSTS_MONEY");
+                }
+                if ((perm.info.flags&PermissionInfo.FLAG_INSTALLED) != 0) {
+                    pw.print(", INSTALLED");
+                }
+                pw.println();
+            }
+        }
+
         if (ps.sharedUser == null || permissionNames != null) {
             PermissionsState permissionsState = ps.getPermissionsState();
             dumpInstallPermissionsLPr(pw, prefix + "  ", permissionNames, permissionsState);
@@ -4155,14 +4177,14 @@
                 if (cmp != null && cmp.size() > 0) {
                     pw.print(prefix); pw.println("    disabledComponents:");
                     for (String s : cmp) {
-                        pw.print(prefix); pw.print("    "); pw.println(s);
+                        pw.print(prefix); pw.print("      "); pw.println(s);
                     }
                 }
                 cmp = ps.getEnabledComponents(user.id);
                 if (cmp != null && cmp.size() > 0) {
                     pw.print(prefix); pw.println("    enabledComponents:");
                     for (String s : cmp) {
-                        pw.print(prefix); pw.print("    "); pw.println(s);
+                        pw.print(prefix); pw.print("      "); pw.println(s);
                     }
                 }
             }
@@ -4267,11 +4289,14 @@
                     pw.print(" type="); pw.print(p.type);
                     pw.print(" prot=");
                     pw.println(PermissionInfo.protectionToString(p.protectionLevel));
-            if (p.packageSetting != null) {
-                pw.print("    packageSetting="); pw.println(p.packageSetting);
-            }
             if (p.perm != null) {
                 pw.print("    perm="); pw.println(p.perm);
+                if (p.perm.info.flags != PermissionInfo.FLAG_INSTALLED) {
+                    pw.print("    flags=0x"); pw.println(Integer.toHexString(p.perm.info.flags));
+                }
+            }
+            if (p.packageSetting != null) {
+                pw.print("    packageSetting="); pw.println(p.packageSetting);
             }
             if (READ_EXTERNAL_STORAGE.equals(p.name)) {
                 pw.print("    enforced=");
@@ -4372,24 +4397,32 @@
                     continue;
                 }
                 pw.print(prefix); pw.print("  "); pw.print(permissionState.getName());
-                pw.print(", granted="); pw.print(permissionState.isGranted());
-                    pw.print(", flags="); pw.println(permissionFlagsToString(
-                        permissionState.getFlags()));
+                pw.print(": granted="); pw.print(permissionState.isGranted());
+                    pw.println(permissionFlagsToString(", flags=",
+                            permissionState.getFlags()));
             }
         }
     }
 
-    private static String permissionFlagsToString(int flags) {
-        StringBuilder flagsString = new StringBuilder();
-        flagsString.append("[ ");
+    private static String permissionFlagsToString(String prefix, int flags) {
+        StringBuilder flagsString = null;
         while (flags != 0) {
+            if (flagsString == null) {
+                flagsString = new StringBuilder();
+                flagsString.append(prefix);
+                flagsString.append("[ ");
+            }
             final int flag = 1 << Integer.numberOfTrailingZeros(flags);
             flags &= ~flag;
             flagsString.append(PackageManager.permissionFlagToString(flag));
             flagsString.append(' ');
         }
-        flagsString.append(']');
-        return flagsString.toString();
+        if (flagsString != null) {
+            flagsString.append(']');
+            return flagsString.toString();
+        } else {
+            return "";
+        }
     }
 
     void dumpInstallPermissionsLPr(PrintWriter pw, String prefix, ArraySet<String> permissionNames,
@@ -4403,8 +4436,8 @@
                     continue;
                 }
                 pw.print(prefix); pw.print("  "); pw.print(permissionState.getName());
-                    pw.print(", granted="); pw.print(permissionState.isGranted());
-                    pw.print(", flags="); pw.println(permissionFlagsToString(
+                    pw.print(": granted="); pw.print(permissionState.isGranted());
+                    pw.println(permissionFlagsToString(", flags=",
                         permissionState.getFlags()));
             }
         }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 4f2b1f9..d9828cc 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -10029,70 +10029,70 @@
                                         WindowManagerPolicy.FINISH_LAYOUT_REDO_LAYOUT;
                                 if (DEBUG_LAYOUT_REPEATS) {
                                     debugLayoutRepeats(
-                                        "dream and commitFinishDrawingLocked true",
-                                        displayContent.pendingLayoutChanges);
+                                            "dream and commitFinishDrawingLocked true",
+                                            displayContent.pendingLayoutChanges);
                                 }
                             }
                             if ((w.mAttrs.flags & FLAG_SHOW_WALLPAPER) != 0) {
                                 if (DEBUG_WALLPAPER_LIGHT) Slog.v(TAG,
-                                        "First draw done in potential wallpaper target " + w);
+                                            "First draw done in potential wallpaper target " + w);
                                 mInnerFields.mWallpaperMayChange = true;
                                 displayContent.pendingLayoutChanges |=
                                         WindowManagerPolicy.FINISH_LAYOUT_REDO_WALLPAPER;
                                 if (DEBUG_LAYOUT_REPEATS) {
                                     debugLayoutRepeats(
-                                        "wallpaper and commitFinishDrawingLocked true",
-                                        displayContent.pendingLayoutChanges);
+                                            "wallpaper and commitFinishDrawingLocked true",
+                                            displayContent.pendingLayoutChanges);
                                 }
                             }
                         }
 
                         winAnimator.setSurfaceBoundariesLocked(recoveringMemory);
+                    }
 
-                        final AppWindowToken atoken = w.mAppToken;
-                        if (DEBUG_STARTING_WINDOW && atoken != null
-                                && w == atoken.startingWindow) {
-                            Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
-                                + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
-                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
+                    final AppWindowToken atoken = w.mAppToken;
+                    if (DEBUG_STARTING_WINDOW && atoken != null
+                            && w == atoken.startingWindow) {
+                        Slog.d(TAG, "updateWindows: starting " + w + " isOnScreen="
+                            + w.isOnScreen() + " allDrawn=" + atoken.allDrawn
+                            + " freezingScreen=" + atoken.mAppAnimator.freezingScreen);
+                    }
+                    if (atoken != null
+                            && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
+                        if (atoken.lastTransactionSequence != mTransactionSequence) {
+                            atoken.lastTransactionSequence = mTransactionSequence;
+                            atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
+                            atoken.startingDisplayed = false;
                         }
-                        if (atoken != null
-                                && (!atoken.allDrawn || atoken.mAppAnimator.freezingScreen)) {
-                            if (atoken.lastTransactionSequence != mTransactionSequence) {
-                                atoken.lastTransactionSequence = mTransactionSequence;
-                                atoken.numInterestingWindows = atoken.numDrawnWindows = 0;
-                                atoken.startingDisplayed = false;
+                        if ((w.isOnScreenIgnoringKeyguard()
+                                || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
+                                && !w.mExiting && !w.mDestroying) {
+                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
+                                Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
+                                        + ", isAnimating=" + winAnimator.isAnimating());
+                                if (!w.isDrawnLw()) {
+                                    Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
+                                            + " pv=" + w.mPolicyVisibility
+                                            + " mDrawState=" + winAnimator.drawStateToString()
+                                            + " ah=" + w.mAttachedHidden
+                                            + " th=" + atoken.hiddenRequested
+                                            + " a=" + winAnimator.mAnimating);
+                                }
                             }
-                            if ((w.isOnScreenIgnoringKeyguard()
-                                    || winAnimator.mAttrType == TYPE_BASE_APPLICATION)
-                                    && !w.mExiting && !w.mDestroying) {
-                                if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) {
-                                    Slog.v(TAG, "Eval win " + w + ": isDrawn=" + w.isDrawnLw()
-                                            + ", isAnimating=" + winAnimator.isAnimating());
-                                    if (!w.isDrawnLw()) {
-                                        Slog.v(TAG, "Not displayed: s=" + winAnimator.mSurfaceControl
-                                                + " pv=" + w.mPolicyVisibility
-                                                + " mDrawState=" + winAnimator.drawStateToString()
-                                                + " ah=" + w.mAttachedHidden
-                                                + " th=" + atoken.hiddenRequested
-                                                + " a=" + winAnimator.mAnimating);
+                            if (w != atoken.startingWindow) {
+                                if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
+                                    atoken.numInterestingWindows++;
+                                    if (w.isDrawnLw()) {
+                                        atoken.numDrawnWindows++;
+                                        if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
+                                                "tokenMayBeDrawn: " + atoken
+                                                + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
+                                                + " mAppFreezing=" + w.mAppFreezing);
+                                        updateAllDrawn = true;
                                     }
                                 }
-                                if (w != atoken.startingWindow) {
-                                    if (!atoken.mAppAnimator.freezingScreen || !w.mAppFreezing) {
-                                        atoken.numInterestingWindows++;
-                                        if (w.isDrawnLw()) {
-                                            atoken.numDrawnWindows++;
-                                            if (DEBUG_VISIBILITY || DEBUG_ORIENTATION) Slog.v(TAG,
-                                                    "tokenMayBeDrawn: " + atoken
-                                                    + " freezingScreen=" + atoken.mAppAnimator.freezingScreen
-                                                    + " mAppFreezing=" + w.mAppFreezing);
-                                            updateAllDrawn = true;
-                                        }
-                                    }
-                                } else if (w.isDrawnLw()) {
-                                    atoken.startingDisplayed = true;
-                                }
+                            } else if (w.isDrawnLw()) {
+                                atoken.startingDisplayed = true;
                             }
                         }
                     }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
index 4498b84..f8ae03f 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsDatabase.java
@@ -21,6 +21,7 @@
 import android.os.Build;
 import android.util.AtomicFile;
 import android.util.Slog;
+import android.util.TimeUtils;
 
 import java.io.BufferedReader;
 import java.io.BufferedWriter;
@@ -191,7 +192,11 @@
 
                 for (File f : files) {
                     final AtomicFile af = new AtomicFile(f);
-                    mSortedStatFiles[i].put(UsageStatsXml.parseBeginTime(af), af);
+                    try {
+                        mSortedStatFiles[i].put(UsageStatsXml.parseBeginTime(af), af);
+                    } catch (IOException e) {
+                        Slog.e(TAG, "failed to index file: " + f, e);
+                    }
                 }
             }
         }
@@ -273,14 +278,21 @@
 
     public void onTimeChanged(long timeDiffMillis) {
         synchronized (mLock) {
+            StringBuilder logBuilder = new StringBuilder();
+            logBuilder.append("Time changed by ");
+            TimeUtils.formatDuration(timeDiffMillis, logBuilder);
+            logBuilder.append(".");
+
+            int filesDeleted = 0;
+            int filesMoved = 0;
+
             for (TimeSparseArray<AtomicFile> files : mSortedStatFiles) {
                 final int fileCount = files.size();
                 for (int i = 0; i < fileCount; i++) {
                     final AtomicFile file = files.valueAt(i);
                     final long newTime = files.keyAt(i) + timeDiffMillis;
                     if (newTime < 0) {
-                        Slog.i(TAG, "Deleting file " + file.getBaseFile().getAbsolutePath()
-                                + " for it is in the future now.");
+                        filesDeleted++;
                         file.delete();
                     } else {
                         try {
@@ -295,14 +307,17 @@
                         }
 
                         final File newFile = new File(file.getBaseFile().getParentFile(), newName);
-                        Slog.i(TAG, "Moving file " + file.getBaseFile().getAbsolutePath() + " to "
-                                + newFile.getAbsolutePath());
+                        filesMoved++;
                         file.getBaseFile().renameTo(newFile);
                     }
                 }
                 files.clear();
             }
 
+            logBuilder.append(" files deleted: ").append(filesDeleted);
+            logBuilder.append(" files moved: ").append(filesMoved);
+            Slog.i(TAG, logBuilder.toString());
+
             // Now re-index the new files.
             indexFilesLocked();
         }
@@ -506,7 +521,14 @@
                 if (path.endsWith(BAK_SUFFIX)) {
                     f = new File(path.substring(0, path.length() - BAK_SUFFIX.length()));
                 }
-                long beginTime = UsageStatsXml.parseBeginTime(f);
+
+                long beginTime;
+                try {
+                    beginTime = UsageStatsXml.parseBeginTime(f);
+                } catch (IOException e) {
+                    beginTime = 0;
+                }
+
                 if (beginTime < expiryTime) {
                     new AtomicFile(f).delete();
                 }
diff --git a/services/usage/java/com/android/server/usage/UsageStatsXml.java b/services/usage/java/com/android/server/usage/UsageStatsXml.java
index 186813e..543f361 100644
--- a/services/usage/java/com/android/server/usage/UsageStatsXml.java
+++ b/services/usage/java/com/android/server/usage/UsageStatsXml.java
@@ -33,11 +33,11 @@
     private static final String VERSION_ATTR = "version";
     static final String CHECKED_IN_SUFFIX = "-c";
 
-    public static long parseBeginTime(AtomicFile file) {
+    public static long parseBeginTime(AtomicFile file) throws IOException {
         return parseBeginTime(file.getBaseFile());
     }
 
-    public static long parseBeginTime(File file) {
+    public static long parseBeginTime(File file) throws IOException {
         String name = file.getName();
 
         // Eat as many occurrences of -c as possible. This is due to a bug where -c
@@ -47,7 +47,12 @@
         while (name.endsWith(CHECKED_IN_SUFFIX)) {
             name = name.substring(0, name.length() - CHECKED_IN_SUFFIX.length());
         }
-        return Long.parseLong(name);
+
+        try {
+            return Long.parseLong(name);
+        } catch (NumberFormatException e) {
+            throw new IOException(e);
+        }
     }
 
     public static void read(AtomicFile file, IntervalStats statsOut) throws IOException {
diff --git a/services/usb/java/com/android/server/usb/UsbHostManager.java b/services/usb/java/com/android/server/usb/UsbHostManager.java
index 6300a9a..965341e 100644
--- a/services/usb/java/com/android/server/usb/UsbHostManager.java
+++ b/services/usb/java/com/android/server/usb/UsbHostManager.java
@@ -231,6 +231,8 @@
             mNewConfigurations = null;
             mNewInterfaces = null;
             mNewEndpoints = null;
+            mNewConfiguration = null;
+            mNewInterface = null;
         }
     }
 
diff --git a/telephony/java/android/telephony/CarrierConfigManager.java b/telephony/java/android/telephony/CarrierConfigManager.java
index e861668..e9c41a1 100644
--- a/telephony/java/android/telephony/CarrierConfigManager.java
+++ b/telephony/java/android/telephony/CarrierConfigManager.java
@@ -273,6 +273,14 @@
      */
     public static final String KEY_DEFAULT_SIM_CALL_MANAGER_STRING = "default_sim_call_manager_string";
 
+    /**
+     * The default flag specifying whether ETWS/CMAS test setting is forcibly disabled in
+     * Settings->More->Emergency broadcasts menu even though developer options is turned on.
+     * @hide
+     */
+    public static final String KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL =
+            "carrier_force_disable_etws_cmas_test_bool";
+
     /* The following 3 fields are related to carrier visual voicemail. */
 
     /**
@@ -381,6 +389,7 @@
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VT_AVAILABLE_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_WFC_IMS_AVAILABLE_BOOL, false);
+        sDefaults.putBoolean(KEY_CARRIER_FORCE_DISABLE_ETWS_CMAS_TEST_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_PROVISIONING_REQUIRED_BOOL, false);
         sDefaults.putBoolean(KEY_CARRIER_VOLTE_TTY_SUPPORTED_BOOL, true);
         sDefaults.putBoolean(KEY_CARRIER_ALLOW_TURNOFF_IMS_BOOL, true);
diff --git a/wifi/java/android/net/wifi/WifiManager.java b/wifi/java/android/net/wifi/WifiManager.java
index f390075..d915e5d 100644
--- a/wifi/java/android/net/wifi/WifiManager.java
+++ b/wifi/java/android/net/wifi/WifiManager.java
@@ -1302,7 +1302,7 @@
      * Return the results of the latest access point scan.
      * @return the list of access points found in the most recent scan. An app must hold
      * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_COARSE_LOCATION} or
-     * {@link android.Manifest.permission#ACCESS_COARSE_LOCATION ACCESS_FINE_LOCATION} permission
+     * {@link android.Manifest.permission#ACCESS_FINE_LOCATION ACCESS_FINE_LOCATION} permission
      * in order to get valid results.
      */
     public List<ScanResult> getScanResults() {