Merge "Import translations. DO NOT MERGE" into oc-dev
diff --git a/core/java/android/app/ActivityManager.java b/core/java/android/app/ActivityManager.java
index 9af74ba..0925217 100644
--- a/core/java/android/app/ActivityManager.java
+++ b/core/java/android/app/ActivityManager.java
@@ -126,6 +126,14 @@
 
     private static volatile boolean sSystemReady = false;
 
+
+    private static final int FIRST_START_FATAL_ERROR_CODE = -100;
+    private static final int LAST_START_FATAL_ERROR_CODE = -1;
+    private static final int FIRST_START_SUCCESS_CODE = 0;
+    private static final int LAST_START_SUCCESS_CODE = 99;
+    private static final int FIRST_START_NON_FATAL_ERROR_CODE = 100;
+    private static final int LAST_START_NON_FATAL_ERROR_CODE = 199;
+
     /**
      * System property to enable task snapshots.
      * @hide
@@ -219,53 +227,56 @@
      */
     public static final String META_HOME_ALTERNATE = "android.app.home.alternate";
 
+    // NOTE: Before adding a new start result, please reference the defined ranges to ensure the
+    // result is properly categorized.
+
     /**
      * Result for IActivityManager.startVoiceActivity: active session is currently hidden.
      * @hide
      */
-    public static final int START_VOICE_HIDDEN_SESSION = -10;
+    public static final int START_VOICE_HIDDEN_SESSION = FIRST_START_FATAL_ERROR_CODE;
 
     /**
      * Result for IActivityManager.startVoiceActivity: active session does not match
      * the requesting token.
      * @hide
      */
-    public static final int START_VOICE_NOT_ACTIVE_SESSION = -9;
+    public static final int START_VOICE_NOT_ACTIVE_SESSION = FIRST_START_FATAL_ERROR_CODE + 1;
 
     /**
      * Result for IActivityManager.startActivity: trying to start a background user
      * activity that shouldn't be displayed for all users.
      * @hide
      */
-    public static final int START_NOT_CURRENT_USER_ACTIVITY = -8;
+    public static final int START_NOT_CURRENT_USER_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 2;
 
     /**
      * Result for IActivityManager.startActivity: trying to start an activity under voice
      * control when that activity does not support the VOICE category.
      * @hide
      */
-    public static final int START_NOT_VOICE_COMPATIBLE = -7;
+    public static final int START_NOT_VOICE_COMPATIBLE = FIRST_START_FATAL_ERROR_CODE + 3;
 
     /**
      * Result for IActivityManager.startActivity: an error where the
      * start had to be canceled.
      * @hide
      */
-    public static final int START_CANCELED = -6;
+    public static final int START_CANCELED = FIRST_START_FATAL_ERROR_CODE + 4;
 
     /**
      * Result for IActivityManager.startActivity: an error where the
      * thing being started is not an activity.
      * @hide
      */
-    public static final int START_NOT_ACTIVITY = -5;
+    public static final int START_NOT_ACTIVITY = FIRST_START_FATAL_ERROR_CODE + 5;
 
     /**
      * Result for IActivityManager.startActivity: an error where the
      * caller does not have permission to start the activity.
      * @hide
      */
-    public static final int START_PERMISSION_DENIED = -4;
+    public static final int START_PERMISSION_DENIED = FIRST_START_FATAL_ERROR_CODE + 6;
 
     /**
      * Result for IActivityManager.startActivity: an error where the
@@ -273,49 +284,49 @@
      * a result.
      * @hide
      */
-    public static final int START_FORWARD_AND_REQUEST_CONFLICT = -3;
+    public static final int START_FORWARD_AND_REQUEST_CONFLICT = FIRST_START_FATAL_ERROR_CODE + 7;
 
     /**
      * Result for IActivityManager.startActivity: an error where the
      * requested class is not found.
      * @hide
      */
-    public static final int START_CLASS_NOT_FOUND = -2;
+    public static final int START_CLASS_NOT_FOUND = FIRST_START_FATAL_ERROR_CODE + 8;
 
     /**
      * Result for IActivityManager.startActivity: an error where the
      * given Intent could not be resolved to an activity.
      * @hide
      */
-    public static final int START_INTENT_NOT_RESOLVED = -1;
+    public static final int START_INTENT_NOT_RESOLVED = FIRST_START_FATAL_ERROR_CODE + 9;
 
     /**
      * Result for IActivityManaqer.startActivity: the activity was started
      * successfully as normal.
      * @hide
      */
-    public static final int START_SUCCESS = 0;
+    public static final int START_SUCCESS = FIRST_START_SUCCESS_CODE;
 
     /**
      * Result for IActivityManaqer.startActivity: the caller asked that the Intent not
      * be executed if it is the recipient, and that is indeed the case.
      * @hide
      */
-    public static final int START_RETURN_INTENT_TO_CALLER = 1;
+    public static final int START_RETURN_INTENT_TO_CALLER = FIRST_START_SUCCESS_CODE + 1;
 
     /**
      * Result for IActivityManaqer.startActivity: activity wasn't really started, but
      * a task was simply brought to the foreground.
      * @hide
      */
-    public static final int START_TASK_TO_FRONT = 2;
+    public static final int START_TASK_TO_FRONT = FIRST_START_SUCCESS_CODE + 2;
 
     /**
      * Result for IActivityManaqer.startActivity: activity wasn't really started, but
      * the given Intent was given to the existing top activity.
      * @hide
      */
-    public static final int START_DELIVERED_TO_TOP = 3;
+    public static final int START_DELIVERED_TO_TOP = FIRST_START_SUCCESS_CODE + 3;
 
     /**
      * Result for IActivityManaqer.startActivity: request was canceled because
@@ -323,14 +334,15 @@
      * (such as pressing home) is performed.
      * @hide
      */
-    public static final int START_SWITCHES_CANCELED = 4;
+    public static final int START_SWITCHES_CANCELED = FIRST_START_NON_FATAL_ERROR_CODE;
 
     /**
      * Result for IActivityManaqer.startActivity: a new activity was attempted to be started
      * while in Lock Task Mode.
      * @hide
      */
-    public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION = 5;
+    public static final int START_RETURN_LOCK_TASK_MODE_VIOLATION =
+            FIRST_START_NON_FATAL_ERROR_CODE + 1;
 
     /**
      * Flag for IActivityManaqer.startActivity: do special start mode where
@@ -566,6 +578,22 @@
     }
 
     /**
+     * Returns whether the launch was successful.
+     * @hide
+     */
+    public static final boolean isStartResultSuccessful(int result) {
+        return FIRST_START_SUCCESS_CODE <= result && result <= LAST_START_SUCCESS_CODE;
+    }
+
+    /**
+     * Returns whether the launch result was a fatal error.
+     * @hide
+     */
+    public static final boolean isStartResultFatalError(int result) {
+        return FIRST_START_FATAL_ERROR_CODE <= result && result <= LAST_START_FATAL_ERROR_CODE;
+    }
+
+    /**
      * Screen compatibility mode: the application most always run in
      * compatibility mode.
      * @hide
diff --git a/core/java/android/app/Instrumentation.java b/core/java/android/app/Instrumentation.java
index 69ed439..16cbb7c 100644
--- a/core/java/android/app/Instrumentation.java
+++ b/core/java/android/app/Instrumentation.java
@@ -1921,7 +1921,7 @@
 
     /** @hide */
     public static void checkStartActivityResult(int res, Object intent) {
-        if (res >= ActivityManager.START_SUCCESS) {
+        if (!ActivityManager.isStartResultFatalError(res)) {
             return;
         }
 
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index ccbd5b4..8a15b1f 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -16,6 +16,8 @@
 
 package android.app;
 
+import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
+
 import android.annotation.ColorInt;
 import android.annotation.DrawableRes;
 import android.annotation.IntDef;
@@ -42,7 +44,6 @@
 import android.media.session.MediaSession;
 import android.net.Uri;
 import android.os.BadParcelableException;
-import android.os.Binder;
 import android.os.Build;
 import android.os.Bundle;
 import android.os.IBinder;
@@ -72,6 +73,7 @@
 import android.widget.RemoteViews;
 
 import com.android.internal.R;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.util.ArrayUtils;
 import com.android.internal.util.NotificationColorUtil;
 import com.android.internal.util.Preconditions;
@@ -2670,6 +2672,19 @@
         private static final boolean USE_ONLY_TITLE_IN_LOW_PRIORITY_SUMMARY =
                 SystemProperties.getBoolean("notifications.only_title", true);
 
+        /**
+         * The lightness difference that has to be added to the primary text color to obtain the
+         * secondary text color when the background is light.
+         */
+        private static final int LIGHTNESS_TEXT_DIFFERENCE_LIGHT = 20;
+
+        /**
+         * The lightness difference that has to be added to the primary text color to obtain the
+         * secondary text color when the background is dark.
+         * A bit less then the above value, since it looks better on dark backgrounds.
+         */
+        private static final int LIGHTNESS_TEXT_DIFFERENCE_DARK = -10;
+
         private Context mContext;
         private Notification mN;
         private Bundle mUserExtras = new Bundle();
@@ -3836,11 +3851,26 @@
             contentView.setTextColor(id, mPrimaryTextColor);
         }
 
-        private int getPrimaryTextColor() {
+        /**
+         * @return the primary text color
+         * @hide
+         */
+        @VisibleForTesting
+        public int getPrimaryTextColor() {
             ensureColors();
             return mPrimaryTextColor;
         }
 
+        /**
+         * @return the secondary text color
+         * @hide
+         */
+        @VisibleForTesting
+        public int getSecondaryTextColor() {
+            ensureColors();
+            return mSecondaryTextColor;
+        }
+
         private int getActionBarColor() {
             ensureColors();
             return mActionBarColor;
@@ -3880,16 +3910,21 @@
                     double textLum = NotificationColorUtil.calculateLuminance(mForegroundColor);
                     double contrast = NotificationColorUtil.calculateContrast(mForegroundColor,
                             backgroundColor);
-                    boolean textDark = backLum > textLum;
+                    // We only respect the given colors if worst case Black or White still has
+                    // contrast
+                    boolean backgroundLight = backLum > textLum
+                                    && satisfiesTextContrast(backgroundColor, Color.BLACK)
+                            || backLum <= textLum
+                                    && !satisfiesTextContrast(backgroundColor, Color.WHITE);
                     if (contrast < 4.5f) {
-                        if (textDark) {
+                        if (backgroundLight) {
                             mSecondaryTextColor = NotificationColorUtil.findContrastColor(
                                     mForegroundColor,
                                     backgroundColor,
                                     true /* findFG */,
                                     4.5f);
                             mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
-                                    mSecondaryTextColor, -20);
+                                    mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_LIGHT);
                         } else {
                             mSecondaryTextColor =
                                     NotificationColorUtil.findContrastColorAgainstDark(
@@ -3898,16 +3933,17 @@
                                     true /* findFG */,
                                     4.5f);
                             mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
-                                    mSecondaryTextColor, 10);
+                                    mSecondaryTextColor, -LIGHTNESS_TEXT_DIFFERENCE_DARK);
                         }
                     } else {
                         mPrimaryTextColor = mForegroundColor;
                         mSecondaryTextColor = NotificationColorUtil.changeColorLightness(
-                                mPrimaryTextColor, textDark ? 10 : -20);
+                                mPrimaryTextColor, backgroundLight ? LIGHTNESS_TEXT_DIFFERENCE_LIGHT
+                                        : LIGHTNESS_TEXT_DIFFERENCE_DARK);
                         if (NotificationColorUtil.calculateContrast(mSecondaryTextColor,
                                 backgroundColor) < 4.5f) {
                             // oh well the secondary is not good enough
-                            if (textDark) {
+                            if (backgroundLight) {
                                 mSecondaryTextColor = NotificationColorUtil.findContrastColor(
                                         mSecondaryTextColor,
                                         backgroundColor,
@@ -3922,7 +3958,9 @@
                                         4.5f);
                             }
                             mPrimaryTextColor = NotificationColorUtil.changeColorLightness(
-                                    mSecondaryTextColor, textDark ? -20 : 10);
+                                    mSecondaryTextColor, backgroundLight
+                                            ? -LIGHTNESS_TEXT_DIFFERENCE_LIGHT
+                                            : -LIGHTNESS_TEXT_DIFFERENCE_DARK);
                         }
                     }
                 }
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index eae9e1e..c613d97 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -862,10 +862,10 @@
                 out.writeInt(mAutofillType);
                 out.writeStringArray(mAutofillHints);
                 final AutofillValue sanitizedValue;
-                if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
-                    sanitizedValue = mAutofillOverlay.value;
-                } else if (writeSensitive) {
+                if (writeSensitive) {
                     sanitizedValue = mAutofillValue;
+                } else if (mAutofillOverlay != null && mAutofillOverlay.value != null) {
+                    sanitizedValue = mAutofillOverlay.value;
                 } else {
                     sanitizedValue = null;
                 }
@@ -1936,7 +1936,7 @@
     }
 
     /** @hide */
-    public void dump() {
+    public void dump(boolean showSensitive) {
         if (mActivityComponent == null) {
             Log.i(TAG, "dump(): calling ensureData() first");
             ensureData();
@@ -1949,11 +1949,11 @@
             WindowNode node = getWindowNodeAt(i);
             Log.i(TAG, "Window #" + i + " [" + node.getLeft() + "," + node.getTop()
                     + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getTitle());
-            dump("  ", node.getRootViewNode());
+            dump("  ", node.getRootViewNode(), showSensitive);
         }
     }
 
-    void dump(String prefix, ViewNode node) {
+    void dump(String prefix, ViewNode node, boolean showSensitive) {
         Log.i(TAG, prefix + "View [" + node.getLeft() + "," + node.getTop()
                 + " " + node.getWidth() + "x" + node.getHeight() + "]" + " " + node.getClassName());
         int id = node.getId();
@@ -1992,12 +1992,15 @@
         }
         CharSequence text = node.getText();
         if (text != null) {
+            final String safeText = node.isSanitized() || showSensitive ? text.toString()
+                    : "REDACTED[" + text.length() + " chars]";
             Log.i(TAG, prefix + "  Text (sel " + node.getTextSelectionStart() + "-"
-                    + node.getTextSelectionEnd() + "): " + text);
+                    + node.getTextSelectionEnd() + "): " + safeText);
             Log.i(TAG, prefix + "  Text size: " + node.getTextSize() + " , style: #"
                     + node.getTextStyle());
             Log.i(TAG, prefix + "  Text color fg: #" + Integer.toHexString(node.getTextColor())
                     + ", bg: #" + Integer.toHexString(node.getTextBackgroundColor()));
+            Log.i(TAG, prefix + "  Input type: " + node.getInputType());
         }
         String webDomain = node.getWebDomain();
         if (webDomain != null) {
@@ -2031,7 +2034,6 @@
             Log.i(TAG, prefix + "Autofill info: id= " + autofillId
                     + ", type=" + node.getAutofillType()
                     + ", options=" + Arrays.toString(node.getAutofillOptions())
-                    + ", inputType=" + node.getInputType()
                     + ", hints=" + Arrays.toString(node.getAutofillHints())
                     + ", value=" + node.getAutofillValue()
                     + ", sanitized=" + node.isSanitized());
@@ -2043,7 +2045,7 @@
             String cprefix = prefix + "    ";
             for (int i=0; i<NCHILDREN; i++) {
                 ViewNode cnode = node.getChildAt(i);
-                dump(cprefix, cnode);
+                dump(cprefix, cnode, showSensitive);
             }
         }
     }
diff --git a/core/java/android/app/job/JobInfo.java b/core/java/android/app/job/JobInfo.java
index 007ea88..3cb59f2 100644
--- a/core/java/android/app/job/JobInfo.java
+++ b/core/java/android/app/job/JobInfo.java
@@ -111,8 +111,11 @@
     /* Minimum flex for a periodic job, in milliseconds. */
     private static final long MIN_FLEX_MILLIS = 5 * 60 * 1000L; // 5 minutes
 
-    /* Minimum backoff interval for a job, in milliseconds */
-    private static final long MIN_BACKOFF_MILLIS = 10 * 1000L;      // 10 seconds
+    /**
+     * Minimum backoff interval for a job, in milliseconds
+     * @hide
+     */
+    public static final long MIN_BACKOFF_MILLIS = 10 * 1000L;      // 10 seconds
 
     /**
      * Query the minimum interval allowed for periodic scheduled jobs.  Attempting
@@ -431,7 +434,7 @@
     /**
      * The amount of time the JobScheduler will wait before rescheduling a failed job. This value
      * will be increased depending on the backoff policy specified at job creation time. Defaults
-     * to 5 seconds.
+     * to 30 seconds, minimum is currently 10 seconds.
      */
     public long getInitialBackoffMillis() {
         final long minBackoff = getMinBackoffMillis();
diff --git a/core/java/android/content/BroadcastReceiver.java b/core/java/android/content/BroadcastReceiver.java
index c3d6606..f907721 100644
--- a/core/java/android/content/BroadcastReceiver.java
+++ b/core/java/android/content/BroadcastReceiver.java
@@ -330,10 +330,32 @@
      * This can be called by an application in {@link #onReceive} to allow
      * it to keep the broadcast active after returning from that function.
      * This does <em>not</em> change the expectation of being relatively
-     * responsive to the broadcast (finishing it within 10s), but does allow
+     * responsive to the broadcast, but does allow
      * the implementation to move work related to it over to another thread
      * to avoid glitching the main UI thread due to disk IO.
      *
+     * <p>As a general rule, broadcast receivers are allowed to run for up to 10 seconds
+     * before they system will consider them non-responsive and ANR the app.  Since these usually
+     * execute on the app's main thread, they are already bound by the ~5 second time limit
+     * of various operations that can happen there (not to mention just avoiding UI jank), so
+     * the receive limit is generally not of concern.  However, once you use {@goAsync}, though
+     * able to be off the main thread, the broadcast execution limit still applies, and that
+     * includes the time spent between calling this method and ultimately
+     * {@link PendingResult#finish() PendingResult.finish()}.</p>
+     *
+     * <p>If you are taking advantage of this method to have more time to execute, it is useful
+     * to know that the available time can be longer in certain situations.  In particular, if
+     * the broadcast you are receiving is not a foreground broadcast (that is, the sender has not
+     * used {@link Intent#FLAG_RECEIVER_FOREGROUND}), then more time is allowed for the receivers
+     * to run, allowing them to execute for 30 seconds or even a bit more.  This is something that
+     * receivers should rarely take advantage of (long work should be punted to another system
+     * facility such as {@link android.app.job.JobScheduler}, {@link android.app.Service}, or
+     * see especially {@link android.support.v4.app.JobIntentService}), but can be useful in
+     * certain rare cases where it is necessary to do some work as soon as the broadcast is
+     * delivered.  Keep in mind that the work you do here will block further broadcasts until
+     * it completes, so taking advantage of this at all excessively can be counter-productive
+     * and cause later events to be received more slowly.</p>
+     *
      * @return Returns a {@link PendingResult} representing the result of
      * the active broadcast.  The BroadcastRecord itself is no longer active;
      * all data and other interaction must go through {@link PendingResult}
diff --git a/core/java/android/content/pm/IPackageManager.aidl b/core/java/android/content/pm/IPackageManager.aidl
index 9096e44..702b91c 100644
--- a/core/java/android/content/pm/IPackageManager.aidl
+++ b/core/java/android/content/pm/IPackageManager.aidl
@@ -623,6 +623,8 @@
 
     void deletePreloadsFileCache();
 
+    ComponentName getInstantAppResolverComponent();
+
     ComponentName getInstantAppResolverSettingsComponent();
 
     ComponentName getInstantAppInstallerComponent();
diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java
index e3e0cc5..f779aeb 100644
--- a/core/java/android/content/pm/ShortcutManager.java
+++ b/core/java/android/content/pm/ShortcutManager.java
@@ -886,6 +886,11 @@
 
     /**
      * Return the max width for icons, in pixels.
+     *
+     * <p> Note that this method returns max width of icon's visible part. Hence, it does not take
+     * into account the inset introduced by {@link AdaptiveIconDrawable}. To calculate bitmap image
+     * to function as {@link AcaptiveIconDrawable}, multiply
+     * 1 + 2 * {@link AdaptiveIconDrawable#getExtraInsetFraction()} to the returned size.
      */
     public int getIconMaxWidth() {
         try {
diff --git a/core/java/android/hardware/fingerprint/FingerprintManager.java b/core/java/android/hardware/fingerprint/FingerprintManager.java
index fccc877..8e57e85 100644
--- a/core/java/android/hardware/fingerprint/FingerprintManager.java
+++ b/core/java/android/hardware/fingerprint/FingerprintManager.java
@@ -118,6 +118,15 @@
      * @hide
      */
     public static final int FINGERPRINT_ERROR_VENDOR = 8;
+
+    /**
+     * The operation was canceled because FINGERPRINT_ERROR_LOCKOUT occurred too many times.
+     * Fingerprint authentication is disabled until the user unlocks with strong authentication
+     * (PIN/Pattern/Password)
+     * @hide
+     */
+    public static final int FINGERPRINT_ERROR_LOCKOUT_PERMANENT = 9;
+
     /**
      * @hide
      */
@@ -871,9 +880,11 @@
                 case MSG_REMOVED:
                     sendRemovedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
                             msg.arg2 /* groupId */);
+                    break;
                 case MSG_ENUMERATED:
                     sendEnumeratedResult((Long) msg.obj /* deviceId */, msg.arg1 /* fingerId */,
                             msg.arg2 /* groupId */);
+                    break;
             }
         }
 
@@ -1013,6 +1024,9 @@
                 return mContext.getString(com.android.internal.R.string.fingerprint_error_canceled);
             case FINGERPRINT_ERROR_LOCKOUT:
                 return mContext.getString(com.android.internal.R.string.fingerprint_error_lockout);
+            case FINGERPRINT_ERROR_LOCKOUT_PERMANENT:
+                return mContext.getString(
+                        com.android.internal.R.string.fingerprint_error_lockout_permanent);
             case FINGERPRINT_ERROR_VENDOR: {
                     String[] msgArray = mContext.getResources().getStringArray(
                             com.android.internal.R.array.fingerprint_error_vendor);
diff --git a/core/java/android/os/UserManager.java b/core/java/android/os/UserManager.java
index f2df7da..7bd3bf6 100644
--- a/core/java/android/os/UserManager.java
+++ b/core/java/android/os/UserManager.java
@@ -19,6 +19,7 @@
 import android.Manifest;
 import android.accounts.AccountManager;
 import android.annotation.IntDef;
+import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.RequiresPermission;
 import android.annotation.SystemApi;
@@ -2129,7 +2130,7 @@
      * @return the list of users that were created.
      * @hide
      */
-    public List<UserInfo> getUsers(boolean excludeDying) {
+    public @NonNull List<UserInfo> getUsers(boolean excludeDying) {
         try {
             return mService.getUsers(excludeDying);
         } catch (RemoteException re) {
diff --git a/core/java/android/view/LayoutInflater.java b/core/java/android/view/LayoutInflater.java
index 0e06cd3..f987e4e 100644
--- a/core/java/android/view/LayoutInflater.java
+++ b/core/java/android/view/LayoutInflater.java
@@ -639,6 +639,11 @@
                 }
             }
 
+            Object lastContext = mConstructorArgs[0];
+            if (mConstructorArgs[0] == null) {
+                // Fill in the context if not already within inflation.
+                mConstructorArgs[0] = mContext;
+            }
             Object[] args = mConstructorArgs;
             args[1] = attrs;
 
@@ -648,6 +653,7 @@
                 final ViewStub viewStub = (ViewStub) view;
                 viewStub.setLayoutInflater(cloneInContext((Context) args[0]));
             }
+            mConstructorArgs[0] = lastContext;
             return view;
 
         } catch (NoSuchMethodException e) {
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index 02ac9bd..d3d753b 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -2770,6 +2770,7 @@
      *         1                         PFLAG3_HAS_OVERLAPPING_RENDERING_FORCED
      *        1                          PFLAG3_TEMPORARY_DETACH
      *       1                           PFLAG3_NO_REVEAL_ON_FOCUS
+     *      1                            PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT
      * |-------|-------|-------|-------|
      */
 
@@ -2858,14 +2859,6 @@
      */
     static final int PFLAG3_SCROLL_INDICATOR_END = 0x2000;
 
-    /**
-     * Flag indicating that when layout is completed we should notify
-     * that the view was entered for autofill purposes. To minimize
-     * showing autofill for views not visible to the user we evaluate
-     * user visibility which cannot be done until the view is laid out.
-     */
-    static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x4000;
-
     static final int DRAG_MASK = PFLAG2_DRAG_CAN_ACCEPT | PFLAG2_DRAG_HOVERED;
 
     static final int SCROLL_INDICATORS_NONE = 0x0000;
@@ -3050,6 +3043,14 @@
      */
     private static final int PFLAG3_NO_REVEAL_ON_FOCUS = 0x4000000;
 
+    /**
+     * Flag indicating that when layout is completed we should notify
+     * that the view was entered for autofill purposes. To minimize
+     * showing autofill for views not visible to the user we evaluate
+     * user visibility which cannot be done until the view is laid out.
+     */
+    static final int PFLAG3_NOTIFY_AUTOFILL_ENTER_ON_LAYOUT = 0x8000000;
+
     /* End of masks for mPrivateFlags3 */
 
     /**
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 68c74da..39ac399 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -804,9 +804,26 @@
                     + ", value=" + value + ", action=" + action + ", flags=" + flags);
         }
 
+        boolean restartIfNecessary = (flags & FLAG_MANUAL_REQUEST) != 0;
+
         try {
-            mService.updateSession(mSessionId, id, bounds, value, action, flags,
-                    mContext.getUserId());
+            if (restartIfNecessary) {
+                final int newId = mService.updateOrRestartSession(mContext.getActivityToken(),
+                        mServiceClient.asBinder(), id, bounds, value, mContext.getUserId(),
+                        mCallback != null, flags, mContext.getOpPackageName(), mSessionId, action);
+                if (newId != mSessionId) {
+                    if (sDebug) Log.d(TAG, "Session restarted: " + mSessionId + "=>" + newId);
+                    mSessionId = newId;
+                    final AutofillClient client = getClientLocked();
+                    if (client != null) {
+                        client.autofillCallbackResetableStateAvailable();
+                    }
+                }
+            } else {
+                mService.updateSession(mSessionId, id, bounds, value, action, flags,
+                        mContext.getUserId());
+            }
+
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/view/autofill/IAutoFillManager.aidl b/core/java/android/view/autofill/IAutoFillManager.aidl
index a12e956..627afa7 100644
--- a/core/java/android/view/autofill/IAutoFillManager.aidl
+++ b/core/java/android/view/autofill/IAutoFillManager.aidl
@@ -39,6 +39,9 @@
     boolean restoreSession(int sessionId, in IBinder activityToken, in IBinder appCallback);
     void updateSession(int sessionId, in AutofillId id, in Rect bounds,
             in AutofillValue value, int action, int flags, int userId);
+    int updateOrRestartSession(IBinder activityToken, in IBinder appCallback,
+            in AutofillId autoFillId, in Rect bounds, in AutofillValue value, int userId,
+            boolean hasCallback, int flags, String packageName, int sessionId, int action);
     void finishSession(int sessionId, int userId);
     void cancelSession(int sessionId, int userId);
     void setAuthenticationResult(in Bundle data, int sessionId, int authenticationId, int userId);
diff --git a/core/java/android/view/textclassifier/TextClassifierImpl.java b/core/java/android/view/textclassifier/TextClassifierImpl.java
index 5f72fc7..290d811 100644
--- a/core/java/android/view/textclassifier/TextClassifierImpl.java
+++ b/core/java/android/view/textclassifier/TextClassifierImpl.java
@@ -624,8 +624,14 @@
                     return new Intent(Intent.ACTION_VIEW)
                             .setData(Uri.parse(String.format("geo:0,0?q=%s", text)));
                 case TextClassifier.TYPE_URL:
-                    if (!text.startsWith("https://") && !text.startsWith("http://")) {
-                        text = "http://" + text;
+                    final String httpPrefix = "http://";
+                    final String httpsPrefix = "https://";
+                    if (text.toLowerCase().startsWith(httpPrefix)) {
+                        text = httpPrefix + text.substring(httpPrefix.length());
+                    } else if (text.toLowerCase().startsWith(httpsPrefix)) {
+                        text = httpsPrefix + text.substring(httpsPrefix.length());
+                    } else {
+                        text = httpPrefix + text;
                     }
                     return new Intent(Intent.ACTION_VIEW, Uri.parse(text))
                             .putExtra(Browser.EXTRA_APPLICATION_ID, context.getPackageName());
diff --git a/core/java/android/widget/Editor.java b/core/java/android/widget/Editor.java
index bb658c1..1fef7cb 100644
--- a/core/java/android/widget/Editor.java
+++ b/core/java/android/widget/Editor.java
@@ -2016,7 +2016,7 @@
     /**
      * Asynchronously invalidates an action mode using the TextClassifier.
      */
-    private void invalidateActionModeAsync() {
+    void invalidateActionModeAsync() {
         getSelectionActionModeHelper().invalidateActionModeAsync();
     }
 
diff --git a/core/java/android/widget/PopupWindow.java b/core/java/android/widget/PopupWindow.java
index 59fb02d..8464c6e 100644
--- a/core/java/android/widget/PopupWindow.java
+++ b/core/java/android/widget/PopupWindow.java
@@ -1667,32 +1667,17 @@
             int anchorHeight, int drawingLocationY, int screenLocationY, int displayFrameTop,
             int displayFrameBottom, boolean allowResize) {
         final int winOffsetY = screenLocationY - drawingLocationY;
-        final int popupScreenTop = outParams.y + winOffsetY;
-        final int spaceBelow = displayFrameBottom - popupScreenTop;
-        if (popupScreenTop >= 0 && height <= spaceBelow) {
+        final int anchorTopInScreen = outParams.y + winOffsetY;
+        final int spaceBelow = displayFrameBottom - anchorTopInScreen;
+        if (anchorTopInScreen >= 0 && height <= spaceBelow) {
             return true;
         }
 
-        final int popupScreenBottom;
-        if (mOverlapAnchor) {
-            // popupScreenTop equals the anchor's top at this point.
-            // When shown above the anchor, an overlapping popup's bottom should be aligned with
-            // the anchor's bottom.
-            popupScreenBottom = popupScreenTop + anchorHeight;
-        } else {
-            // popupScreenTop equals the anchor's bottom at this point.
-            // When shown above the anchor, a non-overlapping popup's bottom is aligned with
-            // the anchor's top.
-            popupScreenBottom = popupScreenTop - anchorHeight;
-        }
-        final int spaceAbove = popupScreenBottom - displayFrameTop;
+        final int spaceAbove = anchorTopInScreen - anchorHeight - displayFrameTop;
         if (height <= spaceAbove) {
             // Move everything up.
             if (mOverlapAnchor) {
-                // Add one anchorHeight to compensate for the correction made at the start of
-                // findDropDownPosition, and another to account for being aligned to the anchor's
-                // bottom, not top.
-                yOffset += anchorHeight * 2;
+                yOffset += anchorHeight;
             }
             outParams.y = drawingLocationY - height + yOffset;
 
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 89182b0..3d54fe7 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -400,6 +400,7 @@
                 CharSequence text, int selectionStart, int selectionEnd, LocaleList locales) {
             mTextClassifier = Preconditions.checkNotNull(textClassifier);
             mText = Preconditions.checkNotNull(text).toString();
+            mLastClassificationText = null; // invalidate.
             Preconditions.checkArgument(selectionEnd > selectionStart);
             mSelectionStart = selectionStart;
             mSelectionEnd = selectionEnd;
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 1f54c84..77f27d9 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -1639,12 +1639,21 @@
         boolean canInputOrMove = (mMovement != null || getKeyListener() != null);
         boolean clickable = canInputOrMove || isClickable();
         boolean longClickable = canInputOrMove || isLongClickable();
+        int focusable = getFocusable();
 
         n = a.getIndexCount();
         for (int i = 0; i < n; i++) {
             int attr = a.getIndex(i);
 
             switch (attr) {
+                case com.android.internal.R.styleable.View_focusable:
+                    TypedValue val = new TypedValue();
+                    if (a.getValue(attr, val)) {
+                        focusable = (val.type == TypedValue.TYPE_INT_BOOLEAN)
+                                ? (val.data == 0 ? NOT_FOCUSABLE : FOCUSABLE)
+                                : val.data;
+                    }
+
                 case com.android.internal.R.styleable.View_clickable:
                     clickable = a.getBoolean(attr, clickable);
                     break;
@@ -1656,6 +1665,13 @@
         }
         a.recycle();
 
+        // Some apps were relying on the undefined behavior of focusable winning over
+        // focusableInTouchMode != focusable in TextViews if both were specified in XML (usually
+        // when starting with EditText and setting only focusable=false). To keep those apps from
+        // breaking, re-apply the focusable attribute here.
+        if (focusable != getFocusable()) {
+            setFocusable(focusable);
+        }
         setClickable(clickable);
         setLongClickable(longClickable);
 
@@ -10756,7 +10772,11 @@
 
         switch (id) {
             case ID_SELECT_ALL:
+                final boolean hadSelection = hasSelection();
                 selectAllText();
+                if (mEditor != null && hadSelection) {
+                    mEditor.invalidateActionModeAsync();
+                }
                 return true;
 
             case ID_UNDO:
diff --git a/core/java/com/android/internal/util/NotificationColorUtil.java b/core/java/com/android/internal/util/NotificationColorUtil.java
index cd41f9e..1ba92bf 100644
--- a/core/java/com/android/internal/util/NotificationColorUtil.java
+++ b/core/java/com/android/internal/util/NotificationColorUtil.java
@@ -533,6 +533,10 @@
         return ColorUtilsFromCompat.calculateContrast(foregroundColor, backgroundColor);
     }
 
+    public static boolean satisfiesTextContrast(int backgroundColor, int foregroundColor) {
+        return NotificationColorUtil.calculateContrast(backgroundColor, foregroundColor) >= 4.5;
+    }
+
     /**
      * Composite two potentially translucent colors over each other and returns the result.
      */
@@ -540,6 +544,10 @@
         return ColorUtilsFromCompat.compositeColors(foreground, background);
     }
 
+    public static boolean isColorLight(int backgroundColor) {
+        return calculateLuminance(backgroundColor) > 0.5f;
+    }
+
     /**
      * Framework copy of functions needed from android.support.v4.graphics.ColorUtils.
      */
diff --git a/core/jni/android/graphics/Shader.cpp b/core/jni/android/graphics/Shader.cpp
index 214d97c..b529e37 100644
--- a/core/jni/android/graphics/Shader.cpp
+++ b/core/jni/android/graphics/Shader.cpp
@@ -60,14 +60,17 @@
 static jlong BitmapShader_constructor(JNIEnv* env, jobject o, jlong matrixPtr, jobject jbitmap,
         jint tileModeX, jint tileModeY) {
     const SkMatrix* matrix = reinterpret_cast<const SkMatrix*>(matrixPtr);
-    SkBitmap bitmap;
+    sk_sp<SkImage> image;
     if (jbitmap) {
         // Only pass a valid SkBitmap object to the constructor if the Bitmap exists. Otherwise,
         // we'll pass an empty SkBitmap to avoid crashing/excepting for compatibility.
-        android::bitmap::toBitmap(env, jbitmap).getSkBitmapForShaders(&bitmap);
+        image = android::bitmap::toBitmap(env, jbitmap).makeImage(nullptr);
     }
 
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+    if (!image.get()) {
+        SkBitmap bitmap;
+        image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
+    }
     sk_sp<SkShader> baseShader = image->makeShader(
             (SkShader::TileMode)tileModeX, (SkShader::TileMode)tileModeY);
 
diff --git a/core/proto/android/service/fingerprint.proto b/core/proto/android/service/fingerprint.proto
index 79dba86..f88b762 100644
--- a/core/proto/android/service/fingerprint.proto
+++ b/core/proto/android/service/fingerprint.proto
@@ -54,4 +54,7 @@
 
     // Total number of lockouts.
     int32 lockout = 4;
+
+    // Total number of permanent lockouts.
+    int32 lockout_permanent = 5;
 }
diff --git a/core/res/res/layout/time_picker_text_input_material.xml b/core/res/res/layout/time_picker_text_input_material.xml
index 76ce826..2bef027 100644
--- a/core/res/res/layout/time_picker_text_input_material.xml
+++ b/core/res/res/layout/time_picker_text_input_material.xml
@@ -37,7 +37,8 @@
             android:layout_width="50dp"
             android:layout_height="wrap_content"
             android:inputType="number"
-            android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField" />
+            android:textAppearance="@style/TextAppearance.Material.TimePicker.InputField"
+            android:imeOptions="actionNext"/>
         <TextView
             android:id="@+id/label_hour"
             android:layout_width="wrap_content"
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index 98356a2..f747d3d 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1335,6 +1335,8 @@
     <string name="fingerprint_error_canceled">Fingerprint operation canceled.</string>
     <!-- Generic error message shown when the fingerprint operation fails because too many attempts have been made. -->
     <string name="fingerprint_error_lockout">Too many attempts. Try again later.</string>
+    <!-- Generic error message shown when the fingerprint operation fails because strong authentication is required -->
+    <string name="fingerprint_error_lockout_permanent">Too many attempts. Fingerprint sensor disabled.</string>
     <!-- Generic error message shown when the fingerprint hardware can't recognize the fingerprint -->
     <string name="fingerprint_error_unable_to_process">Try again.</string>
 
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index 74779f3..6e3f0e0 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -2281,6 +2281,7 @@
   <java-symbol type="array" name="fingerprint_acquired_vendor" />
   <java-symbol type="string" name="fingerprint_error_canceled" />
   <java-symbol type="string" name="fingerprint_error_lockout" />
+  <java-symbol type="string" name="fingerprint_error_lockout_permanent" />
   <java-symbol type="string" name="fingerprint_name_template" />
 
   <!-- Fingerprint config -->
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
new file mode 100644
index 0000000..ac1ac19
--- /dev/null
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright (C) 2017 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package android.app;
+
+import static com.android.internal.util.NotificationColorUtil.satisfiesTextContrast;
+
+import static org.junit.Assert.assertTrue;
+
+import android.content.Context;
+import android.media.session.MediaSession;
+import android.support.test.InstrumentationRegistry;
+import android.support.test.filters.SmallTest;
+import android.support.test.runner.AndroidJUnit4;
+
+import com.android.internal.util.NotificationColorUtil;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@SmallTest
+public class NotificationTest {
+
+    private Context mContext;
+
+    @Before
+    public void setUp() {
+        mContext = InstrumentationRegistry.getContext();
+    }
+
+    @Test
+    public void testColorSatisfiedWhenBgDarkTextDarker() {
+        Notification.Builder builder = getMediaNotification();
+        builder.build();
+
+        // An initial guess where the foreground color is actually darker than an already dark bg
+        int backgroundColor = 0xff585868;
+        int initialForegroundColor = 0xff505868;
+        builder.setColorPalette(backgroundColor, initialForegroundColor);
+        int primaryTextColor = builder.getPrimaryTextColor();
+        assertTrue(satisfiesTextContrast(primaryTextColor, backgroundColor));
+        int secondaryTextColor = builder.getSecondaryTextColor();
+        assertTrue(satisfiesTextContrast(secondaryTextColor, backgroundColor));
+    }
+
+    private Notification.Builder getMediaNotification() {
+        MediaSession session = new MediaSession(mContext, "test");
+        return new Notification.Builder(mContext, "color")
+                .setSmallIcon(com.android.internal.R.drawable.emergency_icon)
+                .setContentTitle("Title")
+                .setContentText("Text")
+                .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
+    }
+}
diff --git a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
index 7b7031b..29447ed 100644
--- a/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
+++ b/core/tests/coretests/src/android/view/textclassifier/TextClassificationManagerTest.java
@@ -124,19 +124,40 @@
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
         assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
-                isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+                isTextClassification(
+                        classifiedText,
+                        TextClassifier.TYPE_EMAIL,
+                        "mailto:" + classifiedText));
     }
 
     @Test
     public void testTextClassifyText_url() {
         if (isTextClassifierDisabled()) return;
 
-        String text = "Visit http://www.android.com for more information";
+        String text = "Visit www.android.com for more information";
         String classifiedText = "www.android.com";
         int startIndex = text.indexOf(classifiedText);
         int endIndex = startIndex + classifiedText.length();
         assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
-                isTextClassification(classifiedText, TextClassifier.TYPE_URL));
+                isTextClassification(
+                        classifiedText,
+                        TextClassifier.TYPE_URL,
+                        "http://" + classifiedText));
+    }
+
+    @Test
+    public void testTextClassifyText_url_inCaps() {
+        if (isTextClassifierDisabled()) return;
+
+        String text = "Visit HTTP://ANDROID.COM for more information";
+        String classifiedText = "HTTP://ANDROID.COM";
+        int startIndex = text.indexOf(classifiedText);
+        int endIndex = startIndex + classifiedText.length();
+        assertThat(mClassifier.classifyText(text, startIndex, endIndex, LOCALES),
+                isTextClassification(
+                        classifiedText,
+                        TextClassifier.TYPE_URL,
+                        "http://ANDROID.COM"));
     }
 
     @Test
@@ -149,7 +170,10 @@
         int endIndex = startIndex + classifiedText.length();
         LocaleList nullLocales = null;
         assertThat(mClassifier.classifyText(text, startIndex, endIndex, nullLocales),
-                isTextClassification(classifiedText, TextClassifier.TYPE_EMAIL));
+                isTextClassification(
+                        classifiedText,
+                        TextClassifier.TYPE_EMAIL,
+                        "mailto:" + classifiedText));
     }
 
     @Test
@@ -206,18 +230,23 @@
     }
 
     private static Matcher<TextClassification> isTextClassification(
-            final String text, final String type) {
+            final String text, final String type, final String intentUri) {
         return new BaseMatcher<TextClassification>() {
             @Override
             public boolean matches(Object o) {
                 if (o instanceof TextClassification) {
                     TextClassification result = (TextClassification) o;
                     final boolean typeRequirementSatisfied;
+                    String scheme;
                     switch (type) {
+                        case TextClassifier.TYPE_EMAIL:
+                            scheme = result.getIntent().getData().getScheme();
+                            typeRequirementSatisfied = "mailto".equals(scheme);
+                            break;
                         case TextClassifier.TYPE_URL:
-                            String scheme = result.getIntent().getData().getScheme();
-                            typeRequirementSatisfied = "http".equalsIgnoreCase(scheme)
-                                    || "https".equalsIgnoreCase(scheme);
+                            scheme = result.getIntent().getData().getScheme();
+                            typeRequirementSatisfied = "http".equals(scheme)
+                                    || "https".equals(scheme);
                             break;
                         default:
                             typeRequirementSatisfied = true;
@@ -226,7 +255,8 @@
                     return typeRequirementSatisfied
                             && text.equals(result.getText())
                             && result.getEntityCount() > 0
-                            && type.equals(result.getEntity(0));
+                            && type.equals(result.getEntity(0))
+                            && intentUri.equals(result.getIntent().getDataString());
                     // TODO: Include other properties.
                 }
                 return false;
@@ -235,7 +265,8 @@
             @Override
             public void describeTo(Description description) {
                 description.appendText("text=").appendValue(text)
-                        .appendText(", type=").appendValue(type);
+                        .appendText(", type=").appendValue(type)
+                        .appendText(", intent.data=").appendValue(intentUri);
             }
         };
     }
diff --git a/libs/hwui/hwui/Bitmap.cpp b/libs/hwui/hwui/Bitmap.cpp
index d765584..b0e486d 100644
--- a/libs/hwui/hwui/Bitmap.cpp
+++ b/libs/hwui/hwui/Bitmap.cpp
@@ -16,6 +16,7 @@
 #include "Bitmap.h"
 
 #include "Caches.h"
+#include "pipeline/skia/SkiaOpenGLPipeline.h"
 #include "renderthread/EglManager.h"
 #include "renderthread/RenderThread.h"
 #include "renderthread/RenderProxy.h"
@@ -34,11 +35,15 @@
 #include <private/gui/ComposerService.h>
 #include <binder/IServiceManager.h>
 #include <ui/PixelFormat.h>
+#include <GrTexture.h>
 
 #include <SkCanvas.h>
+#include <SkImagePriv.h>
 
 namespace android {
 
+Mutex Bitmap::gLock;
+
 static bool computeAllocationSize(size_t rowBytes, int height, size_t* size) {
     int32_t rowBytes32 = SkToS32(rowBytes);
     int64_t bigSize = (int64_t) height * rowBytes32;
@@ -317,8 +322,7 @@
         return nullptr;
     }
     SkImageInfo info = SkImageInfo::Make(graphicBuffer->getWidth(), graphicBuffer->getHeight(),
-            kRGBA_8888_SkColorType, kPremul_SkAlphaType,
-            SkColorSpace::MakeSRGB());
+            kRGBA_8888_SkColorType, kPremul_SkAlphaType, SkColorSpace::MakeSRGB());
     return sk_sp<Bitmap>(new Bitmap(graphicBuffer.get(), info));
 }
 
@@ -393,6 +397,7 @@
     mPixelStorage.hardware.buffer = buffer;
     buffer->incStrong(buffer);
     mRowBytes = bytesPerPixel(buffer->getPixelFormat()) * buffer->getStride();
+    setImmutable(); // HW bitmaps are always immutable
 }
 
 Bitmap::~Bitmap() {
@@ -486,7 +491,13 @@
 void Bitmap::getSkBitmap(SkBitmap* outBitmap) {
     outBitmap->setHasHardwareMipMap(mHasHardwareMipMap);
     if (isHardware()) {
-        outBitmap->allocPixels(info());
+        if (uirenderer::Properties::isSkiaEnabled()) {
+            // TODO: add color correctness for Skia pipeline - pass null color space for now
+            outBitmap->allocPixels(SkImageInfo::Make(info().width(), info().height(),
+                    info().colorType(), info().alphaType(), nullptr));
+        } else {
+            outBitmap->allocPixels(info());
+        }
         uirenderer::renderthread::RenderProxy::copyGraphicBufferInto(graphicBuffer(), outBitmap);
         return;
     }
@@ -512,4 +523,28 @@
     return nullptr;
 }
 
+sk_sp<SkImage> Bitmap::makeImage(const uirenderer::renderthread::RenderThread* renderThread) {
+    AutoMutex _lock(gLock); //TODO: implement lock free solution
+    auto image = mImage;
+    //TODO: use new API SkImage::isValid() instead of SkImage::getTexture()->getContext()
+    if (!image.get() || (image->getTexture() && nullptr == image->getTexture()->getContext())) {
+        if (isHardware() && uirenderer::RenderPipelineType::SkiaGL
+                == uirenderer::Properties::getRenderPipelineType()) {
+            //TODO: add Vulkan support
+            if (renderThread) {
+                image = uirenderer::skiapipeline::SkiaOpenGLPipeline::makeTextureImage(
+                        *renderThread, this);
+            } else {
+                image = uirenderer::renderthread::RenderProxy::makeTextureImage(this);
+            }
+        } else {
+            SkBitmap skiaBitmap;
+            getSkBitmapForShaders(&skiaBitmap);
+            image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
+        }
+        mImage = image;
+    }
+    return image;
+}
+
 } // namespace android
diff --git a/libs/hwui/hwui/Bitmap.h b/libs/hwui/hwui/Bitmap.h
index da45f76..621e439 100644
--- a/libs/hwui/hwui/Bitmap.h
+++ b/libs/hwui/hwui/Bitmap.h
@@ -22,6 +22,8 @@
 #include <SkPixelRef.h>
 #include <cutils/compiler.h>
 #include <ui/GraphicBuffer.h>
+#include <utils/Mutex.h>
+#include <SkImage.h>
 
 namespace android {
 
@@ -111,6 +113,13 @@
     }
 
     GraphicBuffer* graphicBuffer();
+
+    // makeImage creates or returns a cached SkImage. Can be invoked from UI or render thread.
+    // If invoked on the render thread, then RenderThread* argument is required.
+    // If not invoked on the render thread, then RenderThread* must be nullptr.
+    // makeImage is wrapping a gralloc buffer with an EGLImage and is passing a texture to Skia.
+    // This is a temporary implementation until Skia can wrap the gralloc buffer in a SkImage.
+    sk_sp<SkImage> makeImage(const uirenderer::renderthread::RenderThread*);
 protected:
     virtual bool onNewLockPixels(LockRec* rec) override;
     virtual void onUnlockPixels() override { };
@@ -145,6 +154,9 @@
             GraphicBuffer* buffer;
         } hardware;
     } mPixelStorage;
+
+    sk_sp<SkImage> mImage;
+    static Mutex gLock;
 };
 
 } //namespace android
\ No newline at end of file
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index ae13131..4885873 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -28,6 +28,8 @@
 
 #include <cutils/properties.h>
 #include <strings.h>
+#include <SkImagePriv.h>
+#include <gl/GrGLTypes.h>
 
 using namespace android::uirenderer::renderthread;
 
@@ -197,6 +199,87 @@
     }
 }
 
+static void deleteImageTexture(void* context) {
+     EGLImageKHR EGLimage = reinterpret_cast<EGLImageKHR>(context);
+     if (EGLimage != EGL_NO_IMAGE_KHR) {
+        EGLDisplay display = eglGetCurrentDisplay();
+        if (EGL_NO_DISPLAY == display) {
+            display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+        }
+        eglDestroyImageKHR(display, EGLimage);
+     }
+}
+
+sk_sp<SkImage> SkiaOpenGLPipeline::makeTextureImage(
+        const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap) {
+    renderThread.eglManager().initialize();
+
+    GraphicBuffer* buffer = bitmap->graphicBuffer();
+    EGLDisplay display = eglGetCurrentDisplay();
+    if (EGL_NO_DISPLAY == display) {
+        display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+    }
+    LOG_ALWAYS_FATAL_IF(!bitmap->isHardware(),
+                "Texture image requires a HW bitmap.");
+    // We use an EGLImage to access the content of the GraphicBuffer
+    // The EGL image is later bound to a 2D texture
+    EGLClientBuffer clientBuffer = (EGLClientBuffer) buffer->getNativeBuffer();
+    EGLint imageAttrs[] = { EGL_IMAGE_PRESERVED_KHR, EGL_TRUE, EGL_NONE };
+    EGLImageKHR EGLimage = eglCreateImageKHR(display, EGL_NO_CONTEXT, EGL_NATIVE_BUFFER_ANDROID,
+            clientBuffer, imageAttrs);
+    if (EGLimage == EGL_NO_IMAGE_KHR) {
+        ALOGW("Could not create EGL image, err =%s",
+                uirenderer::renderthread::EglManager::eglErrorString());
+        return nullptr;
+    }
+
+    GLuint textureId = 0;
+    glGenTextures(1, &textureId);
+    glBindTexture(GL_TEXTURE_EXTERNAL_OES, textureId);
+    glEGLImageTargetTexture2DOES(GL_TEXTURE_EXTERNAL_OES, EGLimage);
+
+    GLenum status = GL_NO_ERROR;
+    while ((status = glGetError()) != GL_NO_ERROR) {
+        ALOGW("glEGLImageTargetTexture2DOES failed (%#x)", status);
+        eglDestroyImageKHR(display, EGLimage);
+        return nullptr;
+    }
+
+    sk_sp<GrContext> grContext = sk_ref_sp(renderThread.getGrContext());
+    grContext->resetContext();
+
+    GrGLTextureInfo textureInfo;
+    textureInfo.fTarget = GL_TEXTURE_EXTERNAL_OES;
+    textureInfo.fID = textureId;
+
+    GrBackendTextureDesc textureDescription;
+    textureDescription.fWidth = bitmap->info().width();
+    textureDescription.fHeight = bitmap->info().height();
+    textureDescription.fOrigin = kTopLeft_GrSurfaceOrigin;
+    textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&textureInfo);
+    PixelFormat format = buffer->getPixelFormat();
+    switch (format) {
+    case PIXEL_FORMAT_RGBA_8888:
+        textureDescription.fConfig = kRGBA_8888_GrPixelConfig;
+        break;
+    case PIXEL_FORMAT_RGBA_FP16:
+        textureDescription.fConfig = kRGBA_half_GrPixelConfig;
+        break;
+    default:
+        eglDestroyImageKHR(display, EGLimage);
+        return nullptr;
+    }
+
+    // TODO: add color correctness - pass null color space for now
+    sk_sp<SkImage> image = SkImage::MakeFromTexture(grContext.get(), textureDescription,
+                bitmap->info().alphaType(), nullptr, deleteImageTexture, EGLimage);
+    if (!image.get()) {
+        eglDestroyImageKHR(display, EGLimage);
+        return nullptr;
+    }
+    return image;
+}
+
 } /* namespace skiapipeline */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
index 36685dd..f3ce189 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.h
@@ -46,6 +46,8 @@
     bool isContextReady() override;
 
     static void invokeFunctor(const renderthread::RenderThread& thread, Functor* functor);
+    static sk_sp<SkImage> makeTextureImage(
+            const uirenderer::renderthread::RenderThread& renderThread, Bitmap* bitmap);
 
 private:
     renderthread::EglManager& mEglManager;
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
index a18d264..1a6e709 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLReadback.cpp
@@ -61,6 +61,7 @@
     textureDescription.fTextureHandle = reinterpret_cast<GrBackendObject>(&externalTexture);
 
     CopyResult copyResult = CopyResult::UnknownError;
+    // TODO: add color correctness - pass null color space for now
     sk_sp<SkImage> image(SkImage::MakeFromAdoptedTexture(grContext.get(), textureDescription));
     if (image) {
         SkAutoLockPixels alp(*bitmap);
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 10c1865..349d4cc 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -155,11 +155,11 @@
     GrContext* context = thread.getGrContext();
     if (context) {
         ATRACE_FORMAT("Bitmap#prepareToDraw %dx%d", bitmap->width(), bitmap->height());
-        SkBitmap skiaBitmap;
-        bitmap->getSkBitmap(&skiaBitmap);
-        sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skiaBitmap, kNever_SkCopyPixelsMode);
-        SkImage_pinAsTexture(image.get(), context);
-        SkImage_unpinAsTexture(image.get(), context);
+        auto image = bitmap->makeImage(&thread);
+        if (image.get() && !bitmap->isHardware()) {
+            SkImage_pinAsTexture(image.get(), context);
+            SkImage_unpinAsTexture(image.get(), context);
+        }
     }
 }
 
diff --git a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
index 559d268..5d7bbfa 100644
--- a/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
+++ b/libs/hwui/pipeline/skia/SkiaRecordingCanvas.cpp
@@ -168,11 +168,8 @@
 }
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& bitmap, float left, float top, const SkPaint* paint) {
-    SkBitmap skBitmap;
-    bitmap.getSkBitmap(&skBitmap);
-
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(skBitmap, kNever_SkCopyPixelsMode);
-    if (!skBitmap.isImmutable()) {
+    sk_sp<SkImage> image = bitmap.makeImage(nullptr);
+    if (!bitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
     SkPaint tmpPaint;
@@ -181,12 +178,10 @@
 
 void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, const SkMatrix& matrix,
         const SkPaint* paint) {
-    SkBitmap bitmap;
-    hwuiBitmap.getSkBitmap(&bitmap);
     SkAutoCanvasRestore acr(&mRecorder, true);
     concat(matrix);
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
-    if (!bitmap.isImmutable()) {
+    sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+    if (!hwuiBitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
     SkPaint tmpPaint;
@@ -196,12 +191,10 @@
 void SkiaRecordingCanvas::drawBitmap(Bitmap& hwuiBitmap, float srcLeft, float srcTop,
         float srcRight, float srcBottom, float dstLeft, float dstTop, float dstRight,
         float dstBottom, const SkPaint* paint) {
-    SkBitmap bitmap;
-    hwuiBitmap.getSkBitmap(&bitmap);
     SkRect srcRect = SkRect::MakeLTRB(srcLeft, srcTop, srcRight, srcBottom);
     SkRect dstRect = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
-    if (!bitmap.isImmutable()) {
+    sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+    if (!hwuiBitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
     SkPaint tmpPaint;
@@ -210,11 +203,8 @@
 
 void SkiaRecordingCanvas::drawNinePatch(Bitmap& hwuiBitmap, const Res_png_9patch& chunk,
         float dstLeft, float dstTop, float dstRight, float dstBottom, const SkPaint* paint) {
-    SkBitmap bitmap;
-    hwuiBitmap.getSkBitmap(&bitmap);
-
     SkCanvas::Lattice lattice;
-    NinePatchUtils::SetLatticeDivs(&lattice, chunk, bitmap.width(), bitmap.height());
+    NinePatchUtils::SetLatticeDivs(&lattice, chunk, hwuiBitmap.width(), hwuiBitmap.height());
 
     lattice.fFlags = nullptr;
     int numFlags = 0;
@@ -231,8 +221,8 @@
 
     lattice.fBounds = nullptr;
     SkRect dst = SkRect::MakeLTRB(dstLeft, dstTop, dstRight, dstBottom);
-    sk_sp<SkImage> image = SkMakeImageFromRasterBitmap(bitmap, kNever_SkCopyPixelsMode);
-    if (!bitmap.isImmutable()) {
+    sk_sp<SkImage> image = hwuiBitmap.makeImage(nullptr);
+    if (!hwuiBitmap.isImmutable()) {
         mDisplayList->mMutableImages.push_back(image.get());
     }
 
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index a1f1717..5c2ec0e 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -693,6 +693,18 @@
     }
 }
 
+CREATE_BRIDGE2(makeTextureImage, RenderThread* thread, Bitmap* bitmap) {
+    return args->thread->makeTextureImage(args->bitmap).release();
+}
+
+sk_sp<SkImage> RenderProxy::makeTextureImage(Bitmap* bitmap) {
+    SETUP_TASK(makeTextureImage);
+    args->bitmap = bitmap;
+    args->thread = &RenderThread::getInstance();
+    sk_sp<SkImage> hardwareImage(reinterpret_cast<SkImage*>(staticPostAndWait(task)));
+    return hardwareImage;
+}
+
 void RenderProxy::post(RenderTask* task) {
     mRenderThread.queue(task);
 }
diff --git a/libs/hwui/renderthread/RenderProxy.h b/libs/hwui/renderthread/RenderProxy.h
index a60ed55..97ad796 100644
--- a/libs/hwui/renderthread/RenderProxy.h
+++ b/libs/hwui/renderthread/RenderProxy.h
@@ -135,6 +135,8 @@
     static sk_sp<Bitmap> allocateHardwareBitmap(SkBitmap& bitmap);
 
     static int copyGraphicBufferInto(GraphicBuffer* buffer, SkBitmap* bitmap);
+
+    static sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
 private:
     RenderThread& mRenderThread;
     CanvasContext* mContext;
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index 1450ec9..d62b556 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -17,6 +17,7 @@
 #include "RenderThread.h"
 
 #include "../renderstate/RenderState.h"
+#include "../pipeline/skia/SkiaOpenGLPipeline.h"
 #include "../pipeline/skia/SkiaOpenGLReadback.h"
 #include "CanvasContext.h"
 #include "EglManager.h"
@@ -433,6 +434,24 @@
     return next;
 }
 
+sk_sp<SkImage> RenderThread::makeTextureImage(Bitmap* bitmap) {
+    auto renderType = Properties::getRenderPipelineType();
+    sk_sp<SkImage> hardwareImage;
+    switch (renderType) {
+        case RenderPipelineType::SkiaGL:
+            hardwareImage = skiapipeline::SkiaOpenGLPipeline::makeTextureImage(*this, bitmap);
+            break;
+        case RenderPipelineType::SkiaVulkan:
+            //TODO: add Vulkan support
+            break;
+        default:
+            LOG_ALWAYS_FATAL("makeTextureImage: canvas context type %d not supported",
+                    (int32_t) renderType);
+            break;
+    }
+    return hardwareImage;
+}
+
 } /* namespace renderthread */
 } /* namespace uirenderer */
 } /* namespace android */
diff --git a/libs/hwui/renderthread/RenderThread.h b/libs/hwui/renderthread/RenderThread.h
index 9bc5985..34542c6 100644
--- a/libs/hwui/renderthread/RenderThread.h
+++ b/libs/hwui/renderthread/RenderThread.h
@@ -33,6 +33,7 @@
 
 namespace android {
 
+class Bitmap;
 class DisplayEventReceiver;
 
 namespace uirenderer {
@@ -104,6 +105,8 @@
 
     VulkanManager& vulkanManager() { return *mVkManager; }
 
+    sk_sp<SkImage> makeTextureImage(Bitmap* bitmap);
+
 protected:
     virtual bool threadLoop() override;
 
diff --git a/packages/SettingsLib/res/values-eu/strings.xml b/packages/SettingsLib/res/values-eu/strings.xml
index aa6b3c2..fd20d47 100644
--- a/packages/SettingsLib/res/values-eu/strings.xml
+++ b/packages/SettingsLib/res/values-eu/strings.xml
@@ -319,7 +319,7 @@
     <string name="accessibility_display_daltonizer_preference_subtitle" msgid="3484969015295282911">"Eginbidea esperimentala da eta eragina izan dezake funtzionamenduan."</string>
     <string name="daltonizer_type_overridden" msgid="3116947244410245916">"<xliff:g id="TITLE">%1$s</xliff:g> hobespena gainjarri zaio"</string>
     <string name="power_remaining_duration_only" msgid="845431008899029842">"<xliff:g id="TIME">%1$s</xliff:g> inguru gelditzen dira"</string>
-    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> gelditzen dira guztiz kargatu arte"</string>
+    <string name="power_remaining_charging_duration_only" msgid="1421102457410268886">"<xliff:g id="TIME">%1$s</xliff:g> falta dira guztiz kargatu arte"</string>
     <string name="power_remaining_duration_only_short" msgid="5329694252258605547">"<xliff:g id="TIME">%1$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> inguru gelditzen dira"</string>
     <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
@@ -327,7 +327,7 @@
     <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> guztiz kargatu arte"</string>
     <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Ezezaguna"</string>
-    <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzea"</string>
+    <string name="battery_info_status_charging" msgid="1705179948350365604">"Kargatzen"</string>
     <string name="battery_info_status_charging_lower" msgid="8689770213898117994">"kargatzen"</string>
     <string name="battery_info_status_discharging" msgid="310932812698268588">"Ez da kargatzen ari"</string>
     <string name="battery_info_status_not_charging" msgid="2820070506621483576">"Ez da kargatzen ari"</string>
diff --git a/packages/SettingsLib/res/values-fr/strings.xml b/packages/SettingsLib/res/values-fr/strings.xml
index 5d29ec0..c69f324 100644
--- a/packages/SettingsLib/res/values-fr/strings.xml
+++ b/packages/SettingsLib/res/values-fr/strings.xml
@@ -324,7 +324,7 @@
     <string name="power_discharging_duration" msgid="2843747179907396142">"<xliff:g id="LEVEL">%1$s</xliff:g> - encore environ <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_discharging_duration_short" msgid="4192244429001842403">"<xliff:g id="LEVEL">%1$s</xliff:g> – Temps restant : <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="power_charging" msgid="1779532561355864267">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="STATE">%2$s</xliff:g>"</string>
-    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> avant une charge complète"</string>
+    <string name="power_charging_duration" msgid="4676999980973411875">"<xliff:g id="LEVEL">%1$s</xliff:g> - <xliff:g id="TIME">%2$s</xliff:g> jusqu\'à la charge complète"</string>
     <string name="power_charging_duration_short" msgid="1098603958472207920">"<xliff:g id="LEVEL">%1$s</xliff:g> – <xliff:g id="TIME">%2$s</xliff:g>"</string>
     <string name="battery_info_status_unknown" msgid="196130600938058547">"Inconnu"</string>
     <string name="battery_info_status_charging" msgid="1705179948350365604">"Batterie en charge"</string>
diff --git a/packages/SettingsLib/res/values-gl/strings.xml b/packages/SettingsLib/res/values-gl/strings.xml
index 929332f..3250d03 100644
--- a/packages/SettingsLib/res/values-gl/strings.xml
+++ b/packages/SettingsLib/res/values-gl/strings.xml
@@ -349,7 +349,7 @@
     <string name="screen_zoom_summary_very_large" msgid="7108563375663670067">"Máis grande"</string>
     <string name="screen_zoom_summary_extremely_large" msgid="7427320168263276227">"O máis grande"</string>
     <string name="screen_zoom_summary_custom" msgid="5611979864124160447">"Personalizado (<xliff:g id="DENSITYDPI">%d</xliff:g>)"</string>
-    <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e suxestións"</string>
+    <string name="help_feedback_label" msgid="6815040660801785649">"Axuda e comentarios"</string>
     <string name="content_description_menu_button" msgid="8182594799812351266">"Menú"</string>
     <string name="time_zone_gmt" msgid="2587097992671450782">"GMT"</string>
     <string name="retail_demo_reset_message" msgid="118771671364131297">"Insire contrasinal para restablec. en demostración"</string>
diff --git a/packages/SettingsLib/res/values-in/strings.xml b/packages/SettingsLib/res/values-in/strings.xml
index e0157bc..9e7355b 100644
--- a/packages/SettingsLib/res/values-in/strings.xml
+++ b/packages/SettingsLib/res/values-in/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="wifi_fail_to_scan" msgid="1265540342578081461">"Tidak dapat memindai jaringan"</string>
-    <string name="wifi_security_none" msgid="7985461072596594400">"Tidak Ada"</string>
+    <string name="wifi_security_none" msgid="7985461072596594400">"Tidak ada"</string>
     <string name="wifi_remembered" msgid="4955746899347821096">"Disimpan"</string>
     <string name="wifi_disabled_generic" msgid="4259794910584943386">"Nonaktif"</string>
     <string name="wifi_disabled_network_failure" msgid="2364951338436007124">"Kegagalan Konfigurasi IP"</string>
@@ -229,7 +229,7 @@
     <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Monitor Telefoni akan mengumpulkan log jika mendeteksi masalah pada fungsi telefoni/modem dan mengirimkan notifikasi ke pengguna untuk melaporkan bug"</string>
     <string name="debug_input_category" msgid="1811069939601180246">"Masukan"</string>
     <string name="debug_drawing_category" msgid="6755716469267367852">"Gambar"</string>
-    <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat perangkat keras"</string>
+    <string name="debug_hw_drawing_category" msgid="6220174216912308658">"Render yang dipercepat hardware"</string>
     <string name="media_category" msgid="4388305075496848353">"Media"</string>
     <string name="debug_monitoring_category" msgid="7640508148375798343">"Memantau"</string>
     <string name="strict_mode" msgid="1938795874357830695">"Mode ketat diaktifkan"</string>
diff --git a/packages/SettingsLib/res/values-mn/strings.xml b/packages/SettingsLib/res/values-mn/strings.xml
index 52840e3..12c52812 100644
--- a/packages/SettingsLib/res/values-mn/strings.xml
+++ b/packages/SettingsLib/res/values-mn/strings.xml
@@ -205,10 +205,10 @@
     <string name="debug_view_attributes" msgid="6485448367803310384">"Харах тохируулгын шалгалтыг идэвхжүүлэх"</string>
     <string name="mobile_data_always_on_summary" msgid="8149773901431697910">"Wi‑Fi идэвхтэй байхад ч гэсэн гар утасны датаг идэвхтэй байлгадаг (сүлжээг түргэн солихын тулд)."</string>
     <string name="adb_warning_title" msgid="6234463310896563253">"USB дебаг хийхийг зөвшөөрөх үү?"</string>
-    <string name="adb_warning_message" msgid="7316799925425402244">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликешн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string>
+    <string name="adb_warning_message" msgid="7316799925425402244">"USB дебаг нь зөвхөн хөгжүүлэлтийн зорилготой. Үүнийг өөрийн компьютер болон төхөөрөмжийн хооронд өгөгдөл хуулах, өөрийн төхөөрөмж дээр мэдэгдэлгүйгээр аппликейшн суулгах, лог датаг унших зэрэгт ашиглаж болно."</string>
     <string name="adb_keys_warning_message" msgid="5659849457135841625">"Таны өмнө нь зөвшөөрөл өгсөн бүх компьютерээс USB дебаг хандалтыг нь хураах уу?"</string>
     <string name="dev_settings_warning_title" msgid="7244607768088540165">"Хөгжлийн тохиргоог зөвшөөрөх үү?"</string>
-    <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликешнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
+    <string name="dev_settings_warning_message" msgid="2298337781139097964">"Эдгээр тохиргоо нь зөвхөн хөгжүүлэлтэд ашиглах зорилготой. Эдгээр нь таны төхөөрөмж буюу түүн дээрх аппликейшнүүдийг эвдрэх, буруу ажиллах шалтгаан нь болж болно."</string>
     <string name="verify_apps_over_usb_title" msgid="4177086489869041953">"Апп-г USB-р тулгах"</string>
     <string name="verify_apps_over_usb_summary" msgid="9164096969924529200">"ADB/ADT-р суулгасан апп-уудыг хорлонтой авиртай эсэхийг шалгах."</string>
     <string name="bluetooth_disable_absolute_volume_summary" msgid="6031284410786545957">"Хэт чанга дуугаралт эсвэл муу тохиргоо зэрэг алсын зайн төхөөрөмжийн дуугаралттай холбоотой асуудлын үед Bluetooth-ийн үнэмлэхүй дууны түвшинг идэвхгүй болго."</string>
@@ -219,12 +219,12 @@
     <string name="hdcp_checking_dialog_title" msgid="5141305530923283">"HDCP шалгах авирыг тохируулах"</string>
     <string name="debug_debugging_category" msgid="6781250159513471316">"Согог хайх"</string>
     <string name="debug_app" msgid="8349591734751384446">"Согог засах апп сонгоно уу"</string>
-    <string name="debug_app_not_set" msgid="718752499586403499">"Дебаг аппликешн тохируулаагүй"</string>
-    <string name="debug_app_set" msgid="2063077997870280017">"Согог засах аппликешн: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
-    <string name="select_application" msgid="5156029161289091703">"Аппликешн сонгох"</string>
+    <string name="debug_app_not_set" msgid="718752499586403499">"Дебаг аппликейшн тохируулаагүй"</string>
+    <string name="debug_app_set" msgid="2063077997870280017">"Согог засах аппликейшн: <xliff:g id="APP_NAME">%1$s</xliff:g>"</string>
+    <string name="select_application" msgid="5156029161289091703">"Аппликейшн сонгох"</string>
     <string name="no_application" msgid="2813387563129153880">"Юуг ч биш"</string>
     <string name="wait_for_debugger" msgid="1202370874528893091">"Согог засагчийг хүлээх"</string>
-    <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликешн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
+    <string name="wait_for_debugger_summary" msgid="1766918303462746804">"Согог засагдсан аппликейшн ажиллахын өмнө согог засагчийг хавсаргагдахыг хүлээнэ"</string>
     <string name="telephony_monitor_switch" msgid="1764958220062121194">"Утасны хяналт"</string>
     <string name="telephony_monitor_switch_summary" msgid="7695552966547975635">"Утасны хяналт нь утас/модемын ажиллагаанд асуудал илрүүлсэн тохиолдолд лог цуглуулж, хэрэглэгчид алдааг засах мэдэгдэл илгээнэ"</string>
     <string name="debug_input_category" msgid="1811069939601180246">"Оруулах"</string>
diff --git a/packages/SettingsLib/res/values-sw/strings.xml b/packages/SettingsLib/res/values-sw/strings.xml
index a6ad468..ef43134 100644
--- a/packages/SettingsLib/res/values-sw/strings.xml
+++ b/packages/SettingsLib/res/values-sw/strings.xml
@@ -102,8 +102,8 @@
     <string name="running_process_item_user_label" msgid="3129887865552025943">"Mtumiaji: <xliff:g id="USER_NAME">%1$s</xliff:g>"</string>
     <string name="launch_defaults_some" msgid="313159469856372621">"Baadhi ya chaguo-msingi zimewekwa"</string>
     <string name="launch_defaults_none" msgid="4241129108140034876">"Hakuna chaguo-misingi zilizowekwa"</string>
-    <string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya maandishi kwa hotuba"</string>
-    <string name="tts_settings_title" msgid="1237820681016639683">"Kubadilisha maandishi hadi usemi"</string>
+    <string name="tts_settings" msgid="8186971894801348327">"Mipangilio ya kusoma maandishi kwa sauti"</string>
+    <string name="tts_settings_title" msgid="1237820681016639683">"Kipengele cha kusoma maandishi kwa sauti"</string>
     <string name="tts_default_rate_title" msgid="6030550998379310088">"Kasi ya kutamka"</string>
     <string name="tts_default_rate_summary" msgid="4061815292287182801">"Kasi ya kutamkwa kwa maneno"</string>
     <string name="tts_default_pitch_title" msgid="6135942113172488671">"Uzito wa sauti"</string>
@@ -117,7 +117,7 @@
     <string name="tts_install_data_title" msgid="4264378440508149986">"Sakinisha data ya sauti"</string>
     <string name="tts_install_data_summary" msgid="5742135732511822589">"Sakinisha data ya sauti inayohitajika kuunganisha usemi"</string>
     <string name="tts_engine_security_warning" msgid="8786238102020223650">"Hotuba hii inawezesha injini huenda ikaweza kukusanya maandishi ambayo yatazungumziwa, ikijumlisha data ya kibinafsi ya nenosiri na namba ya kaddi ya mkopo. Inatoka kwa injini ya <xliff:g id="TTS_PLUGIN_ENGINE_NAME">%s</xliff:g> Wezesha matumizi ya hotuba hii iliyowezeshwa ya injini?"</string>
-    <string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi kwa towe ya maandishi hadi sauti."</string>
+    <string name="tts_engine_network_required" msgid="1190837151485314743">"Lugha hii inahitaji muunganisho wa mtandao unaofanya kazi ili kipengele cha kusoma maandishi kwa sauti kifanye kazi."</string>
     <string name="tts_default_sample_string" msgid="4040835213373086322">"Huu ni mfano wa usanisi usemaji"</string>
     <string name="tts_status_title" msgid="7268566550242584413">"Hali ya lugha chaguo-msingi"</string>
     <string name="tts_status_ok" msgid="1309762510278029765">"<xliff:g id="LOCALE">%1$s</xliff:g> inaweza kutumiwa kikamilifu"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index 0ab296e..3135f1d 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -204,6 +204,13 @@
         return colorAccent;
     }
 
+    public static int getThemeAttr(Context context, int attr) {
+        TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
+        int theme = ta.getResourceId(0, 0);
+        ta.recycle();
+        return theme;
+    }
+
     public static Drawable getDrawable(Context context, int attr) {
         TypedArray ta = context.obtainStyledAttributes(new int[]{attr});
         Drawable drawable = ta.getDrawable(0);
diff --git a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
index 46fbb24..3a2397f 100755
--- a/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
+++ b/packages/SettingsLib/src/com/android/settingslib/graph/BatteryMeterDrawableBase.java
@@ -88,12 +88,6 @@
     private final Path mClipPath = new Path();
     private final Path mTextPath = new Path();
 
-    private int mDarkModeBackgroundColor;
-    private int mDarkModeFillColor;
-
-    private int mLightModeBackgroundColor;
-    private int mLightModeFillColor;
-
     public BatteryMeterDrawableBase(Context context, int frameColor) {
         mContext = context;
         final Resources res = context.getResources();
@@ -156,15 +150,6 @@
         mPlusPaint = new Paint(mBoltPaint);
         mPlusPoints = loadPoints(res, R.array.batterymeter_plus_points);
 
-        mDarkModeBackgroundColor =
-                Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_background);
-        mDarkModeFillColor =
-                Utils.getDefaultColor(mContext, R.color.dark_mode_icon_color_dual_tone_fill);
-        mLightModeBackgroundColor =
-                Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_background);
-        mLightModeFillColor =
-                Utils.getDefaultColor(mContext, R.color.light_mode_icon_color_dual_tone_fill);
-
         mIntrinsicWidth = context.getResources().getDimensionPixelSize(R.dimen.battery_width);
         mIntrinsicHeight = context.getResources().getDimensionPixelSize(R.dimen.battery_height);
     }
@@ -259,16 +244,6 @@
         return color;
     }
 
-    public void setDarkIntensity(float darkIntensity) {
-        if (darkIntensity == mOldDarkIntensity) {
-            return;
-        }
-        int backgroundColor = getBackgroundColor(darkIntensity);
-        int fillColor = getFillColor(darkIntensity);
-        setColors(fillColor, backgroundColor);
-        mOldDarkIntensity = darkIntensity;
-    }
-
     public void setColors(int fillColor, int backgroundColor) {
         mIconTint = fillColor;
         mFramePaint.setColor(backgroundColor);
@@ -277,20 +252,6 @@
         invalidateSelf();
     }
 
-    private int getBackgroundColor(float darkIntensity) {
-        return getColorForDarkIntensity(
-                darkIntensity, mLightModeBackgroundColor, mDarkModeBackgroundColor);
-    }
-
-    private int getFillColor(float darkIntensity) {
-        return getColorForDarkIntensity(
-                darkIntensity, mLightModeFillColor, mDarkModeFillColor);
-    }
-
-    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
-        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
-    }
-
     @Override
     public void draw(Canvas c) {
         final int level = mLevel;
diff --git a/packages/SystemUI/res/drawable/pip_expand.xml b/packages/SystemUI/res/drawable/pip_expand.xml
new file mode 100644
index 0000000..cdb2ee5
--- /dev/null
+++ b/packages/SystemUI/res/drawable/pip_expand.xml
@@ -0,0 +1,29 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+Copyright (C) 2017 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.
+-->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="36dp"
+    android:height="36dp"
+    android:viewportWidth="36"
+    android:viewportHeight="36">
+
+    <path
+        android:pathData="M0 0h36v36H0z" />
+    <path
+        android:fillColor="#FFFFFF"
+        android:pathData="M10 21H7v8h8v-3h-5v-5zm-3-6h3v-5h5V7H7v8zm19 11h-5v3h8v-8h-3v5zM21
+7v3h5v5h3V7h-8z" />
+</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_ll.xml b/packages/SystemUI/res/drawable/pip_expand_ll.xml
deleted file mode 100644
index a8b82b5..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_ll.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="60dp"
-    android:height="60dp"
-    android:viewportWidth="60"
-    android:viewportHeight="60">
-
-    <path
-        android:fillColor="#fff"
-        android:pathData="M7.5,52h45a5,5,0,0,0,5-5V12.95A5,5,0,0,0,52.5,8H7.5a5,5,0,0,0-5,4.95V47A5,5,0,0,0,7.5,52Zm-1-5V13a1,1,0,0,1,1-1h45a1,1,0,0,1,1,1V47a1,1,0,0,1-1,1H7.5A1,1,0,0,1,6.5,47Z" />
-    <path
-        android:pathData="M0,0V60H60V0H0Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M35,39.14v2a1,1,0,0,0,1,1H46.5a1,1,0,0,0,1-1V30.64a1,1,0,0,0-1-1h-2a1,1,0,0,0-1,1v7.5H36A1,1,0,0,0,35,39.14Z" />
-    <path
-        android:fillColor="#fff"
-        android:pathData="M13.5,30.36h2a1,1,0,0,0,1-1v-7.5H24a1,1,0,0,0,1-1v-2a1,1,0,0,0-1-1H13.5a1,1,0,0,0-1,1v10.5A1,1,0,0,0,13.5,30.36Z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_lr.xml b/packages/SystemUI/res/drawable/pip_expand_lr.xml
deleted file mode 100644
index 44d97ef..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_lr.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="60dp"
-    android:height="60dp"
-    android:viewportWidth="60"
-    android:viewportHeight="60">
-
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M57.5,47V12.95c0-2.75-2.25-4.95-5-4.95h-45c-2.75,0-5,2.2-5,4.95V47c0,2.75,2.25,5,5,5h45
-C55.25,52,57.5,49.75,57.5,47z
-M52.5,48h-45c-0.55,0-1-0.45-1-1V13c0-0.55,0.45-1,1-1h45c0.55,0,1,0.45,1,1v34
-C53.5,47.55,53.05,48,52.5,48z" />
-    <path
-        android:pathData="M60,0v60H0L0,0L60,0z" />
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M25,39.14v2c0,0.55-0.45,1-1,1H13.5c-0.55,0-1-0.45-1-1v-10.5c0-0.55,0.45-1,1-1h2c0.55,0,1,0.45,1,1v7.5
-H24C24.55,38.14,25,38.59,25,39.14z" />
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M46.5,30.36h-2c-0.55,0-1-0.45-1-1v-7.5H36c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h10.5
-c0.55,0,1,0.45,1,1v10.5C47.5,29.91,47.05,30.36,46.5,30.36z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_pl.xml b/packages/SystemUI/res/drawable/pip_expand_pl.xml
deleted file mode 100644
index 57b9358..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_pl.xml
+++ /dev/null
@@ -1,39 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="60dp"
-    android:height="60dp"
-    android:viewportWidth="60"
-    android:viewportHeight="60">
-
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M47,2.5H12.95C10.2,2.5,8,4.75,8,7.5v45c0,2.75,2.2,5,4.95,5H47c2.75,0,5-2.25,5-5v-45
-C52,4.75,49.75,2.5,47,2.5z
-M48,7.5v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45c0-0.55,0.45-1,1-1h34
-C47.55,6.5,48,6.95,48,7.5z" />
-    <path
-        android:pathData="M0,0l60,0v60H0L0,0z" />
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M39.14,35h2c0.55,0,1,0.45,1,1v10.5c0,0.55-0.45,1-1,1h-10.5c-0.55,0-1-0.45-1-1v-2c0-0.55,0.45-1,1-1h7.5
-V36C38.14,35.45,38.59,35,39.14,35z" />
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M30.36,13.5v2c0,0.55-0.45,1-1,1h-7.5V24c0,0.55-0.45,1-1,1h-2c-0.55,0-1-0.45-1-1V13.5c0-0.55,0.45-1,1-1
-h10.5C29.91,12.5,30.36,12.95,30.36,13.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/drawable/pip_expand_pr.xml b/packages/SystemUI/res/drawable/pip_expand_pr.xml
deleted file mode 100644
index e34a95d..0000000
--- a/packages/SystemUI/res/drawable/pip_expand_pr.xml
+++ /dev/null
@@ -1,38 +0,0 @@
-<?xml version="1.0" encoding="utf-8"?>
-<!--
-Copyright (C) 2017 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.
--->
-<vector xmlns:android="http://schemas.android.com/apk/res/android"
-    android:width="60dp"
-    android:height="60dp"
-    android:viewportWidth="60"
-    android:viewportHeight="60">
-
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M8,7.5v45c0,2.75,2.25,5,5,5h34.05c2.75,0,4.95-2.25,4.95-5v-45c0-2.75-2.2-5-4.95-5H13
-C10.25,2.5,8,4.75,8,7.5z
-M13,6.5h34c0.55,0,1,0.45,1,1v45c0,0.55-0.45,1-1,1H13c-0.55,0-1-0.45-1-1v-45C12,6.95,12.45,6.5,13,6.5z" />
-    <path
-        android:pathData="M60,0L0,0l0,60h60V0z" />
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M20.86,35h-2c-0.55,0-1,0.45-1,1v10.5c0,0.55,0.45,1,1,1h10.5c0.55,0,1-0.45,1-1v-2c0-0.55-0.45-1-1-1h-7.5
-V36C21.86,35.45,21.41,35,20.86,35z" />
-    <path
-        android:fillColor="#FFFFFF"
-        android:pathData="M29.64,13.5v2c0,0.55,0.45,1,1,1h7.5V24c0,0.55,0.45,1,1,1h2c0.55,0,1-0.45,1-1V13.5c0-0.55-0.45-1-1-1
-h-10.5C30.09,12.5,29.64,12.95,29.64,13.5z" />
-</vector>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/pip_menu_activity.xml b/packages/SystemUI/res/layout/pip_menu_activity.xml
index 8c66bab..8b7f692 100644
--- a/packages/SystemUI/res/layout/pip_menu_activity.xml
+++ b/packages/SystemUI/res/layout/pip_menu_activity.xml
@@ -38,6 +38,8 @@
               android:layout_height="60dp"
               android:layout_gravity="center"
               android:contentDescription="@string/pip_phone_expand"
+              android:padding="10dp"
+              android:src="@drawable/pip_expand"
               android:background="?android:selectableItemBackgroundBorderless" />
       </FrameLayout>
 
diff --git a/packages/SystemUI/res/layout/signal_cluster_view.xml b/packages/SystemUI/res/layout/signal_cluster_view.xml
index 9a97d60..2e22943 100644
--- a/packages/SystemUI/res/layout/signal_cluster_view.xml
+++ b/packages/SystemUI/res/layout/signal_cluster_view.xml
@@ -40,13 +40,13 @@
         android:layout_width="wrap_content"
         >
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="@style/DualToneLightTheme"
+            android:theme="?attr/lightIconTheme"
             android:id="@+id/ethernet"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             />
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="@style/DualToneDarkTheme"
+            android:theme="?attr/darkIconTheme"
             android:id="@+id/ethernet_dark"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
@@ -79,13 +79,13 @@
         android:layout_width="wrap_content"
         >
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="@style/DualToneLightTheme"
+            android:theme="?attr/lightIconTheme"
             android:id="@+id/wifi_signal"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             />
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="@style/DualToneDarkTheme"
+            android:theme="?attr/darkIconTheme"
             android:id="@+id/wifi_signal_dark"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
@@ -120,14 +120,14 @@
         android:layout_width="wrap_content"
         android:contentDescription="@string/accessibility_no_sims">
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="@style/DualToneLightTheme"
+            android:theme="?attr/lightIconTheme"
             android:id="@+id/no_sims"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
             android:src="@drawable/stat_sys_no_sims"
             />
         <com.android.systemui.statusbar.AlphaOptimizedImageView
-            android:theme="@style/DualToneDarkTheme"
+            android:theme="?attr/darkIconTheme"
             android:id="@+id/no_sims_dark"
             android:layout_height="wrap_content"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml
index a57b17e..06b945d 100644
--- a/packages/SystemUI/res/values/attrs.xml
+++ b/packages/SystemUI/res/values/attrs.xml
@@ -128,5 +128,8 @@
         <!-- The initial color for the scrim. -->
         <attr name="scrimColor" format="color" />
     </declare-styleable>
+
+    <attr name="lightIconTheme" format="reference" />
+    <attr name="darkIconTheme" format="reference" />
 </resources>
 
diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml
index c00b562..6604b6c 100644
--- a/packages/SystemUI/res/values/dimens.xml
+++ b/packages/SystemUI/res/values/dimens.xml
@@ -768,7 +768,7 @@
 
     <!-- The bottom margin of the expand container when there are actions.
          Equal to pip_action_size - pip_action_padding. -->
-    <dimen name="pip_expand_container_edge_margin">36dp</dimen>
+    <dimen name="pip_expand_container_edge_margin">30dp</dimen>
 
     <dimen name="default_gear_space">18dp</dimen>
     <dimen name="cell_overlay_padding">18dp</dimen>
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index 9650cea..44da876 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -290,7 +290,14 @@
     <style name="Animation.StatusBar">
     </style>
 
-    <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings" />
+    <style name="systemui_theme" parent="@*android:style/Theme.DeviceDefault.QuickSettings">
+        <item name="lightIconTheme">@style/DualToneLightTheme</item>
+        <item name="darkIconTheme">@style/DualToneDarkTheme</item>
+    </style>
+    <style name="qs_theme" parent="systemui_theme">
+        <item name="lightIconTheme">@style/QSIconTheme</item>
+        <item name="darkIconTheme">@style/QSIconTheme</item>
+    </style>
 
     <style name="systemui_theme_remote_input" parent="@android:style/Theme.DeviceDefault.Light">
         <item name="android:colorAccent">@color/remote_input_accent</item>
@@ -346,6 +353,11 @@
         <item name="fillColor">@color/dark_mode_icon_color_dual_tone_fill</item>
         <item name="singleToneColor">@color/dark_mode_icon_color_single_tone</item>
     </style>
+    <style name="QSIconTheme">
+        <item name="backgroundColor">?android:attr/textColorHint</item>
+        <item name="fillColor">?android:attr/textColorPrimary</item>
+        <item name="singleToneColor">?android:attr/textColorPrimary</item>
+    </style>
 
     <style name="TextAppearance.Volume">
         <item name="android:textStyle">normal</item>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 67a2989..2d30476 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -502,6 +502,12 @@
             }
         }
 
+        if (msgId == FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT) {
+            mLockPatternUtils.requireStrongAuth(
+                    LockPatternUtils.StrongAuthTracker.STRONG_AUTH_REQUIRED_AFTER_LOCKOUT,
+                    getCurrentUser());
+        }
+
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
index 911ef24..9dd39d4 100644
--- a/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
+++ b/packages/SystemUI/src/com/android/systemui/BatteryMeterView.java
@@ -17,25 +17,28 @@
 
 import static android.provider.Settings.System.SHOW_BATTERY_PERCENT;
 
+import android.animation.ArgbEvaluator;
 import android.content.Context;
 import android.content.res.Resources;
 import android.content.res.TypedArray;
-import android.graphics.Rect;
-import android.util.ArraySet;
-import android.util.AttributeSet;
-import android.util.TypedValue;
 import android.database.ContentObserver;
+import android.graphics.Rect;
 import android.net.Uri;
 import android.os.Handler;
 import android.provider.Settings;
+import android.util.ArraySet;
+import android.util.AttributeSet;
+import android.util.TypedValue;
+import android.view.ContextThemeWrapper;
 import android.view.Gravity;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.ViewGroup;
 import android.widget.ImageView;
 import android.widget.LinearLayout;
-
 import android.widget.TextView;
+
+import com.android.settingslib.Utils;
 import com.android.settingslib.graph.BatteryMeterDrawableBase;
 import com.android.systemui.statusbar.phone.StatusBarIconController;
 import com.android.systemui.statusbar.policy.BatteryController;
@@ -63,6 +66,12 @@
     private int mLevel;
     private boolean mForceShowPercent;
 
+    private int mDarkModeBackgroundColor;
+    private int mDarkModeFillColor;
+
+    private int mLightModeBackgroundColor;
+    private int mLightModeFillColor;
+
     public BatteryMeterView(Context context) {
         this(context, null, 0);
     }
@@ -98,6 +107,16 @@
         addView(mBatteryIconView, mlp);
 
         updateShowPercent();
+
+        Context dualToneDarkTheme = new ContextThemeWrapper(context,
+                Utils.getThemeAttr(context, R.attr.darkIconTheme));
+        Context dualToneLightTheme = new ContextThemeWrapper(context,
+                Utils.getThemeAttr(context, R.attr.lightIconTheme));
+        mDarkModeBackgroundColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.backgroundColor);
+        mDarkModeFillColor = Utils.getColorAttr(dualToneDarkTheme, R.attr.fillColor);
+        mLightModeBackgroundColor = Utils.getColorAttr(dualToneLightTheme, R.attr.backgroundColor);
+        mLightModeFillColor = Utils.getColorAttr(dualToneLightTheme, R.attr.fillColor);
+
         // Init to not dark at all.
         onDarkChanged(new Rect(), 0, DarkIconDispatcher.DEFAULT_ICON_TINT);
     }
@@ -107,11 +126,6 @@
         updateShowPercent();
     }
 
-    // StatusBarIconController reaches in here and adjusts the layout parameters of the icon
-    public ImageView getBatteryIconView() {
-        return mBatteryIconView;
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         return false;
@@ -170,7 +184,7 @@
     private void updatePercentText() {
         if (mBatteryPercentView != null) {
             mBatteryPercentView.setText(
-                    NumberFormat.getPercentInstance().format(mLevel/100f));
+                    NumberFormat.getPercentInstance().format(mLevel / 100f));
         }
     }
 
@@ -224,8 +238,13 @@
 
     @Override
     public void onDarkChanged(Rect area, float darkIntensity, int tint) {
-        mDrawable.setDarkIntensity(DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0);
-        setTextColor(DarkIconDispatcher.getTint(area, this, tint));
+        float intensity = DarkIconDispatcher.isInArea(area, this) ? darkIntensity : 0;
+        int foreground = getColorForDarkIntensity(intensity, mLightModeFillColor,
+                mDarkModeFillColor);
+        int background = getColorForDarkIntensity(intensity, mLightModeBackgroundColor,
+                mDarkModeBackgroundColor);
+        mDrawable.setColors(foreground, background);
+        setTextColor(foreground);
     }
 
     public void setTextColor(int color) {
@@ -235,8 +254,8 @@
         }
     }
 
-    public void setRawColors(int fgColor, int bgColor) {
-        mDrawable.setColors(fgColor, bgColor);
+    private int getColorForDarkIntensity(float darkIntensity, int lightColor, int darkColor) {
+        return (int) ArgbEvaluator.getInstance().evaluate(darkIntensity, lightColor, darkColor);
     }
 
     private final class SettingObserver extends ContentObserver {
diff --git a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
index 9b74cd6..cdad8ae 100644
--- a/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
+++ b/packages/SystemUI/src/com/android/systemui/RecentsComponent.java
@@ -23,7 +23,7 @@
 public interface RecentsComponent {
     void showRecentApps(boolean triggeredFromAltTab, boolean fromHome);
     void hideRecentApps(boolean triggeredFromAltTab, boolean triggeredFromHomeKey);
-    void toggleRecents(Display display);
+    void toggleRecents();
     void preloadRecents();
     void showNextAffiliatedTask();
     void showPrevAffiliatedTask();
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
index 5eb483d..f198229 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/WorkLockActivityController.java
@@ -64,7 +64,7 @@
         options.setTaskOverlay(true, false /* canResume */);
 
         final int result = startActivityAsUser(intent, options.toBundle(), UserHandle.USER_CURRENT);
-        if (result >= ActivityManager.START_SUCCESS) {
+        if (ActivityManager.isStartResultSuccessful(result)) {
             // OK
         } else {
             // Starting the activity inside the task failed. We can't be sure why, so to be
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
index 65f24cf..766914c 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivity.java
@@ -303,7 +303,6 @@
                 mMenuContainerAnimator.cancel();
             }
             notifyMenuStateChange(menuState);
-            updateExpandButtonFromBounds(stackBounds, movementBounds);
             mMenuContainerAnimator = new AnimatorSet();
             ObjectAnimator menuAnim = ObjectAnimator.ofFloat(mMenuContainer, View.ALPHA,
                     mMenuContainer.getAlpha(), 1f);
@@ -388,24 +387,6 @@
         }
     }
 
-    private void updateExpandButtonFromBounds(Rect stackBounds, Rect movementBounds) {
-        if (stackBounds == null) {
-            return;
-        }
-
-        boolean isLandscapePip = stackBounds.width() > stackBounds.height();
-        boolean left = stackBounds.left < movementBounds.centerX();
-        boolean top = stackBounds.top < movementBounds.centerY();
-        boolean expandL = (left && top) || (!left && !top);
-        int iconResId;
-        if (isLandscapePip) {
-            iconResId = expandL ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
-        } else {
-            iconResId = expandL ? R.drawable.pip_expand_pl : R.drawable.pip_expand_pr;
-        }
-        mExpandButton.setImageResource(iconResId);
-    }
-
     private void setActions(Rect stackBounds, List<RemoteAction> actions) {
         mActions.clear();
         mActions.addAll(actions);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
index 5b54d85..30240c3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipNotification.java
@@ -168,8 +168,7 @@
     void onConfigurationChanged(Context context) {
         Resources res = context.getResources();
         mDefaultTitle = res.getString(R.string.pip_notification_unknown_title);
-        mDefaultIconResId = res.getConfiguration().getLayoutDirection() == View.LAYOUT_DIRECTION_LTR
-                        ? R.drawable.pip_expand_ll : R.drawable.pip_expand_lr;
+        mDefaultIconResId = R.drawable.pip_expand;
         if (mNotified) {
             // update notification
             notifyPipNotification();
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
index 5cf049a..3f090f8 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSFragment.java
@@ -23,6 +23,7 @@
 import android.os.Bundle;
 import android.support.annotation.VisibleForTesting;
 import android.util.Log;
+import android.view.ContextThemeWrapper;
 import android.view.LayoutInflater;
 import android.view.View;
 import android.view.View.OnClickListener;
@@ -33,6 +34,7 @@
 import com.android.systemui.Interpolators;
 import com.android.systemui.R;
 import com.android.systemui.R.id;
+import com.android.systemui.R.style;
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.qs.customize.QSCustomizer;
 import com.android.systemui.statusbar.phone.NotificationsQuickSettingsContainer;
@@ -67,6 +69,7 @@
     @Override
     public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container,
             Bundle savedInstanceState) {
+        inflater =inflater.cloneInContext(new ContextThemeWrapper(getContext(), R.style.qs_theme));
         return inflater.inflate(R.layout.qs_panel, container, false);
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/recents/Recents.java b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
index d3bd89f..72dd2da 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/Recents.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/Recents.java
@@ -324,14 +324,14 @@
 
     @Override
     public void toggleRecentApps() {
-        toggleRecents(mContext.getSystemService(WindowManager.class).getDefaultDisplay());
+        toggleRecents();
     }
 
     /**
      * Toggles the Recents activity.
      */
     @Override
-    public void toggleRecents(Display display) {
+    public void toggleRecents() {
         // Ensure the device has been provisioned before allowing the user to interact with
         // recents
         if (!isUserSetup()) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
index 7bc591f..c0e4b99 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsActivity.java
@@ -222,6 +222,10 @@
                                 getApplicationContext()).onActionEnd(
                                 LatencyTracker.ACTION_TOGGLE_RECENTS));
                     }
+                    DejankUtils.postAfterTraversal(() -> {
+                        Recents.getTaskLoader().startLoader(RecentsActivity.this);
+                        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
+                    });
                     return true;
                 }
             };
@@ -376,8 +380,6 @@
 
         // Notify of the next draw
         mRecentsView.getViewTreeObserver().addOnPreDrawListener(mRecentsDrawnEventListener);
-
-        Recents.getTaskLoader().getHighResThumbnailLoader().setVisible(true);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
index f431517..8594ec62 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -27,6 +27,7 @@
 
 import android.annotation.NonNull;
 import android.app.ActivityManager;
+import android.app.ActivityManager.StackInfo;
 import android.app.ActivityManager.TaskSnapshot;
 import android.app.ActivityOptions;
 import android.app.AppGlobals;
@@ -95,6 +96,8 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Random;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Executors;
 
 /**
  * Acts as a shim around the real system services that we need to access data from, and provides
@@ -143,6 +146,7 @@
     Canvas mBgProtectionCanvas;
 
     private final Handler mHandler = new H();
+    private final ExecutorService mOnewayExecutor = Executors.newSingleThreadExecutor();
 
     /**
      * An abstract class to track task stack changes.
@@ -466,13 +470,20 @@
         if (mIam == null) return false;
 
         try {
-            ActivityManager.StackInfo homeStackInfo = mIam.getStackInfo(
-                    ActivityManager.StackId.HOME_STACK_ID);
-            ActivityManager.StackInfo fullscreenStackInfo = mIam.getStackInfo(
-                    ActivityManager.StackId.FULLSCREEN_WORKSPACE_STACK_ID);
-            ActivityManager.StackInfo recentsStackInfo = mIam.getStackInfo(
-                    ActivityManager.StackId.RECENTS_STACK_ID);
-
+            List<StackInfo> stackInfos = mIam.getAllStackInfos();
+            ActivityManager.StackInfo homeStackInfo = null;
+            ActivityManager.StackInfo fullscreenStackInfo = null;
+            ActivityManager.StackInfo recentsStackInfo = null;
+            for (int i = 0; i < stackInfos.size(); i++) {
+                StackInfo stackInfo = stackInfos.get(i);
+                if (stackInfo.stackId == HOME_STACK_ID) {
+                    homeStackInfo = stackInfo;
+                } else if (stackInfo.stackId == FULLSCREEN_WORKSPACE_STACK_ID) {
+                    fullscreenStackInfo = stackInfo;
+                } else if (stackInfo.stackId == RECENTS_STACK_ID) {
+                    recentsStackInfo = stackInfo;
+                }
+            }
             boolean homeStackVisibleNotOccluded = isStackNotOccluded(homeStackInfo,
                     fullscreenStackInfo);
             boolean recentsStackVisibleNotOccluded = isStackNotOccluded(recentsStackInfo,
@@ -755,10 +766,12 @@
      * Sends a message to close other system windows.
      */
     public void sendCloseSystemWindows(String reason) {
-        try {
-            mIam.closeSystemDialogs(reason);
-        } catch (RemoteException e) {
-        }
+        mOnewayExecutor.submit(() -> {
+            try {
+                mIam.closeSystemDialogs(reason);
+            } catch (RemoteException e) {
+            }
+        });
     }
 
     /**
@@ -998,9 +1011,7 @@
      * Returns the current user id.
      */
     public int getCurrentUser() {
-        if (mAm == null) return 0;
-
-        return mAm.getCurrentUser();
+        return KeyguardUpdateMonitor.getCurrentUser();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
index be8da9f..974139a 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/HighResThumbnailLoader.java
@@ -50,6 +50,7 @@
     private boolean mLoading;
     private boolean mVisible;
     private boolean mFlingingFast;
+    private boolean mTaskLoadQueueIdle;
 
     public HighResThumbnailLoader(SystemServicesProxy ssp, Looper looper) {
         mMainThreadHandler = new Handler(looper);
@@ -71,13 +72,22 @@
         updateLoading();
     }
 
+    /**
+     * Sets whether the other task load queue is idling. Avoid double-loading bitmaps by not
+     * starting this queue until the other queue is idling.
+     */
+    public void setTaskLoadQueueIdle(boolean idle) {
+        mTaskLoadQueueIdle = idle;
+        updateLoading();
+    }
+
     @VisibleForTesting
     boolean isLoading() {
         return mLoading;
     }
 
     private void updateLoading() {
-        setLoading(mVisible && !mFlingingFast);
+        setLoading(mVisible && !mFlingingFast && mTaskLoadQueueIdle);
     }
 
     private void setLoading(boolean loading) {
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
index 4b53cd1..7ee0906 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoadPlan.java
@@ -33,6 +33,7 @@
 import android.util.SparseBooleanArray;
 import android.util.SparseIntArray;
 
+import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.Prefs;
 import com.android.systemui.R;
 import com.android.systemui.recents.Recents;
@@ -86,7 +87,7 @@
         mCurrentQuietProfiles.clear();
 
         if (currentUserId == UserHandle.USER_CURRENT) {
-            currentUserId = ActivityManager.getCurrentUser();
+            currentUserId = KeyguardUpdateMonitor.getCurrentUser();
         }
         UserManager userManager = (UserManager) mContext.getSystemService(Context.USER_SERVICE);
         List<UserInfo> profiles = userManager.getProfiles(currentUserId);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
index 802cb831..97a9659 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/model/RecentsTaskLoader.java
@@ -48,6 +48,7 @@
  * A Task load queue
  */
 class TaskResourceLoadQueue {
+
     ConcurrentLinkedQueue<Task> mQueue = new ConcurrentLinkedQueue<Task>();
 
     /** Adds a new task to the load queue */
@@ -104,15 +105,18 @@
     boolean mCancelled;
     boolean mWaitingOnLoadQueue;
 
+    private final OnIdleChangedListener mOnIdleChangedListener;
+
     /** Constructor, creates a new loading thread that loads task resources in the background */
     public BackgroundTaskLoader(TaskResourceLoadQueue loadQueue,
             TaskKeyLruCache<Drawable> iconCache, Bitmap defaultThumbnail,
-            BitmapDrawable defaultIcon) {
+            BitmapDrawable defaultIcon, OnIdleChangedListener onIdleChangedListener) {
         mLoadQueue = loadQueue;
         mIconCache = iconCache;
         mDefaultThumbnail = defaultThumbnail;
         mDefaultIcon = defaultIcon;
         mMainThreadHandler = new Handler();
+        mOnIdleChangedListener = onIdleChangedListener;
         mLoadThread = new HandlerThread("Recents-TaskResourceLoader",
                 android.os.Process.THREAD_PRIORITY_BACKGROUND);
         mLoadThread.start();
@@ -169,7 +173,11 @@
                     synchronized(mLoadQueue) {
                         try {
                             mWaitingOnLoadQueue = true;
+                            mMainThreadHandler.post(
+                                    () -> mOnIdleChangedListener.onIdleChanged(true));
                             mLoadQueue.wait();
+                            mMainThreadHandler.post(
+                                    () -> mOnIdleChangedListener.onIdleChanged(false));
                             mWaitingOnLoadQueue = false;
                         } catch (InterruptedException ie) {
                             ie.printStackTrace();
@@ -230,6 +238,10 @@
             }
         }
     }
+
+    interface OnIdleChangedListener {
+        void onIdleChanged(boolean idle);
+    }
 }
 
 /**
@@ -298,15 +310,16 @@
 
         // Initialize the proxy, cache and loaders
         int numRecentTasks = ActivityManager.getMaxRecentTasksStatic();
+        mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
+                Looper.getMainLooper());
         mLoadQueue = new TaskResourceLoadQueue();
         mIconCache = new TaskKeyLruCache<>(iconCacheSize, mClearActivityInfoOnEviction);
         mActivityLabelCache = new TaskKeyLruCache<>(numRecentTasks, mClearActivityInfoOnEviction);
         mContentDescriptionCache = new TaskKeyLruCache<>(numRecentTasks,
                 mClearActivityInfoOnEviction);
         mActivityInfoCache = new LruCache(numRecentTasks);
-        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon);
-        mHighResThumbnailLoader = new HighResThumbnailLoader(Recents.getSystemServices(),
-                Looper.getMainLooper());
+        mLoader = new BackgroundTaskLoader(mLoadQueue, mIconCache, mDefaultThumbnail, mDefaultIcon,
+                mHighResThumbnailLoader::setTaskLoadQueueIdle);
     }
 
     /** Returns the size of the app icon cache. */
@@ -360,9 +373,6 @@
         mTempCache.evictAll();
         if (!opts.onlyLoadForCache) {
             mNumVisibleTasksLoaded = opts.numVisibleTasks;
-
-            // Start the loader
-            mLoader.start(context);
         }
     }
 
@@ -608,6 +618,13 @@
     }
 
     /**
+     * Starts loading tasks.
+     */
+    public void startLoader(Context ctx) {
+        mLoader.start(ctx);
+    }
+
+    /**
      * Stops the task loader and clears all queued, pending task loads.
      */
     private void stopLoader() {
diff --git a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
index 8f24ec7..24a2927 100644
--- a/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
+++ b/packages/SystemUI/src/com/android/systemui/stackdivider/DividerView.java
@@ -1159,7 +1159,7 @@
      */
     public int growsRecents() {
         boolean result = mGrowRecents
-                && mWindowManagerProxy.getDockSide() == WindowManager.DOCKED_TOP
+                && mDockSide == WindowManager.DOCKED_TOP
                 && getCurrentPosition() == getSnapAlgorithm().getLastSplitTarget().position;
         if (result) {
             return getSnapAlgorithm().getMiddleTarget().position;
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
index f6bd14c..9a3de61 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/MediaNotificationProcessor.java
@@ -28,6 +28,7 @@
 import android.support.v7.graphics.Palette;
 import android.util.LayoutDirection;
 
+import com.android.internal.util.NotificationColorUtil;
 import com.android.systemui.R;
 
 import java.util.List;
@@ -120,7 +121,7 @@
                 paletteBuilder.addFilter(mBlackWhiteFilter);
                 palette = paletteBuilder.generate();
                 int foregroundColor;
-                if (ColorUtils.calculateLuminance(backgroundColor) > 0.5) {
+                if (NotificationColorUtil.isColorLight(backgroundColor)) {
                     Palette.Swatch first = palette.getDarkVibrantSwatch();
                     Palette.Swatch second = palette.getVibrantSwatch();
                     if (first != null && second != null) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
index 1fd329c..8d9d461 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/NavigationBarView.java
@@ -36,16 +36,15 @@
 import android.util.SparseArray;
 import android.view.ContextThemeWrapper;
 import android.view.Display;
-import android.view.IDockedStackListener.Stub;
 import android.view.MotionEvent;
 import android.view.Surface;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.WindowManager;
-import android.view.WindowManagerGlobal;
 import android.view.inputmethod.InputMethodManager;
 import android.widget.FrameLayout;
 
+import com.android.settingslib.Utils;
 import com.android.systemui.Dependency;
 import com.android.systemui.DockedStackExistsListener;
 import com.android.systemui.R;
@@ -336,8 +335,10 @@
             mAccessibilityIcon = getDrawable(ctx, R.drawable.ic_sysbar_accessibility_button,
                     R.drawable.ic_sysbar_accessibility_button_dark);
 
-            Context darkContext = new ContextThemeWrapper(ctx, R.style.DualToneDarkTheme);
-            Context lightContext = new ContextThemeWrapper(ctx, R.style.DualToneLightTheme);
+            int dualToneDarkTheme = Utils.getThemeAttr(ctx, R.attr.darkIconTheme);
+            int dualToneLightTheme = Utils.getThemeAttr(ctx, R.attr.lightIconTheme);
+            Context darkContext = new ContextThemeWrapper(ctx, dualToneDarkTheme);
+            Context lightContext = new ContextThemeWrapper(ctx, dualToneLightTheme);
             mImeIcon = getDrawable(darkContext, lightContext,
                     R.drawable.ic_ime_switcher_default, R.drawable.ic_ime_switcher_default);
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
index 4d632af..f57b6b3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/recents/model/HighResThumbnailLoaderTest.java
@@ -62,6 +62,7 @@
         when(mMockSystemServicesProxy.getTaskThumbnail(anyInt(), anyBoolean()))
                 .thenReturn(mThumbnailData);
         mLoader.setVisible(true);
+        mLoader.setTaskLoadQueueIdle(true);
     }
 
     @Test
@@ -75,6 +76,11 @@
         assertFalse(mLoader.isLoading());
         mLoader.setFlingingFast(false);
         assertTrue(mLoader.isLoading());
+        mLoader.setFlingingFast(false);
+        mLoader.setTaskLoadQueueIdle(false);
+        assertFalse(mLoader.isLoading());
+        mLoader.setTaskLoadQueueIdle(true);
+        assertTrue(mLoader.isLoading());
     }
 
     @Test
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 41a78a7..93b5ed5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -172,7 +172,6 @@
         startTrackingPackageChanges();
     }
 
-
     private void startTrackingPackageChanges() {
         PackageMonitor monitor = new PackageMonitor() {
             @Override
@@ -335,6 +334,7 @@
     void listSessions(int userId, IResultReceiver receiver) {
         Slog.i(TAG, "listSessions() for userId " + userId);
         mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
         final Bundle resultData = new Bundle();
         final ArrayList<String> sessions = new ArrayList<>();
 
@@ -364,6 +364,7 @@
     void reset() {
         Slog.i(TAG, "reset()");
         mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
         synchronized (mLock) {
             final int size = mServicesCache.size();
             for (int i = 0; i < size; i++) {
@@ -376,6 +377,8 @@
     // Called by Shell command.
     void setLogLevel(int level) {
         Slog.i(TAG, "setLogLevel(): " + level);
+        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
         boolean debug = false;
         boolean verbose = false;
         if (level == AutofillManager.FLAG_ADD_CLIENT_VERBOSE) {
@@ -391,6 +394,8 @@
 
     // Called by Shell command.
     int getLogLevel() {
+        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
         synchronized (mLock) {
             if (sVerbose) return AutofillManager.FLAG_ADD_CLIENT_VERBOSE;
             if (sDebug) return AutofillManager.FLAG_ADD_CLIENT_DEBUG;
@@ -400,6 +405,8 @@
 
     // Called by Shell command.
     public int getMaxPartitions() {
+        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
+
         synchronized (mLock) {
             return sPartitionMaxCount;
         }
@@ -407,6 +414,7 @@
 
     // Called by Shell command.
     public void setMaxPartitions(int max) {
+        mContext.enforceCallingPermission(MANAGE_AUTO_FILL, TAG);
         Slog.i(TAG, "setMaxPartitions(): " + max);
         synchronized (mLock) {
             sPartitionMaxCount = max;
@@ -550,18 +558,39 @@
         }
 
         @Override
-        public void updateSession(int sessionId, AutofillId id, Rect bounds,
+        public void updateSession(int sessionId, AutofillId autoFillId, Rect bounds,
                 AutofillValue value, int action, int flags, int userId) {
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
                 if (service != null) {
-                    service.updateSessionLocked(sessionId, getCallingUid(), id, bounds, value,
-                            action, flags);
+                    service.updateSessionLocked(sessionId, getCallingUid(), autoFillId, bounds,
+                            value, action, flags);
                 }
             }
         }
 
         @Override
+        public int updateOrRestartSession(IBinder activityToken, IBinder appCallback,
+                AutofillId autoFillId, Rect bounds, AutofillValue value, int userId,
+                boolean hasCallback, int flags, String packageName, int sessionId, int action) {
+            boolean restart = false;
+            synchronized (mLock) {
+                final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
+                if (service != null) {
+                    restart = service.updateSessionLocked(sessionId, getCallingUid(), autoFillId,
+                            bounds, value, action, flags);
+                }
+            }
+            if (restart) {
+                return startSession(activityToken, appCallback, autoFillId, bounds, value, userId,
+                        hasCallback, flags, packageName);
+            }
+
+            // Nothing changed...
+            return sessionId;
+        }
+
+        @Override
         public void finishSession(int sessionId, int userId) {
             synchronized (mLock) {
                 final AutofillManagerServiceImpl service = peekServiceForUserLocked(userId);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index 35371a7..2cb0bd5 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -16,6 +16,7 @@
 
 package com.android.server.autofill;
 
+import static android.service.autofill.FillRequest.FLAG_MANUAL_REQUEST;
 import static android.view.autofill.AutofillManager.ACTION_START_SESSION;
 import static android.view.autofill.AutofillManager.NO_SESSION;
 
@@ -275,7 +276,7 @@
         pruneAbandonedSessionsLocked();
 
         final Session newSession = createSessionByTokenLocked(activityToken, uid, appCallbackToken,
-                hasCallback, flags, packageName);
+                hasCallback, packageName);
         if (newSession == null) {
             return NO_SESSION;
         }
@@ -359,8 +360,7 @@
     }
 
     private Session createSessionByTokenLocked(@NonNull IBinder activityToken, int uid,
-            @NonNull IBinder appCallbackToken, boolean hasCallback, int flags,
-            @NonNull String packageName) {
+            @NonNull IBinder appCallbackToken, boolean hasCallback, @NonNull String packageName) {
         // use random ids so that one app cannot know that another app creates sessions
         int sessionId;
         int tries = 0;
@@ -402,18 +402,29 @@
         }
     }
 
-    void updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
+    /**
+     * Updates a session and returns whether it should be restarted.
+     */
+    boolean updateSessionLocked(int sessionId, int uid, AutofillId autofillId, Rect virtualBounds,
             AutofillValue value, int action, int flags) {
         final Session session = mSessions.get(sessionId);
         if (session == null || session.uid != uid) {
-            if (sVerbose) {
-                Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId + "(" + uid
-                        + ")");
+            if ((flags & FLAG_MANUAL_REQUEST) != 0) {
+                if (sDebug) {
+                    Slog.d(TAG, "restarting session " + sessionId + " due to manual request on "
+                            + autofillId);
+                }
+                return true;
             }
-            return;
+            if (sVerbose) {
+                Slog.v(TAG, "updateSessionLocked(): session gone for " + sessionId
+                        + "(" + uid + ")");
+            }
+            return false;
         }
 
         session.updateLocked(autofillId, virtualBounds, value, action, flags);
+        return false;
     }
 
     void removeSessionLocked(int sessionId) {
diff --git a/services/autofill/java/com/android/server/autofill/RemoteFillService.java b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
index 35f4fae..9aebf6d 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteFillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteFillService.java
@@ -404,10 +404,86 @@
     }
 
     private static abstract class PendingRequest implements Runnable {
-        void cancel() {
+        protected final Object mLock = new Object();
+        private final WeakReference<RemoteFillService> mWeakService;
 
+        private final Runnable mTimeoutTrigger;
+        private final Handler mServiceHandler;
+
+        @GuardedBy("mLock")
+        private boolean mCancelled;
+
+        @GuardedBy("mLock")
+        private boolean mCompleted;
+
+        PendingRequest(RemoteFillService service) {
+            mWeakService = new WeakReference<>(service);
+            mServiceHandler = service.mHandler.getHandler();
+            mTimeoutTrigger = () -> {
+                synchronized (mLock) {
+                    if (mCancelled) {
+                        return;
+                    }
+                    mCompleted = true;
+                }
+
+                final RemoteFillService remoteService = mWeakService.get();
+                if (remoteService != null) {
+                    fail(remoteService);
+                }
+            };
+            mServiceHandler.postAtTime(mTimeoutTrigger,
+                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
         }
 
+        protected RemoteFillService getService() {
+            return mWeakService.get();
+        }
+
+        /**
+         * Sub-classes must call this method when the remote service finishes, i.e., when it
+         * called {@code onFill...} or {@code onSave...}.
+         *
+         * @return {@code false} in the service is already finished, {@code true} otherwise.
+         */
+        protected final boolean finish() {
+            synchronized (mLock) {
+                if (mCompleted || mCancelled) {
+                    return false;
+                }
+                mCompleted = true;
+            }
+            mServiceHandler.removeCallbacks(mTimeoutTrigger);
+            return true;
+        }
+
+        protected boolean isCancelledLocked() {
+            return mCancelled;
+        }
+
+        /**
+         * Cancels the service.
+         *
+         * @return {@code false} if service is already canceled, {@code true} otherwise.
+         */
+        boolean cancel() {
+            synchronized (mLock) {
+                if (mCancelled || mCompleted) {
+                    return false;
+                }
+                mCancelled = true;
+            }
+
+            mServiceHandler.removeCallbacks(mTimeoutTrigger);
+            return true;
+        }
+
+        /**
+         * Called by the self-destructure timeout when the AutofilllService didn't reply to the
+         * request on time.
+         */
+        abstract void fail(RemoteFillService remoteService);
+
         /**
          * @return whether this request leads to a final state where no
          * other requests can be made.
@@ -418,22 +494,14 @@
     }
 
     private static final class PendingFillRequest extends PendingRequest {
-        private final Object mLock = new Object();
-
-        private final WeakReference<RemoteFillService> mWeakService;
         private final FillRequest mRequest;
         private final IFillCallback mCallback;
         private ICancellationSignal mCancellation;
 
-        @GuardedBy("mLock")
-        private boolean mCancelled;
-
-        @GuardedBy("mLock")
-        private boolean mCompleted;
-
         public PendingFillRequest(FillRequest request, RemoteFillService service) {
+            super(service);
             mRequest = request;
-            mWeakService = new WeakReference<>(service);
+
             mCallback = new IFillCallback.Stub() {
                 @Override
                 public void onCancellable(ICancellationSignal cancellation) {
@@ -441,7 +509,7 @@
                         final boolean cancelled;
                         synchronized (mLock) {
                             mCancellation = cancellation;
-                            cancelled = mCancelled;
+                            cancelled = isCancelledLocked();
                         }
                         if (cancelled) {
                             try {
@@ -455,15 +523,10 @@
 
                 @Override
                 public void onSuccess(FillResponse response) {
-                    synchronized (mLock) {
-                        if (mCompleted) {
-                            return;
-                        }
-                        mCompleted = true;
-                    }
-                    RemoteFillService remoteService = mWeakService.get();
+                    if (!finish()) return;
+
+                    final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
-                        service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
                         remoteService.dispatchOnFillRequestSuccess(PendingFillRequest.this,
                                 getCallingUid(), request.getFlags(), response);
                     }
@@ -471,132 +534,100 @@
 
                 @Override
                 public void onFailure(CharSequence message) {
-                    synchronized (mLock) {
-                        if (mCompleted) {
-                            return;
-                        }
-                        mCompleted = true;
-                    }
-                    RemoteFillService remoteService = mWeakService.get();
+                    if (!finish()) return;
+
+                    final RemoteFillService remoteService = getService();
                     if (remoteService != null) {
-                        service.mHandler.getHandler().removeCallbacks(PendingFillRequest.this);
                         remoteService.dispatchOnFillRequestFailure(
                                 PendingFillRequest.this, message);
                     }
                 }
             };
-            service.mHandler.getHandler().postAtTime(() -> {
-                cancel();
-                try {
-                    mCallback.onFailure(null);
-                } catch (RemoteException e) {
-                    /* ignore */
-                }
-            }, PendingFillRequest.this,
-                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
+        }
+
+        @Override
+        void fail(RemoteFillService remoteService) {
+            remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
         }
 
         @Override
         public void run() {
-            RemoteFillService remoteService = mWeakService.get();
+            final RemoteFillService remoteService = getService();
             if (remoteService != null) {
                 try {
                     remoteService.mAutoFillService.onFillRequest(mRequest, mCallback);
                 } catch (RemoteException e) {
                     Slog.e(LOG_TAG, "Error calling on fill request", e);
-                    cancel();
+
+                    remoteService.dispatchOnFillRequestFailure(PendingFillRequest.this, null);
                 }
             }
         }
 
         @Override
-        public void cancel() {
-            final ICancellationSignal cancellation;
-            synchronized (mLock) {
-                if (mCancelled) {
-                    return;
+        public boolean cancel() {
+            if (!super.cancel()) return false;
+
+            final ICancellationSignal cancellation = mCancellation;
+            if (cancellation != null) {
+                try {
+                    cancellation.cancel();
+                } catch (RemoteException e) {
+                    Slog.e(LOG_TAG, "Error cancelling a fill request", e);
                 }
-                mCancelled = true;
-                cancellation = mCancellation;
             }
-            if (cancellation == null) {
-                return;
-            }
-            try {
-                cancellation.cancel();
-            } catch (RemoteException e) {
-                Slog.e(LOG_TAG, "Error cancelling a fill request", e);
-            }
+            return true;
         }
     }
 
     private static final class PendingSaveRequest extends PendingRequest {
-        private final Object mLock = new Object();
-
-        private final WeakReference<RemoteFillService> mWeakService;
         private final SaveRequest mRequest;
         private final ISaveCallback mCallback;
 
-        @GuardedBy("mLock")
-        private boolean mCompleted;
-
         public PendingSaveRequest(@NonNull SaveRequest request,
                 @NonNull RemoteFillService service) {
+            super(service);
             mRequest = request;
-            mWeakService = new WeakReference<>(service);
+
             mCallback = new ISaveCallback.Stub() {
                 @Override
                 public void onSuccess() {
-                    synchronized (mLock) {
-                        if (mCompleted) {
-                            return;
-                        }
-                        mCompleted = true;
-                    }
-                    cancel();
-                    RemoteFillService service = mWeakService.get();
-                    if (service != null) {
-                        service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
-                        service.dispatchOnSaveRequestSuccess(
-                                PendingSaveRequest.this);
+                    if (!finish()) return;
+
+                    final RemoteFillService remoteService = getService();
+                    if (remoteService != null) {
+                        remoteService.dispatchOnSaveRequestSuccess(PendingSaveRequest.this);
                     }
                 }
 
                 @Override
                 public void onFailure(CharSequence message) {
-                    synchronized (mLock) {
-                        if (mCompleted) {
-                            return;
-                        }
-                        mCompleted = true;
-                    }
-                    RemoteFillService service = mWeakService.get();
-                    if (service != null) {
-                        service.mHandler.getHandler().removeCallbacks(PendingSaveRequest.this);
-                        service.dispatchOnSaveRequestFailure(
-                                PendingSaveRequest.this, message);
+                    if (!finish()) return;
+
+                    final RemoteFillService remoteService = getService();
+                    if (remoteService != null) {
+                        remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this,
+                                message);
                     }
                 }
             };
-            service.mHandler.getHandler().postAtTime(() -> {
-                cancel();
-                try {
-                    mCallback.onFailure(null);
-                } catch (RemoteException e) {
-                    /* ignore */
-                }
-            }, PendingSaveRequest.this,
-                    SystemClock.uptimeMillis() + TIMEOUT_REMOTE_REQUEST_MILLIS);
+        }
+
+        @Override
+        void fail(RemoteFillService remoteService) {
+            remoteService.dispatchOnSaveRequestFailure(PendingSaveRequest.this, null);
         }
 
         @Override
         public void run() {
-            final RemoteFillService service = mWeakService.get();
-            if (service != null) {
+            final RemoteFillService remoteService = getService();
+            if (remoteService != null) {
                 try {
-                    service.mAutoFillService.onSaveRequest(mRequest, mCallback);
+                    remoteService.mAutoFillService.onSaveRequest(mRequest, mCallback);
                 } catch (RemoteException e) {
                     Slog.e(LOG_TAG, "Error calling on save request", e);
+
+                    remoteService.dispatchOnFillRequestFailure(PendingSaveRequest.this, null);
                 }
             }
         }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 6d58e72..0122301 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -818,6 +818,7 @@
                 }
             }
             if (atLeastOneChanged) {
+                if (sDebug) Slog.d(TAG, "at least one field changed - showing save UI");
                 mService.setSaveShown();
                 getUiForShowing().showSaveUi(mService.getServiceLabel(), saveInfo, mPackageName,
                         this);
@@ -887,7 +888,7 @@
 
             if (sVerbose) {
                 Slog.v(TAG, "Dumping structure of " + context + " before calling service.save()");
-                context.getStructure().dump();
+                context.getStructure().dump(false);
             }
         }
 
@@ -1401,7 +1402,7 @@
                     pw.println(context.getStructure() + " (look at logcat)");
 
                     // TODO: add method on AssistStructure to dump on pw
-                    context.getStructure().dump();
+                    context.getStructure().dump(false);
                 }
             }
         } else {
diff --git a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
index 4f69f64..c3d55054 100644
--- a/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
+++ b/services/autofill/java/com/android/server/autofill/ui/AutoFillUI.java
@@ -16,6 +16,7 @@
 package com.android.server.autofill.ui;
 
 import static com.android.server.autofill.Helper.sDebug;
+import static com.android.server.autofill.Helper.sVerbose;
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
@@ -108,6 +109,8 @@
      * Displays an error message to the user.
      */
     public void showError(@Nullable CharSequence message, @NonNull AutoFillUiCallback callback) {
+        Slog.w(TAG, "showError(): " + message);
+
         mHandler.post(() -> {
             if (mCallback != callback) {
                 return;
@@ -237,6 +240,7 @@
      */
     public void showSaveUi(@NonNull CharSequence providerLabel, @NonNull SaveInfo info,
             @NonNull String packageName, @NonNull AutoFillUiCallback callback) {
+        if (sVerbose) Slog.v(TAG, "showSaveUi() for " + packageName + ": " + info);
         int numIds = 0;
         numIds += info.getRequiredIds() == null ? 0 : info.getRequiredIds().length;
         numIds += info.getOptionalIds() == null ? 0 : info.getOptionalIds().length;
diff --git a/services/backup/java/com/android/server/backup/BackupManagerService.java b/services/backup/java/com/android/server/backup/BackupManagerService.java
index 3f8d508..30de4ba 100644
--- a/services/backup/java/com/android/server/backup/BackupManagerService.java
+++ b/services/backup/java/com/android/server/backup/BackupManagerService.java
@@ -790,6 +790,11 @@
             return false;
         }
 
+        // 4. it is an "instant" app
+        if (app.isInstantApp()) {
+            return false;
+        }
+
         // Everything else checks out; the only remaining roadblock would be if the
         // package were disabled
         return !appIsDisabled(app, pm);
diff --git a/services/core/java/com/android/server/UiModeManagerService.java b/services/core/java/com/android/server/UiModeManagerService.java
index 04421cc..6b5366a 100644
--- a/services/core/java/com/android/server/UiModeManagerService.java
+++ b/services/core/java/com/android/server/UiModeManagerService.java
@@ -640,7 +640,7 @@
                     int result = ActivityManager.getService().startActivityWithConfig(
                             null, null, homeIntent, null, null, null, 0, 0,
                             mConfiguration, null, UserHandle.USER_CURRENT);
-                    if (result >= ActivityManager.START_SUCCESS) {
+                    if (ActivityManager.isStartResultSuccessful(result)) {
                         dockAppStarted = true;
                     } else if (result != ActivityManager.START_INTENT_NOT_RESOLVED) {
                         Slog.e(TAG, "Could not start dock app: " + homeIntent
diff --git a/services/core/java/com/android/server/am/ActivityManagerService.java b/services/core/java/com/android/server/am/ActivityManagerService.java
index e585f7b..df32089 100644
--- a/services/core/java/com/android/server/am/ActivityManagerService.java
+++ b/services/core/java/com/android/server/am/ActivityManagerService.java
@@ -5391,8 +5391,9 @@
             boolean doLowMem = app.instr == null;
             boolean doOomAdj = doLowMem;
             if (!app.killedByAm) {
-                Slog.i(TAG, "Process " + app.processName + " (pid " + pid
-                        + ") has died");
+                Slog.i(TAG, "Process " + app.processName + " (pid " + pid + ") has died: "
+                        + ProcessList.makeOomAdjString(app.setAdj)
+                        + ProcessList.makeProcStateString(app.setProcState));
                 mAllowLowerMemLevel = true;
             } else {
                 // Note that we always want to do oom adj to update our state with the
@@ -5400,7 +5401,8 @@
                 mAllowLowerMemLevel = false;
                 doLowMem = false;
             }
-            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName);
+            EventLog.writeEvent(EventLogTags.AM_PROC_DIED, app.userId, app.pid, app.processName,
+                    app.setAdj, app.setProcState);
             if (DEBUG_CLEANUP) Slog.v(TAG_CLEANUP,
                 "Dying app: " + app + ", pid: " + pid + ", thread: " + thread.asBinder());
             handleAppDiedLocked(app, false, true);
diff --git a/services/core/java/com/android/server/am/ActivityStarter.java b/services/core/java/com/android/server/am/ActivityStarter.java
index 6d4eb5b..a2eec5c 100644
--- a/services/core/java/com/android/server/am/ActivityStarter.java
+++ b/services/core/java/com/android/server/am/ActivityStarter.java
@@ -544,7 +544,7 @@
             ActivityRecord r, int result, int prevFocusedStackId, ActivityRecord sourceRecord,
             ActivityStack targetStack) {
 
-        if (result < START_SUCCESS) {
+        if (ActivityManager.isStartResultFatalError(result)) {
             return;
         }
 
@@ -956,7 +956,8 @@
             // If we are not able to proceed, disassociate the activity from the task. Leaving an
             // activity in an incomplete state can lead to issues, such as performing operations
             // without a window container.
-            if (result < START_SUCCESS && mStartActivity.getTask() != null) {
+            if (ActivityManager.isStartResultFatalError(result)
+                    && mStartActivity.getTask() != null) {
                 mStartActivity.getTask().removeActivity(mStartActivity);
             }
             mService.mWindowManager.continueSurfaceLayout();
diff --git a/services/core/java/com/android/server/am/EventLogTags.logtags b/services/core/java/com/android/server/am/EventLogTags.logtags
index 372ab6b..b2d3137 100644
--- a/services/core/java/com/android/server/am/EventLogTags.logtags
+++ b/services/core/java/com/android/server/am/EventLogTags.logtags
@@ -34,7 +34,7 @@
 # Application process bound to work
 30010 am_proc_bound (User|1|5),(PID|1|5),(Process Name|3)
 # Application process died
-30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3)
+30011 am_proc_died (User|1|5),(PID|1|5),(Process Name|3),(OomAdj|1|5),(ProcState|1|5)
 # The Activity Manager failed to pause the given activity.
 30012 am_failed_to_pause (User|1|5),(Token|1|5),(Wanting to pause|3),(Currently pausing|3)
 # Attempting to pause the current activity
diff --git a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
index fe49813..4fc6ddd 100644
--- a/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
+++ b/services/core/java/com/android/server/fingerprint/AuthenticationClient.java
@@ -34,8 +34,13 @@
 public abstract class AuthenticationClient extends ClientMonitor {
     private long mOpId;
 
-    public abstract boolean handleFailedAttempt();
+    public abstract int handleFailedAttempt();
     public abstract void resetFailedAttempts();
+
+    public static final int LOCKOUT_NONE = 0;
+    public static final int LOCKOUT_TIMED = 1;
+    public static final int LOCKOUT_PERMANENT = 2;
+
     private boolean mAlreadyCancelled;
 
     public AuthenticationClient(Context context, long halDeviceId, IBinder token,
@@ -79,19 +84,21 @@
                 FingerprintUtils.vibrateFingerprintError(getContext());
             }
             // allow system-defined limit of number of attempts before giving up
-            boolean inLockoutMode =  handleFailedAttempt();
-            // send lockout event in case driver doesn't enforce it.
-            if (inLockoutMode) {
+            int lockoutMode =  handleFailedAttempt();
+            if (lockoutMode != LOCKOUT_NONE) {
                 try {
-                    Slog.w(TAG, "Forcing lockout (fp driver code should do this!)");
-                    stop(false); // cancel fingerprint authentication
-                    receiver.onError(getHalDeviceId(),
-                            FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */);
+                    Slog.w(TAG, "Forcing lockout (fp driver code should do this!), mode(" +
+                            lockoutMode + ")");
+                    stop(false);
+                    int errorCode = lockoutMode == LOCKOUT_TIMED ?
+                            FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
+                            FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+                    receiver.onError(getHalDeviceId(), errorCode, 0 /* vendorCode */);
                 } catch (RemoteException e) {
                     Slog.w(TAG, "Failed to notify lockout:", e);
                 }
             }
-            result |= inLockoutMode;
+            result |= lockoutMode != LOCKOUT_NONE; // in a lockout mode
         } else {
             if (receiver != null) {
                 FingerprintUtils.vibrateFingerprintSuccess(getContext());
diff --git a/services/core/java/com/android/server/fingerprint/FingerprintService.java b/services/core/java/com/android/server/fingerprint/FingerprintService.java
index 6f5b028..6cc7071 100644
--- a/services/core/java/com/android/server/fingerprint/FingerprintService.java
+++ b/services/core/java/com/android/server/fingerprint/FingerprintService.java
@@ -108,6 +108,7 @@
         int acquire; // total number of acquisitions. Should be >= accept+reject due to poor image
                      // acquisition in some cases (too fast, too slow, dirty sensor, etc.)
         int lockout; // total number of lockouts
+        int permanentLockout; // total number of permanent lockouts
     }
 
     private final ArrayList<FingerprintServiceLockoutResetMonitor> mLockoutMonitors =
@@ -118,13 +119,16 @@
             Collections.synchronizedMap(new HashMap<>());
     private final AppOpsManager mAppOps;
     private static final long FAIL_LOCKOUT_TIMEOUT_MS = 30*1000;
-    private static final int MAX_FAILED_ATTEMPTS = 5;
+    private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED = 5;
+    private static final int MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT = 20;
+
     private static final long CANCEL_TIMEOUT_LIMIT = 3000; // max wait for onCancel() from HAL,in ms
     private final String mKeyguardPackage;
     private int mCurrentUserId = UserHandle.USER_NULL;
     private final FingerprintUtils mFingerprintUtils = FingerprintUtils.getInstance();
     private Context mContext;
     private long mHalDeviceId;
+    private boolean mTimedLockoutCleared;
     private int mFailedAttempts;
     @GuardedBy("this")
     private IBiometricsFingerprint mDaemon;
@@ -173,7 +177,7 @@
         @Override
         public void onReceive(Context context, Intent intent) {
             if (ACTION_LOCKOUT_RESET.equals(intent.getAction())) {
-                resetFailedAttempts();
+                resetFailedAttempts(false /* clearAttemptCounter */);
             }
         }
     };
@@ -181,7 +185,7 @@
     private final Runnable mResetFailedAttemptsRunnable = new Runnable() {
         @Override
         public void run() {
-            resetFailedAttempts();
+            resetFailedAttempts(true /* clearAttemptCounter */);
         }
     };
 
@@ -369,6 +373,7 @@
         if (client != null && client.onError(error, vendorCode)) {
             removeClient(client);
         }
+
         if (DEBUG) Slog.v(TAG, "handleError(client="
                 + (client != null ? client.getOwnerString() : "null") + ", error = " + error + ")");
         // This is the magic code that starts the next client when the old client finishes.
@@ -438,7 +443,7 @@
         if (client != null && client.onAcquired(acquiredInfo, vendorCode)) {
             removeClient(client);
         }
-        if (mPerformanceStats != null && !inLockoutMode()
+        if (mPerformanceStats != null && getLockoutMode() == AuthenticationClient.LOCKOUT_NONE
                 && client instanceof AuthenticationClient) {
             // ignore enrollment acquisitions or acquisitions when we're locked out
             mPerformanceStats.acquire++;
@@ -482,8 +487,14 @@
         }
     }
 
-    private boolean inLockoutMode() {
-        return mFailedAttempts >= MAX_FAILED_ATTEMPTS;
+    private int getLockoutMode() {
+        if (mFailedAttempts >= MAX_FAILED_ATTEMPTS_LOCKOUT_PERMANENT) {
+            return AuthenticationClient.LOCKOUT_PERMANENT;
+        } else if (mFailedAttempts > 0 && mTimedLockoutCleared == false &&
+                (mFailedAttempts % MAX_FAILED_ATTEMPTS_LOCKOUT_TIMED == 0)) {
+            return AuthenticationClient.LOCKOUT_TIMED;
+        }
+        return AuthenticationClient.LOCKOUT_NONE;
     }
 
     private void scheduleLockoutReset() {
@@ -801,22 +812,27 @@
         AuthenticationClient client = new AuthenticationClient(getContext(), mHalDeviceId, token,
                 receiver, mCurrentUserId, groupId, opId, restricted, opPackageName) {
             @Override
-            public boolean handleFailedAttempt() {
+            public int handleFailedAttempt() {
                 mFailedAttempts++;
-                if (mFailedAttempts == MAX_FAILED_ATTEMPTS) {
+                mTimedLockoutCleared = false;
+                final int lockoutMode = getLockoutMode();
+                if (lockoutMode == AuthenticationClient.LOCKOUT_PERMANENT) {
+                    mPerformanceStats.permanentLockout++;
+                } else if (lockoutMode == AuthenticationClient.LOCKOUT_TIMED) {
                     mPerformanceStats.lockout++;
                 }
-                if (inLockoutMode()) {
-                    // Failing multiple times will continue to push out the lockout time.
+
+                // Failing multiple times will continue to push out the lockout time
+                if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
                     scheduleLockoutReset();
-                    return true;
+                    return lockoutMode;
                 }
-                return false;
+                return AuthenticationClient.LOCKOUT_NONE;
             }
 
             @Override
             public void resetFailedAttempts() {
-                FingerprintService.this.resetFailedAttempts();
+                FingerprintService.this.resetFailedAttempts(true /* clearAttemptCounter */);
             }
 
             @Override
@@ -830,11 +846,15 @@
             }
         };
 
-        if (inLockoutMode()) {
-            Slog.v(TAG, "In lockout mode; disallowing authentication");
-            // Don't bother starting the client. Just send the error message.
-            if (!client.onError(FingerprintManager.FINGERPRINT_ERROR_LOCKOUT, 0 /* vendorCode */)) {
-                Slog.w(TAG, "Cannot send timeout message to client");
+        int lockoutMode = getLockoutMode();
+        if (lockoutMode != AuthenticationClient.LOCKOUT_NONE) {
+            Slog.v(TAG, "In lockout mode(" + lockoutMode +
+                    ") ; disallowing authentication");
+            int errorCode = lockoutMode == AuthenticationClient.LOCKOUT_TIMED ?
+                    FingerprintManager.FINGERPRINT_ERROR_LOCKOUT :
+                    FingerprintManager.FINGERPRINT_ERROR_LOCKOUT_PERMANENT;
+            if (!client.onError(errorCode, 0 /* vendorCode */)) {
+                Slog.w(TAG, "Cannot send permanent lockout message to client");
             }
             return;
         }
@@ -864,11 +884,16 @@
         startClient(client, true /* initiatedByClient */);
     }
 
-    protected void resetFailedAttempts() {
-        if (DEBUG && inLockoutMode()) {
-            Slog.v(TAG, "Reset fingerprint lockout");
+    // attempt counter should only be cleared when Keyguard goes away or when
+    // a fingerprint is successfully authenticated
+    protected void resetFailedAttempts(boolean clearAttemptCounter) {
+        if (DEBUG && getLockoutMode() != AuthenticationClient.LOCKOUT_NONE) {
+            Slog.v(TAG, "Reset fingerprint lockout, clearAttemptCounter=" + clearAttemptCounter);
         }
-        mFailedAttempts = 0;
+        if (clearAttemptCounter) {
+            mFailedAttempts = 0;
+        }
+        mTimedLockoutCleared = true;
         // If we're asked to reset failed attempts externally (i.e. from Keyguard),
         // the alarm might still be pending; remove it.
         cancelLockoutReset();
@@ -1301,6 +1326,7 @@
                 set.put("reject", (stats != null) ? stats.reject : 0);
                 set.put("acquire", (stats != null) ? stats.acquire : 0);
                 set.put("lockout", (stats != null) ? stats.lockout : 0);
+                set.put("permanentLockout", (stats != null) ? stats.permanentLockout : 0);
                 // cryptoStats measures statistics about secure fingerprint transactions
                 // (e.g. to unlock password storage, make secure purchases, etc.)
                 set.put("acceptCrypto", (cryptoStats != null) ? cryptoStats.accept : 0);
@@ -1336,6 +1362,7 @@
                 proto.write(FingerprintActionStatsProto.REJECT, normal.reject);
                 proto.write(FingerprintActionStatsProto.ACQUIRE, normal.acquire);
                 proto.write(FingerprintActionStatsProto.LOCKOUT, normal.lockout);
+                proto.write(FingerprintActionStatsProto.LOCKOUT_PERMANENT, normal.lockout);
                 proto.end(countsToken);
             }
 
@@ -1348,6 +1375,7 @@
                 proto.write(FingerprintActionStatsProto.REJECT, crypto.reject);
                 proto.write(FingerprintActionStatsProto.ACQUIRE, crypto.acquire);
                 proto.write(FingerprintActionStatsProto.LOCKOUT, crypto.lockout);
+                proto.write(FingerprintActionStatsProto.LOCKOUT_PERMANENT, crypto.lockout);
                 proto.end(countsToken);
             }
 
diff --git a/services/core/java/com/android/server/job/JobSchedulerService.java b/services/core/java/com/android/server/job/JobSchedulerService.java
index e2c1274..c08f866 100644
--- a/services/core/java/com/android/server/job/JobSchedulerService.java
+++ b/services/core/java/com/android/server/job/JobSchedulerService.java
@@ -218,6 +218,11 @@
         private static final String KEY_BG_MODERATE_JOB_COUNT = "bg_moderate_job_count";
         private static final String KEY_BG_LOW_JOB_COUNT = "bg_low_job_count";
         private static final String KEY_BG_CRITICAL_JOB_COUNT = "bg_critical_job_count";
+        private static final String KEY_MAX_STANDARD_RESCHEDULE_COUNT
+                = "max_standard_reschedule_count";
+        private static final String KEY_MAX_WORK_RESCHEDULE_COUNT = "max_work_reschedule_count";
+        private static final String KEY_MIN_LINEAR_BACKOFF_TIME = "min_linear_backoff_time";
+        private static final String KEY_MIN_EXP_BACKOFF_TIME = "min_exp_backoff_time";
 
         private static final int DEFAULT_MIN_IDLE_COUNT = 1;
         private static final int DEFAULT_MIN_CHARGING_COUNT = 1;
@@ -233,6 +238,10 @@
         private static final int DEFAULT_BG_MODERATE_JOB_COUNT = 4;
         private static final int DEFAULT_BG_LOW_JOB_COUNT = 1;
         private static final int DEFAULT_BG_CRITICAL_JOB_COUNT = 1;
+        private static final int DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT = Integer.MAX_VALUE;
+        private static final int DEFAULT_MAX_WORK_RESCHEDULE_COUNT = Integer.MAX_VALUE;
+        private static final long DEFAULT_MIN_LINEAR_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
+        private static final long DEFAULT_MIN_EXP_BACKOFF_TIME = JobInfo.MIN_BACKOFF_MILLIS;
 
         /**
          * Minimum # of idle jobs that must be ready in order to force the JMS to schedule things
@@ -303,6 +312,24 @@
          * memory state.
          */
         int BG_CRITICAL_JOB_COUNT = DEFAULT_BG_CRITICAL_JOB_COUNT;
+        /**
+         * The maximum number of times we allow a job to have itself rescheduled before
+         * giving up on it, for standard jobs.
+         */
+        int MAX_STANDARD_RESCHEDULE_COUNT = DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT;
+        /**
+         * The maximum number of times we allow a job to have itself rescheduled before
+         * giving up on it, for jobs that are executing work.
+         */
+        int MAX_WORK_RESCHEDULE_COUNT = DEFAULT_MAX_WORK_RESCHEDULE_COUNT;
+        /**
+         * The minimum backoff time to allow for linear backoff.
+         */
+        long MIN_LINEAR_BACKOFF_TIME = DEFAULT_MIN_LINEAR_BACKOFF_TIME;
+        /**
+         * The minimum backoff time to allow for exponential backoff.
+         */
+        long MIN_EXP_BACKOFF_TIME = DEFAULT_MIN_EXP_BACKOFF_TIME;
 
         private ContentResolver mResolver;
         private final KeyValueListParser mParser = new KeyValueListParser(',');
@@ -374,6 +401,14 @@
                 if ((FG_JOB_COUNT+BG_CRITICAL_JOB_COUNT) > MAX_JOB_CONTEXTS_COUNT) {
                     BG_CRITICAL_JOB_COUNT = MAX_JOB_CONTEXTS_COUNT - FG_JOB_COUNT;
                 }
+                MAX_STANDARD_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_STANDARD_RESCHEDULE_COUNT,
+                        DEFAULT_MAX_STANDARD_RESCHEDULE_COUNT);
+                MAX_WORK_RESCHEDULE_COUNT = mParser.getInt(KEY_MAX_WORK_RESCHEDULE_COUNT,
+                        DEFAULT_MAX_WORK_RESCHEDULE_COUNT);
+                MIN_LINEAR_BACKOFF_TIME = mParser.getLong(KEY_MIN_LINEAR_BACKOFF_TIME,
+                        DEFAULT_MIN_LINEAR_BACKOFF_TIME);
+                MIN_EXP_BACKOFF_TIME = mParser.getLong(KEY_MIN_EXP_BACKOFF_TIME,
+                        DEFAULT_MIN_EXP_BACKOFF_TIME);
             }
         }
 
@@ -421,11 +456,38 @@
 
             pw.print("    "); pw.print(KEY_BG_CRITICAL_JOB_COUNT); pw.print("=");
             pw.print(BG_CRITICAL_JOB_COUNT); pw.println();
+
+            pw.print("    "); pw.print(KEY_MAX_STANDARD_RESCHEDULE_COUNT); pw.print("=");
+            pw.print(MAX_STANDARD_RESCHEDULE_COUNT); pw.println();
+
+            pw.print("    "); pw.print(KEY_MAX_WORK_RESCHEDULE_COUNT); pw.print("=");
+            pw.print(MAX_WORK_RESCHEDULE_COUNT); pw.println();
+
+            pw.print("    "); pw.print(KEY_MIN_LINEAR_BACKOFF_TIME); pw.print("=");
+            pw.print(MIN_LINEAR_BACKOFF_TIME); pw.println();
+
+            pw.print("    "); pw.print(KEY_MIN_EXP_BACKOFF_TIME); pw.print("=");
+            pw.print(MIN_EXP_BACKOFF_TIME); pw.println();
         }
     }
 
     final Constants mConstants;
 
+    static final Comparator<JobStatus> mEnqueueTimeComparator = (o1, o2) -> {
+        if (o1.enqueueTime < o2.enqueueTime) {
+            return -1;
+        }
+        return o1.enqueueTime > o2.enqueueTime ? 1 : 0;
+    };
+
+    static <T> void addOrderedItem(ArrayList<T> array, T newItem, Comparator<T> comparator) {
+        int where = Collections.binarySearch(array, newItem, comparator);
+        if (where < 0) {
+            where = ~where;
+        }
+        array.add(where, newItem);
+    }
+
     /**
      * Cleans up outstanding jobs when a package is removed. Even if it's being replaced later we
      * still clean up. On reinstall the package will have a new uid.
@@ -647,7 +709,7 @@
                 // This is a new job, we can just immediately put it on the pending
                 // list and try to run it.
                 mJobPackageTracker.notePending(jobStatus);
-                mPendingJobs.add(jobStatus);
+                addOrderedItem(mPendingJobs, jobStatus, mEnqueueTimeComparator);
                 maybeRunPendingJobsLocked();
             }
         }
@@ -771,7 +833,7 @@
                 // except those using the idle exemption flag.
                 for (int i=0; i<mActiveServices.size(); i++) {
                     JobServiceContext jsc = mActiveServices.get(i);
-                    final JobStatus executing = jsc.getRunningJob();
+                    final JobStatus executing = jsc.getRunningJobLocked();
                     if (executing != null
                             && (executing.getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0) {
                         jsc.cancelExecutingJobLocked(JobParameters.REASON_DEVICE_IDLE);
@@ -798,7 +860,7 @@
         if (mPendingJobs.size() <= 0) {
             for (int i=0; i<mActiveServices.size(); i++) {
                 final JobServiceContext jsc = mActiveServices.get(i);
-                final JobStatus job = jsc.getRunningJob();
+                final JobStatus job = jsc.getRunningJobLocked();
                 if (job != null
                         && (job.getJob().getFlags() & JobInfo.FLAG_WILL_BE_FOREGROUND) == 0
                         && !job.dozeWhitelisted) {
@@ -918,6 +980,7 @@
         if (!jobStatus.isPreparedLocked()) {
             Slog.wtf(TAG, "Not yet prepared when started tracking: " + jobStatus);
         }
+        jobStatus.enqueueTime = SystemClock.elapsedRealtime();
         final boolean update = mJobs.add(jobStatus);
         if (mReadyToRock) {
             for (int i = 0; i < mControllers.size(); i++) {
@@ -953,7 +1016,7 @@
     private boolean stopJobOnServiceContextLocked(JobStatus job, int reason) {
         for (int i=0; i<mActiveServices.size(); i++) {
             JobServiceContext jsc = mActiveServices.get(i);
-            final JobStatus executing = jsc.getRunningJob();
+            final JobStatus executing = jsc.getRunningJobLocked();
             if (executing != null && executing.matches(job.getUid(), job.getJobId())) {
                 jsc.cancelExecutingJobLocked(reason);
                 return true;
@@ -970,11 +1033,7 @@
     private boolean isCurrentlyActiveLocked(JobStatus job) {
         for (int i=0; i<mActiveServices.size(); i++) {
             JobServiceContext serviceContext = mActiveServices.get(i);
-            // The 'unsafe' direct-internal-reference running-job inspector is okay to
-            // use here because we are already holding the necessary lock *and* we
-            // immediately discard the returned object reference, if any; we return
-            // only a boolean state indicator to the caller.
-            final JobStatus running = serviceContext.getRunningJobUnsafeLocked();
+            final JobStatus running = serviceContext.getRunningJobLocked();
             if (running != null && running.matches(job.getUid(), job.getJobId())) {
                 return true;
             }
@@ -1016,18 +1075,38 @@
         final int backoffAttempts = failureToReschedule.getNumFailures() + 1;
         long delayMillis;
 
+        if (failureToReschedule.hasWorkLocked()) {
+            if (backoffAttempts > mConstants.MAX_WORK_RESCHEDULE_COUNT) {
+                Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
+                        + backoffAttempts + " > work limit "
+                        + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
+                return null;
+            }
+        } else if (backoffAttempts > mConstants.MAX_STANDARD_RESCHEDULE_COUNT) {
+            Slog.w(TAG, "Not rescheduling " + failureToReschedule + ": attempt #"
+                    + backoffAttempts + " > std limit " + mConstants.MAX_STANDARD_RESCHEDULE_COUNT);
+            return null;
+        }
+
         switch (job.getBackoffPolicy()) {
-            case JobInfo.BACKOFF_POLICY_LINEAR:
-                delayMillis = initialBackoffMillis * backoffAttempts;
-                break;
+            case JobInfo.BACKOFF_POLICY_LINEAR: {
+                long backoff = initialBackoffMillis;
+                if (backoff < mConstants.MIN_LINEAR_BACKOFF_TIME) {
+                    backoff = mConstants.MIN_LINEAR_BACKOFF_TIME;
+                }
+                delayMillis = backoff * backoffAttempts;
+            } break;
             default:
                 if (DEBUG) {
                     Slog.v(TAG, "Unrecognised back-off policy, defaulting to exponential.");
                 }
-            case JobInfo.BACKOFF_POLICY_EXPONENTIAL:
-                delayMillis =
-                        (long) Math.scalb(initialBackoffMillis, backoffAttempts - 1);
-                break;
+            case JobInfo.BACKOFF_POLICY_EXPONENTIAL: {
+                long backoff = initialBackoffMillis;
+                if (backoff < mConstants.MIN_EXP_BACKOFF_TIME) {
+                    backoff = mConstants.MIN_EXP_BACKOFF_TIME;
+                }
+                delayMillis = (long) Math.scalb(backoff, backoffAttempts - 1);
+            } break;
         }
         delayMillis =
                 Math.min(delayMillis, JobInfo.MAX_BACKOFF_DELAY_MILLIS);
@@ -1163,7 +1242,7 @@
                         // state is such that all ready jobs should be run immediately.
                         if (runNow != null && isReadyToBeExecutedLocked(runNow)) {
                             mJobPackageTracker.notePending(runNow);
-                            mPendingJobs.add(runNow);
+                            addOrderedItem(mPendingJobs, runNow, mEnqueueTimeComparator);
                         } else {
                             queueReadyJobsForExecutionLocked();
                         }
@@ -1237,6 +1316,9 @@
             if (newReadyJobs != null) {
                 noteJobsPending(newReadyJobs);
                 mPendingJobs.addAll(newReadyJobs);
+                if (mPendingJobs.size() > 1) {
+                    mPendingJobs.sort(mEnqueueTimeComparator);
+                }
             }
             newReadyJobs = null;
         }
@@ -1326,6 +1408,9 @@
                 }
                 noteJobsPending(runnableJobs);
                 mPendingJobs.addAll(runnableJobs);
+                if (mPendingJobs.size() > 1) {
+                    mPendingJobs.sort(mEnqueueTimeComparator);
+                }
             } else {
                 if (DEBUG) {
                     Slog.d(TAG, "maybeQueueReadyJobsForExecutionLocked: Not running anything.");
@@ -1515,7 +1600,7 @@
         int numForeground = 0;
         for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
             final JobServiceContext js = mActiveServices.get(i);
-            final JobStatus status = js.getRunningJob();
+            final JobStatus status = js.getRunningJobLocked();
             if ((contextIdToJobMap[i] = status) != null) {
                 numActive++;
                 if (status.lastEvaluatedPriority >= JobInfo.PRIORITY_TOP_APP) {
@@ -1591,10 +1676,10 @@
         for (int i=0; i<MAX_JOB_CONTEXTS_COUNT; i++) {
             boolean preservePreferredUid = false;
             if (act[i]) {
-                JobStatus js = mActiveServices.get(i).getRunningJob();
+                JobStatus js = mActiveServices.get(i).getRunningJobLocked();
                 if (js != null) {
                     if (DEBUG) {
-                        Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJob());
+                        Slog.d(TAG, "preempting job: " + mActiveServices.get(i).getRunningJobLocked());
                     }
                     // preferredUid will be set to uid of currently running job.
                     mActiveServices.get(i).preemptExecutingJobLocked();
@@ -2099,7 +2184,7 @@
                         continue;
                     }
 
-                    job.dump(pw, "    ", true);
+                    job.dump(pw, "    ", true, now);
                     pw.print("    Ready: ");
                     pw.print(isReadyToBeExecutedLocked(job));
                     pw.print(" (job=");
@@ -2169,22 +2254,22 @@
                 JobStatus job = mPendingJobs.get(i);
                 pw.print("  Pending #"); pw.print(i); pw.print(": ");
                 pw.println(job.toShortString());
-                job.dump(pw, "    ", false);
+                job.dump(pw, "    ", false, now);
                 int priority = evaluateJobPriorityLocked(job);
                 if (priority != JobInfo.PRIORITY_DEFAULT) {
                     pw.print("    Evaluated priority: "); pw.println(priority);
                 }
                 pw.print("    Tag: "); pw.println(job.getTag());
                 pw.print("    Enq: ");
-                TimeUtils.formatDuration(now - job.madePending, pw);
-                pw.println(" ago");
+                TimeUtils.formatDuration(job.madePending - now, pw);
+                pw.println();
             }
             pw.println();
             pw.println("Active jobs:");
             for (int i=0; i<mActiveServices.size(); i++) {
                 JobServiceContext jsc = mActiveServices.get(i);
                 pw.print("  Slot #"); pw.print(i); pw.print(": ");
-                final JobStatus job = jsc.getRunningJob();
+                final JobStatus job = jsc.getRunningJobLocked();
                 if (job == null) {
                     pw.println("inactive");
                     continue;
@@ -2195,13 +2280,14 @@
                     pw.print(", timeout at: ");
                     TimeUtils.formatDuration(jsc.getTimeoutElapsed() - now, pw);
                     pw.println();
-                    job.dump(pw, "    ", false);
-                    int priority = evaluateJobPriorityLocked(jsc.getRunningJob());
+                    job.dump(pw, "    ", false, now);
+                    int priority = evaluateJobPriorityLocked(jsc.getRunningJobLocked());
                     if (priority != JobInfo.PRIORITY_DEFAULT) {
                         pw.print("    Evaluated priority: "); pw.println(priority);
                     }
-                    pw.print("    Active at "); pw.println(job.madeActive);
-                    pw.print("    Pending for ");
+                    pw.print("    Active at ");
+                    TimeUtils.formatDuration(job.madeActive - now, pw);
+                    pw.print(", pending for ");
                     TimeUtils.formatDuration(job.madeActive - job.madePending, pw);
                     pw.println();
                 }
diff --git a/services/core/java/com/android/server/job/JobServiceContext.java b/services/core/java/com/android/server/job/JobServiceContext.java
index bdcf642..ff39baf 100644
--- a/services/core/java/com/android/server/job/JobServiceContext.java
+++ b/services/core/java/com/android/server/job/JobServiceContext.java
@@ -146,7 +146,7 @@
     }
 
     /**
-     * Give a job to this context for execution. Callers must first check {@link #getRunningJob()}
+     * Give a job to this context for execution. Callers must first check {@link #getRunningJobLocked()}
      * and ensure it is null to make sure this is a valid context.
      * @param job The status of the job that we are going to run.
      * @return True if the job is valid and is running. False if the job cannot be executed.
@@ -210,23 +210,8 @@
 
     /**
      * Used externally to query the running job. Will return null if there is no job running.
-     * Be careful when using this function, at any moment it's possible that the job returned may
-     * stop executing.
      */
-    JobStatus getRunningJob() {
-        final JobStatus job;
-        synchronized (mLock) {
-            job = mRunningJob;
-        }
-        return job == null ? null : new JobStatus(job);
-    }
-
-    /**
-     * Internal non-cloning inspection of the currently running job, if any.  The lock
-     * must be held when calling this *and* for the entire lifetime of using its returned
-     * JobStatus object!
-     */
-    JobStatus getRunningJobUnsafeLocked() {
+    JobStatus getRunningJobLocked() {
         return mRunningJob;
     }
 
@@ -256,7 +241,7 @@
     }
 
     boolean timeoutIfExecutingLocked(String pkgName, int userId, boolean matchJobId, int jobId) {
-        final JobStatus executing = getRunningJob();
+        final JobStatus executing = getRunningJobLocked();
         if (executing != null && (userId == UserHandle.USER_ALL || userId == executing.getUserId())
                 && (pkgName == null || pkgName.equals(executing.getSourcePackageName()))
                 && (!matchJobId || jobId == executing.getJobId())) {
diff --git a/services/core/java/com/android/server/job/JobStore.java b/services/core/java/com/android/server/job/JobStore.java
index 57b1ccc..497d36f 100644
--- a/services/core/java/com/android/server/job/JobStore.java
+++ b/services/core/java/com/android/server/job/JobStore.java
@@ -454,10 +454,12 @@
                 synchronized (mLock) {
                     jobs = readJobMapImpl(fis);
                     if (jobs != null) {
+                        long now = SystemClock.elapsedRealtime();
                         IActivityManager am = ActivityManager.getService();
                         for (int i=0; i<jobs.size(); i++) {
                             JobStatus js = jobs.get(i);
                             js.prepareLocked(am);
+                            js.enqueueTime = now;
                             this.jobSet.add(js);
                         }
                     }
diff --git a/services/core/java/com/android/server/job/controllers/JobStatus.java b/services/core/java/com/android/server/job/controllers/JobStatus.java
index 4d507d6..53bf402 100644
--- a/services/core/java/com/android/server/job/controllers/JobStatus.java
+++ b/services/core/java/com/android/server/job/controllers/JobStatus.java
@@ -22,14 +22,10 @@
 import android.app.job.JobWorkItem;
 import android.content.ClipData;
 import android.content.ComponentName;
-import android.content.ContentProvider;
-import android.content.Intent;
 import android.net.Uri;
-import android.os.Binder;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
-import android.text.format.DateUtils;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -180,7 +176,10 @@
     // Used by shell commands
     public int overrideState = 0;
 
-    // Metrics about queue latency
+    // When this job was enqueued, for ordering.  (in elapsedRealtimeMillis)
+    public long enqueueTime;
+
+    // Metrics about queue latency.  (in uptimeMillis)
     public long madePending;
     public long madeActive;
 
@@ -349,6 +348,10 @@
         return null;
     }
 
+    public boolean hasWorkLocked() {
+        return (pendingWork != null && pendingWork.size() > 0) || hasExecutingWorkLocked();
+    }
+
     public boolean hasExecutingWorkLocked() {
         return executingWork != null && executingWork.size() > 0;
     }
@@ -744,10 +747,11 @@
         sb.append(getSourceUid());
         if (earliestRunTimeElapsedMillis != NO_EARLIEST_RUNTIME
                 || latestRunTimeElapsedMillis != NO_LATEST_RUNTIME) {
+            long now = SystemClock.elapsedRealtime();
             sb.append(" TIME=");
-            sb.append(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
-            sb.append("-");
-            sb.append(formatRunTime(latestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
+            formatRunTime(sb, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, now);
+            sb.append(":");
+            formatRunTime(sb, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, now);
         }
         if (job.getNetworkType() != JobInfo.NETWORK_TYPE_NONE) {
             sb.append(" NET=");
@@ -789,17 +793,19 @@
         return sb.toString();
     }
 
-    private String formatRunTime(long runtime, long  defaultValue) {
+    private void formatRunTime(PrintWriter pw, long runtime, long  defaultValue, long now) {
         if (runtime == defaultValue) {
-            return "none";
+            pw.print("none");
         } else {
-            long elapsedNow = SystemClock.elapsedRealtime();
-            long nextRuntime = runtime - elapsedNow;
-            if (nextRuntime > 0) {
-                return DateUtils.formatElapsedTime(nextRuntime / 1000);
-            } else {
-                return "-" + DateUtils.formatElapsedTime(nextRuntime / -1000);
-            }
+            TimeUtils.formatDuration(runtime - now, pw);
+        }
+    }
+
+    private void formatRunTime(StringBuilder sb, long runtime, long  defaultValue, long now) {
+        if (runtime == defaultValue) {
+            sb.append("none");
+        } else {
+            TimeUtils.formatDuration(runtime - now, sb);
         }
     }
 
@@ -881,7 +887,7 @@
     }
 
     // Dumpsys infrastructure
-    public void dump(PrintWriter pw, String prefix, boolean full) {
+    public void dump(PrintWriter pw, String prefix, boolean full, long elapsedRealtimeMillis) {
         pw.print(prefix); UserHandle.formatUid(pw, callingUid);
         pw.print(" tag="); pw.println(tag);
         pw.print(prefix);
@@ -1020,10 +1026,14 @@
                 dumpJobWorkItem(pw, prefix, executingWork.get(i), i);
             }
         }
-        pw.print(prefix); pw.print("Earliest run time: ");
-        pw.println(formatRunTime(earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME));
-        pw.print(prefix); pw.print("Latest run time: ");
-        pw.println(formatRunTime(latestRunTimeElapsedMillis, NO_LATEST_RUNTIME));
+        pw.print(prefix); pw.print("Enqueue time: ");
+        TimeUtils.formatDuration(enqueueTime, elapsedRealtimeMillis, pw);
+        pw.println();
+        pw.print(prefix); pw.print("Run time: earliest=");
+        formatRunTime(pw, earliestRunTimeElapsedMillis, NO_EARLIEST_RUNTIME, elapsedRealtimeMillis);
+        pw.print(", latest=");
+        formatRunTime(pw, latestRunTimeElapsedMillis, NO_LATEST_RUNTIME, elapsedRealtimeMillis);
+        pw.println();
         if (numFailures != 0) {
             pw.print(prefix); pw.print("Num failures: "); pw.println(numFailures);
         }
diff --git a/services/core/java/com/android/server/om/OverlayManagerService.java b/services/core/java/com/android/server/om/OverlayManagerService.java
index 0e1f485..ef3e7bc 100644
--- a/services/core/java/com/android/server/om/OverlayManagerService.java
+++ b/services/core/java/com/android/server/om/OverlayManagerService.java
@@ -20,6 +20,7 @@
 import static android.content.Intent.ACTION_PACKAGE_ADDED;
 import static android.content.Intent.ACTION_PACKAGE_CHANGED;
 import static android.content.Intent.ACTION_PACKAGE_REMOVED;
+import static android.content.Intent.ACTION_USER_ADDED;
 import static android.content.Intent.ACTION_USER_REMOVED;
 import static android.content.pm.PackageManager.SIGNATURE_MATCH;
 
@@ -46,6 +47,7 @@
 import android.os.ShellCallback;
 import android.os.SystemProperties;
 import android.os.UserHandle;
+import android.os.UserManager;
 import android.text.TextUtils;
 import android.util.ArrayMap;
 import android.util.ArraySet;
@@ -243,11 +245,14 @@
                     packageFilter, null, null);
 
             final IntentFilter userFilter = new IntentFilter();
+            userFilter.addAction(ACTION_USER_ADDED);
             userFilter.addAction(ACTION_USER_REMOVED);
             getContext().registerReceiverAsUser(new UserReceiver(), UserHandle.ALL,
                     userFilter, null, null);
 
             restoreSettings();
+
+            initIfNeeded();
             onSwitchUser(UserHandle.USER_SYSTEM);
 
             publishBinderService(Context.OVERLAY_SERVICE, mService);
@@ -269,14 +274,31 @@
         }
     }
 
+    private void initIfNeeded() {
+        final UserManager um = getContext().getSystemService(UserManager.class);
+        final List<UserInfo> users = um.getUsers(true /*excludeDying*/);
+        synchronized (mLock) {
+            final int userCount = users.size();
+            for (int i = 0; i < userCount; i++) {
+                final UserInfo userInfo = users.get(i);
+                if (!userInfo.supportsSwitchTo() && userInfo.id != UserHandle.USER_SYSTEM) {
+                    // Initialize any users that can't be switched to, as there state would
+                    // never be setup in onSwitchUser(). We will switch to the system user right
+                    // after this, and its state will be setup there.
+                    final List<String> targets = mImpl.updateOverlaysForUser(users.get(i).id);
+                    updateOverlayPaths(users.get(i).id, targets);
+                }
+            }
+        }
+    }
+
     @Override
     public void onSwitchUser(final int newUserId) {
         // ensure overlays in the settings are up-to-date, and propagate
         // any asset changes to the rest of the system
-        final List<String> targets;
         synchronized (mLock) {
-            targets = mImpl.onSwitchUser(newUserId);
-            updateAssetsLocked(newUserId, targets);
+            final List<String> targets = mImpl.updateOverlaysForUser(newUserId);
+            updateAssets(newUserId, targets);
         }
         schedulePersistSettings();
     }
@@ -428,10 +450,19 @@
     private final class UserReceiver extends BroadcastReceiver {
         @Override
         public void onReceive(@NonNull final Context context, @NonNull final Intent intent) {
+            final int userId = intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
             switch (intent.getAction()) {
+                case ACTION_USER_ADDED:
+                    if (userId != UserHandle.USER_NULL) {
+                        final ArrayList<String> targets;
+                        synchronized (mLock) {
+                            targets = mImpl.updateOverlaysForUser(userId);
+                        }
+                        updateOverlayPaths(userId, targets);
+                    }
+                    break;
+
                 case ACTION_USER_REMOVED:
-                    final int userId =
-                            intent.getIntExtra(Intent.EXTRA_USER_HANDLE, UserHandle.USER_NULL);
                     if (userId != UserHandle.USER_NULL) {
                         synchronized (mLock) {
                             mImpl.onUserRemoved(userId);
@@ -647,9 +678,7 @@
         public void onOverlaysChanged(@NonNull final String targetPackageName, final int userId) {
             schedulePersistSettings();
             FgThread.getHandler().post(() -> {
-                synchronized (mLock) {
-                    updateAssetsLocked(userId, targetPackageName);
-                }
+                updateAssets(userId, targetPackageName);
 
                 final Intent intent = new Intent(Intent.ACTION_OVERLAY_CHANGED,
                         Uri.fromParts("package", targetPackageName, null));
@@ -670,13 +699,10 @@
         }
     }
 
-    private void updateAssetsLocked(final int userId, final String targetPackageName) {
-        final List<String> list = new ArrayList<>();
-        list.add(targetPackageName);
-        updateAssetsLocked(userId, list);
-    }
-
-    private void updateAssetsLocked(final int userId, List<String> targetPackageNames) {
+    /**
+     * Updates the target packages' set of enabled overlays in PackageManager.
+     */
+    private void updateOverlayPaths(int userId, List<String> targetPackageNames) {
         if (DEBUG) {
             Slog.d(TAG, "Updating overlay assets");
         }
@@ -706,12 +732,19 @@
             }
 
             if (!pm.setEnabledOverlayPackages(
-                        userId, targetPackageName, pendingChanges.get(targetPackageName))) {
+                    userId, targetPackageName, pendingChanges.get(targetPackageName))) {
                 Slog.e(TAG, String.format("Failed to change enabled overlays for %s user %d",
-                            targetPackageName, userId));
+                        targetPackageName, userId));
             }
         }
+    }
 
+    private void updateAssets(final int userId, final String targetPackageName) {
+        updateAssets(userId, Collections.singletonList(targetPackageName));
+    }
+
+    private void updateAssets(final int userId, List<String> targetPackageNames) {
+        updateOverlayPaths(userId, targetPackageNames);
         final IActivityManager am = ActivityManager.getService();
         try {
             am.scheduleApplicationInfoChanged(targetPackageNames, userId);
diff --git a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
index 5196c66..261bcc5 100644
--- a/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
+++ b/services/core/java/com/android/server/om/OverlayManagerServiceImpl.java
@@ -68,15 +68,15 @@
         mListener = listener;
     }
 
-    /*
-     * Call this when switching to a new Android user. Will return a list of
-     * target packages that must refresh their overlays. This list is the union
+    /**
+     * Call this to synchronize the Settings for a user with what PackageManager knows about a user.
+     * Returns a list of target packages that must refresh their overlays. This list is the union
      * of two sets: the set of targets with currently active overlays, and the
      * set of targets that had, but no longer have, active overlays.
      */
-    List<String> onSwitchUser(final int newUserId) {
+    ArrayList<String> updateOverlaysForUser(final int newUserId) {
         if (DEBUG) {
-            Slog.d(TAG, "onSwitchUser newUserId=" + newUserId);
+            Slog.d(TAG, "updateOverlaysForUser newUserId=" + newUserId);
         }
 
         final Set<String> packagesToUpdateAssets = new ArraySet<>();
diff --git a/services/core/java/com/android/server/om/OverlayManagerSettings.java b/services/core/java/com/android/server/om/OverlayManagerSettings.java
index 2f83793..353b710 100644
--- a/services/core/java/com/android/server/om/OverlayManagerSettings.java
+++ b/services/core/java/com/android/server/om/OverlayManagerSettings.java
@@ -22,12 +22,14 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.content.om.OverlayInfo;
+import android.os.UserHandle;
 import android.util.AndroidRuntimeException;
 import android.util.ArrayMap;
 import android.util.Slog;
 import android.util.Xml;
 
 import com.android.internal.util.FastXmlSerializer;
+import com.android.internal.util.IndentingPrintWriter;
 import com.android.internal.util.XmlUtils;
 
 import org.xmlpull.v1.XmlPullParser;
@@ -266,32 +268,32 @@
         return true;
     }
 
-    private static final String TAB1 = "    ";
-    private static final String TAB2 = TAB1 + TAB1;
-    private static final String TAB3 = TAB2 + TAB1;
-
-    void dump(@NonNull final PrintWriter pw) {
+    void dump(@NonNull final PrintWriter p) {
+        final IndentingPrintWriter pw = new IndentingPrintWriter(p, "  ");
         pw.println("Settings");
-        pw.println(TAB1 + "Items");
+        pw.increaseIndent();
 
         if (mItems.isEmpty()) {
-            pw.println(TAB2 + "<none>");
+            pw.println("<none>");
             return;
         }
 
         final int N = mItems.size();
         for (int i = 0; i < N; i++) {
             final SettingsItem item = mItems.get(i);
-            final StringBuilder sb = new StringBuilder();
-            sb.append(TAB2 + item.mPackageName + ":" + item.getUserId() + " {\n");
-            sb.append(TAB3 + "mPackageName.......: " + item.mPackageName + "\n");
-            sb.append(TAB3 + "mUserId............: " + item.getUserId() + "\n");
-            sb.append(TAB3 + "mTargetPackageName.: " + item.getTargetPackageName() + "\n");
-            sb.append(TAB3 + "mBaseCodePath......: " + item.getBaseCodePath() + "\n");
-            sb.append(TAB3 + "mState.............: " + OverlayInfo.stateToString(item.getState()) + "\n");
-            sb.append(TAB3 + "mIsEnabled.........: " + item.isEnabled() + "\n");
-            sb.append(TAB2 + "}");
-            pw.println(sb.toString());
+            pw.println(item.mPackageName + ":" + item.getUserId() + " {");
+            pw.increaseIndent();
+
+            pw.print("mPackageName.......: "); pw.println(item.mPackageName);
+            pw.print("mUserId............: "); pw.println(item.getUserId());
+            pw.print("mTargetPackageName.: "); pw.println(item.getTargetPackageName());
+            pw.print("mBaseCodePath......: "); pw.println(item.getBaseCodePath());
+            pw.print("mState.............: "); pw.println(OverlayInfo.stateToString(item.getState()));
+            pw.print("mIsEnabled.........: "); pw.println(item.isEnabled());
+            pw.print("mIsStatic..........: "); pw.println(item.isStatic());
+
+            pw.decreaseIndent();
+            pw.println("}");
         }
     }
 
@@ -527,12 +529,6 @@
                 .filter(item -> item.getTargetPackageName().equals(targetPackageName));
     }
 
-    private void assertNotNull(@Nullable final Object o) {
-        if (o == null) {
-            throw new AndroidRuntimeException("object must not be null");
-        }
-    }
-
     static final class BadKeyException extends RuntimeException {
         BadKeyException(@NonNull final String packageName, final int userId) {
             super("Bad key mPackageName=" + packageName + " mUserId=" + userId);
diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java
index f79f6f4..29f9f7c 100644
--- a/services/core/java/com/android/server/pm/LauncherAppsService.java
+++ b/services/core/java/com/android/server/pm/LauncherAppsService.java
@@ -546,12 +546,12 @@
             try {
                 code = mActivityManagerInternal.startActivitiesAsPackage(publisherPackage,
                         userId, intents, startActivityOptions);
-                if (code >= ActivityManager.START_SUCCESS) {
+                if (ActivityManager.isStartResultSuccessful(code)) {
                     return true; // Success
                 } else {
                     Log.e(TAG, "Couldn't start activity, code=" + code);
                 }
-                return code >= ActivityManager.START_SUCCESS;
+                return false;
             } catch (SecurityException e) {
                 if (DEBUG) {
                     Slog.d(TAG, "SecurityException while launching intent", e);
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index 0e91d30..24d08ac 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3185,6 +3185,17 @@
         return null;
     }
 
+    @Override
+    public @Nullable ComponentName getInstantAppResolverComponent() {
+        synchronized (mPackages) {
+            final Pair<ComponentName, String> instantAppResolver = getInstantAppResolverLPr();
+            if (instantAppResolver == null) {
+                return null;
+            }
+            return instantAppResolver.first;
+        }
+    }
+
     private @Nullable Pair<ComponentName, String> getInstantAppResolverLPr() {
         final String[] packageArray =
                 mContext.getResources().getStringArray(R.array.config_ephemeralResolverPackage);
diff --git a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
index 3e920d4..bf92ce7 100644
--- a/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
+++ b/services/core/java/com/android/server/pm/PackageManagerShellCommand.java
@@ -148,6 +148,8 @@
                     return runSetHomeActivity();
                 case "get-privapp-permissions":
                     return runGetPrivappPermissions();
+                case "get-instantapp-resolver":
+                    return runGetInstantAppResolver();
                 case "has-feature":
                     return runHasFeature();
                 default:
@@ -1272,6 +1274,21 @@
         return 0;
     }
 
+    private int runGetInstantAppResolver() {
+        final PrintWriter pw = getOutPrintWriter();
+        try {
+            final ComponentName instantAppsResolver = mInterface.getInstantAppResolverComponent();
+            if (instantAppsResolver == null) {
+                return 1;
+            }
+            pw.println(instantAppsResolver.flattenToString());
+            return 0;
+        } catch (Exception e) {
+            pw.println(e.toString());
+            return 1;
+        }
+    }
+
     private int runHasFeature() {
         final PrintWriter err = getErrPrintWriter();
         final String featureName = getNextArg();
diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java
index ac4b828..feeee3f 100644
--- a/services/core/java/com/android/server/pm/ShortcutService.java
+++ b/services/core/java/com/android/server/pm/ShortcutService.java
@@ -54,6 +54,7 @@
 import android.graphics.Bitmap.CompressFormat;
 import android.graphics.Canvas;
 import android.graphics.RectF;
+import android.graphics.drawable.AdaptiveIconDrawable;
 import android.graphics.drawable.Icon;
 import android.net.Uri;
 import android.os.Binder;
@@ -1356,7 +1357,7 @@
             if (icon == null) {
                 return; // has no icon
             }
-
+            int maxIconDimension = mMaxIconDimension;
             Bitmap bitmap;
             try {
                 switch (icon.getType()) {
@@ -1368,9 +1369,12 @@
                         return;
                     }
                     case Icon.TYPE_BITMAP:
-                    case Icon.TYPE_ADAPTIVE_BITMAP: {
                         bitmap = icon.getBitmap(); // Don't recycle in this case.
                         break;
+                    case Icon.TYPE_ADAPTIVE_BITMAP: {
+                        bitmap = icon.getBitmap(); // Don't recycle in this case.
+                        maxIconDimension *= (1 + 2 * AdaptiveIconDrawable.getExtraInsetFraction());
+
                     }
                     default:
                         // This shouldn't happen because we've already validated the icon, but
@@ -1378,7 +1382,7 @@
                         throw ShortcutInfo.getInvalidIconException();
                 }
                 mShortcutBitmapSaver.saveBitmapLocked(shortcut,
-                        mMaxIconDimension, mIconPersistFormat, mIconPersistQuality);
+                        maxIconDimension, mIconPersistFormat, mIconPersistQuality);
             } finally {
                 // Once saved, we won't use the original icon information, so null it out.
                 shortcut.clearIcon();
diff --git a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
index 1284b1b..0e8960e 100644
--- a/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
+++ b/services/tests/servicestests/src/com/android/server/pm/PackageParserTest.java
@@ -498,6 +498,7 @@
         pkg.mRestrictedAccountType = "foo19";
         pkg.mRequiredAccountType = "foo20";
         pkg.mOverlayTarget = "foo21";
+        pkg.mOverlayPriority = 100;
         pkg.mSigningKeys = new ArraySet<>();
         pkg.mUpgradeKeySets = new ArraySet<>();
         pkg.mKeySetMapping = new ArrayMap<>();
diff --git a/telephony/java/com/android/ims/ImsReasonInfo.java b/telephony/java/com/android/ims/ImsReasonInfo.java
index bd8492b3..48f07d6 100644
--- a/telephony/java/com/android/ims/ImsReasonInfo.java
+++ b/telephony/java/com/android/ims/ImsReasonInfo.java
@@ -45,6 +45,8 @@
     public static final int CODE_LOCAL_IMS_SERVICE_DOWN = 106;
     // No pending incoming call exists
     public static final int CODE_LOCAL_NO_PENDING_CALL = 107;
+    // IMS Call ended during conference merge process
+    public static final int CODE_LOCAL_ENDED_BY_CONFERENCE_MERGE = 108;
 
     // IMS -> Telephony
     // Service unavailable; by power off
diff --git a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
index c1f0038..f0163be 100644
--- a/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
+++ b/tests/VoiceInteraction/src/com/android/test/voiceinteraction/AssistVisualizer.java
@@ -107,7 +107,7 @@
 
     public void logTree() {
         if (mAssistStructure != null) {
-            mAssistStructure.dump();
+            mAssistStructure.dump(true);
         }
     }
 
diff --git a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
index 1156b01..1a4067f 100644
--- a/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
+++ b/tools/aapt2/integration-tests/AppOne/AndroidManifest.xml
@@ -17,4 +17,6 @@
 <manifest xmlns:android="http://schemas.android.com/apk/res/android"
     package="com.android.aapt.app.one" coreApp="true">
     <uses-sdk android:minSdkVersion="21" />
+
+    <uses-permission-sdk-23 android:name="android.permission.TEST" android:maxSdkVersion="22" />
 </manifest>
diff --git a/tools/aapt2/link/ManifestFixer.cpp b/tools/aapt2/link/ManifestFixer.cpp
index f998d31..53c66a6 100644
--- a/tools/aapt2/link/ManifestFixer.cpp
+++ b/tools/aapt2/link/ManifestFixer.cpp
@@ -295,6 +295,7 @@
   manifest_action["original-package"];
   manifest_action["protected-broadcast"];
   manifest_action["uses-permission"];
+  manifest_action["uses-permission-sdk-23"];
   manifest_action["permission"];
   manifest_action["permission-tree"];
   manifest_action["permission-group"];