Merge "FRP: Add config flag for disabling credential FRP" into oc-mr1-dev
diff --git a/core/java/android/app/ITaskStackListener.aidl b/core/java/android/app/ITaskStackListener.aidl
index b5b1017..a56965b 100644
--- a/core/java/android/app/ITaskStackListener.aidl
+++ b/core/java/android/app/ITaskStackListener.aidl
@@ -30,7 +30,7 @@
     void onTaskStackChanged();
 
     /** Called whenever an Activity is moved to the pinned stack from another stack. */
-    void onActivityPinned(String packageName, int taskId);
+    void onActivityPinned(String packageName, int userId, int taskId);
 
     /** Called whenever an Activity is moved from the pinned stack to another stack. */
     void onActivityUnpinned();
diff --git a/core/java/android/app/TaskStackListener.java b/core/java/android/app/TaskStackListener.java
index a52ca0a..4674c9c 100644
--- a/core/java/android/app/TaskStackListener.java
+++ b/core/java/android/app/TaskStackListener.java
@@ -31,7 +31,8 @@
     }
 
     @Override
-    public void onActivityPinned(String packageName, int taskId) throws RemoteException {
+    public void onActivityPinned(String packageName, int userId, int taskId)
+            throws RemoteException {
     }
 
     @Override
diff --git a/core/java/android/app/timezone/RulesUpdaterContract.java b/core/java/android/app/timezone/RulesUpdaterContract.java
index 9c62f46..2a22ead 100644
--- a/core/java/android/app/timezone/RulesUpdaterContract.java
+++ b/core/java/android/app/timezone/RulesUpdaterContract.java
@@ -51,7 +51,7 @@
      * applies.
      */
     public static final String ACTION_TRIGGER_RULES_UPDATE_CHECK =
-            "android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK";
+            "com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK";
 
     /**
      * The extra containing the {@code byte[]} that should be passed to
@@ -61,7 +61,7 @@
      * {@link #ACTION_TRIGGER_RULES_UPDATE_CHECK} intent has been processed.
      */
     public static final String EXTRA_CHECK_TOKEN =
-            "android.intent.extra.timezone.CHECK_TOKEN";
+            "com.android.intent.extra.timezone.CHECK_TOKEN";
 
     /**
      * Creates an intent that would trigger a time zone rules update check.
diff --git a/core/java/android/hardware/Camera.java b/core/java/android/hardware/Camera.java
index aa35a66..931b5c9 100644
--- a/core/java/android/hardware/Camera.java
+++ b/core/java/android/hardware/Camera.java
@@ -16,10 +16,11 @@
 
 package android.hardware;
 
-import android.app.ActivityThread;
+import static android.system.OsConstants.*;
+
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
-import android.app.job.JobInfo;
+import android.app.ActivityThread;
 import android.content.Context;
 import android.graphics.ImageFormat;
 import android.graphics.Point;
@@ -34,11 +35,11 @@
 import android.os.ServiceManager;
 import android.renderscript.Allocation;
 import android.renderscript.Element;
-import android.renderscript.RenderScript;
 import android.renderscript.RSIllegalArgumentException;
+import android.renderscript.RenderScript;
 import android.renderscript.Type;
-import android.util.Log;
 import android.text.TextUtils;
+import android.util.Log;
 import android.view.Surface;
 import android.view.SurfaceHolder;
 
@@ -48,8 +49,6 @@
 import java.util.LinkedHashMap;
 import java.util.List;
 
-import static android.system.OsConstants.*;
-
 /**
  * The Camera class is used to set image capture settings, start/stop preview,
  * snap pictures, and retrieve frames for encoding for video.  This class is a
@@ -243,12 +242,19 @@
 
     /**
      * Returns the number of physical cameras available on this device.
+     *
+     * @return total number of accessible camera devices, or 0 if there are no
+     *   cameras or an error was encountered enumerating them.
      */
     public native static int getNumberOfCameras();
 
     /**
      * Returns the information about a particular camera.
      * If {@link #getNumberOfCameras()} returns N, the valid id is 0 to N-1.
+     *
+     * @throws RuntimeException if an invalid ID is provided, or if there is an
+     *    error retrieving the information (generally due to a hardware or other
+     *    low-level failure).
      */
     public static void getCameraInfo(int cameraId, CameraInfo cameraInfo) {
         _getCameraInfo(cameraId, cameraInfo);
@@ -362,7 +368,10 @@
     /**
      * Creates a new Camera object to access the first back-facing camera on the
      * device. If the device does not have a back-facing camera, this returns
-     * null.
+     * null. Otherwise acts like the {@link #open(int)} call.
+     *
+     * @return a new Camera object for the first back-facing camera, or null if there is no
+     *  backfacing camera
      * @see #open(int)
      */
     public static Camera open() {
@@ -609,6 +618,8 @@
      *
      * @throws IOException if a connection cannot be re-established (for
      *     example, if the camera is still in use by another process).
+     * @throws RuntimeException if release() has been called on this Camera
+     *     instance.
      */
     public native final void reconnect() throws IOException;
 
@@ -637,6 +648,8 @@
      *     or null to remove the preview surface
      * @throws IOException if the method fails (for example, if the surface
      *     is unavailable or unsuitable).
+     * @throws RuntimeException if release() has been called on this Camera
+     *    instance.
      */
     public final void setPreviewDisplay(SurfaceHolder holder) throws IOException {
         if (holder != null) {
@@ -684,6 +697,8 @@
      *     texture
      * @throws IOException if the method fails (for example, if the surface
      *     texture is unavailable or unsuitable).
+     * @throws RuntimeException if release() has been called on this Camera
+     *    instance.
      */
     public native final void setPreviewTexture(SurfaceTexture surfaceTexture) throws IOException;
 
@@ -733,12 +748,20 @@
      * {@link #setPreviewCallbackWithBuffer(Camera.PreviewCallback)} were
      * called, {@link Camera.PreviewCallback#onPreviewFrame(byte[], Camera)}
      * will be called when preview data becomes available.
+     *
+     * @throws RuntimeException if starting preview fails; usually this would be
+     *    because of a hardware or other low-level error, or because release()
+     *    has been called on this Camera instance.
      */
     public native final void startPreview();
 
     /**
      * Stops capturing and drawing preview frames to the surface, and
      * resets the camera for a future call to {@link #startPreview()}.
+     *
+     * @throws RuntimeException if stopping preview fails; usually this would be
+     *    because of a hardware or other low-level error, or because release()
+     *    has been called on this Camera instance.
      */
     public final void stopPreview() {
         _stopPreview();
@@ -777,6 +800,8 @@
      *
      * @param cb a callback object that receives a copy of each preview frame,
      *     or null to stop receiving callbacks.
+     * @throws RuntimeException if release() has been called on this Camera
+     *     instance.
      * @see android.media.MediaActionSound
      */
     public final void setPreviewCallback(PreviewCallback cb) {
@@ -803,6 +828,8 @@
      *
      * @param cb a callback object that receives a copy of the next preview frame,
      *     or null to stop receiving callbacks.
+     * @throws RuntimeException if release() has been called on this Camera
+     *     instance.
      * @see android.media.MediaActionSound
      */
     public final void setOneShotPreviewCallback(PreviewCallback cb) {
@@ -840,6 +867,8 @@
      *
      * @param cb a callback object that receives a copy of the preview frame,
      *     or null to stop receiving callbacks and clear the buffer queue.
+     * @throws RuntimeException if release() has been called on this Camera
+     *     instance.
      * @see #addCallbackBuffer(byte[])
      * @see android.media.MediaActionSound
      */
@@ -1259,6 +1288,9 @@
      * success sound to the user.</p>
      *
      * @param cb the callback to run
+     * @throws RuntimeException if starting autofocus fails; usually this would
+     *    be because of a hardware or other low-level error, or because
+     *    release() has been called on this Camera instance.
      * @see #cancelAutoFocus()
      * @see android.hardware.Camera.Parameters#setAutoExposureLock(boolean)
      * @see android.hardware.Camera.Parameters#setAutoWhiteBalanceLock(boolean)
@@ -1279,6 +1311,9 @@
      * this function will return the focus position to the default.
      * If the camera does not support auto-focus, this is a no-op.
      *
+     * @throws RuntimeException if canceling autofocus fails; usually this would
+     *    be because of a hardware or other low-level error, or because
+     *    release() has been called on this Camera instance.
      * @see #autoFocus(Camera.AutoFocusCallback)
      */
     public final void cancelAutoFocus()
@@ -1333,6 +1368,9 @@
      * Sets camera auto-focus move callback.
      *
      * @param cb the callback to run
+     * @throws RuntimeException if enabling the focus move callback fails;
+     *    usually this would be because of a hardware or other low-level error,
+     *    or because release() has been called on this Camera instance.
      */
     public void setAutoFocusMoveCallback(AutoFocusMoveCallback cb) {
         mAutoFocusMoveCallback = cb;
@@ -1384,7 +1422,7 @@
     };
 
     /**
-     * Equivalent to takePicture(shutter, raw, null, jpeg).
+     * Equivalent to <pre>takePicture(Shutter, raw, null, jpeg)</pre>.
      *
      * @see #takePicture(ShutterCallback, PictureCallback, PictureCallback, PictureCallback)
      */
@@ -1422,6 +1460,9 @@
      * @param raw       the callback for raw (uncompressed) image data, or null
      * @param postview  callback with postview image data, may be null
      * @param jpeg      the callback for JPEG image data, or null
+     * @throws RuntimeException if starting picture capture fails; usually this
+     *    would be because of a hardware or other low-level error, or because
+     *    release() has been called on this Camera instance.
      */
     public final void takePicture(ShutterCallback shutter, PictureCallback raw,
             PictureCallback postview, PictureCallback jpeg) {
@@ -1534,6 +1575,9 @@
      *
      * @param degrees the angle that the picture will be rotated clockwise.
      *                Valid values are 0, 90, 180, and 270.
+     * @throws RuntimeException if setting orientation fails; usually this would
+     *    be because of a hardware or other low-level error, or because
+     *    release() has been called on this Camera instance.
      * @see #setPreviewDisplay(SurfaceHolder)
      */
     public native final void setDisplayOrientation(int degrees);
@@ -1559,6 +1603,9 @@
      *         changed. {@code false} if the shutter sound state could not be
      *         changed. {@code true} is also returned if shutter sound playback
      *         is already set to the requested state.
+     * @throws RuntimeException if the call fails; usually this would be because
+     *    of a hardware or other low-level error, or because release() has been
+     *    called on this Camera instance.
      * @see #takePicture
      * @see CameraInfo#canDisableShutterSound
      * @see ShutterCallback
@@ -1903,6 +1950,9 @@
      * If modifications are made to the returned Parameters, they must be passed
      * to {@link #setParameters(Camera.Parameters)} to take effect.
      *
+     * @throws RuntimeException if reading parameters fails; usually this would
+     *    be because of a hardware or other low-level error, or because
+     *    release() has been called on this Camera instance.
      * @see #setParameters(Camera.Parameters)
      */
     public Parameters getParameters() {
diff --git a/core/java/android/service/autofill/AutofillServiceInfo.java b/core/java/android/service/autofill/AutofillServiceInfo.java
index e64eb0d..1a9afcc 100644
--- a/core/java/android/service/autofill/AutofillServiceInfo.java
+++ b/core/java/android/service/autofill/AutofillServiceInfo.java
@@ -29,11 +29,12 @@
 import android.util.AttributeSet;
 import android.util.Log;
 import android.util.Xml;
-import org.xmlpull.v1.XmlPullParser;
-import org.xmlpull.v1.XmlPullParserException;
 
 import com.android.internal.R;
 
+import org.xmlpull.v1.XmlPullParser;
+import org.xmlpull.v1.XmlPullParserException;
+
 import java.io.IOException;
 
 /**
@@ -147,4 +148,9 @@
     public String getSettingsActivity() {
         return mSettingsActivity;
     }
+
+    @Override
+    public String toString() {
+        return mServiceInfo == null ? "null" : mServiceInfo.toString();
+    }
 }
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index f888ba2..e906a1f 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -1342,11 +1342,17 @@
         }
     }
 
-    private void setSessionFinished() {
-        if (sVerbose) Log.v(TAG, "setSessionFinished()");
+    /**
+     * Marks the state of the session as finished.
+     *
+     * @param newState {@link #STATE_FINISHED} (because the autofill service returned a {@code null}
+     *  FillResponse) or {@link #STATE_UNKNOWN} (because the session was removed).
+     */
+    private void setSessionFinished(int newState) {
         synchronized (mLock) {
+            if (sVerbose) Log.v(TAG, "setSessionFinished(): from " + mState + " to " + newState);
             resetSessionLocked();
-            mState = STATE_FINISHED;
+            mState = newState;
         }
     }
 
@@ -1413,7 +1419,7 @@
 
         if (sessionFinished) {
             // Callback call was "hijacked" to also update the session state.
-            setSessionFinished();
+            setSessionFinished(STATE_FINISHED);
         }
     }
 
@@ -1898,10 +1904,10 @@
         }
 
         @Override
-        public void setSessionFinished() {
+        public void setSessionFinished(int newState) {
             final AutofillManager afm = mAfm.get();
             if (afm != null) {
-                afm.post(() -> afm.setSessionFinished());
+                afm.post(() -> afm.setSessionFinished(newState));
             }
         }
     }
diff --git a/core/java/android/view/autofill/IAutoFillManagerClient.aidl b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
index db6855a..3dabcec 100644
--- a/core/java/android/view/autofill/IAutoFillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAutoFillManagerClient.aidl
@@ -82,8 +82,9 @@
    void setSaveUiState(int sessionId, boolean shown);
 
    /**
-     * Marks the state of the session as finished (because the AutofillService returned a null
-     * FillResponse).
+     * Marks the state of the session as finished.
+     * @param newState STATE_FINISHED (because the autofill service returned a null
+     * FillResponse) or STATE_UNKNOWN (because the session was removed).
      */
-   void setSessionFinished();
+   void setSessionFinished(int newState);
 }
diff --git a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
index b6034d1..aa172f9 100644
--- a/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
+++ b/core/java/android/view/textclassifier/logging/SmartSelectionEventTracker.java
@@ -582,6 +582,7 @@
                 case ActionType.SMART_SHARE:  // fall through
                 case ActionType.DRAG:  // fall through
                 case ActionType.ABANDON:  // fall through
+                case ActionType.OTHER:  // fall through
                     return true;
                 default:
                     return false;
diff --git a/core/java/android/widget/SelectionActionModeHelper.java b/core/java/android/widget/SelectionActionModeHelper.java
index 4ebb3cf..fceefaf 100644
--- a/core/java/android/widget/SelectionActionModeHelper.java
+++ b/core/java/android/widget/SelectionActionModeHelper.java
@@ -49,6 +49,8 @@
 @UiThread
 final class SelectionActionModeHelper {
 
+    private static final String LOG_TAG = "SelectActionModeHelper";
+
     /**
      * Maximum time (in milliseconds) to wait for a result before timing out.
      */
@@ -216,6 +218,7 @@
         private int mSelectionStart;
         private int mSelectionEnd;
         private boolean mAllowReset;
+        private final LogAbandonRunnable mDelayedLogAbandon = new LogAbandonRunnable();
 
         SelectionTracker(TextView textView) {
             mTextView = Preconditions.checkNotNull(textView);
@@ -227,6 +230,10 @@
          */
         public void onOriginalSelection(
                 CharSequence text, int selectionStart, int selectionEnd, boolean editableText) {
+            // If we abandoned a selection and created a new one very shortly after, we may still
+            // have a pending request to log ABANDON, which we flush here.
+            mDelayedLogAbandon.flush();
+
             mOriginalStart = mSelectionStart = selectionStart;
             mOriginalEnd = mSelectionEnd = selectionEnd;
             mAllowReset = false;
@@ -267,12 +274,7 @@
         public void onSelectionDestroyed() {
             mAllowReset = false;
             // Wait a few ms to see if the selection was destroyed because of a text change event.
-            mTextView.postDelayed(() -> {
-                mLogger.logSelectionAction(
-                        mSelectionStart, mSelectionEnd,
-                        SelectionEvent.ActionType.ABANDON, null /* classification */);
-                mSelectionStart = mSelectionEnd = -1;
-            }, 100 /* ms */);
+            mDelayedLogAbandon.schedule(100 /* ms */);
         }
 
         /**
@@ -329,6 +331,38 @@
         private boolean isSelectionStarted() {
             return mSelectionStart >= 0 && mSelectionEnd >= 0 && mSelectionStart != mSelectionEnd;
         }
+
+        /** A helper for keeping track of pending abandon logging requests. */
+        private final class LogAbandonRunnable implements Runnable {
+            private boolean mIsPending;
+
+            /** Schedules an abandon to be logged with the given delay. Flush if necessary. */
+            void schedule(int delayMillis) {
+                if (mIsPending) {
+                    Log.e(LOG_TAG, "Force flushing abandon due to new scheduling request");
+                    flush();
+                }
+                mIsPending = true;
+                mTextView.postDelayed(this, delayMillis);
+            }
+
+            /** If there is a pending log request, execute it now. */
+            void flush() {
+                mTextView.removeCallbacks(this);
+                run();
+            }
+
+            @Override
+            public void run() {
+                if (mIsPending) {
+                    mLogger.logSelectionAction(
+                            mSelectionStart, mSelectionEnd,
+                            SelectionEvent.ActionType.ABANDON, null /* classification */);
+                    mSelectionStart = mSelectionEnd = -1;
+                    mIsPending = false;
+                }
+            }
+        }
     }
 
     // TODO: Write tests
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index 167587e..9eed12f 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -1357,7 +1357,7 @@
 
     <!-- The package of the time zone rules updater application. Expected to be the same
          for all Android devices that support APK-based time zone rule updates.
-         A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
+         A package-targeted com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
          will be sent to the updater app if the system server detects an update to the updater or
          data app packages.
          The package referenced here must have the android.permission.UPDATE_TIME_ZONE_RULES
@@ -1368,7 +1368,7 @@
 
     <!-- The package of the time zone rules data application. Expected to be configured
          by OEMs to reference their own priv-app APK package.
-         A package-targeted android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
+         A package-targeted com.android.intent.action.timezone.TRIGGER_RULES_UPDATE_CHECK intent
          will be sent to the updater app if the system server detects an update to the updater or
          data app packages.
          [This is only used if config_enableUpdateableTimeZoneRules and
diff --git a/graphics/java/android/graphics/drawable/VectorDrawable.java b/graphics/java/android/graphics/drawable/VectorDrawable.java
index c3ef450..ceac325 100644
--- a/graphics/java/android/graphics/drawable/VectorDrawable.java
+++ b/graphics/java/android/graphics/drawable/VectorDrawable.java
@@ -31,6 +31,7 @@
 import android.graphics.PorterDuffColorFilter;
 import android.graphics.Rect;
 import android.graphics.Shader;
+import android.os.Trace;
 import android.util.ArrayMap;
 import android.util.AttributeSet;
 import android.util.DisplayMetrics;
@@ -605,38 +606,44 @@
     public void inflate(@NonNull Resources r, @NonNull XmlPullParser parser,
             @NonNull AttributeSet attrs, @Nullable Theme theme)
             throws XmlPullParserException, IOException {
-        if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
-            // This VD has been used to display other VD resource content, clean up.
-            if (mVectorState.mRootGroup != null) {
-                // Subtract the native allocation for all the nodes.
-                VMRuntime.getRuntime().registerNativeFree(mVectorState.mRootGroup.getNativeSize());
-                // Remove child nodes' reference to tree
-                mVectorState.mRootGroup.setTree(null);
+        try {
+            Trace.traceBegin(Trace.TRACE_TAG_RESOURCES, "VectorDrawable#inflate");
+            if (mVectorState.mRootGroup != null || mVectorState.mNativeTree != null) {
+                // This VD has been used to display other VD resource content, clean up.
+                if (mVectorState.mRootGroup != null) {
+                    // Subtract the native allocation for all the nodes.
+                    VMRuntime.getRuntime().registerNativeFree(
+                            mVectorState.mRootGroup.getNativeSize());
+                    // Remove child nodes' reference to tree
+                    mVectorState.mRootGroup.setTree(null);
+                }
+                mVectorState.mRootGroup = new VGroup();
+                if (mVectorState.mNativeTree != null) {
+                    // Subtract the native allocation for the tree wrapper, which contains root node
+                    // as well as rendering related data.
+                    VMRuntime.getRuntime().registerNativeFree(mVectorState.NATIVE_ALLOCATION_SIZE);
+                    mVectorState.mNativeTree.release();
+                }
+                mVectorState.createNativeTree(mVectorState.mRootGroup);
             }
-            mVectorState.mRootGroup = new VGroup();
-            if (mVectorState.mNativeTree != null) {
-                // Subtract the native allocation for the tree wrapper, which contains root node
-                // as well as rendering related data.
-                VMRuntime.getRuntime().registerNativeFree(mVectorState.NATIVE_ALLOCATION_SIZE);
-                mVectorState.mNativeTree.release();
-            }
-            mVectorState.createNativeTree(mVectorState.mRootGroup);
+            final VectorDrawableState state = mVectorState;
+            state.setDensity(Drawable.resolveDensity(r, 0));
+
+            final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
+            updateStateFromTypedArray(a);
+            a.recycle();
+
+            mDpiScaledDirty = true;
+
+            state.mCacheDirty = true;
+            inflateChildElements(r, parser, attrs, theme);
+
+            state.onTreeConstructionFinished();
+            // Update local properties.
+            updateLocalState(r);
+        } finally {
+            Trace.traceEnd(Trace.TRACE_TAG_RESOURCES);
         }
-        final VectorDrawableState state = mVectorState;
-        state.setDensity(Drawable.resolveDensity(r, 0));
-
-        final TypedArray a = obtainAttributes(r, theme, attrs, R.styleable.VectorDrawable);
-        updateStateFromTypedArray(a);
-        a.recycle();
-
-        mDpiScaledDirty = true;
-
-        state.mCacheDirty = true;
-        inflateChildElements(r, parser, attrs, theme);
-
-        state.onTreeConstructionFinished();
-        // Update local properties.
-        updateLocalState(r);
     }
 
     private void updateStateFromTypedArray(TypedArray a) throws XmlPullParserException {
diff --git a/libs/hwui/OpenGLReadback.cpp b/libs/hwui/OpenGLReadback.cpp
index f9a1cc5..2687410 100644
--- a/libs/hwui/OpenGLReadback.cpp
+++ b/libs/hwui/OpenGLReadback.cpp
@@ -280,6 +280,11 @@
 
 bool OpenGLReadbackImpl::copyLayerInto(renderthread::RenderThread& renderThread,
         GlLayer& layer, SkBitmap* bitmap) {
+    if (!layer.isRenderable()) {
+        // layer has never been updated by DeferredLayerUpdater, abort copy
+        return false;
+    }
+
     return CopyResult::Success == copyTextureInto(Caches::getInstance(),
             renderThread.renderState(), layer.getTexture(), layer.getTexTransform(),
             Rect(), bitmap);
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 8a1de02..ca179c9 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -22,6 +22,7 @@
 #include "SkShader.h"
 #include <utils/Log.h>
 #include "utils/Macros.h"
+#include "utils/TraceUtils.h"
 #include "utils/VectorDrawableUtils.h"
 
 #include <math.h>
@@ -593,14 +594,17 @@
 void Tree::updateBitmapCache(Bitmap& bitmap, bool useStagingData) {
     SkBitmap outCache;
     bitmap.getSkBitmap(&outCache);
+    int cacheWidth = outCache.width();
+    int cacheHeight = outCache.height();
+    ATRACE_FORMAT("VectorDrawable repaint %dx%d", cacheWidth, cacheHeight);
     outCache.eraseColor(SK_ColorTRANSPARENT);
     SkCanvas outCanvas(outCache);
     float viewportWidth = useStagingData ?
             mStagingProperties.getViewportWidth() : mProperties.getViewportWidth();
     float viewportHeight = useStagingData ?
             mStagingProperties.getViewportHeight() : mProperties.getViewportHeight();
-    float scaleX = outCache.width() / viewportWidth;
-    float scaleY = outCache.height() / viewportHeight;
+    float scaleX = cacheWidth / viewportWidth;
+    float scaleY = cacheHeight / viewportHeight;
     outCanvas.scale(scaleX, scaleY);
     mRootNode->draw(&outCanvas, useStagingData);
 }
diff --git a/libs/hwui/tests/common/scenes/TvApp.cpp b/libs/hwui/tests/common/scenes/TvApp.cpp
new file mode 100644
index 0000000..04fc2d4
--- /dev/null
+++ b/libs/hwui/tests/common/scenes/TvApp.cpp
@@ -0,0 +1,274 @@
+/*
+ * 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.
+ */
+
+#include "TestSceneBase.h"
+#include "tests/common/BitmapAllocationTestUtils.h"
+#include "SkBlendMode.h"
+
+class TvApp;
+class TvAppNoRoundedCorner;
+class TvAppColorFilter;
+class TvAppNoRoundedCornerColorFilter;
+
+static bool _TvApp(
+        BitmapAllocationTestUtils::registerBitmapAllocationScene<TvApp>(
+                "tvapp", "A dense grid of cards:"
+                "with rounded corner, using overlay RenderNode for dimming."));
+
+static bool _TvAppNoRoundedCorner(
+        BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCorner>(
+                "tvapp_norc", "A dense grid of cards:"
+                "no rounded corner, using overlay RenderNode for dimming"));
+
+static bool _TvAppColorFilter(
+        BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppColorFilter>(
+                "tvapp_cf", "A dense grid of cards:"
+                "with rounded corner, using ColorFilter for dimming"));
+
+static bool _TvAppNoRoundedCornerColorFilter(
+        BitmapAllocationTestUtils::registerBitmapAllocationScene<TvAppNoRoundedCornerColorFilter>(
+                "tvapp_norc_cf", "A dense grid of cards:"
+                "no rounded corner, using ColorFilter for dimming"));
+
+class TvApp : public TestScene {
+public:
+    TvApp(BitmapAllocationTestUtils::BitmapAllocator allocator)
+        : TestScene()
+        , mAllocator(allocator) { }
+
+    sp<RenderNode> mBg;
+    std::vector<sp<RenderNode>> mCards;
+    std::vector<sp<RenderNode>> mInfoAreas;
+    std::vector<sp<RenderNode>> mImages;
+    std::vector<sp<RenderNode>> mOverlays;
+    std::vector<sk_sp<Bitmap>> mCachedBitmaps;
+    BitmapAllocationTestUtils::BitmapAllocator mAllocator;
+    sk_sp<Bitmap> mSingleBitmap;
+    int mSeed = 0;
+    int mSeed2 = 0;
+
+    void createContent(int width, int height, Canvas& canvas) override {
+        mBg = createBitmapNode(canvas, 0xFF9C27B0, 0, 0, width, height);
+        canvas.drawRenderNode(mBg.get());
+
+        canvas.insertReorderBarrier(true);
+        mSingleBitmap = mAllocator(dp(160), dp(120), kRGBA_8888_SkColorType,
+                 [](SkBitmap& skBitmap) {
+             skBitmap.eraseColor(0xFF0000FF);
+        });
+
+        for (int y = dp(18) - dp(178); y < height - dp(18); y += dp(178)) {
+            bool isFirstCard = true;
+            for (int x = dp(18); x < width - dp(18); x += dp(178)) {
+                sp<RenderNode> card = createCard(x, y, dp(160), dp(160), isFirstCard);
+                isFirstCard = false;
+                canvas.drawRenderNode(card.get());
+                mCards.push_back(card);
+            }
+        }
+        canvas.insertReorderBarrier(false);
+    }
+
+    void doFrame(int frameNr) override {
+        size_t numCards = mCards.size();
+        for (size_t ci = 0; ci < numCards; ci++) {
+            updateCard(ci, frameNr);
+        }
+    }
+
+private:
+    sp<RenderNode> createBitmapNode(Canvas& canvas, SkColor color, int left, int top,
+            int width, int height) {
+        return TestUtils::createNode(left, top, left + width , top + height,
+                [this, width, height, color](RenderProperties& props, Canvas& canvas) {
+            sk_sp<Bitmap> bitmap = mAllocator(width, height, kRGBA_8888_SkColorType,
+                    [color](SkBitmap& skBitmap) {
+                 skBitmap.eraseColor(color);
+            });
+            canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+        });
+    }
+
+    sp<RenderNode> createSharedBitmapNode(Canvas& canvas, int left, int top,
+            int width, int height, sk_sp<Bitmap>bitmap) {
+        return TestUtils::createNode(left, top, left + width , top + height,
+                [bitmap](RenderProperties& props, Canvas& canvas) {
+            canvas.drawBitmap(*bitmap, 0, 0, nullptr);
+        });
+    }
+
+    sp<RenderNode> createInfoNode(Canvas& canvas, int left, int top,
+            int width, int height, const char* text, const char* text2) {
+        return TestUtils::createNode(left, top, left + width , top + height,
+                [text, text2](RenderProperties& props, Canvas& canvas) {
+            canvas.drawColor(0xFFFFEEEE, SkBlendMode::kSrcOver);
+
+            SkPaint paint;
+            paint.setTextEncoding(SkPaint::kGlyphID_TextEncoding);
+            paint.setAntiAlias(true);
+            paint.setTextSize(24);
+
+            paint.setColor(Color::Black);
+            TestUtils::drawUtf8ToCanvas(&canvas, text, paint, 10, 30);
+            paint.setTextSize(20);
+            TestUtils::drawUtf8ToCanvas(&canvas, text2, paint, 10, 54);
+
+        });
+    }
+
+    sp<RenderNode> createColorNode(Canvas& canvas, int left, int top,
+            int width, int height, SkColor color) {
+        return TestUtils::createNode(left, top, left + width , top + height,
+                [color](RenderProperties& props, Canvas& canvas) {
+            canvas.drawColor(color, SkBlendMode::kSrcOver);
+        });
+    }
+
+    virtual bool useSingleBitmap() {
+        return false;
+    }
+
+    virtual float roundedCornerRadius() {
+        return dp(2);
+    }
+
+    // when true, use overlay RenderNode for dimming, otherwise apply a ColorFilter to dim image
+    virtual bool useOverlay() {
+        return true;
+    }
+
+    sp<RenderNode> createCard(int x, int y, int width, int height, bool selected) {
+        return TestUtils::createNode(x, y, x + width, y + height,
+                [width, height, selected, this](RenderProperties& props, Canvas& canvas) {
+            if (selected) {
+                props.setElevation(dp(16));
+                props.setScaleX(1.2);
+                props.setScaleY(1.2);
+            }
+            props.mutableOutline().setRoundRect(0, 0, width, height, roundedCornerRadius(), 1);
+            props.mutableOutline().setShouldClip(true);
+
+            sk_sp<Bitmap> bitmap = useSingleBitmap() ? mSingleBitmap
+                 : mAllocator(width, dp(120), kRGBA_8888_SkColorType, [this](SkBitmap& skBitmap) {
+                       skBitmap.eraseColor(0xFF000000 | ((mSeed << 3) & 0xFF));
+                   });
+            sp<RenderNode> cardImage = createSharedBitmapNode(canvas, 0, 0, width, dp(120),
+                    bitmap);
+            canvas.drawRenderNode(cardImage.get());
+            mCachedBitmaps.push_back(bitmap);
+            mImages.push_back(cardImage);
+
+            char buffer[128];
+            sprintf(buffer, "Video %d-%d", mSeed, mSeed + 1);
+            mSeed++;
+            char buffer2[128];
+            sprintf(buffer2, "Studio %d", mSeed2++);
+            sp<RenderNode> infoArea = createInfoNode(canvas, 0, dp(120), width, height, buffer, buffer2);
+            canvas.drawRenderNode(infoArea.get());
+            mInfoAreas.push_back(infoArea);
+
+            if (useOverlay()) {
+                sp<RenderNode> overlayColor = createColorNode(canvas, 0, 0, width, height, 0x00000000);
+                canvas.drawRenderNode(overlayColor.get());
+                mOverlays.push_back(overlayColor);
+            }
+        });
+    }
+
+    void updateCard(int ci, int curFrame) {
+        // updating card's translation Y
+        sp<RenderNode> card = mCards[ci];
+        card->setPropertyFieldsDirty(RenderNode::Y);
+        card->mutateStagingProperties().setTranslationY(curFrame % 150);
+
+        // re-recording card's canvas, not necessary but to add some burden to CPU
+        std::unique_ptr<Canvas> cardcanvas(Canvas::create_recording_canvas(
+                card->stagingProperties().getWidth(),
+                card->stagingProperties().getHeight()));
+        sp<RenderNode> image = mImages[ci];
+        sp<RenderNode> infoArea = mInfoAreas[ci];
+        cardcanvas->drawRenderNode(infoArea.get());
+
+        if (useOverlay()) {
+             cardcanvas->drawRenderNode(image.get());
+            // re-recording card overlay's canvas, animating overlay color alpha
+            sp<RenderNode> overlay = mOverlays[ci];
+            std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+                    overlay->stagingProperties().getWidth(),
+                    overlay->stagingProperties().getHeight()));
+            canvas->drawColor((curFrame % 150) << 24, SkBlendMode::kSrcOver);
+            overlay->setStagingDisplayList(canvas->finishRecording());
+            cardcanvas->drawRenderNode(overlay.get());
+        } else {
+            // re-recording image node's canvas, animating ColorFilter
+            std::unique_ptr<Canvas> canvas(Canvas::create_recording_canvas(
+                    image->stagingProperties().getWidth(),
+                    image->stagingProperties().getHeight()));
+            SkPaint paint;
+            sk_sp<SkColorFilter> filter(SkColorFilter::MakeModeFilter((curFrame % 150) << 24,
+                    SkBlendMode::kSrcATop));
+            paint.setColorFilter(filter);
+            sk_sp<Bitmap> bitmap = mCachedBitmaps[ci];
+            canvas->drawBitmap(*bitmap, 0, 0, &paint);
+            image->setStagingDisplayList(canvas->finishRecording());
+            cardcanvas->drawRenderNode(image.get());
+        }
+
+        card->setStagingDisplayList(cardcanvas->finishRecording());
+    }
+};
+
+class TvAppNoRoundedCorner : public TvApp {
+public:
+    TvAppNoRoundedCorner(BitmapAllocationTestUtils::BitmapAllocator allocator)
+        : TvApp(allocator) { }
+
+private:
+
+    virtual float roundedCornerRadius() override {
+        return dp(0);
+    }
+};
+
+class TvAppColorFilter : public TvApp {
+public:
+    TvAppColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+        : TvApp(allocator) { }
+
+private:
+
+    virtual bool useOverlay() override {
+        return false;
+    }
+};
+
+class TvAppNoRoundedCornerColorFilter : public TvApp {
+public:
+    TvAppNoRoundedCornerColorFilter(BitmapAllocationTestUtils::BitmapAllocator allocator)
+        : TvApp(allocator) { }
+
+private:
+
+    virtual float roundedCornerRadius() override {
+        return dp(0);
+    }
+
+    virtual bool useOverlay() override {
+        return false;
+    }
+};
+
+
diff --git a/media/java/android/media/IMediaRouterService.aidl b/media/java/android/media/IMediaRouterService.aidl
index dc7fa8c..3308fc9 100644
--- a/media/java/android/media/IMediaRouterService.aidl
+++ b/media/java/android/media/IMediaRouterService.aidl
@@ -28,7 +28,6 @@
 
     MediaRouterClientState getState(IMediaRouterClient client);
     boolean isPlaybackActive(IMediaRouterClient client);
-    boolean isGlobalBluetoothA2doOn();
 
     void setDiscoveryRequest(IMediaRouterClient client, int routeTypes, boolean activeScan);
     void setSelectedRoute(IMediaRouterClient client, String routeId, boolean explicit);
diff --git a/media/java/android/media/MediaRouter.java b/media/java/android/media/MediaRouter.java
index b072f65..013e85e 100644
--- a/media/java/android/media/MediaRouter.java
+++ b/media/java/android/media/MediaRouter.java
@@ -184,25 +184,33 @@
 
         void updateAudioRoutes(AudioRoutesInfo newRoutes) {
             boolean audioRoutesChanged = false;
+            boolean forceUseDefaultRoute = false;
+
             if (newRoutes.mainType != mCurAudioRoutesInfo.mainType) {
                 mCurAudioRoutesInfo.mainType = newRoutes.mainType;
                 int name;
-                if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HEADPHONES) != 0
-                        || (newRoutes.mainType&AudioRoutesInfo.MAIN_HEADSET) != 0) {
+                if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HEADPHONES) != 0
+                        || (newRoutes.mainType & AudioRoutesInfo.MAIN_HEADSET) != 0) {
                     name = com.android.internal.R.string.default_audio_route_name_headphones;
-                } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
+                } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_DOCK_SPEAKERS) != 0) {
                     name = com.android.internal.R.string.default_audio_route_name_dock_speakers;
-                } else if ((newRoutes.mainType&AudioRoutesInfo.MAIN_HDMI) != 0) {
+                } else if ((newRoutes.mainType & AudioRoutesInfo.MAIN_HDMI) != 0) {
                     name = com.android.internal.R.string.default_media_route_name_hdmi;
                 } else {
                     name = com.android.internal.R.string.default_audio_route_name;
                 }
                 mDefaultAudioVideo.mNameResId = name;
                 dispatchRouteChanged(mDefaultAudioVideo);
+
+                if ((newRoutes.mainType & (AudioRoutesInfo.MAIN_HEADSET
+                        | AudioRoutesInfo.MAIN_HEADPHONES | AudioRoutesInfo.MAIN_USB)) != 0) {
+                    forceUseDefaultRoute = true;
+                }
                 audioRoutesChanged = true;
             }
 
             if (!TextUtils.equals(newRoutes.bluetoothName, mCurAudioRoutesInfo.bluetoothName)) {
+                forceUseDefaultRoute = false;
                 mCurAudioRoutesInfo.bluetoothName = newRoutes.bluetoothName;
                 if (mCurAudioRoutesInfo.bluetoothName != null) {
                     if (mBluetoothA2dpRoute == null) {
@@ -231,30 +239,18 @@
                 Log.v(TAG, "Audio routes updated: " + newRoutes + ", a2dp=" + isBluetoothA2dpOn());
                 if (mSelectedRoute == null || mSelectedRoute == mDefaultAudioVideo
                         || mSelectedRoute == mBluetoothA2dpRoute) {
-                    selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, getDefaultSystemAudioRoute(), false);
+                    if (forceUseDefaultRoute || mBluetoothA2dpRoute == null) {
+                        selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mDefaultAudioVideo, false);
+                    } else {
+                        selectRouteStatic(ROUTE_TYPE_LIVE_AUDIO, mBluetoothA2dpRoute, false);
+                    }
                 }
             }
         }
 
-        RouteInfo getDefaultSystemAudioRoute() {
-            boolean globalBluetoothA2doOn = false;
-            try {
-                globalBluetoothA2doOn = mMediaRouterService.isGlobalBluetoothA2doOn();
-            } catch (RemoteException ex) {
-                Log.e(TAG, "Unable to call isSystemBluetoothA2doOn.", ex);
-            }
-            return (globalBluetoothA2doOn && mBluetoothA2dpRoute != null)
-                    ? mBluetoothA2dpRoute : mDefaultAudioVideo;
-        }
-
-        RouteInfo getCurrentSystemAudioRoute() {
-            return (isBluetoothA2dpOn() && mBluetoothA2dpRoute != null)
-                    ? mBluetoothA2dpRoute : mDefaultAudioVideo;
-        }
-
         boolean isBluetoothA2dpOn() {
             try {
-                return mAudioService.isBluetoothA2dpOn();
+                return mBluetoothA2dpRoute != null && mAudioService.isBluetoothA2dpOn();
             } catch (RemoteException e) {
                 Log.e(TAG, "Error querying Bluetooth A2DP state", e);
                 return false;
@@ -608,6 +604,7 @@
                         || mSelectedRoute == null) {
                     return;
                 }
+                Log.v(TAG, "onRestoreRoute() : a2dp=" + isBluetoothA2dpOn());
                 mSelectedRoute.select();
             }
         }
@@ -940,10 +937,12 @@
         Log.v(TAG, "Selecting route: " + route);
         assert(route != null);
         final RouteInfo oldRoute = sStatic.mSelectedRoute;
+        final RouteInfo currentSystemRoute = sStatic.isBluetoothA2dpOn()
+                ? sStatic.mBluetoothA2dpRoute : sStatic.mDefaultAudioVideo;
         boolean wasDefaultOrBluetoothRoute = (oldRoute == sStatic.mDefaultAudioVideo
                 || oldRoute == sStatic.mBluetoothA2dpRoute);
         if (oldRoute == route
-                && (!wasDefaultOrBluetoothRoute || route == sStatic.getCurrentSystemAudioRoute())) {
+                && (!wasDefaultOrBluetoothRoute || route == currentSystemRoute)) {
             return;
         }
         if (!route.matchesTypes(types)) {
@@ -1014,8 +1013,7 @@
 
     static void selectDefaultRouteStatic() {
         // TODO: Be smarter about the route types here; this selects for all valid.
-        if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute
-                && sStatic.mBluetoothA2dpRoute != null && sStatic.isBluetoothA2dpOn()) {
+        if (sStatic.mSelectedRoute != sStatic.mBluetoothA2dpRoute && sStatic.isBluetoothA2dpOn()) {
             selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mBluetoothA2dpRoute, false);
         } else {
             selectRouteStatic(ROUTE_TYPE_ANY, sStatic.mDefaultAudioVideo, false);
diff --git a/packages/SettingsLib/res/values-pa/strings.xml b/packages/SettingsLib/res/values-pa/strings.xml
index 6e93e869..bdd8927 100644
--- a/packages/SettingsLib/res/values-pa/strings.xml
+++ b/packages/SettingsLib/res/values-pa/strings.xml
@@ -331,7 +331,7 @@
     <string name="convert_to_file_encryption_enabled" msgid="2861258671151428346">"ਤਬਦੀਲ ਕਰੋ ..."</string>
     <string name="convert_to_file_encryption_done" msgid="7859766358000523953">"ਫ਼ਾਈਲ ਪਹਿਲਾਂ ਤੋਂ ਇਨਕ੍ਰਿਪਟਡ ਹੈ"</string>
     <string name="title_convert_fbe" msgid="1263622876196444453">"ਫ਼ਾਈਲ ਆਧਾਰਿਤ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਤਬਦੀਲ ਕੀਤਾ ਜਾ ਰਿਹਾ ਹੈ"</string>
-    <string name="convert_to_fbe_warning" msgid="6139067817148865527">" ਡਾਟਾ  ਪਾਰਟੀਸ਼ਨ ਦਾ ਫ਼ਾਈਲ ਆਧਾਰਿਤ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਰੁਪਾਂਤਰਣ ਕਰੋ\n !! ਚਿਤਾਵਨੀ !! ਇਹ ਤੁਹਾਡੇ ਸਾਰੇ ਡੈਟੇ ਨੂੰ ਮਿਟਾ ਦੇਵੇਗਾ\n ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਿਕ ਹੈ, ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।\n ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਮਿਟਾਓ ਅਤੇ ਰੁਪਾਂਤਰਣ ਕਰੋ...\' ਨੂੰ ਦਬਾਓ।"</string>
+    <string name="convert_to_fbe_warning" msgid="6139067817148865527">" ਡਾਟਾ  ਪਾਰਟੀਸ਼ਨ ਦਾ ਫ਼ਾਈਲ ਆਧਾਰਿਤ ਇਨਕ੍ਰਿਪਸ਼ਨ ਵਿੱਚ ਰੁਪਾਂਤਰਣ ਕਰੋ\n !! ਚਿਤਾਵਨੀ !! ਇਹ ਤੁਹਾਡੇ ਸਾਰੇ  ਡਾਟੇ  ਨੂੰ ਮਿਟਾ ਦੇਵੇਗਾ\n ਇਹ ਵਿਸ਼ੇਸ਼ਤਾ ਪ੍ਰਯੋਗਿਕ ਹੈ, ਅਤੇ ਸ਼ਾਇਦ ਸਹੀ ਢੰਗ ਨਾਲ ਕੰਮ ਨਾ ਕਰੇ।\n ਜਾਰੀ ਰੱਖਣ ਲਈ \'ਮਿਟਾਓ ਅਤੇ ਰੁਪਾਂਤਰਣ ਕਰੋ...\' ਨੂੰ ਦਬਾਓ।"</string>
     <string name="button_convert_fbe" msgid="5152671181309826405">"ਮਿਟਾਓ ਅਤੇ ਰੁਪਾਂਤਰਣ ਕਰੋ..."</string>
     <string name="picture_color_mode" msgid="4560755008730283695">"ਤਸਵੀਰ ਰੰਗ ਮੋਡ"</string>
     <string name="picture_color_mode_desc" msgid="1141891467675548590">"sRGB ਵਰਤੋਂ ਕਰੋ"</string>
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index d95402c..cd23c97 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -1069,6 +1069,7 @@
                 cb.onDreamingStateChanged(mIsDreaming);
             }
         }
+        updateFingerprintListeningState();
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
index b3f992d..bae9ef8a 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipManager.java
@@ -30,6 +30,7 @@
 import android.os.Handler;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.Pair;
 import android.view.IPinnedStackController;
 import android.view.IPinnedStackListener;
 import android.view.IWindowManager;
@@ -70,11 +71,11 @@
      */
     TaskStackListener mTaskStackListener = new TaskStackListener() {
         @Override
-        public void onActivityPinned(String packageName, int taskId) {
+        public void onActivityPinned(String packageName, int userId, int taskId) {
             mTouchHandler.onActivityPinned();
             mMediaController.onActivityPinned();
             mMenuController.onActivityPinned();
-            mNotificationController.onActivityPinned(packageName,
+            mNotificationController.onActivityPinned(packageName, userId,
                     true /* deferUntilAnimationEnds */);
 
             SystemServicesProxy.getInstance(mContext).setPipVisibility(true);
@@ -82,13 +83,15 @@
 
         @Override
         public void onActivityUnpinned() {
-            ComponentName topPipActivity = PipUtils.getTopPinnedActivity(mContext,
-                    mActivityManager);
-            mMenuController.onActivityUnpinned(topPipActivity);
-            mTouchHandler.onActivityUnpinned(topPipActivity);
-            mNotificationController.onActivityUnpinned(topPipActivity);
+            final Pair<ComponentName, Integer> topPipActivityInfo = PipUtils.getTopPinnedActivity(
+                    mContext, mActivityManager);
+            final ComponentName topActivity = topPipActivityInfo.first;
+            final int userId = topActivity != null ? topPipActivityInfo.second : 0;
+            mMenuController.onActivityUnpinned();
+            mTouchHandler.onActivityUnpinned(topActivity);
+            mNotificationController.onActivityUnpinned(topActivity, userId);
 
-            SystemServicesProxy.getInstance(mContext).setPipVisibility(topPipActivity != null);
+            SystemServicesProxy.getInstance(mContext).setPipVisibility(topActivity != null);
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
index b3a0794..174a7ef 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMediaController.java
@@ -230,7 +230,7 @@
     private void resolveActiveMediaController(List<MediaController> controllers) {
         if (controllers != null) {
             final ComponentName topActivity = PipUtils.getTopPinnedActivity(mContext,
-                    mActivityManager);
+                    mActivityManager).first;
             if (topActivity != null) {
                 for (int i = 0; i < controllers.size(); i++) {
                     final MediaController controller = controllers.get(i);
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
index 34666fb..68743b3 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipMenuActivityController.java
@@ -223,7 +223,7 @@
         }
     }
 
-    public void onActivityUnpinned(ComponentName topPipActivity) {
+    public void onActivityUnpinned() {
         hideMenu();
         setStartActivityRequested(false);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
index 696fdbc..6d083e9 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipNotificationController.java
@@ -35,10 +35,15 @@
 import android.content.pm.ApplicationInfo;
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManager.NameNotFoundException;
-import android.content.res.Resources;
-import android.graphics.drawable.Icon;
+import android.graphics.Bitmap;
+import android.graphics.Bitmap.Config;
+import android.graphics.Canvas;
+import android.graphics.drawable.Drawable;
 import android.net.Uri;
+import android.os.UserHandle;
+import android.util.IconDrawableFactory;
 import android.util.Log;
+import android.util.Pair;
 
 import com.android.systemui.R;
 import com.android.systemui.SystemUI;
@@ -57,22 +62,29 @@
     private IActivityManager mActivityManager;
     private AppOpsManager mAppOpsManager;
     private NotificationManager mNotificationManager;
+    private IconDrawableFactory mIconDrawableFactory;
 
     private PipMotionHelper mMotionHelper;
 
     // Used when building a deferred notification
     private String mDeferredNotificationPackageName;
+    private int mDeferredNotificationUserId;
 
     private AppOpsManager.OnOpChangedListener mAppOpsChangedListener = new OnOpChangedListener() {
         @Override
         public void onOpChanged(String op, String packageName) {
             try {
                 // Dismiss the PiP once the user disables the app ops setting for that package
-                final ApplicationInfo appInfo = mContext.getPackageManager().getApplicationInfo(
-                        packageName, 0);
-                if (mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid, packageName)
-                        != MODE_ALLOWED) {
-                    mMotionHelper.dismissPip();
+                final Pair<ComponentName, Integer> topPipActivityInfo =
+                        PipUtils.getTopPinnedActivity(mContext, mActivityManager);
+                if (topPipActivityInfo.first != null) {
+                    final ApplicationInfo appInfo = mContext.getPackageManager()
+                            .getApplicationInfoAsUser(packageName, 0, topPipActivityInfo.second);
+                    if (appInfo.packageName.equals(topPipActivityInfo.first.getPackageName()) &&
+                                mAppOpsManager.checkOpNoThrow(OP_PICTURE_IN_PICTURE, appInfo.uid,
+                                        packageName) != MODE_ALLOWED) {
+                        mMotionHelper.dismissPip();
+                    }
                 }
             } catch (NameNotFoundException e) {
                 // Unregister the listener if the package can't be found
@@ -88,16 +100,18 @@
         mAppOpsManager = (AppOpsManager) context.getSystemService(Context.APP_OPS_SERVICE);
         mNotificationManager = NotificationManager.from(context);
         mMotionHelper = motionHelper;
+        mIconDrawableFactory = IconDrawableFactory.newInstance(context);
     }
 
-    public void onActivityPinned(String packageName, boolean deferUntilAnimationEnds) {
+    public void onActivityPinned(String packageName, int userId, boolean deferUntilAnimationEnds) {
         // Clear any existing notification
         mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
 
         if (deferUntilAnimationEnds) {
             mDeferredNotificationPackageName = packageName;
+            mDeferredNotificationUserId = userId;
         } else {
-            showNotificationForApp(mDeferredNotificationPackageName);
+            showNotificationForApp(packageName, userId);
         }
 
         // Register for changes to the app ops setting for this package while it is in PiP
@@ -106,22 +120,25 @@
 
     public void onPinnedStackAnimationEnded() {
         if (mDeferredNotificationPackageName != null) {
-            showNotificationForApp(mDeferredNotificationPackageName);
+            showNotificationForApp(mDeferredNotificationPackageName, mDeferredNotificationUserId);
             mDeferredNotificationPackageName = null;
+            mDeferredNotificationUserId = 0;
         }
     }
 
-    public void onActivityUnpinned(ComponentName topPipActivity) {
+    public void onActivityUnpinned(ComponentName topPipActivity, int userId) {
         // Unregister for changes to the previously PiP'ed package
         unregisterAppOpsListener();
 
         // Reset the deferred notification package
         mDeferredNotificationPackageName = null;
+        mDeferredNotificationUserId = 0;
 
         if (topPipActivity != null) {
             // onActivityUnpinned() is only called after the transition is complete, so we don't
             // need to defer until the animation ends to update the notification
-            onActivityPinned(topPipActivity.getPackageName(), false /* deferUntilAnimationEnds */);
+            onActivityPinned(topPipActivity.getPackageName(), userId,
+                    false /* deferUntilAnimationEnds */);
         } else {
             mNotificationManager.cancel(NOTIFICATION_TAG, NOTIFICATION_ID);
         }
@@ -130,20 +147,27 @@
     /**
      * Builds and shows the notification for the given app.
      */
-    private void showNotificationForApp(String packageName) {
+    private void showNotificationForApp(String packageName, int userId) {
         // Build a new notification
-        final Notification.Builder builder =
-                new Notification.Builder(mContext, NotificationChannels.GENERAL)
-                        .setLocalOnly(true)
-                        .setOngoing(true)
-                        .setSmallIcon(R.drawable.pip_notification_icon)
-                        .setColor(mContext.getColor(
-                                com.android.internal.R.color.system_notification_accent_color));
-        if (updateNotificationForApp(builder, packageName)) {
-            SystemUI.overrideNotificationAppName(mContext, builder);
+        try {
+            final UserHandle user = UserHandle.of(userId);
+            final Context userContext = mContext.createPackageContextAsUser(
+                    mContext.getPackageName(), 0, user);
+            final Notification.Builder builder =
+                    new Notification.Builder(userContext, NotificationChannels.GENERAL)
+                            .setLocalOnly(true)
+                            .setOngoing(true)
+                            .setSmallIcon(R.drawable.pip_notification_icon)
+                            .setColor(mContext.getColor(
+                                    com.android.internal.R.color.system_notification_accent_color));
+            if (updateNotificationForApp(builder, packageName, user)) {
+                SystemUI.overrideNotificationAppName(mContext, builder);
 
-            // Show the new notification
-            mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
+                // Show the new notification
+                mNotificationManager.notify(NOTIFICATION_TAG, NOTIFICATION_ID, builder.build());
+            }
+        } catch (NameNotFoundException e) {
+            Log.e(TAG, "Could not show notification for application", e);
         }
     }
 
@@ -151,33 +175,33 @@
      * Updates the notification builder with app-specific information, returning whether it was
      * successful.
      */
-    private boolean updateNotificationForApp(Notification.Builder builder, String packageName) {
+    private boolean updateNotificationForApp(Notification.Builder builder, String packageName,
+            UserHandle user) throws NameNotFoundException {
         final PackageManager pm = mContext.getPackageManager();
         final ApplicationInfo appInfo;
         try {
-            appInfo = pm.getApplicationInfo(packageName, 0);
+            appInfo = pm.getApplicationInfoAsUser(packageName, 0, user.getIdentifier());
         } catch (NameNotFoundException e) {
             Log.e(TAG, "Could not update notification for application", e);
             return false;
         }
 
         if (appInfo != null) {
-            final String appName = pm.getApplicationLabel(appInfo).toString();
+            final String appName = pm.getUserBadgedLabel(pm.getApplicationLabel(appInfo), user)
+                    .toString();
             final String message = mContext.getString(R.string.pip_notification_message, appName);
             final Intent settingsIntent = new Intent(ACTION_PICTURE_IN_PICTURE_SETTINGS,
                     Uri.fromParts("package", packageName, null));
+            settingsIntent.putExtra(Intent.EXTRA_USER_HANDLE, user);
             settingsIntent.setFlags(FLAG_ACTIVITY_NEW_TASK | FLAG_ACTIVITY_CLEAR_TASK);
-            final Icon appIcon = appInfo.icon != 0
-                    ? Icon.createWithResource(packageName, appInfo.icon)
-                    : Icon.createWithResource(Resources.getSystem(),
-                            com.android.internal.R.drawable.sym_def_app_icon);
 
+            final Drawable iconDrawable = mIconDrawableFactory.getBadgedIcon(appInfo);
             builder.setContentTitle(mContext.getString(R.string.pip_notification_title, appName))
                     .setContentText(message)
-                    .setContentIntent(PendingIntent.getActivity(mContext, packageName.hashCode(),
-                            settingsIntent, FLAG_CANCEL_CURRENT))
+                    .setContentIntent(PendingIntent.getActivityAsUser(mContext, packageName.hashCode(),
+                            settingsIntent, FLAG_CANCEL_CURRENT, null, user))
                     .setStyle(new Notification.BigTextStyle().bigText(message))
-                    .setLargeIcon(appIcon);
+                    .setLargeIcon(createBitmap(iconDrawable).createAshmemBitmap());
             return true;
         }
         return false;
@@ -191,4 +215,17 @@
     private void unregisterAppOpsListener() {
         mAppOpsManager.stopWatchingMode(mAppOpsChangedListener);
     }
+
+    /**
+     * Bakes a drawable into a bitmap.
+     */
+    private Bitmap createBitmap(Drawable d) {
+        Bitmap bitmap = Bitmap.createBitmap(d.getIntrinsicWidth(), d.getIntrinsicHeight(),
+                Config.ARGB_8888);
+        Canvas c = new Canvas(bitmap);
+        d.setBounds(0, 0, d.getIntrinsicWidth(), d.getIntrinsicHeight());
+        d.draw(c);
+        c.setBitmap(null);
+        return bitmap;
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
index a8cdd1b..56275fd 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/phone/PipUtils.java
@@ -24,16 +24,17 @@
 import android.content.Context;
 import android.os.RemoteException;
 import android.util.Log;
+import android.util.Pair;
 
 public class PipUtils {
 
     private static final String TAG = "PipUtils";
 
     /**
-     * @return the ComponentName of the top non-SystemUI activity in the pinned stack, or null if
-     *         none exists.
+     * @return the ComponentName and user id of the top non-SystemUI activity in the pinned stack.
+     *         The component name may be null if no such activity exists.
      */
-    public static ComponentName getTopPinnedActivity(Context context,
+    public static Pair<ComponentName, Integer> getTopPinnedActivity(Context context,
             IActivityManager activityManager) {
         try {
             final String sysUiPackageName = context.getPackageName();
@@ -44,13 +45,13 @@
                     ComponentName cn = ComponentName.unflattenFromString(
                             pinnedStackInfo.taskNames[i]);
                     if (cn != null && !cn.getPackageName().equals(sysUiPackageName)) {
-                        return cn;
+                        return new Pair<>(cn, pinnedStackInfo.taskUserIds[i]);
                     }
                 }
             }
         } catch (RemoteException e) {
             Log.w(TAG, "Unable to get pinned stack.");
         }
-        return null;
+        return new Pair<>(null, 0);
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
index e8c1295..186de5c4 100644
--- a/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
+++ b/packages/SystemUI/src/com/android/systemui/pip/tv/PipManager.java
@@ -654,7 +654,7 @@
         }
 
         @Override
-        public void onActivityPinned(String packageName, int taskId) {
+        public void onActivityPinned(String packageName, int userId, int taskId) {
             if (DEBUG) Log.d(TAG, "onActivityPinned()");
             if (!checkCurrentUserId(mContext, DEBUG)) {
                 return;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
index aecf95f..5d5c4a0 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsImpl.java
@@ -173,7 +173,7 @@
         }
 
         @Override
-        public void onActivityPinned(String packageName, int taskId) {
+        public void onActivityPinned(String packageName, int userId, int taskId) {
             // Check this is for the right user
             if (!checkCurrentUserId(mContext, false /* debug */)) {
                 return;
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 c66b2dd..c9ef43e 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/misc/SystemServicesProxy.java
@@ -176,7 +176,7 @@
         public void onTaskStackChangedBackground() { }
         public void onTaskStackChanged() { }
         public void onTaskSnapshotChanged(int taskId, TaskSnapshot snapshot) { }
-        public void onActivityPinned(String packageName, int taskId) { }
+        public void onActivityPinned(String packageName, int userId, int taskId) { }
         public void onActivityUnpinned() { }
         public void onPinnedActivityRestartAttempt(boolean clearedTask) { }
         public void onPinnedStackAnimationStarted() { }
@@ -231,9 +231,10 @@
         }
 
         @Override
-        public void onActivityPinned(String packageName, int taskId) throws RemoteException {
+        public void onActivityPinned(String packageName, int userId, int taskId)
+                throws RemoteException {
             mHandler.removeMessages(H.ON_ACTIVITY_PINNED);
-            mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, taskId, 0, packageName).sendToTarget();
+            mHandler.obtainMessage(H.ON_ACTIVITY_PINNED, userId, taskId, packageName).sendToTarget();
         }
 
         @Override
@@ -1387,7 +1388,8 @@
                     }
                     case ON_ACTIVITY_PINNED: {
                         for (int i = mTaskStackListeners.size() - 1; i >= 0; i--) {
-                            mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1);
+                            mTaskStackListeners.get(i).onActivityPinned((String) msg.obj, msg.arg1,
+                                    msg.arg2);
                         }
                         break;
                     }
diff --git a/proto/src/metrics_constants.proto b/proto/src/metrics_constants.proto
index f15749f..54c9ec5 100644
--- a/proto/src/metrics_constants.proto
+++ b/proto/src/metrics_constants.proto
@@ -4527,6 +4527,17 @@
     // Type TYPE_FAILURE: An invalid opperation was reported by the app's AutofillManager
     AUTOFILL_PENDING_SAVE_UI_OPERATION = 1134;
 
+    // Autofill service called API that disables itself
+    // Package: Package of the autofill service
+    // OS: O MR
+    AUTOFILL_SERVICE_DISABLED_SELF = 1135;
+
+    // Counter showing how long it took (in ms) to show the autofill UI after a field was focused
+    // Tag FIELD_AUTOFILL_SERVICE: Package of service that processed the request
+    // Package: Package of the autofill service
+    // OS: O MR
+    AUTOFILL_UI_LATENCY = 1136;
+
     // ---- End O-MR1 Constants, all O-MR1 constants go above this line ----
 
     // Add new aosp constants above this line.
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index a1c75bf..1f4161a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -115,11 +115,24 @@
     private final SparseBooleanArray mDisabledUsers = new SparseBooleanArray();
 
     private final LocalLog mRequestsHistory = new LocalLog(20);
+    private final LocalLog mUiLatencyHistory = new LocalLog(20);
 
     private final BroadcastReceiver mBroadcastReceiver = new BroadcastReceiver() {
         @Override
         public void onReceive(Context context, Intent intent) {
             if (Intent.ACTION_CLOSE_SYSTEM_DIALOGS.equals(intent.getAction())) {
+                if (sDebug) Slog.d(TAG, "Close system dialogs");
+
+                // TODO(b/64940307): we need to destroy all sessions that are finished but showing
+                // Save UI because there is no way to show the Save UI back when the activity
+                // beneath it is brought back to top. Ideally, we should just hide the UI and
+                // bring it back when the activity resumes.
+                synchronized (mLock) {
+                    for (int i = 0; i < mServicesCache.size(); i++) {
+                        mServicesCache.valueAt(i).destroyFinishedSessionsLocked();
+                    }
+                }
+
                 mUi.hideAll(null);
             }
         }
@@ -294,7 +307,7 @@
         AutofillManagerServiceImpl service = mServicesCache.get(resolvedUserId);
         if (service == null) {
             service = new AutofillManagerServiceImpl(mContext, mLock, mRequestsHistory,
-                    resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
+                    mUiLatencyHistory, resolvedUserId, mUi, mDisabledUsers.get(resolvedUserId));
             mServicesCache.put(userId, service);
         }
         return service;
@@ -724,6 +737,8 @@
                 if (showHistory) {
                     pw.println("Requests history:");
                     mRequestsHistory.reverseDump(fd, pw, args);
+                    pw.println("UI latency history:");
+                    mUiLatencyHistory.reverseDump(fd, pw, args);
                 }
             } finally {
                 setDebugLocked(oldDebug);
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index e28e1c9..3a3b570 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -35,6 +35,7 @@
 import android.content.pm.ServiceInfo;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
+import android.metrics.LogMaker;
 import android.os.AsyncTask;
 import android.os.Binder;
 import android.os.Bundle;
@@ -63,6 +64,8 @@
 
 import com.android.internal.R;
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.logging.MetricsLogger;
+import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.os.HandlerCaller;
 import com.android.server.autofill.ui.AutoFillUI;
 
@@ -89,6 +92,7 @@
     private final Context mContext;
     private final Object mLock;
     private final AutoFillUI mUi;
+    private final MetricsLogger mMetricsLogger = new MetricsLogger();
 
     private RemoteCallbackList<IAutoFillManagerClient> mClients;
     private AutofillServiceInfo mInfo;
@@ -96,6 +100,8 @@
     private static final Random sRandom = new Random();
 
     private final LocalLog mRequestsHistory;
+    private final LocalLog mUiLatencyHistory;
+
     /**
      * Whether service was disabled for user due to {@link UserManager} restrictions.
      */
@@ -137,10 +143,11 @@
     private long mLastPrune = 0;
 
     AutofillManagerServiceImpl(Context context, Object lock, LocalLog requestsHistory,
-            int userId, AutoFillUI ui, boolean disabled) {
+            LocalLog uiLatencyHistory, int userId, AutoFillUI ui, boolean disabled) {
         mContext = context;
         mLock = lock;
         mRequestsHistory = requestsHistory;
+        mUiLatencyHistory = uiLatencyHistory;
         mUserId = userId;
         mUi = ui;
         updateLocked(disabled);
@@ -218,8 +225,10 @@
             if (serviceInfo != null) {
                 mInfo = new AutofillServiceInfo(mContext.getPackageManager(),
                         serviceComponent, mUserId);
+                if (sDebug) Slog.d(TAG, "Set component for user " + mUserId + " as " + mInfo);
             } else {
                 mInfo = null;
+                if (sDebug) Slog.d(TAG, "Reset component for user " + mUserId);
             }
             final boolean isEnabled = isEnabled();
             if (wasEnabled != isEnabled) {
@@ -345,17 +354,31 @@
     }
 
     void disableOwnedAutofillServicesLocked(int uid) {
-        if (mInfo == null || mInfo.getServiceInfo().applicationInfo.uid != uid) {
+        Slog.i(TAG, "disableOwnedServices(" + uid + "): " + mInfo);
+        if (mInfo == null) return;
+
+        final ServiceInfo serviceInfo = mInfo.getServiceInfo();
+        if (serviceInfo.applicationInfo.uid != uid) {
+            Slog.w(TAG, "disableOwnedServices(): ignored when called by UID " + uid
+                    + " instead of " + serviceInfo.applicationInfo.uid
+                    + " for service " + mInfo);
             return;
         }
+
+
         final long identity = Binder.clearCallingIdentity();
         try {
             final String autoFillService = getComponentNameFromSettings();
-            if (mInfo.getServiceInfo().getComponentName().equals(
-                    ComponentName.unflattenFromString(autoFillService))) {
+            final ComponentName componentName = serviceInfo.getComponentName();
+            if (componentName.equals(ComponentName.unflattenFromString(autoFillService))) {
+                mMetricsLogger.action(MetricsEvent.AUTOFILL_SERVICE_DISABLED_SELF,
+                        componentName.getPackageName());
                 Settings.Secure.putStringForUser(mContext.getContentResolver(),
                         Settings.Secure.AUTOFILL_SERVICE, null, mUserId);
                 destroySessionsLocked();
+            } else {
+                Slog.w(TAG, "disableOwnedServices(): ignored because current service ("
+                        + serviceInfo + ") does not match Settings (" + autoFillService + ")");
             }
         } finally {
             Binder.restoreCallingIdentity(identity);
@@ -379,7 +402,7 @@
 
         final Session newSession = new Session(this, mUi, mContext, mHandlerCaller, mUserId, mLock,
                 sessionId, uid, activityToken, appCallbackToken, hasCallback,
-                mInfo.getServiceInfo().getComponentName(), packageName);
+                mUiLatencyHistory, mInfo.getServiceInfo().getComponentName(), packageName);
         mSessions.put(newSession.id, newSession);
 
         return newSession;
@@ -452,7 +475,7 @@
             final int sessionCount = mSessions.size();
             for (int i = sessionCount - 1; i >= 0; i--) {
                 final Session session = mSessions.valueAt(i);
-                if (session.isSaveUiPendingForToken(token)) {
+                if (session.isSaveUiPendingForTokenLocked(token)) {
                     session.onPendingSaveUi(operation, token);
                     return;
                 }
@@ -641,6 +664,18 @@
         }
     }
 
+    // TODO(b/64940307): remove this method if SaveUI is refactored to be attached on activities
+    void destroyFinishedSessionsLocked() {
+        final int sessionCount = mSessions.size();
+        for (int i = sessionCount - 1; i >= 0; i--) {
+            final Session session = mSessions.valueAt(i);
+            if (session.isSavingLocked()) {
+                if (sDebug) Slog.d(TAG, "destroyFinishedSessionsLocked(): " + session.id);
+                session.forceRemoveSelfLocked();
+            }
+        }
+    }
+
     void listSessionsLocked(ArrayList<String> output) {
         final int numSessions = mSessions.size();
         for (int i = 0; i < numSessions; i++) {
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index ff6e94b..905db67 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -50,6 +50,7 @@
 import android.os.IBinder;
 import android.os.Parcelable;
 import android.os.RemoteException;
+import android.os.SystemClock;
 import android.service.autofill.AutofillService;
 import android.service.autofill.Dataset;
 import android.service.autofill.FillContext;
@@ -61,8 +62,10 @@
 import android.service.autofill.ValueFinder;
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.LocalLog;
 import android.util.Slog;
 import android.util.SparseArray;
+import android.util.TimeUtils;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
 import android.view.autofill.AutofillValue;
@@ -177,6 +180,20 @@
     private PendingUi mPendingSaveUi;
 
     /**
+     * When the session started (using elapsed time since boot).
+     */
+    private final long mStartTime;
+
+    /**
+     * When the UI was shown for the first time (using elapsed time since boot).
+     */
+    @GuardedBy("mLock")
+    private long mUiShownTime;
+
+    @GuardedBy("mLock")
+    private final LocalLog mUiLatencyHistory;
+
+    /**
      * Receiver of assist data from the app's {@link Activity}.
      */
     private final IResultReceiver mAssistReceiver = new IResultReceiver.Stub() {
@@ -397,10 +414,11 @@
     Session(@NonNull AutofillManagerServiceImpl service, @NonNull AutoFillUI ui,
             @NonNull Context context, @NonNull HandlerCaller handlerCaller, int userId,
             @NonNull Object lock, int sessionId, int uid, @NonNull IBinder activityToken,
-            @NonNull IBinder client, boolean hasCallback,
+            @NonNull IBinder client, boolean hasCallback, @NonNull LocalLog uiLatencyHistory,
             @NonNull ComponentName componentName, @NonNull String packageName) {
         id = sessionId;
         this.uid = uid;
+        mStartTime = SystemClock.elapsedRealtime();
         mService = service;
         mLock = lock;
         mUi = ui;
@@ -408,6 +426,7 @@
         mRemoteFillService = new RemoteFillService(context, componentName, userId, this);
         mActivityToken = activityToken;
         mHasCallback = hasCallback;
+        mUiLatencyHistory = uiLatencyHistory;
         mPackageName = packageName;
         mClient = IAutoFillManagerClient.Stub.asInterface(client);
 
@@ -1347,6 +1366,31 @@
 
         getUiForShowing().showFillUi(filledId, response, filterText,
                 mService.getServicePackageName(), mPackageName, this);
+
+        synchronized (mLock) {
+            if (mUiShownTime == 0) {
+                // Log first time UI is shown.
+                mUiShownTime = SystemClock.elapsedRealtime();
+                final long duration = mUiShownTime - mStartTime;
+                if (sDebug) {
+                    final StringBuilder msg = new StringBuilder("1st UI for ")
+                            .append(mActivityToken)
+                            .append(" shown in ");
+                    TimeUtils.formatDuration(duration, msg);
+                    Slog.d(TAG, msg.toString());
+                }
+                final StringBuilder historyLog = new StringBuilder("id=").append(id)
+                        .append(" app=").append(mActivityToken)
+                        .append(" svc=").append(mService.getServicePackageName())
+                        .append(" latency=");
+                TimeUtils.formatDuration(duration, historyLog);
+                mUiLatencyHistory.log(historyLog.toString());
+
+                final LogMaker metricsLog = newLogMaker(MetricsEvent.AUTOFILL_UI_LATENCY)
+                        .setCounterValue((int) duration);
+                mMetricsLogger.write(metricsLog);
+            }
+        }
     }
 
     boolean isDestroyed() {
@@ -1368,7 +1412,7 @@
                 if (mHasCallback) {
                     mClient.notifyNoFillUi(id, mCurrentViewId, sessionFinished);
                 } else if (sessionFinished) {
-                    mClient.setSessionFinished();
+                    mClient.setSessionFinished(AutofillManager.STATE_FINISHED);
                 }
             } catch (RemoteException e) {
                 Slog.e(TAG, "Error notifying client no fill UI: id=" + mCurrentViewId, e);
@@ -1655,6 +1699,14 @@
         pw.print(prefix); pw.print("uid: "); pw.println(uid);
         pw.print(prefix); pw.print("mPackagename: "); pw.println(mPackageName);
         pw.print(prefix); pw.print("mActivityToken: "); pw.println(mActivityToken);
+        pw.print(prefix); pw.print("mStartTime: "); pw.println(mStartTime);
+        pw.print(prefix); pw.print("Time to show UI: ");
+        if (mUiShownTime == 0) {
+            pw.println("N/A");
+        } else {
+            TimeUtils.formatDuration(mUiShownTime - mStartTime, pw);
+            pw.println();
+        }
         pw.print(prefix); pw.print("mResponses: ");
         if (mResponses == null) {
             pw.println("null");
@@ -1780,18 +1832,17 @@
     void forceRemoveSelfLocked() {
         if (sVerbose) Slog.v(TAG, "forceRemoveSelfLocked(): " + mPendingSaveUi);
 
+        final boolean isPendingSaveUi = isSaveUiPendingLocked();
         mPendingSaveUi = null;
         removeSelfLocked();
-
-        mHandlerCaller.getHandler().post(() -> {
-            try {
-                mClient.setState(mService.isEnabled(), true, false);
-            } catch (RemoteException e) {
-                Slog.w(TAG, "error updating client state: " + e);
-            }
-        });
-
         mUi.destroyAll(mPendingSaveUi, this, false);
+        if (!isPendingSaveUi) {
+            try {
+                mClient.setSessionFinished(AutofillManager.STATE_UNKNOWN);
+            } catch (RemoteException e) {
+                Slog.e(TAG, "Error notifying client to finish session", e);
+            }
+        }
     }
 
     /**
@@ -1814,7 +1865,7 @@
                     + id + " destroyed");
             return;
         }
-        if (isSaveUiPending()) {
+        if (isSaveUiPendingLocked()) {
             Slog.i(TAG, "removeSelfLocked() ignored, waiting for pending save ui");
             return;
         }
@@ -1835,14 +1886,14 @@
      * a specific {@code token} created by
      * {@link PendingUi#PendingUi(IBinder, int, IAutoFillManagerClient)}.
      */
-    boolean isSaveUiPendingForToken(@NonNull IBinder token) {
-        return isSaveUiPending() && token.equals(mPendingSaveUi.getToken());
+    boolean isSaveUiPendingForTokenLocked(@NonNull IBinder token) {
+        return isSaveUiPendingLocked() && token.equals(mPendingSaveUi.getToken());
     }
 
     /**
      * Checks whether this session is hiding the Save UI to handle a custom description link.
      */
-    private boolean isSaveUiPending() {
+    private boolean isSaveUiPendingLocked() {
         return mPendingSaveUi != null && mPendingSaveUi.getState() == PendingUi.STATE_PENDING;
     }
 
diff --git a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
index 32f4d69..cd9bdb7 100644
--- a/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
+++ b/services/autofill/java/com/android/server/autofill/ui/SaveUi.java
@@ -263,9 +263,7 @@
         } else {
             noButton.setText(R.string.autofill_save_no);
         }
-        final View.OnClickListener cancelListener =
-                (v) -> mListener.onCancel(info.getNegativeActionListener());
-        noButton.setOnClickListener(cancelListener);
+        noButton.setOnClickListener((v) -> mListener.onCancel(info.getNegativeActionListener()));
 
         final View yesButton = view.findViewById(R.id.autofill_save_yes);
         yesButton.setOnClickListener((v) -> mListener.onSave());
@@ -273,9 +271,6 @@
         mDialog = new Dialog(context, R.style.Theme_DeviceDefault_Light_Panel);
         mDialog.setContentView(view);
 
-        // Dialog can be dismissed when touched outside.
-        mDialog.setOnDismissListener((d) -> mListener.onCancel(info.getNegativeActionListener()));
-
         final Window window = mDialog.getWindow();
         window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
         window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
@@ -305,7 +300,7 @@
 
         if (actualWidth <= maxWidth && actualHeight <= maxHeight) {
             if (sDebug) {
-                Slog.d(TAG, "Addingservice icon "
+                Slog.d(TAG, "Adding service icon "
                         + "(" + actualWidth + "x" + actualHeight + ") as it's less than maximum "
                         + "(" + maxWidth + "x" + maxHeight + ").");
             }
diff --git a/services/core/java/com/android/server/ConnectivityService.java b/services/core/java/com/android/server/ConnectivityService.java
index e70a294..2b4f0f3 100644
--- a/services/core/java/com/android/server/ConnectivityService.java
+++ b/services/core/java/com/android/server/ConnectivityService.java
@@ -2205,7 +2205,7 @@
                 // A network factory has connected.  Send it all current NetworkRequests.
                 for (NetworkRequestInfo nri : mNetworkRequests.values()) {
                     if (nri.request.isListen()) continue;
-                    NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+                    NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
                     ac.sendMessage(android.net.NetworkFactory.CMD_REQUEST_NETWORK,
                             (nai != null ? nai.getCurrentScore() : 0), 0, nri.request);
                 }
@@ -2282,9 +2282,9 @@
             // Remove all previously satisfied requests.
             for (int i = 0; i < nai.numNetworkRequests(); i++) {
                 NetworkRequest request = nai.requestAt(i);
-                NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(request.requestId);
+                NetworkAgentInfo currentNetwork = getNetworkForRequest(request.requestId);
                 if (currentNetwork != null && currentNetwork.network.netId == nai.network.netId) {
-                    mNetworkForRequestId.remove(request.requestId);
+                    clearNetworkForRequest(request.requestId);
                     sendUpdatedScoreToFactories(request, 0);
                 }
             }
@@ -2360,7 +2360,7 @@
             }
         }
         rematchAllNetworksAndRequests(null, 0);
-        if (nri.request.isRequest() && mNetworkForRequestId.get(nri.request.requestId) == null) {
+        if (nri.request.isRequest() && getNetworkForRequest(nri.request.requestId) == null) {
             sendUpdatedScoreToFactories(nri.request, 0);
         }
     }
@@ -2415,7 +2415,7 @@
                     // 2. Unvalidated WiFi will not be reaped when validated cellular
                     //    is currently satisfying the request.  This is desirable when
                     //    WiFi ends up validating and out scoring cellular.
-                    mNetworkForRequestId.get(nri.request.requestId).getCurrentScore() <
+                    getNetworkForRequest(nri.request.requestId).getCurrentScore() <
                             nai.getCurrentScoreAsValidated())) {
                 return false;
             }
@@ -2442,7 +2442,7 @@
         if (mNetworkRequests.get(nri.request) == null) {
             return;
         }
-        if (mNetworkForRequestId.get(nri.request.requestId) != null) {
+        if (getNetworkForRequest(nri.request.requestId) != null) {
             return;
         }
         if (VDBG || (DBG && nri.request.isRequest())) {
@@ -2482,7 +2482,7 @@
         mNetworkRequestInfoLogs.log("RELEASE " + nri);
         if (nri.request.isRequest()) {
             boolean wasKept = false;
-            NetworkAgentInfo nai = mNetworkForRequestId.get(nri.request.requestId);
+            NetworkAgentInfo nai = getNetworkForRequest(nri.request.requestId);
             if (nai != null) {
                 boolean wasBackgroundNetwork = nai.isBackgroundNetwork();
                 nai.removeRequest(nri.request.requestId);
@@ -2499,7 +2499,7 @@
                 } else {
                     wasKept = true;
                 }
-                mNetworkForRequestId.remove(nri.request.requestId);
+                clearNetworkForRequest(nri.request.requestId);
                 if (!wasBackgroundNetwork && nai.isBackgroundNetwork()) {
                     // Went from foreground to background.
                     updateCapabilities(nai.getCurrentScore(), nai, nai.networkCapabilities);
@@ -4296,7 +4296,8 @@
      * and the are the highest scored network available.
      * the are keyed off the Requests requestId.
      */
-    // TODO: Yikes, this is accessed on multiple threads: add synchronization.
+    // NOTE: Accessed on multiple threads, must be synchronized on itself.
+    @GuardedBy("mNetworkForRequestId")
     private final SparseArray<NetworkAgentInfo> mNetworkForRequestId =
             new SparseArray<NetworkAgentInfo>();
 
@@ -4326,8 +4327,26 @@
     // priority networks like Wi-Fi are active.
     private final NetworkRequest mDefaultMobileDataRequest;
 
+    private NetworkAgentInfo getNetworkForRequest(int requestId) {
+        synchronized (mNetworkForRequestId) {
+            return mNetworkForRequestId.get(requestId);
+        }
+    }
+
+    private void clearNetworkForRequest(int requestId) {
+        synchronized (mNetworkForRequestId) {
+            mNetworkForRequestId.remove(requestId);
+        }
+    }
+
+    private void setNetworkForRequest(int requestId, NetworkAgentInfo nai) {
+        synchronized (mNetworkForRequestId) {
+            mNetworkForRequestId.put(requestId, nai);
+        }
+    }
+
     private NetworkAgentInfo getDefaultNetwork() {
-        return mNetworkForRequestId.get(mDefaultRequest.requestId);
+        return getNetworkForRequest(mDefaultRequest.requestId);
     }
 
     private boolean isDefaultNetwork(NetworkAgentInfo nai) {
@@ -4886,7 +4905,7 @@
             // requests or not, and doesn't affect the network's score.
             if (nri.request.isListen()) continue;
 
-            final NetworkAgentInfo currentNetwork = mNetworkForRequestId.get(nri.request.requestId);
+            final NetworkAgentInfo currentNetwork = getNetworkForRequest(nri.request.requestId);
             final boolean satisfies = newNetwork.satisfies(nri.request);
             if (newNetwork == currentNetwork && satisfies) {
                 if (VDBG) {
@@ -4918,7 +4937,7 @@
                         if (VDBG) log("   accepting network in place of null");
                     }
                     newNetwork.unlingerRequest(nri.request);
-                    mNetworkForRequestId.put(nri.request.requestId, newNetwork);
+                    setNetworkForRequest(nri.request.requestId, newNetwork);
                     if (!newNetwork.addRequest(nri.request)) {
                         Slog.wtf(TAG, "BUG: " + newNetwork.name() + " already has " + nri.request);
                     }
@@ -4952,7 +4971,7 @@
                 }
                 newNetwork.removeRequest(nri.request.requestId);
                 if (currentNetwork == newNetwork) {
-                    mNetworkForRequestId.remove(nri.request.requestId);
+                    clearNetworkForRequest(nri.request.requestId);
                     sendUpdatedScoreToFactories(nri.request, 0);
                 } else {
                     Slog.wtf(TAG, "BUG: Removing request " + nri.request.requestId + " from " +
diff --git a/services/core/java/com/android/server/am/ActivityStackSupervisor.java b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
index ab6e602..b2dc3e6 100644
--- a/services/core/java/com/android/server/am/ActivityStackSupervisor.java
+++ b/services/core/java/com/android/server/am/ActivityStackSupervisor.java
@@ -3042,7 +3042,7 @@
         ensureActivitiesVisibleLocked(null, 0, !PRESERVE_WINDOWS);
         resumeFocusedStackTopActivityLocked();
 
-        mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName,
+        mService.mTaskChangeNotificationController.notifyActivityPinned(r.packageName, r.userId,
                 r.getTask().taskId);
     }
 
diff --git a/services/core/java/com/android/server/am/TaskChangeNotificationController.java b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
index 8297169..6a986bb 100644
--- a/services/core/java/com/android/server/am/TaskChangeNotificationController.java
+++ b/services/core/java/com/android/server/am/TaskChangeNotificationController.java
@@ -95,7 +95,7 @@
     };
 
     private final TaskStackConsumer mNotifyActivityPinned = (l, m) -> {
-        l.onActivityPinned((String) m.obj, m.arg1);
+        l.onActivityPinned((String) m.obj, m.arg1, m.arg2);
     };
 
     private final TaskStackConsumer mNotifyActivityUnpinned = (l, m) -> {
@@ -278,10 +278,10 @@
     }
 
     /** Notifies all listeners when an Activity is pinned. */
-    void notifyActivityPinned(String packageName, int taskId) {
+    void notifyActivityPinned(String packageName, int userId, int taskId) {
         mHandler.removeMessages(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG);
         final Message msg = mHandler.obtainMessage(NOTIFY_ACTIVITY_PINNED_LISTENERS_MSG,
-                taskId, 0, packageName);
+                userId, taskId, packageName);
         forAllLocalListeners(mNotifyActivityPinned, msg);
         msg.sendToTarget();
     }
diff --git a/services/core/java/com/android/server/media/MediaRouterService.java b/services/core/java/com/android/server/media/MediaRouterService.java
index 3795b7f..1cfd5f0 100644
--- a/services/core/java/com/android/server/media/MediaRouterService.java
+++ b/services/core/java/com/android/server/media/MediaRouterService.java
@@ -271,14 +271,6 @@
 
     // Binder call
     @Override
-    public boolean isGlobalBluetoothA2doOn() {
-        synchronized (mLock) {
-            return mGlobalBluetoothA2dpOn;
-        }
-    }
-
-    // Binder call
-    @Override
     public void setDiscoveryRequest(IMediaRouterClient client,
             int routeTypes, boolean activeScan) {
         if (client == null) {
@@ -383,7 +375,7 @@
             synchronized (mLock) {
                 a2dpOn = mGlobalBluetoothA2dpOn;
             }
-            Slog.v(TAG, "restoreBluetoothA2dp( " + a2dpOn + ")");
+            Slog.v(TAG, "restoreBluetoothA2dp(" + a2dpOn + ")");
             mAudioService.setBluetoothA2dpOn(a2dpOn);
         } catch (RemoteException e) {
             Slog.w(TAG, "RemoteException while calling setBluetoothA2dpOn.");
diff --git a/services/core/java/com/android/server/notification/NotificationManagerService.java b/services/core/java/com/android/server/notification/NotificationManagerService.java
index 92b360b..08b96d1 100644
--- a/services/core/java/com/android/server/notification/NotificationManagerService.java
+++ b/services/core/java/com/android/server/notification/NotificationManagerService.java
@@ -16,8 +16,10 @@
 
 package com.android.server.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_MIN;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 import static android.content.pm.PackageManager.FEATURE_LEANBACK;
 import static android.content.pm.PackageManager.FEATURE_TELEVISION;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
@@ -1143,6 +1145,12 @@
     }
 
     @VisibleForTesting
+    NotificationRecord getNotificationRecord(String key) {
+        return mNotificationsByKey.get(key);
+    }
+
+
+    @VisibleForTesting
     void setSystemReady(boolean systemReady) {
         mSystemReady = systemReady;
     }
@@ -1217,7 +1225,7 @@
         mUsageStats = usageStats;
         mRankingHandler = new RankingHandlerWorker(mRankingThread.getLooper());
         mRankingHelper = new RankingHelper(getContext(),
-                getContext().getPackageManager(),
+                mPackageManagerClient,
                 mRankingHandler,
                 mUsageStats,
                 extractorNames);
@@ -1477,7 +1485,7 @@
                 }
             }
         }
-        mRankingHelper.updateNotificationChannel(pkg, uid, channel);
+        mRankingHelper.updateNotificationChannel(pkg, uid, channel, true);
 
         if (!fromListener) {
             final NotificationChannel modifiedChannel =
@@ -3485,6 +3493,21 @@
                 user, null, System.currentTimeMillis());
         final NotificationRecord r = new NotificationRecord(getContext(), n, channel);
 
+        if ((notification.flags & Notification.FLAG_FOREGROUND_SERVICE) != 0
+                && (channel.getUserLockedFields() & NotificationChannel.USER_LOCKED_IMPORTANCE) == 0
+                && (r.getImportance() == IMPORTANCE_MIN || r.getImportance() == IMPORTANCE_NONE)) {
+            // Increase the importance of foreground service notifications unless the user had an
+            // opinion otherwise
+            if (TextUtils.isEmpty(channelId)
+                    || NotificationChannel.DEFAULT_CHANNEL_ID.equals(channelId)) {
+                r.setImportance(IMPORTANCE_LOW, "Bumped for foreground service");
+            } else {
+                channel.setImportance(IMPORTANCE_LOW);
+                mRankingHelper.updateNotificationChannel(pkg, notificationUid, channel, false);
+                r.updateNotificationChannel(channel);
+            }
+        }
+
         if (!checkDisqualifyingFeatures(userId, notificationUid, id, tag, r,
                 r.sbn.getOverrideGroupKey() != null)) {
             return;
diff --git a/services/core/java/com/android/server/notification/RankingConfig.java b/services/core/java/com/android/server/notification/RankingConfig.java
index 36da04d..332ab6d 100644
--- a/services/core/java/com/android/server/notification/RankingConfig.java
+++ b/services/core/java/com/android/server/notification/RankingConfig.java
@@ -38,7 +38,7 @@
             int uid, boolean includeDeleted);
     void createNotificationChannel(String pkg, int uid, NotificationChannel channel,
             boolean fromTargetApp);
-    void updateNotificationChannel(String pkg, int uid, NotificationChannel channel);
+    void updateNotificationChannel(String pkg, int uid, NotificationChannel channel, boolean fromUser);
     NotificationChannel getNotificationChannel(String pkg, int uid, String channelId, boolean includeDeleted);
     void deleteNotificationChannel(String pkg, int uid, String channelId);
     void permanentlyDeleteNotificationChannel(String pkg, int uid, String channelId);
diff --git a/services/core/java/com/android/server/notification/RankingHelper.java b/services/core/java/com/android/server/notification/RankingHelper.java
index f193a19..9db4584 100644
--- a/services/core/java/com/android/server/notification/RankingHelper.java
+++ b/services/core/java/com/android/server/notification/RankingHelper.java
@@ -589,7 +589,8 @@
     }
 
     @Override
-    public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel) {
+    public void updateNotificationChannel(String pkg, int uid, NotificationChannel updatedChannel,
+            boolean fromUser) {
         Preconditions.checkNotNull(updatedChannel);
         Preconditions.checkNotNull(updatedChannel.getId());
         Record r = getOrCreateRecord(pkg, uid);
@@ -603,7 +604,11 @@
         if (updatedChannel.getLockscreenVisibility() == Notification.VISIBILITY_PUBLIC) {
             updatedChannel.setLockscreenVisibility(Ranking.VISIBILITY_NO_OVERRIDE);
         }
-        lockFieldsForUpdate(channel, updatedChannel);
+        updatedChannel.unlockFields(updatedChannel.getUserLockedFields());
+        updatedChannel.lockFields(channel.getUserLockedFields());
+        if (fromUser) {
+            lockFieldsForUpdate(channel, updatedChannel);
+        }
         r.channels.put(updatedChannel.getId(), updatedChannel);
 
         if (NotificationChannel.DEFAULT_CHANNEL_ID.equals(updatedChannel.getId())) {
@@ -828,8 +833,6 @@
 
     @VisibleForTesting
     void lockFieldsForUpdate(NotificationChannel original, NotificationChannel update) {
-        update.unlockFields(update.getUserLockedFields());
-        update.lockFields(original.getUserLockedFields());
         if (original.canBypassDnd() != update.canBypassDnd()) {
             update.lockFields(NotificationChannel.USER_LOCKED_PRIORITY);
         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index ea1c029..aae9170 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -3312,6 +3312,24 @@
             removeCodePathLI(dstCodePath);
             return null;
         }
+
+        // If we have a profile for a compressed APK, copy it to the reference location.
+        // Since the package is the stub one, remove the stub suffix to get the normal package and
+        // APK name.
+        File profileFile = new File(getPrebuildProfilePath(pkg).replace(STUB_SUFFIX, ""));
+        if (profileFile.exists()) {
+            try {
+                // We could also do this lazily before calling dexopt in
+                // PackageDexOptimizer to prevent this happening on first boot. The issue
+                // is that we don't have a good way to say "do this only once".
+                if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
+                        pkg.applicationInfo.uid, pkg.packageName)) {
+                    Log.e(TAG, "decompressPackage failed to copy system profile!");
+                }
+            } catch (Exception e) {
+                Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ", e);
+            }
+        }
         return dstCodePath;
     }
 
@@ -9723,7 +9741,7 @@
      * and {@code numberOfPackagesFailed}.
      */
     private int[] performDexOptUpgrade(List<PackageParser.Package> pkgs, boolean showDialog,
-            String compilerFilter, boolean bootComplete) {
+            final String compilerFilter, boolean bootComplete) {
 
         int numberOfPackagesVisited = 0;
         int numberOfPackagesOptimized = 0;
@@ -9734,6 +9752,8 @@
         for (PackageParser.Package pkg : pkgs) {
             numberOfPackagesVisited++;
 
+            boolean useProfileForDexopt = false;
+
             if ((isFirstBoot() || isUpgrade()) && isSystemApp(pkg)) {
                 // Copy over initial preopt profiles since we won't get any JIT samples for methods
                 // that are already compiled.
@@ -9747,11 +9767,28 @@
                         if (!mInstaller.copySystemProfile(profileFile.getAbsolutePath(),
                                 pkg.applicationInfo.uid, pkg.packageName)) {
                             Log.e(TAG, "Installer failed to copy system profile!");
+                        } else {
+                            useProfileForDexopt = true;
                         }
                     } catch (Exception e) {
                         Log.e(TAG, "Failed to copy profile " + profileFile.getAbsolutePath() + " ",
                                 e);
                     }
+                } else {
+                    PackageSetting disabledPs = mSettings.getDisabledSystemPkgLPr(pkg.packageName);
+                    // Handle compressed APKs in this path. Only do this for stubs with profiles to
+                    // minimize the number off apps being speed-profile compiled during first boot.
+                    // The other paths will not change the filter.
+                    if (disabledPs != null && disabledPs.pkg.isStub) {
+                        // The package is the stub one, remove the stub suffix to get the normal
+                        // package and APK names.
+                        String systemProfilePath =
+                                getPrebuildProfilePath(disabledPs.pkg).replace(STUB_SUFFIX, "");
+                        File systemProfile = new File(systemProfilePath);
+                        // Use the profile for compilation if there exists one for the same package
+                        // in the system partition.
+                        useProfileForDexopt = systemProfile.exists();
+                    }
                 }
             }
 
@@ -9780,6 +9817,14 @@
                 }
             }
 
+            String pkgCompilerFilter = compilerFilter;
+            if (useProfileForDexopt) {
+                // Use background dexopt mode to try and use the profile. Note that this does not
+                // guarantee usage of the profile.
+                pkgCompilerFilter =
+                        PackageManagerServiceCompilerMapping.getCompilerFilterForReason(
+                                PackageManagerService.REASON_BACKGROUND_DEXOPT);
+            }
             // If the OTA updates a system app which was previously preopted to a non-preopted state
             // the app might end up being verified at runtime. That's because by default the apps
             // are verify-profile but for preopted apps there's no profile.
@@ -9788,9 +9833,9 @@
             // filter (by default 'quicken').
             // Note that at this stage unused apps are already filtered.
             if (isSystemApp(pkg) &&
-                    DexFile.isProfileGuidedCompilerFilter(compilerFilter) &&
+                    DexFile.isProfileGuidedCompilerFilter(pkgCompilerFilter) &&
                     !Environment.getReferenceProfile(pkg.packageName).exists()) {
-                compilerFilter = getNonProfileGuidedCompilerFilter(compilerFilter);
+                pkgCompilerFilter = getNonProfileGuidedCompilerFilter(pkgCompilerFilter);
             }
 
             // checkProfiles is false to avoid merging profiles during boot which
@@ -9801,7 +9846,7 @@
             int dexoptFlags = bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0;
             int primaryDexOptStaus = performDexOptTraced(new DexoptOptions(
                     pkg.packageName,
-                    compilerFilter,
+                    pkgCompilerFilter,
                     dexoptFlags));
 
             switch (primaryDexOptStaus) {
diff --git a/services/core/java/com/android/server/policy/PhoneWindowManager.java b/services/core/java/com/android/server/policy/PhoneWindowManager.java
index bc531c3..f79f0e8 100644
--- a/services/core/java/com/android/server/policy/PhoneWindowManager.java
+++ b/services/core/java/com/android/server/policy/PhoneWindowManager.java
@@ -2623,18 +2623,15 @@
             attrs.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_KEYGUARD;
         }
 
-        if (ActivityManager.isHighEndGfx()) {
-            if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
-                attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
-            }
-            final boolean forceWindowDrawsStatusBarBackground =
-                    (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND)
-                            != 0;
-            if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
-                    || forceWindowDrawsStatusBarBackground
-                            && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
-                attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
-            }
+        if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0) {
+            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION;
+        }
+        final boolean forceWindowDrawsStatusBarBackground =
+                (attrs.privateFlags & PRIVATE_FLAG_FORCE_DRAW_STATUS_BAR_BACKGROUND) != 0;
+        if ((attrs.flags & FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS) != 0
+                || forceWindowDrawsStatusBarBackground
+                        && attrs.height == MATCH_PARENT && attrs.width == MATCH_PARENT) {
+            attrs.subtreeSystemUiVisibility |= View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN;
         }
     }
 
diff --git a/services/core/java/com/android/server/power/PowerManagerService.java b/services/core/java/com/android/server/power/PowerManagerService.java
index be44607..f84b20c 100644
--- a/services/core/java/com/android/server/power/PowerManagerService.java
+++ b/services/core/java/com/android/server/power/PowerManagerService.java
@@ -120,7 +120,7 @@
         implements Watchdog.Monitor {
     private static final String TAG = "PowerManagerService";
 
-    private static final boolean DEBUG = true;
+    private static final boolean DEBUG = false;
     private static final boolean DEBUG_SPEW = DEBUG && true;
 
     // Message: Sent when a user activity timeout occurs to update the power state.
diff --git a/services/core/java/com/android/server/utils/ManagedApplicationService.java b/services/core/java/com/android/server/utils/ManagedApplicationService.java
index 0f251fd..1ea7058 100644
--- a/services/core/java/com/android/server/utils/ManagedApplicationService.java
+++ b/services/core/java/com/android/server/utils/ManagedApplicationService.java
@@ -44,6 +44,7 @@
     private final int mClientLabel;
     private final String mSettingsAction;
     private final BinderChecker mChecker;
+    private final boolean mIsImportant;
 
     private final DeathRecipient mDeathRecipient = new DeathRecipient() {
         @Override
@@ -64,13 +65,14 @@
 
     private ManagedApplicationService(final Context context, final ComponentName component,
             final int userId, int clientLabel, String settingsAction,
-            BinderChecker binderChecker) {
+            BinderChecker binderChecker, boolean isImportant) {
         mContext = context;
         mComponent = component;
         mUserId = userId;
         mClientLabel = clientLabel;
         mSettingsAction = settingsAction;
         mChecker = binderChecker;
+        mIsImportant = isImportant;
     }
 
     /**
@@ -99,13 +101,15 @@
      * @param settingsAction an action that can be used to open the Settings UI to enable/disable
      *      binding to these services.
      * @param binderChecker an interface used to validate the returned binder object.
+     * @param isImportant bind the user service with BIND_IMPORTANT.
      * @return a ManagedApplicationService instance.
      */
     public static ManagedApplicationService build(@NonNull final Context context,
         @NonNull final ComponentName component, final int userId, @NonNull int clientLabel,
-        @NonNull String settingsAction, @NonNull BinderChecker binderChecker) {
+        @NonNull String settingsAction, @NonNull BinderChecker binderChecker,
+        boolean isImportant) {
         return new ManagedApplicationService(context, component, userId, clientLabel,
-            settingsAction, binderChecker);
+            settingsAction, binderChecker, isImportant);
     }
 
     /**
@@ -248,9 +252,12 @@
 
             mPendingConnection = serviceConnection;
 
+            int flags = Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE;
+            if (mIsImportant) {
+                flags |= Context.BIND_IMPORTANT;
+            }
             try {
-                if (!mContext.bindServiceAsUser(intent, serviceConnection,
-                        Context.BIND_AUTO_CREATE | Context.BIND_FOREGROUND_SERVICE,
+                if (!mContext.bindServiceAsUser(intent, serviceConnection, flags,
                         new UserHandle(mUserId))) {
                     Slog.w(TAG, "Unable to bind service: " + intent);
                 }
diff --git a/services/core/java/com/android/server/vr/VrManagerService.java b/services/core/java/com/android/server/vr/VrManagerService.java
index 1f0b2f0..830ebda 100644
--- a/services/core/java/com/android/server/vr/VrManagerService.java
+++ b/services/core/java/com/android/server/vr/VrManagerService.java
@@ -1026,7 +1026,7 @@
             @NonNull ComponentName component, int userId) {
         return ManagedApplicationService.build(context, component, userId,
                 R.string.vr_listener_binding_label, Settings.ACTION_VR_LISTENER_SETTINGS,
-                sBinderChecker);
+                sBinderChecker, /*isImportant*/true);
     }
 
     /**
diff --git a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
index 04b42f1..7ea42da 100644
--- a/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
+++ b/services/tests/notification/src/com/android/server/notification/NotificationManagerServiceTest.java
@@ -16,12 +16,15 @@
 
 package com.android.server.notification;
 
+import static android.app.NotificationManager.IMPORTANCE_HIGH;
 import static android.app.NotificationManager.IMPORTANCE_LOW;
 import static android.app.NotificationManager.IMPORTANCE_NONE;
+import static android.app.NotificationManager.IMPORTANCE_UNSPECIFIED;
 import static android.content.pm.PackageManager.PERMISSION_DENIED;
 
 import static junit.framework.Assert.assertEquals;
 import static junit.framework.Assert.assertFalse;
+import static junit.framework.Assert.assertNull;
 import static junit.framework.Assert.assertTrue;
 import static junit.framework.Assert.fail;
 
@@ -56,6 +59,7 @@
 import android.graphics.Color;
 import android.media.AudioManager;
 import android.os.Binder;
+import android.os.Build;
 import android.os.Process;
 import android.os.UserHandle;
 import android.provider.Settings.Secure;
@@ -241,6 +245,7 @@
                 nb.build(), new UserHandle(mUid), null, 0);
         return new NotificationRecord(mContext, sbn, channel);
     }
+
     private NotificationRecord generateNotificationRecord(NotificationChannel channel) {
         return generateNotificationRecord(channel, null);
     }
@@ -342,7 +347,7 @@
 
         // Recreating the channel doesn't throw, but ignores importance.
         final NotificationChannel dupeChannel =
-                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+                new NotificationChannel("id", "name", IMPORTANCE_HIGH);
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(dupeChannel)));
         final NotificationChannel createdChannel =
@@ -378,7 +383,7 @@
 
         // The user modifies importance directly, can no longer be changed by the app.
         final NotificationChannel updatedChannel =
-                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+                new NotificationChannel("id", "name", IMPORTANCE_HIGH);
         mBinderService.updateNotificationChannelForPackage(PKG, mUid, updatedChannel);
 
         // Recreating with a lower importance leaves channel unchanged.
@@ -388,7 +393,7 @@
                 new ParceledListSlice(Arrays.asList(dupeChannel)));
         final NotificationChannel createdChannel =
                 mBinderService.getNotificationChannel(PKG, "id");
-        assertEquals(NotificationManager.IMPORTANCE_HIGH, createdChannel.getImportance());
+        assertEquals(IMPORTANCE_HIGH, createdChannel.getImportance());
     }
 
     @Test
@@ -397,7 +402,7 @@
         final NotificationChannel channel1 =
                 new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_DEFAULT);
         final NotificationChannel channel2 =
-                new NotificationChannel("id", "name", NotificationManager.IMPORTANCE_HIGH);
+                new NotificationChannel("id", "name", IMPORTANCE_HIGH);
         mBinderService.createNotificationChannels(PKG,
                 new ParceledListSlice(Arrays.asList(channel1, channel2)));
         final NotificationChannel createdChannel =
@@ -410,7 +415,7 @@
         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(true);
 
         NotificationChannel channel = new NotificationChannel("id", "name",
-                NotificationManager.IMPORTANCE_HIGH);
+                IMPORTANCE_HIGH);
         NotificationRecord r = generateNotificationRecord(channel);
         assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
         verify(mUsageStats, times(1)).registerSuspendedByAdmin(eq(r));
@@ -421,11 +426,68 @@
         when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
 
         NotificationChannel channel = new NotificationChannel("id", "name",
-                NotificationManager.IMPORTANCE_HIGH);
-        channel.setImportance(IMPORTANCE_NONE);
+                NotificationManager.IMPORTANCE_NONE);
         NotificationRecord r = generateNotificationRecord(channel);
         assertTrue(mNotificationManagerService.isBlocked(r, mUsageStats));
         verify(mUsageStats, times(1)).registerBlocked(eq(r));
+
+        mBinderService.createNotificationChannels(
+                PKG, new ParceledListSlice(Arrays.asList(channel)));
+        final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        waitForIdle();
+        assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+    }
+
+    @Test
+    public void testEnqueuedBlockedNotifications_appBlockedChannelForegroundService()
+            throws Exception {
+        when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+        NotificationChannel channel = new NotificationChannel("blocked", "name",
+                NotificationManager.IMPORTANCE_NONE);
+        mBinderService.createNotificationChannels(
+                PKG, new ParceledListSlice(Arrays.asList(channel)));
+
+        final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        waitForIdle();
+        assertEquals(1, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+        assertEquals(IMPORTANCE_LOW,
+                mNotificationManagerService.getNotificationRecord(sbn.getKey()).getImportance());
+        assertEquals(IMPORTANCE_LOW,
+                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+    }
+
+    @Test
+    public void testEnqueuedBlockedNotifications_userBlockedChannelForegroundService()
+            throws Exception {
+        when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+        NotificationChannel channel =
+                new NotificationChannel("blockedbyuser", "name", IMPORTANCE_HIGH);
+        mBinderService.createNotificationChannels(
+                PKG, new ParceledListSlice(Arrays.asList(channel)));
+
+        NotificationChannel update =
+                new NotificationChannel("blockedbyuser", "name", IMPORTANCE_NONE);
+        mBinderService.updateNotificationChannelForPackage(PKG, mUid, update);
+        waitForIdle();
+        assertEquals(IMPORTANCE_NONE,
+                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
+
+        final StatusBarNotification sbn = generateNotificationRecord(channel).sbn;
+        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        waitForIdle();
+        assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+        assertNull(mNotificationManagerService.getNotificationRecord(sbn.getKey()));
+        assertEquals(IMPORTANCE_NONE,
+                mBinderService.getNotificationChannel(PKG, channel.getId()).getImportance());
     }
 
     @Test
@@ -442,6 +504,21 @@
     }
 
     @Test
+    public void testEnqueuedBlockedNotifications_blockedAppForegroundService() throws Exception {
+        when(mPackageManager.isPackageSuspendedForUser(anyString(), anyInt())).thenReturn(false);
+
+        mBinderService.setNotificationsEnabledForPackage(PKG, mUid, false);
+
+        final StatusBarNotification sbn = generateNotificationRecord(null).sbn;
+        sbn.getNotification().flags |= Notification.FLAG_FOREGROUND_SERVICE;
+        mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        waitForIdle();
+        assertEquals(0, mBinderService.getActiveNotifications(sbn.getPackageName()).length);
+        assertNull(mNotificationManagerService.getNotificationRecord(sbn.getKey()));
+    }
+
+    @Test
     public void testEnqueueNotificationWithTag_PopulatesGetActiveNotifications() throws Exception {
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
                 generateNotificationRecord(null).getNotification(), 0);
@@ -798,7 +875,7 @@
         mNotificationManagerService.setRankingHelper(mRankingHelper);
         when(mRankingHelper.getNotificationChannel(
                 anyString(), anyInt(), eq("foo"), anyBoolean())).thenReturn(
-                        new NotificationChannel("foo", "foo", NotificationManager.IMPORTANCE_HIGH));
+                        new NotificationChannel("foo", "foo", IMPORTANCE_HIGH));
 
         Notification.TvExtender tv = new Notification.TvExtender().setChannelId("foo");
         mBinderService.enqueueNotificationWithTag(PKG, "opPkg", "tag", 0,
@@ -927,7 +1004,8 @@
         mBinderService.updateNotificationChannelFromPrivilegedListener(
                 null, PKG, Process.myUserHandle(), mTestNotificationChannel);
 
-        verify(mRankingHelper, times(1)).updateNotificationChannel(anyString(), anyInt(), any());
+        verify(mRankingHelper, times(1)).updateNotificationChannel(
+                anyString(), anyInt(), any(), anyBoolean());
 
         verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
@@ -948,7 +1026,8 @@
             // pass
         }
 
-        verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
+        verify(mRankingHelper, never()).updateNotificationChannel(
+                anyString(), anyInt(), any(), anyBoolean());
 
         verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
@@ -974,7 +1053,8 @@
             // pass
         }
 
-        verify(mRankingHelper, never()).updateNotificationChannel(anyString(), anyInt(), any());
+        verify(mRankingHelper, never()).updateNotificationChannel(
+                anyString(), anyInt(), any(), anyBoolean());
 
         verify(mListeners, never()).notifyNotificationChannelChanged(eq(PKG),
                 eq(Process.myUserHandle()), eq(mTestNotificationChannel),
@@ -1345,7 +1425,8 @@
     @Test
     public void testOnlyAutogroupIfGroupChanged_groupChanged_autogroups()
             throws Exception {
-        NotificationRecord r = generateNotificationRecord(mTestNotificationChannel, 0, "group", false);
+        NotificationRecord r =
+                generateNotificationRecord(mTestNotificationChannel, 0, "group", false);
         mNotificationManagerService.addNotification(r);
 
         r = generateNotificationRecord(mTestNotificationChannel, 0, null, false);
@@ -1425,12 +1506,16 @@
 
         // Same notifications are enqueued as posted, everything counts b/c id and tag don't match
         int userId = new UserHandle(mUid).getIdentifier();
-        assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, null));
-        assertEquals(40, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag2"));
-        assertEquals(2, mNotificationManagerService.getNotificationCountLocked("a", userId, 0, "banana"));
+        assertEquals(40,
+                mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, null));
+        assertEquals(40,
+                mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag2"));
+        assertEquals(2,
+                mNotificationManagerService.getNotificationCountLocked("a", userId, 0, "banana"));
 
         // exclude a known notification - it's excluded from only the posted list, not enqueued
-        assertEquals(39, mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag"));
+        assertEquals(39,
+                mNotificationManagerService.getNotificationCountLocked(PKG, userId, 0, "tag"));
     }
 
     @Test
@@ -1560,4 +1645,51 @@
 
         verify(mZenModeHelper, times(1)).updateDefaultZenRules();
     }
+
+    @Test
+    public void testBumpFGImportance_noChannelChangePreOApp() throws Exception {
+        String preOPkg = "preO";
+        int preOUid = 145;
+        final ApplicationInfo legacy = new ApplicationInfo();
+        legacy.targetSdkVersion = Build.VERSION_CODES.N_MR1;
+        when(mPackageManagerClient.getApplicationInfoAsUser(eq(preOPkg), anyInt(), anyInt()))
+                .thenReturn(legacy);
+        when(mPackageManagerClient.getPackageUidAsUser(eq(preOPkg), anyInt())).thenReturn(preOUid);
+        getContext().setMockPackageManager(mPackageManagerClient);
+
+        Notification.Builder nb = new Notification.Builder(mContext,
+                NotificationChannel.DEFAULT_CHANNEL_ID)
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .setPriority(Notification.PRIORITY_MIN);
+
+        StatusBarNotification sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
+                0, nb.build(), new UserHandle(preOUid), null, 0);
+
+        mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        waitForIdle();
+        assertEquals(IMPORTANCE_LOW,
+                mNotificationManagerService.getNotificationRecord(sbn.getKey()).getImportance());
+
+        nb = new Notification.Builder(mContext)
+                .setContentTitle("foo")
+                .setSmallIcon(android.R.drawable.sym_def_app_icon)
+                .setFlag(Notification.FLAG_FOREGROUND_SERVICE, true)
+                .setPriority(Notification.PRIORITY_MIN);
+
+        sbn = new StatusBarNotification(preOPkg, preOPkg, 9, "tag", preOUid,
+                0, nb.build(), new UserHandle(preOUid), null, 0);
+
+        mBinderService.enqueueNotificationWithTag(preOPkg, preOPkg, "tag",
+                sbn.getId(), sbn.getNotification(), sbn.getUserId());
+        waitForIdle();
+        assertEquals(IMPORTANCE_LOW,
+                mNotificationManagerService.getNotificationRecord(sbn.getKey()).getImportance());
+
+        NotificationChannel defaultChannel = mBinderService.getNotificationChannel(
+                preOPkg, NotificationChannel.DEFAULT_CHANNEL_ID);
+        assertEquals(IMPORTANCE_UNSPECIFIED, defaultChannel.getImportance());
+    }
 }
diff --git a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
index 65bf330..61d999a 100644
--- a/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
+++ b/services/tests/notification/src/com/android/server/notification/RankingHelperTest.java
@@ -484,7 +484,7 @@
         final NotificationChannel defaultChannel = mHelper.getNotificationChannel(PKG, UID,
                 NotificationChannel.DEFAULT_CHANNEL_ID, false);
         defaultChannel.setImportance(NotificationManager.IMPORTANCE_LOW);
-        mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
+        mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true);
 
         ByteArrayOutputStream baos = writeXmlAndPurge(PKG, UID, false,
                 NotificationChannel.DEFAULT_CHANNEL_ID);
@@ -633,7 +633,7 @@
         channel2.setBypassDnd(false);
         channel2.setLockscreenVisibility(Notification.VISIBILITY_PUBLIC);
 
-        mHelper.updateNotificationChannel(PKG, UID, channel2);
+        mHelper.updateNotificationChannel(PKG, UID, channel2, true);
 
         // all fields should be changed
         assertEquals(channel2, mHelper.getNotificationChannel(PKG, UID, channel.getId(), false));
@@ -657,7 +657,7 @@
         defaultChannel.setBypassDnd(true);
         defaultChannel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
-        mHelper.updateNotificationChannel(PKG, UID, defaultChannel);
+        mHelper.updateNotificationChannel(PKG, UID, defaultChannel, true);
 
         // ensure app level fields are changed
         assertFalse(mHelper.canShowBadge(PKG, UID));
@@ -681,7 +681,7 @@
         channel.setBypassDnd(true);
         channel.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
 
-        mHelper.updateNotificationChannel(PKG, UID, channel);
+        mHelper.updateNotificationChannel(PKG, UID, channel, true);
 
         // ensure app level fields are not changed
         assertTrue(mHelper.canShowBadge(PKG, UID));
@@ -772,14 +772,14 @@
         update1.setSound(new Uri.Builder().scheme("test").build(),
                 new AudioAttributes.Builder().build());
         update1.lockFields(NotificationChannel.USER_LOCKED_PRIORITY); // should be ignored
-        mHelper.updateNotificationChannel(PKG, UID, update1);
+        mHelper.updateNotificationChannel(PKG, UID, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_SOUND,
                 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
                         .getUserLockedFields());
 
         NotificationChannel update2 = getChannel();
         update2.enableVibration(true);
-        mHelper.updateNotificationChannel(PKG, UID, update2);
+        mHelper.updateNotificationChannel(PKG, UID, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_SOUND
                         | NotificationChannel.USER_LOCKED_VIBRATION,
                 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -792,14 +792,14 @@
 
         final NotificationChannel update1 = getChannel();
         update1.setVibrationPattern(new long[]{7945, 46 ,246});
-        mHelper.updateNotificationChannel(PKG, UID, update1);
+        mHelper.updateNotificationChannel(PKG, UID, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_VIBRATION,
                 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update2 = getChannel();
         update2.enableLights(true);
-        mHelper.updateNotificationChannel(PKG, UID, update2);
+        mHelper.updateNotificationChannel(PKG, UID, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_VIBRATION
                         | NotificationChannel.USER_LOCKED_LIGHTS,
                 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -812,14 +812,14 @@
 
         final NotificationChannel update1 = getChannel();
         update1.setLightColor(Color.GREEN);
-        mHelper.updateNotificationChannel(PKG, UID, update1);
+        mHelper.updateNotificationChannel(PKG, UID, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_LIGHTS,
                 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update2 = getChannel();
         update2.setImportance(IMPORTANCE_DEFAULT);
-        mHelper.updateNotificationChannel(PKG, UID, update2);
+        mHelper.updateNotificationChannel(PKG, UID, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_LIGHTS
                         | NotificationChannel.USER_LOCKED_IMPORTANCE,
                 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -835,14 +835,14 @@
 
         final NotificationChannel update1 = getChannel();
         update1.setBypassDnd(true);
-        mHelper.updateNotificationChannel(PKG, UID, update1);
+        mHelper.updateNotificationChannel(PKG, UID, update1, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY,
                 mHelper.getNotificationChannel(PKG, UID, update1.getId(), false)
                         .getUserLockedFields());
 
         final NotificationChannel update2 = getChannel();
         update2.setLockscreenVisibility(Notification.VISIBILITY_SECRET);
-        mHelper.updateNotificationChannel(PKG, UID, update2);
+        mHelper.updateNotificationChannel(PKG, UID, update2, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
                         | NotificationChannel.USER_LOCKED_VISIBILITY,
                 mHelper.getNotificationChannel(PKG, UID, update2.getId(), false)
@@ -850,7 +850,7 @@
 
         final NotificationChannel update3 = getChannel();
         update3.setShowBadge(false);
-        mHelper.updateNotificationChannel(PKG, UID, update3);
+        mHelper.updateNotificationChannel(PKG, UID, update3, true);
         assertEquals(NotificationChannel.USER_LOCKED_PRIORITY
                         | NotificationChannel.USER_LOCKED_VISIBILITY
                         | NotificationChannel.USER_LOCKED_SHOW_BADGE,
@@ -1263,7 +1263,7 @@
         mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
 
         channel1.setImportance(IMPORTANCE_LOW);
-        mHelper.updateNotificationChannel(PKG, UID, channel1);
+        mHelper.updateNotificationChannel(PKG, UID, channel1, true);
 
         List<NotificationChannelGroup> actual =
                 mHelper.getNotificationChannelGroups(PKG, UID, true).getList();
diff --git a/telephony/java/android/telephony/TelephonyManager.java b/telephony/java/android/telephony/TelephonyManager.java
index 2c02869..011d76b 100644
--- a/telephony/java/android/telephony/TelephonyManager.java
+++ b/telephony/java/android/telephony/TelephonyManager.java
@@ -106,8 +106,6 @@
     public static final String MODEM_ACTIVITY_RESULT_KEY =
             BatteryStats.RESULT_RECEIVER_CONTROLLER_KEY;
 
-    private static ITelephonyRegistry sRegistry;
-
     /**
      * The allowed states of Wi-Fi calling.
      *
@@ -178,11 +176,6 @@
             mContext = context;
         }
         mSubscriptionManager = SubscriptionManager.from(mContext);
-
-        if (sRegistry == null) {
-            sRegistry = ITelephonyRegistry.Stub.asInterface(ServiceManager.getService(
-                    "telephony.registry"));
-        }
     }
 
     /** @hide */
@@ -3506,6 +3499,10 @@
         return ITelecomService.Stub.asInterface(ServiceManager.getService(Context.TELECOM_SERVICE));
     }
 
+    private ITelephonyRegistry getTelephonyRegistry() {
+        return ITelephonyRegistry.Stub.asInterface(ServiceManager.getService("telephony.registry"));
+    }
+
     //
     //
     // PhoneStateListener
@@ -3545,12 +3542,16 @@
             if (listener.mSubId == null) {
                 listener.mSubId = mSubId;
             }
-            sRegistry.listenForSubscriber(listener.mSubId, getOpPackageName(),
-                    listener.callback, events, notifyNow);
+
+            ITelephonyRegistry registry = getTelephonyRegistry();
+            if (registry != null) {
+                registry.listenForSubscriber(listener.mSubId, getOpPackageName(),
+                        listener.callback, events, notifyNow);
+            } else {
+                Rlog.w(TAG, "telephony registry not ready.");
+            }
         } catch (RemoteException ex) {
             // system process dead
-        } catch (NullPointerException ex) {
-            // system process dead
         }
     }