Merge "Import translations. DO NOT MERGE ANYWHERE" into sc-dev
diff --git a/Android.bp b/Android.bp
index 9023a19..4d8924d 100644
--- a/Android.bp
+++ b/Android.bp
@@ -273,6 +273,11 @@
     installable: false,
 }
 
+filegroup {
+    name: "framework-jarjar-rules",
+    srcs: ["framework-jarjar-rules.txt"],
+}
+
 java_defaults {
     name: "framework-minus-apex-defaults",
     defaults: ["framework-aidl-export-defaults"],
@@ -294,7 +299,7 @@
         "--core-library",
         "--multi-dex",
     ],
-    jarjar_rules: "framework-jarjar-rules.txt",
+    jarjar_rules: ":framework-jarjar-rules",
     javac_shard_size: 150,
     plugins: [
         "view-inspector-annotation-processor",
diff --git a/StubLibraries.bp b/StubLibraries.bp
index ed24d43..b6c45ed 100644
--- a/StubLibraries.bp
+++ b/StubLibraries.bp
@@ -255,7 +255,7 @@
 
 modules_system_stubs = [
     "android.net.ipsec.ike.stubs.system",
-    "art.module.public.api.stubs", // Only has public stubs
+    "art.module.public.api.stubs.system",
     "conscrypt.module.public.api.stubs", // Only has public stubs
     "framework-appsearch.stubs.system",
     "framework-connectivity.stubs.system",
diff --git a/api/Android.bp b/api/Android.bp
index b85dc46..db1f64c 100644
--- a/api/Android.bp
+++ b/api/Android.bp
@@ -161,6 +161,7 @@
 genrule {
     name: "frameworks-base-api-system-current.txt",
     srcs: [
+        ":art.module.public.api{.system.api.txt}",
         ":android.net.ipsec.ike{.system.api.txt}",
         ":framework-appsearch{.system.api.txt}",
         ":framework-connectivity{.system.api.txt}",
@@ -215,6 +216,7 @@
 genrule {
     name: "frameworks-base-api-system-removed.txt",
     srcs: [
+        ":art.module.public.api{.system.removed-api.txt}",
         ":android.net.ipsec.ike{.system.removed-api.txt}",
         ":framework-appsearch{.system.removed-api.txt}",
         ":framework-connectivity{.system.removed-api.txt}",
@@ -251,6 +253,7 @@
 genrule {
     name: "frameworks-base-api-module-lib-current.txt",
     srcs: [
+        ":art.module.public.api{.module-lib.api.txt}",
         ":android.net.ipsec.ike{.module-lib.api.txt}",
         ":framework-appsearch{.module-lib.api.txt}",
         ":framework-connectivity{.module-lib.api.txt}",
@@ -307,6 +310,7 @@
 genrule {
     name: "frameworks-base-api-module-lib-removed.txt",
     srcs: [
+        ":art.module.public.api{.module-lib.removed-api.txt}",
         ":android.net.ipsec.ike{.module-lib.removed-api.txt}",
         ":framework-appsearch{.module-lib.removed-api.txt}",
         ":framework-connectivity{.module-lib.removed-api.txt}",
diff --git a/boot/Android.bp b/boot/Android.bp
index e8d88a5..3caede4 100644
--- a/boot/Android.bp
+++ b/boot/Android.bp
@@ -48,57 +48,13 @@
     // bootclasspath.
     fragments: [
         {
-            apex: "com.android.appsearch",
-            module: "com.android.appsearch-bootclasspath-fragment",
-        },
-        {
             apex: "com.android.art",
             module: "art-bootclasspath-fragment",
         },
         {
-            apex: "com.android.conscrypt",
-            module: "com.android.conscrypt-bootclasspath-fragment",
-        },
-        {
             apex: "com.android.i18n",
             module: "i18n-bootclasspath-fragment",
         },
-        {
-            apex: "com.android.ipsec",
-            module: "com.android.ipsec-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.media",
-            module: "com.android.media-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.mediaprovider",
-            module: "com.android.mediaprovider-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.os.statsd",
-            module: "com.android.os.statsd-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.permission",
-            module: "com.android.permission-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.scheduling",
-            module: "com.android.scheduling-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.sdkext",
-            module: "com.android.sdkext-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.tethering",
-            module: "com.android.tethering-bootclasspath-fragment",
-        },
-        {
-            apex: "com.android.wifi",
-            module: "com.android.wifi-bootclasspath-fragment",
-        },
     ],
 
     // Additional information needed by hidden api processing.
diff --git a/core/api/current.txt b/core/api/current.txt
index f546f53..d73e3a0 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -5958,7 +5958,6 @@
     method @NonNull public android.app.Notification.Builder setRemoteInputHistory(CharSequence[]);
     method @NonNull public android.app.Notification.Builder setSettingsText(CharSequence);
     method @NonNull public android.app.Notification.Builder setShortcutId(String);
-    method @Deprecated @NonNull public android.app.Notification.Builder setShowForegroundImmediately(boolean);
     method @NonNull public android.app.Notification.Builder setShowWhen(boolean);
     method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int);
     method @NonNull public android.app.Notification.Builder setSmallIcon(@DrawableRes int, int);
diff --git a/core/api/system-current.txt b/core/api/system-current.txt
index 9befc3b..6f68e3f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -10529,7 +10529,7 @@
     method @Nullable public android.media.MediaSyncEvent getMediaSyncEvent();
     method public int getPersonalizedScore();
     method public int getScore();
-    method public boolean isPersonalizedHotwordDetection();
+    method public boolean isHotwordDetectionPersonalized();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field public static final int AUDIO_CHANNEL_UNSET = -1; // 0xffffffff
     field public static final int CONFIDENCE_LEVEL_HIGH = 5; // 0x5
@@ -10549,11 +10549,11 @@
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setAudioChannel(int);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setConfidenceLevel(int);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setExtras(@NonNull android.os.PersistableBundle);
+    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordDetectionPersonalized(boolean);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordDurationMillis(int);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordOffsetMillis(int);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setHotwordPhraseId(int);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setMediaSyncEvent(@NonNull android.media.MediaSyncEvent);
-    method @NonNull public android.service.voice.HotwordDetectedResult.Builder setPersonalizedHotwordDetection(boolean);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setPersonalizedScore(int);
     method @NonNull public android.service.voice.HotwordDetectedResult.Builder setScore(int);
   }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1865141..9b594b78 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -4595,22 +4595,6 @@
         }
 
         /**
-         * Set to {@code true} to require that the Notification associated with a
-         * foreground service is shown as soon as the service's {@code startForeground()}
-         * method is called, even if the system's UI policy might otherwise defer
-         * its visibility to a later time.
-         * @deprecated Use setForegroundServiceBehavior(int) instead
-         */
-        @Deprecated
-        @NonNull
-        public Builder setShowForegroundImmediately(boolean showImmediately) {
-            setForegroundServiceBehavior(showImmediately
-                    ? FOREGROUND_SERVICE_IMMEDIATE
-                    : FOREGROUND_SERVICE_DEFAULT);
-            return this;
-        }
-
-        /**
          * Specify a desired visibility policy for a Notification associated with a
          * foreground service.  By default, the system can choose to defer
          * visibility of the notification for a short time after the service is
diff --git a/core/java/android/app/WallpaperColors.java b/core/java/android/app/WallpaperColors.java
index be62deb7..edd6047 100644
--- a/core/java/android/app/WallpaperColors.java
+++ b/core/java/android/app/WallpaperColors.java
@@ -101,7 +101,7 @@
     // We also check if the image has dark pixels in it,
     // to avoid bright images with some dark spots.
     private static final float DARK_PIXEL_CONTRAST = 5.5f;
-    private static final float MAX_DARK_AREA = 0.025f;
+    private static final float MAX_DARK_AREA = 0.05f;
 
     private final List<Color> mMainColors;
     private final Map<Integer, Integer> mAllColors;
diff --git a/core/java/android/service/voice/HotwordDetectedResult.java b/core/java/android/service/voice/HotwordDetectedResult.java
index 95e43f3..846f2f9 100644
--- a/core/java/android/service/voice/HotwordDetectedResult.java
+++ b/core/java/android/service/voice/HotwordDetectedResult.java
@@ -118,7 +118,7 @@
      * Returns whether the trigger has happened due to model having been personalized to fit user's
      * voice.
      */
-    private boolean mPersonalizedHotwordDetection = false;
+    private boolean mHotwordDetectionPersonalized = false;
 
     /**
      * Score for the hotword trigger.
@@ -270,7 +270,7 @@
             int hotwordOffsetMillis,
             int hotwordDurationMillis,
             int audioChannel,
-            boolean personalizedHotwordDetection,
+            boolean hotwordDetectionPersonalized,
             int score,
             int personalizedScore,
             int hotwordPhraseId,
@@ -282,7 +282,7 @@
         this.mHotwordOffsetMillis = hotwordOffsetMillis;
         this.mHotwordDurationMillis = hotwordDurationMillis;
         this.mAudioChannel = audioChannel;
-        this.mPersonalizedHotwordDetection = personalizedHotwordDetection;
+        this.mHotwordDetectionPersonalized = hotwordDetectionPersonalized;
         this.mScore = score;
         this.mPersonalizedScore = personalizedScore;
         this.mHotwordPhraseId = hotwordPhraseId;
@@ -334,8 +334,8 @@
      * voice.
      */
     @DataClass.Generated.Member
-    public boolean isPersonalizedHotwordDetection() {
-        return mPersonalizedHotwordDetection;
+    public boolean isHotwordDetectionPersonalized() {
+        return mHotwordDetectionPersonalized;
     }
 
     /**
@@ -400,7 +400,7 @@
                 "hotwordOffsetMillis = " + mHotwordOffsetMillis + ", " +
                 "hotwordDurationMillis = " + mHotwordDurationMillis + ", " +
                 "audioChannel = " + mAudioChannel + ", " +
-                "personalizedHotwordDetection = " + mPersonalizedHotwordDetection + ", " +
+                "hotwordDetectionPersonalized = " + mHotwordDetectionPersonalized + ", " +
                 "score = " + mScore + ", " +
                 "personalizedScore = " + mPersonalizedScore + ", " +
                 "hotwordPhraseId = " + mHotwordPhraseId + ", " +
@@ -426,7 +426,7 @@
                 && mHotwordOffsetMillis == that.mHotwordOffsetMillis
                 && mHotwordDurationMillis == that.mHotwordDurationMillis
                 && mAudioChannel == that.mAudioChannel
-                && mPersonalizedHotwordDetection == that.mPersonalizedHotwordDetection
+                && mHotwordDetectionPersonalized == that.mHotwordDetectionPersonalized
                 && mScore == that.mScore
                 && mPersonalizedScore == that.mPersonalizedScore
                 && mHotwordPhraseId == that.mHotwordPhraseId
@@ -445,7 +445,7 @@
         _hash = 31 * _hash + mHotwordOffsetMillis;
         _hash = 31 * _hash + mHotwordDurationMillis;
         _hash = 31 * _hash + mAudioChannel;
-        _hash = 31 * _hash + Boolean.hashCode(mPersonalizedHotwordDetection);
+        _hash = 31 * _hash + Boolean.hashCode(mHotwordDetectionPersonalized);
         _hash = 31 * _hash + mScore;
         _hash = 31 * _hash + mPersonalizedScore;
         _hash = 31 * _hash + mHotwordPhraseId;
@@ -460,7 +460,7 @@
         // void parcelFieldName(Parcel dest, int flags) { ... }
 
         int flg = 0;
-        if (mPersonalizedHotwordDetection) flg |= 0x20;
+        if (mHotwordDetectionPersonalized) flg |= 0x20;
         if (mMediaSyncEvent != null) flg |= 0x2;
         dest.writeInt(flg);
         dest.writeInt(mConfidenceLevel);
@@ -486,7 +486,7 @@
         // static FieldType unparcelFieldName(Parcel in) { ... }
 
         int flg = in.readInt();
-        boolean personalizedHotwordDetection = (flg & 0x20) != 0;
+        boolean hotwordDetectionPersonalized = (flg & 0x20) != 0;
         int confidenceLevel = in.readInt();
         MediaSyncEvent mediaSyncEvent = (flg & 0x2) == 0 ? null : (MediaSyncEvent) in.readTypedObject(MediaSyncEvent.CREATOR);
         int hotwordOffsetMillis = in.readInt();
@@ -504,7 +504,7 @@
         this.mHotwordOffsetMillis = hotwordOffsetMillis;
         this.mHotwordDurationMillis = hotwordDurationMillis;
         this.mAudioChannel = audioChannel;
-        this.mPersonalizedHotwordDetection = personalizedHotwordDetection;
+        this.mHotwordDetectionPersonalized = hotwordDetectionPersonalized;
         this.mScore = score;
         this.mPersonalizedScore = personalizedScore;
         this.mHotwordPhraseId = hotwordPhraseId;
@@ -541,7 +541,7 @@
         private int mHotwordOffsetMillis;
         private int mHotwordDurationMillis;
         private int mAudioChannel;
-        private boolean mPersonalizedHotwordDetection;
+        private boolean mHotwordDetectionPersonalized;
         private int mScore;
         private int mPersonalizedScore;
         private int mHotwordPhraseId;
@@ -618,10 +618,10 @@
          * voice.
          */
         @DataClass.Generated.Member
-        public @NonNull Builder setPersonalizedHotwordDetection(boolean value) {
+        public @NonNull Builder setHotwordDetectionPersonalized(boolean value) {
             checkNotUsed();
             mBuilderFieldsSet |= 0x20;
-            mPersonalizedHotwordDetection = value;
+            mHotwordDetectionPersonalized = value;
             return this;
         }
 
@@ -708,7 +708,7 @@
                 mAudioChannel = AUDIO_CHANNEL_UNSET;
             }
             if ((mBuilderFieldsSet & 0x20) == 0) {
-                mPersonalizedHotwordDetection = false;
+                mHotwordDetectionPersonalized = false;
             }
             if ((mBuilderFieldsSet & 0x40) == 0) {
                 mScore = defaultScore();
@@ -728,7 +728,7 @@
                     mHotwordOffsetMillis,
                     mHotwordDurationMillis,
                     mAudioChannel,
-                    mPersonalizedHotwordDetection,
+                    mHotwordDetectionPersonalized,
                     mScore,
                     mPersonalizedScore,
                     mHotwordPhraseId,
@@ -745,10 +745,10 @@
     }
 
     @DataClass.Generated(
-            time = 1621631039729L,
+            time = 1621943150502L,
             codegenVersion = "1.0.23",
             sourceFile = "frameworks/base/core/java/android/service/voice/HotwordDetectedResult.java",
-            inputSignatures = "public static final  int CONFIDENCE_LEVEL_NONE\npublic static final  int CONFIDENCE_LEVEL_LOW\npublic static final  int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final  int CONFIDENCE_LEVEL_MEDIUM\npublic static final  int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final  int CONFIDENCE_LEVEL_HIGH\npublic static final  int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final  int HOTWORD_OFFSET_UNSET\npublic static final  int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate  int mHotwordOffsetMillis\nprivate  int mHotwordDurationMillis\nprivate  int mAudioChannel\nprivate  boolean mPersonalizedHotwordDetection\nprivate final  int mScore\nprivate final  int mPersonalizedScore\nprivate final  int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultScore()\nprivate static  int defaultPersonalizedScore()\npublic static  int getMaxScore()\nprivate static  int defaultHotwordPhraseId()\npublic static  int getMaxHotwordPhraseId()\nprivate static  android.os.PersistableBundle defaultExtras()\npublic static  int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
+            inputSignatures = "public static final  int CONFIDENCE_LEVEL_NONE\npublic static final  int CONFIDENCE_LEVEL_LOW\npublic static final  int CONFIDENCE_LEVEL_LOW_MEDIUM\npublic static final  int CONFIDENCE_LEVEL_MEDIUM\npublic static final  int CONFIDENCE_LEVEL_MEDIUM_HIGH\npublic static final  int CONFIDENCE_LEVEL_HIGH\npublic static final  int CONFIDENCE_LEVEL_VERY_HIGH\npublic static final  int HOTWORD_OFFSET_UNSET\npublic static final  int AUDIO_CHANNEL_UNSET\nprivate final @android.service.voice.HotwordDetectedResult.HotwordConfidenceLevelValue int mConfidenceLevel\nprivate @android.annotation.Nullable android.media.MediaSyncEvent mMediaSyncEvent\nprivate  int mHotwordOffsetMillis\nprivate  int mHotwordDurationMillis\nprivate  int mAudioChannel\nprivate  boolean mHotwordDetectionPersonalized\nprivate final  int mScore\nprivate final  int mPersonalizedScore\nprivate final  int mHotwordPhraseId\nprivate final @android.annotation.NonNull android.os.PersistableBundle mExtras\nprivate static  int defaultConfidenceLevel()\nprivate static  int defaultScore()\nprivate static  int defaultPersonalizedScore()\npublic static  int getMaxScore()\nprivate static  int defaultHotwordPhraseId()\npublic static  int getMaxHotwordPhraseId()\nprivate static  android.os.PersistableBundle defaultExtras()\npublic static  int getMaxBundleSize()\npublic @android.annotation.Nullable android.media.MediaSyncEvent getMediaSyncEvent()\nclass HotwordDetectedResult extends java.lang.Object implements [android.os.Parcelable]\n@com.android.internal.util.DataClass(genConstructor=false, genBuilder=true, genEqualsHashCode=true, genHiddenConstDefs=true, genParcelable=true, genToString=true)")
     @Deprecated
     private void __metadata() {}
 
diff --git a/core/java/android/view/TunnelModeEnabledListener.java b/core/java/android/view/TunnelModeEnabledListener.java
new file mode 100644
index 0000000..c158da9
--- /dev/null
+++ b/core/java/android/view/TunnelModeEnabledListener.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import com.android.internal.annotations.VisibleForTesting;
+
+import java.util.concurrent.Executor;
+
+/**
+ * Listens for tunnel mode enabled/disabled events from SurfaceFlinger.
+ * {@hide}
+ */
+public abstract class TunnelModeEnabledListener {
+
+    private long mNativeListener;
+    private final Executor mExecutor;
+
+    public TunnelModeEnabledListener(Executor executor) {
+        mExecutor = executor;
+        mNativeListener = nativeCreate(this);
+    }
+
+    /**
+     * Destroys the listener.
+     */
+    public void destroy() {
+        if (mNativeListener == 0) {
+            return;
+        }
+        unregister(this);
+        nativeDestroy(mNativeListener);
+        mNativeListener = 0;
+    }
+
+    @Override
+    protected void finalize() throws Throwable {
+        try {
+            destroy();
+        } finally {
+            super.finalize();
+        }
+    }
+
+    /**
+     * Reports when tunnel mode has been enabled/disabled.
+     */
+    public abstract void onTunnelModeEnabledChanged(boolean tunnelModeEnabled);
+
+    /**
+     * Registers a listener.
+     */
+    public static void register(TunnelModeEnabledListener listener) {
+        if (listener.mNativeListener == 0) {
+            return;
+        }
+        nativeRegister(listener.mNativeListener);
+    }
+
+    /**
+     * Unregisters a listener.
+     */
+    public static void unregister(TunnelModeEnabledListener listener) {
+        if (listener.mNativeListener == 0) {
+            return;
+        }
+        nativeUnregister(listener.mNativeListener);
+    }
+
+    /**
+     * Dispatch tunnel mode enabled.
+     *
+     * Called from native code on a binder thread.
+     */
+    @VisibleForTesting
+    public static void dispatchOnTunnelModeEnabledChanged(TunnelModeEnabledListener listener,
+            boolean tunnelModeEnabled) {
+        listener.mExecutor.execute(() -> listener.onTunnelModeEnabledChanged(tunnelModeEnabled));
+    }
+
+    private static native long nativeCreate(TunnelModeEnabledListener thiz);
+    private static native void nativeDestroy(long ptr);
+    private static native void nativeRegister(long ptr);
+    private static native void nativeUnregister(long ptr);
+}
diff --git a/core/java/android/widget/AnalogClock.java b/core/java/android/widget/AnalogClock.java
index 5bb8a8e..40cce7c 100644
--- a/core/java/android/widget/AnalogClock.java
+++ b/core/java/android/widget/AnalogClock.java
@@ -18,6 +18,7 @@
 
 import android.annotation.NonNull;
 import android.annotation.Nullable;
+import android.app.AppGlobals;
 import android.compat.annotation.UnsupportedAppUsage;
 import android.content.BroadcastReceiver;
 import android.content.Context;
@@ -61,8 +62,9 @@
 @Deprecated
 public class AnalogClock extends View {
     private static final String LOG_TAG = "AnalogClock";
+
     /** How many times per second that the seconds hand advances. */
-    private static final long SECONDS_HAND_FPS = 30;
+    private final int mSecondsHandFps;
 
     private Clock mClock;
     @Nullable
@@ -106,6 +108,10 @@
     public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
         super(context, attrs, defStyleAttr, defStyleRes);
 
+        mSecondsHandFps = AppGlobals.getIntCoreSetting(
+                WidgetFlags.KEY_ANALOG_CLOCK_SECONDS_HAND_FPS,
+                WidgetFlags.ANALOG_CLOCK_SECONDS_HAND_FPS_DEFAULT);
+
         final TypedArray a = context.obtainStyledAttributes(
                 attrs, com.android.internal.R.styleable.AnalogClock, defStyleAttr, defStyleRes);
         saveAttributeDataForStyleable(context, com.android.internal.R.styleable.AnalogClock,
@@ -743,7 +749,7 @@
         // n positions between two given numbers, where n is the number of ticks per second. This
         // ensures the second hand advances by a consistent distance despite our handler callbacks
         // occurring at inconsistent frequencies.
-        mSeconds = Math.round(rawSeconds * SECONDS_HAND_FPS) / (float) SECONDS_HAND_FPS;
+        mSeconds = Math.round(rawSeconds * mSecondsHandFps) / (float) mSecondsHandFps;
         mMinutes = localTime.getMinute() + mSeconds / 60.0f;
         mHour = localTime.getHour() + mMinutes / 60.0f;
         mChanged = true;
@@ -781,7 +787,7 @@
             // How many milliseconds through the second we currently are.
             long millisOfSecond = Duration.ofNanos(localTime.getNano()).toMillis();
             // How many milliseconds there are between tick positions for the seconds hand.
-            double millisPerTick = 1000 / (double) SECONDS_HAND_FPS;
+            double millisPerTick = 1000 / (double) mSecondsHandFps;
             // How many milliseconds we are past the last tick position.
             long millisPastLastTick = Math.round(millisOfSecond % millisPerTick);
             // How many milliseconds there are until the next tick position.
diff --git a/core/java/android/widget/WidgetFlags.java b/core/java/android/widget/WidgetFlags.java
index 1a49365..0971268 100644
--- a/core/java/android/widget/WidgetFlags.java
+++ b/core/java/android/widget/WidgetFlags.java
@@ -199,6 +199,17 @@
      */
     public static final float MAGNIFIER_ASPECT_RATIO_DEFAULT = 5.5f;
 
+    /** The flag of the fps of the analog clock seconds hand. */
+    public static final String ANALOG_CLOCK_SECONDS_HAND_FPS =
+            "AnalogClockFeature__analog_clock_seconds_hand_fps";
+
+    /** The key name used in app core settings for {@link #ANALOG_CLOCK_SECONDS_HAND_FPS}. */
+    public static final String KEY_ANALOG_CLOCK_SECONDS_HAND_FPS =
+            "widget__analog_clock_seconds_hand_fps";
+
+    /** Default value for the flag {@link #ANALOG_CLOCK_SECONDS_HAND_FPS}. */
+    public static final int ANALOG_CLOCK_SECONDS_HAND_FPS_DEFAULT = 1;
+
     private WidgetFlags() {
     }
 }
diff --git a/core/jni/Android.bp b/core/jni/Android.bp
index 1f805c9..1468633 100644
--- a/core/jni/Android.bp
+++ b/core/jni/Android.bp
@@ -128,6 +128,7 @@
                 "android_graphics_BLASTBufferQueue.cpp",
                 "android_view_SurfaceSession.cpp",
                 "android_view_TextureView.cpp",
+                "android_view_TunnelModeEnabledListener.cpp",
                 "android_view_VelocityTracker.cpp",
                 "android_view_VerifiedKeyEvent.cpp",
                 "android_view_VerifiedMotionEvent.cpp",
diff --git a/core/jni/AndroidRuntime.cpp b/core/jni/AndroidRuntime.cpp
index f76cccb..7e8fc7e 100644
--- a/core/jni/AndroidRuntime.cpp
+++ b/core/jni/AndroidRuntime.cpp
@@ -127,6 +127,7 @@
 extern int register_android_view_SurfaceSession(JNIEnv* env);
 extern int register_android_view_CompositionSamplingListener(JNIEnv* env);
 extern int register_android_view_TextureView(JNIEnv* env);
+extern int register_android_view_TunnelModeEnabledListener(JNIEnv* env);
 extern int register_android_database_CursorWindow(JNIEnv* env);
 extern int register_android_database_SQLiteConnection(JNIEnv* env);
 extern int register_android_database_SQLiteGlobal(JNIEnv* env);
@@ -1521,6 +1522,7 @@
         REG_JNI(register_android_view_SurfaceSession),
         REG_JNI(register_android_view_CompositionSamplingListener),
         REG_JNI(register_android_view_TextureView),
+        REG_JNI(register_android_view_TunnelModeEnabledListener),
         REG_JNI(register_com_google_android_gles_jni_EGLImpl),
         REG_JNI(register_com_google_android_gles_jni_GLImpl),
         REG_JNI(register_android_opengl_jni_EGL14),
diff --git a/core/jni/android_view_TunnelModeEnabledListener.cpp b/core/jni/android_view_TunnelModeEnabledListener.cpp
new file mode 100644
index 0000000..af7bae8
--- /dev/null
+++ b/core/jni/android_view_TunnelModeEnabledListener.cpp
@@ -0,0 +1,130 @@
+/*
+ * Copyright 2021 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.
+ */
+
+#define LOG_TAG "TunnelModeEnabledListener"
+
+#include "android_util_Binder.h"
+#include "core_jni_helpers.h"
+
+#include <nativehelper/JNIHelp.h>
+
+#include <android/gui/BnTunnelModeEnabledListener.h>
+#include <android_runtime/AndroidRuntime.h>
+#include <android_runtime/Log.h>
+#include <utils/Log.h>
+
+#include <gui/SurfaceComposerClient.h>
+#include <ui/Rect.h>
+
+namespace android {
+
+namespace {
+
+struct {
+    jclass mClass;
+    jmethodID mDispatchOnTunnelModeEnabledChanged;
+} gListenerClassInfo;
+
+struct TunnelModeEnabledListener : public gui::BnTunnelModeEnabledListener {
+    TunnelModeEnabledListener(JNIEnv* env, jobject listener)
+          : mListener(env->NewWeakGlobalRef(listener)) {}
+
+    binder::Status onTunnelModeEnabledChanged(bool tunnelModeEnabled) override {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        LOG_ALWAYS_FATAL_IF(env == nullptr,
+                            "Unable to retrieve JNIEnv in onTunnelModeEnabledChanged.");
+
+        jobject listener = env->NewGlobalRef(mListener);
+        if (listener == NULL) {
+            // Weak reference went out of scope
+            return binder::Status::ok();
+        }
+        env->CallStaticVoidMethod(gListenerClassInfo.mClass,
+                                  gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged, listener,
+                                  static_cast<jboolean>(tunnelModeEnabled));
+        env->DeleteGlobalRef(listener);
+
+        if (env->ExceptionCheck()) {
+            ALOGE("TunnelModeEnabledListener.onTunnelModeEnabledChanged() failed.");
+            LOGE_EX(env);
+            env->ExceptionClear();
+        }
+        return binder::Status::ok();
+    }
+
+protected:
+    virtual ~TunnelModeEnabledListener() {
+        JNIEnv* env = AndroidRuntime::getJNIEnv();
+        env->DeleteWeakGlobalRef(mListener);
+    }
+
+private:
+    jweak mListener;
+};
+
+jlong nativeCreate(JNIEnv* env, jclass clazz, jobject obj) {
+    TunnelModeEnabledListener* listener = new TunnelModeEnabledListener(env, obj);
+    listener->incStrong((void*)nativeCreate);
+    return reinterpret_cast<jlong>(listener);
+}
+
+void nativeDestroy(JNIEnv* env, jclass clazz, jlong ptr) {
+    TunnelModeEnabledListener* listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
+    listener->decStrong((void*)nativeCreate);
+}
+
+void nativeRegister(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
+    if (SurfaceComposerClient::addTunnelModeEnabledListener(listener) != OK) {
+        constexpr auto error_msg = "Couldn't addTunnelModeEnabledListener";
+        ALOGE(error_msg);
+        jniThrowRuntimeException(env, error_msg);
+    }
+}
+
+void nativeUnregister(JNIEnv* env, jclass clazz, jlong ptr) {
+    sp<TunnelModeEnabledListener> listener = reinterpret_cast<TunnelModeEnabledListener*>(ptr);
+
+    if (SurfaceComposerClient::removeTunnelModeEnabledListener(listener) != OK) {
+        constexpr auto error_msg = "Couldn't removeTunnelModeEnabledListener";
+        ALOGE(error_msg);
+        jniThrowRuntimeException(env, error_msg);
+    }
+}
+
+const JNINativeMethod gMethods[] = {
+        /* name, signature, funcPtr */
+        {"nativeCreate", "(Landroid/view/TunnelModeEnabledListener;)J", (void*)nativeCreate},
+        {"nativeDestroy", "(J)V", (void*)nativeDestroy},
+        {"nativeRegister", "(J)V", (void*)nativeRegister},
+        {"nativeUnregister", "(J)V", (void*)nativeUnregister}};
+
+} // namespace
+
+int register_android_view_TunnelModeEnabledListener(JNIEnv* env) {
+    int res = jniRegisterNativeMethods(env, "android/view/TunnelModeEnabledListener", gMethods,
+                                       NELEM(gMethods));
+    LOG_ALWAYS_FATAL_IF(res < 0, "Unable to register native methods.");
+
+    jclass clazz = env->FindClass("android/view/TunnelModeEnabledListener");
+    gListenerClassInfo.mClass = MakeGlobalRefOrDie(env, clazz);
+    gListenerClassInfo.mDispatchOnTunnelModeEnabledChanged =
+            env->GetStaticMethodID(clazz, "dispatchOnTunnelModeEnabledChanged",
+                                   "(Landroid/view/TunnelModeEnabledListener;Z)V");
+    return 0;
+}
+
+} // namespace android
diff --git a/core/res/res/values/config.xml b/core/res/res/values/config.xml
index ab53b4c..28f18a4 100644
--- a/core/res/res/values/config.xml
+++ b/core/res/res/values/config.xml
@@ -3971,6 +3971,9 @@
     <!-- URI for in call notification sound -->
     <string translatable="false" name="config_inCallNotificationSound">/product/media/audio/ui/InCallNotification.ogg</string>
 
+    <!-- URI for default ringtone sound file to be used for silent ringer vibration -->
+    <string translatable="false" name="config_defaultRingtoneVibrationSound">/product/media/audio/ui/AttentionalHaptics.ogg</string>
+
     <!-- Default number of notifications from the same app before they are automatically grouped by the OS -->
     <integer translatable="false" name="config_autoGroupAtCount">4</integer>
 
diff --git a/core/res/res/values/public.xml b/core/res/res/values/public.xml
index 552898b..ef5cfe3 100644
--- a/core/res/res/values/public.xml
+++ b/core/res/res/values/public.xml
@@ -3236,6 +3236,8 @@
     <public name="config_systemCompanionDeviceProvider"/>
     <!-- @hide @SystemApi -->
     <public name="config_systemUi" />
+    <!-- @hide For use by platform and tools only. Developers should not specify this value. -->
+    <public name="config_defaultRingtoneVibrationSound"/>
   </staging-public-group>
 
   <staging-public-group type="id" first-id="0x01020055">
diff --git a/core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java b/core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java
new file mode 100644
index 0000000..65dd34f
--- /dev/null
+++ b/core/tests/coretests/src/android/view/TunnelModeEnabledListenerTest.java
@@ -0,0 +1,84 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.view;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import android.platform.test.annotations.Presubmit;
+
+import androidx.test.filters.MediumTest;
+import androidx.test.runner.AndroidJUnit4;
+
+import java.util.concurrent.TimeUnit;
+import java.util.concurrent.atomic.AtomicBoolean;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(AndroidJUnit4.class)
+@MediumTest
+@Presubmit
+public class TunnelModeEnabledListenerTest {
+    private TestableTunnelModeEnabledListener mListener;
+
+    @Before
+    public void init() {
+        mListener = new TestableTunnelModeEnabledListener();
+    }
+
+    @Test
+    public void testRegisterUnregister() {
+        TunnelModeEnabledListener.register(mListener);
+        TunnelModeEnabledListener.unregister(mListener);
+    }
+
+    @Test
+    public void testDispatchUpdatesListener() {
+        TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, true);
+        assertEquals(true, mListener.mTunnelModeEnabled.get());
+        TunnelModeEnabledListener.dispatchOnTunnelModeEnabledChanged(mListener, false);
+        assertEquals(false, mListener.mTunnelModeEnabled.get());
+    }
+
+    @Test
+    public void testRegisterUpdatesListener() throws Exception {
+        TunnelModeEnabledListener.register(mListener);
+        TimeUnit.SECONDS.sleep(1);
+        assertTrue(mListener.mTunnelModeEnabledUpdated.get());
+        TunnelModeEnabledListener.unregister(mListener);
+    }
+
+    private static class TestableTunnelModeEnabledListener extends TunnelModeEnabledListener {
+        AtomicBoolean mTunnelModeEnabled;
+        AtomicBoolean mTunnelModeEnabledUpdated;
+
+        TestableTunnelModeEnabledListener() {
+            super(Runnable::run);
+            mTunnelModeEnabled = new AtomicBoolean(false);
+            mTunnelModeEnabledUpdated = new AtomicBoolean();
+        }
+
+        @Override
+        public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) {
+            mTunnelModeEnabled.set(tunnelModeEnabled);
+            mTunnelModeEnabledUpdated.set(true);
+        }
+    }
+
+}
diff --git a/data/etc/privapp-permissions-platform.xml b/data/etc/privapp-permissions-platform.xml
index 19332c7..8d4739d 100644
--- a/data/etc/privapp-permissions-platform.xml
+++ b/data/etc/privapp-permissions-platform.xml
@@ -473,6 +473,7 @@
         <permission name="android.permission.UPDATE_FONTS" />
         <!-- Permission required for hotword detection service CTS tests -->
         <permission name="android.permission.MANAGE_HOTWORD_DETECTION" />
+        <permission name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
         <permission name="android.permission.MANAGE_APP_HIBERNATION"/>
         <!-- Permission required for CTS test - ResourceObserverNativeTest -->
         <permission name="android.permission.REGISTER_MEDIA_RESOURCE_OBSERVER" />
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
index 187e104..c37e88a 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawer.java
@@ -277,8 +277,9 @@
             // waiting for setContentView before relayoutWindow
             SplashScreenView contentView = viewSupplier.get();
             final StartingWindowRecord record = mStartingWindowRecords.get(taskId);
-            // if record == null, either the starting window added fail or removed already.
-            if (record != null) {
+            // If record == null, either the starting window added fail or removed already.
+            // Do not add this view if the token is mismatch.
+            if (record != null && appToken == record.mAppToken) {
                 // if view == null then creation of content view was failed.
                 if (contentView != null) {
                     try {
@@ -297,15 +298,16 @@
 
         try {
             final WindowManager wm = context.getSystemService(WindowManager.class);
-            postAddWindow(taskId, appToken, rootLayout, wm, params);
-
-            // We use the splash screen worker thread to create SplashScreenView while adding the
-            // window, as otherwise Choreographer#doFrame might be delayed on this thread.
-            // And since Choreographer#doFrame won't happen immediately after adding the window, if
-            // the view is not added to the PhoneWindow on the first #doFrame, the view will not be
-            // rendered on the first frame. So here we need to synchronize the view on the window
-            // before first round relayoutWindow, which will happen after insets animation.
-            mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
+            if (postAddWindow(taskId, appToken, rootLayout, wm, params)) {
+                // We use the splash screen worker thread to create SplashScreenView while adding
+                // the window, as otherwise Choreographer#doFrame might be delayed on this thread.
+                // And since Choreographer#doFrame won't happen immediately after adding the window,
+                // if the view is not added to the PhoneWindow on the first #doFrame, the view will
+                // not be rendered on the first frame. So here we need to synchronize the view on
+                // the window before first round relayoutWindow, which will happen after insets
+                // animation.
+                mChoreographer.postCallback(CALLBACK_INSETS_ANIMATION, setViewSynchronized, null);
+            }
         } catch (RuntimeException e) {
             // don't crash if something else bad happens, for example a
             // failure loading resources because we are loading from an app
@@ -347,7 +349,8 @@
         final int taskId = startingWindowInfo.taskInfo.taskId;
         final TaskSnapshotWindow surface = TaskSnapshotWindow.create(startingWindowInfo, appToken,
                 snapshot, mSplashScreenExecutor, () -> removeWindowNoAnimate(taskId));
-        final StartingWindowRecord tView = new StartingWindowRecord(null/* decorView */, surface);
+        final StartingWindowRecord tView = new StartingWindowRecord(appToken,
+                null/* decorView */, surface);
         mStartingWindowRecords.put(taskId, tView);
     }
 
@@ -382,7 +385,7 @@
         ActivityTaskManager.getInstance().onSplashScreenViewCopyFinished(taskId, parcelable);
     }
 
-    protected void postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
+    protected boolean postAddWindow(int taskId, IBinder appToken, View view, WindowManager wm,
             WindowManager.LayoutParams params) {
         boolean shouldSaveView = true;
         try {
@@ -401,12 +404,13 @@
         }
         if (shouldSaveView) {
             removeWindowNoAnimate(taskId);
-            saveSplashScreenRecord(taskId, view);
+            saveSplashScreenRecord(appToken, taskId, view);
         }
+        return shouldSaveView;
     }
 
-    private void saveSplashScreenRecord(int taskId, View view) {
-        final StartingWindowRecord tView = new StartingWindowRecord(view,
+    private void saveSplashScreenRecord(IBinder appToken, int taskId, View view) {
+        final StartingWindowRecord tView = new StartingWindowRecord(appToken, view,
                 null/* TaskSnapshotWindow */);
         mStartingWindowRecords.put(taskId, tView);
     }
@@ -468,12 +472,15 @@
      * Record the view or surface for a starting window.
      */
     private static class StartingWindowRecord {
+        private final IBinder mAppToken;
         private final View mDecorView;
         private final TaskSnapshotWindow mTaskSnapshotWindow;
         private SplashScreenView mContentView;
         private boolean mSetSplashScreen;
 
-        StartingWindowRecord(View decorView, TaskSnapshotWindow taskSnapshotWindow) {
+        StartingWindowRecord(IBinder appToken, View decorView,
+                TaskSnapshotWindow taskSnapshotWindow) {
+            mAppToken = appToken;
             mDecorView = decorView;
             mTaskSnapshotWindow = taskSnapshotWindow;
         }
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
index 2623535..4e3e133 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/startingsurface/StartingSurfaceDrawerTests.java
@@ -83,11 +83,12 @@
         }
 
         @Override
-        protected void postAddWindow(int taskId, IBinder appToken,
+        protected boolean postAddWindow(int taskId, IBinder appToken,
                 View view, WindowManager wm, WindowManager.LayoutParams params) {
             // listen for addView
             mAddWindowForTask = taskId;
             mViewThemeResId = view.getContext().getThemeResId();
+            return true;
         }
 
         @Override
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 79d505e..f8297bc 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -405,9 +405,11 @@
      */
     public void play() {
         if (mLocalPlayer != null) {
-            // do not play ringtones if stream volume is 0
-            // (typically because ringer mode is silent).
-            if (mAudioManager.getStreamVolume(
+            // Play ringtones if stream volume is over 0 or if it is a haptic-only ringtone
+            // (typically because ringer mode is vibrate).
+            boolean isHapticOnly = AudioManager.hasHapticChannels(mUri)
+                    && !mAudioAttributes.areHapticChannelsMuted() && mVolume == 0;
+            if (isHapticOnly || mAudioManager.getStreamVolume(
                     AudioAttributes.toLegacyStreamType(mAudioAttributes)) != 0) {
                 startLocalPlayer();
             }
diff --git a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
index ed447f8..3d93964 100644
--- a/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
+++ b/packages/SettingsLib/SettingsTransition/src/com/android/settingslib/transition/SettingsTransitionHelper.java
@@ -16,6 +16,7 @@
 
 package com.android.settingslib.transition;
 
+import androidx.annotation.IntDef;
 import android.app.Activity;
 import android.content.Context;
 import android.util.Log;
@@ -29,11 +30,31 @@
 import com.google.android.material.transition.platform.MaterialSharedAxis;
 import com.google.android.material.transition.platform.SlideDistanceProvider;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * A helper class to apply Settings Transition
  */
 public class SettingsTransitionHelper {
 
+    /**
+     * Flags indicating the type of the transition.
+     */
+    @IntDef({
+            TransitionType.TRANSITION_NONE,
+            TransitionType.TRANSITION_SHARED_AXIS,
+            TransitionType.TRANSITION_SLIDE,
+            TransitionType.TRANSITION_FADE
+    })
+    @Retention(RetentionPolicy.SOURCE)
+    public @interface TransitionType {
+        int TRANSITION_NONE = -1;
+        int TRANSITION_SHARED_AXIS = 0;
+        int TRANSITION_SLIDE = 1;
+        int TRANSITION_FADE = 2;
+    }
+
     private static final String TAG = "SettingsTransitionHelper";
     private static final long DURATION = 450L;
     private static final float FADE_THROUGH_THRESHOLD = 0.22F;
diff --git a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
index 4558a8a..fe92e26 100644
--- a/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/bluetooth/CachedBluetoothDevice.java
@@ -1222,19 +1222,22 @@
      */
     public Pair<Drawable, String> getDrawableWithDescription() {
         Uri uri = BluetoothUtils.getUriMetaData(mDevice, BluetoothDevice.METADATA_MAIN_ICON);
+        Pair<Drawable, String> pair = BluetoothUtils.getBtClassDrawableWithDescription(
+                mContext, this);
+
         if (BluetoothUtils.isAdvancedDetailsHeader(mDevice) && uri != null) {
             BitmapDrawable drawable = mDrawableCache.get(uri.toString());
             if (drawable != null) {
                 Resources resources = mContext.getResources();
                 return new Pair<>(new AdaptiveOutlineDrawable(
-                        resources, drawable.getBitmap()),
-                        BluetoothUtils.getBtClassDrawableWithDescription(mContext, this).second);
+                        resources, drawable.getBitmap()), pair.second);
             }
 
             refresh();
         }
 
-        return BluetoothUtils.getBtRainbowDrawableWithDescription(mContext, this);
+        return new Pair<>(BluetoothUtils.buildBtRainbowDrawable(
+                        mContext, pair.first, getAddress().hashCode()), pair.second);
     }
 
     void releaseLruCache() {
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
index 38172f7..f523354 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/bluetooth/CachedBluetoothDeviceTest.java
@@ -31,7 +31,9 @@
 import android.bluetooth.BluetoothDevice;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.graphics.drawable.BitmapDrawable;
 import android.media.AudioManager;
+import android.util.LruCache;
 
 import com.android.settingslib.R;
 import com.android.settingslib.testutils.shadow.ShadowBluetoothAdapter;
@@ -961,6 +963,10 @@
 
     @Test
     public void getDrawableWithDescription_isAdvancedDevice_returnAdvancedIcon() {
+        LruCache lruCache = mock(LruCache.class);
+        mCachedDevice.mDrawableCache = lruCache;
+        BitmapDrawable drawable = mock(BitmapDrawable.class);
+        when(lruCache.get("fake_uri")).thenReturn(drawable);
         when(mDevice.getMetadata(BluetoothDevice.METADATA_MAIN_ICON))
                 .thenReturn("fake_uri".getBytes());
         when(mDevice.getMetadata(BluetoothDevice.METADATA_IS_UNTETHERED_HEADSET))
diff --git a/packages/Shell/AndroidManifest.xml b/packages/Shell/AndroidManifest.xml
index 6e256c1..d2947c6 100644
--- a/packages/Shell/AndroidManifest.xml
+++ b/packages/Shell/AndroidManifest.xml
@@ -528,6 +528,7 @@
 
     <!-- Permission required for hotword detection service CTS tests -->
     <uses-permission android:name="android.permission.MANAGE_HOTWORD_DETECTION" />
+    <uses-permission android:name="android.permission.BIND_HOTWORD_DETECTION_SERVICE" />
 
     <uses-permission android:name="android.permission.MANAGE_APP_HIBERNATION"/>
 
diff --git a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
index 1cf0c5f..2b87737 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/ActivityLaunchAnimator.kt
@@ -4,12 +4,15 @@
 import android.animation.AnimatorListenerAdapter
 import android.animation.ValueAnimator
 import android.app.ActivityManager
+import android.app.ActivityTaskManager
 import android.app.PendingIntent
 import android.content.Context
 import android.graphics.Matrix
 import android.graphics.Rect
+import android.graphics.RectF
 import android.os.Looper
 import android.os.RemoteException
+import android.util.Log
 import android.util.MathUtils
 import android.view.IRemoteAnimationFinishedCallback
 import android.view.IRemoteAnimationRunner
@@ -30,6 +33,8 @@
  * nicely into the starting window.
  */
 class ActivityLaunchAnimator(context: Context) {
+    private val TAG = this::class.java.simpleName
+
     companion object {
         const val ANIMATION_DURATION = 500L
         const val ANIMATION_DURATION_FADE_OUT_CONTENT = 183L
@@ -78,29 +83,49 @@
      * If [controller] is null or [animate] is false, then the intent will be started and no
      * animation will run.
      *
+     * If possible, you should pass the [packageName] of the intent that will be started so that
+     * trampoline activity launches will also be animated.
+     *
      * This method will throw any exception thrown by [intentStarter].
      */
     @JvmOverloads
-    inline fun startIntentWithAnimation(
+    fun startIntentWithAnimation(
         controller: Controller?,
         animate: Boolean = true,
+        packageName: String? = null,
         intentStarter: (RemoteAnimationAdapter?) -> Int
     ) {
         if (controller == null || !animate) {
+            Log.d(TAG, "Starting intent with no animation")
             intentStarter(null)
             controller?.callOnIntentStartedOnMainThread(willAnimate = false)
             return
         }
 
+        Log.d(TAG, "Starting intent with a launch animation")
         val runner = Runner(controller)
         val animationAdapter = RemoteAnimationAdapter(
             runner,
             ANIMATION_DURATION,
             ANIMATION_DURATION - 150 /* statusBarTransitionDelay */
         )
+
+        // Register the remote animation for the given package to also animate trampoline
+        // activity launches.
+        if (packageName != null) {
+            try {
+                ActivityTaskManager.getService().registerRemoteAnimationForNextActivityStart(
+                    packageName, animationAdapter)
+            } catch (e: RemoteException) {
+                Log.w(TAG, "Unable to register the remote animation", e)
+            }
+        }
+
         val launchResult = intentStarter(animationAdapter)
         val willAnimate = launchResult == ActivityManager.START_TASK_TO_FRONT ||
             launchResult == ActivityManager.START_SUCCESS
+
+        Log.d(TAG, "launchResult=$launchResult willAnimate=$willAnimate")
         controller.callOnIntentStartedOnMainThread(willAnimate)
 
         // If we expect an animation, post a timeout to cancel it in case the remote animation is
@@ -110,7 +135,6 @@
         }
     }
 
-    @PublishedApi
     internal fun Controller.callOnIntentStartedOnMainThread(willAnimate: Boolean) {
         if (Looper.myLooper() != Looper.getMainLooper()) {
             this.launchContainer.context.mainExecutor.execute {
@@ -125,15 +149,21 @@
      * Same as [startIntentWithAnimation] but allows [intentStarter] to throw a
      * [PendingIntent.CanceledException] which must then be handled by the caller. This is useful
      * for Java caller starting a [PendingIntent].
+     *
+     * If possible, you should pass the [packageName] of the intent that will be started so that
+     * trampoline activity launches will also be animated.
      */
     @Throws(PendingIntent.CanceledException::class)
     @JvmOverloads
     fun startPendingIntentWithAnimation(
         controller: Controller?,
         animate: Boolean = true,
+        packageName: String? = null,
         intentStarter: PendingIntentStarter
     ) {
-        startIntentWithAnimation(controller, animate) { intentStarter.startPendingIntent(it) }
+        startIntentWithAnimation(controller, animate, packageName) {
+            intentStarter.startPendingIntent(it)
+        }
     }
 
     /** Create a new animation [Runner] controlled by [controller]. */
@@ -278,11 +308,14 @@
     @VisibleForTesting
     inner class Runner(private val controller: Controller) : IRemoteAnimationRunner.Stub() {
         private val launchContainer = controller.launchContainer
-        @PublishedApi internal val context = launchContainer.context
+        private val context = launchContainer.context
         private val transactionApplier = SyncRtSurfaceTransactionApplier(launchContainer)
         private var animator: ValueAnimator? = null
 
+        private val matrix = Matrix()
+        private val invertMatrix = Matrix()
         private var windowCrop = Rect()
+        private var windowCropF = RectF()
         private var timedOut = false
         private var cancelled = false
 
@@ -294,7 +327,6 @@
         // posting it.
         private var onTimeout = Runnable { onAnimationTimedOut() }
 
-        @PublishedApi
         internal fun postTimeout() {
             launchContainer.postDelayed(onTimeout, LAUNCH_TIMEOUT)
         }
@@ -336,11 +368,13 @@
             remoteAnimationNonAppTargets: Array<out RemoteAnimationTarget>,
             iCallback: IRemoteAnimationFinishedCallback
         ) {
+            Log.d(TAG, "Remote animation started")
             val window = remoteAnimationTargets.firstOrNull {
                 it.mode == RemoteAnimationTarget.MODE_OPENING
             }
 
             if (window == null) {
+                Log.d(TAG, "Aborting the animation as no window is opening")
                 removeTimeout()
                 invokeCallback(iCallback)
                 controller.onLaunchAnimationCancelled()
@@ -399,10 +433,12 @@
 
             animator.addListener(object : AnimatorListenerAdapter() {
                 override fun onAnimationStart(animation: Animator?, isReverse: Boolean) {
+                    Log.d(TAG, "Animation started")
                     controller.onLaunchAnimationStart(isExpandingFullyAbove)
                 }
 
                 override fun onAnimationEnd(animation: Animator?) {
+                    Log.d(TAG, "Animation ended")
                     invokeCallback(iCallback)
                     controller.onLaunchAnimationEnd(isExpandingFullyAbove)
                 }
@@ -447,19 +483,52 @@
         }
 
         private fun applyStateToWindow(window: RemoteAnimationTarget, state: State) {
-            val m = Matrix()
-            m.postTranslate(0f, (state.top - window.sourceContainerBounds.top).toFloat())
-            windowCrop.set(state.left, 0, state.right, state.height)
+            val screenBounds = window.screenSpaceBounds
+            val centerX = (screenBounds.left + screenBounds.right) / 2f
+            val centerY = (screenBounds.top + screenBounds.bottom) / 2f
+            val width = screenBounds.right - screenBounds.left
+            val height = screenBounds.bottom - screenBounds.top
 
-            val cornerRadius = minOf(state.topCornerRadius, state.bottomCornerRadius)
+            // Scale the window. We use the max of (widthRatio, heightRatio) so that there is no
+            // blank space on any side.
+            val widthRatio = state.width.toFloat() / width
+            val heightRatio = state.height.toFloat() / height
+            val scale = maxOf(widthRatio, heightRatio)
+            matrix.reset()
+            matrix.setScale(scale, scale, centerX, centerY)
+
+            // Align it to the top and center it in the x-axis.
+            val heightChange = height * scale - height
+            val translationX = state.centerX - centerX
+            val translationY = state.top - screenBounds.top + heightChange / 2f
+            matrix.postTranslate(translationX, translationY)
+
+            // Crop it. The matrix will also be applied to the crop, so we apply the inverse
+            // operation. Given that we only scale (by factor > 0) then translate, we can assume
+            // that the matrix is invertible.
+            val cropX = state.left.toFloat() - screenBounds.left
+            val cropY = state.top.toFloat() - screenBounds.top
+            windowCropF.set(cropX, cropY, cropX + state.width, cropY + state.height)
+            matrix.invert(invertMatrix)
+            invertMatrix.mapRect(windowCropF)
+            windowCrop.set(
+                windowCropF.left.roundToInt(),
+                windowCropF.top.roundToInt(),
+                windowCropF.right.roundToInt(),
+                windowCropF.bottom.roundToInt()
+            )
+
+            // The scale will also be applied to the corner radius, so we divide by the scale to
+            // keep the original radius.
+            val cornerRadius = minOf(state.topCornerRadius, state.bottomCornerRadius) / scale
             val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(window.leash)
-                    .withAlpha(1f)
-                    .withMatrix(m)
-                    .withWindowCrop(windowCrop)
-                    .withLayer(window.prefixOrderIndex)
-                    .withCornerRadius(cornerRadius)
-                    .withVisibility(true)
-                    .build()
+                .withAlpha(1f)
+                .withMatrix(matrix)
+                .withWindowCrop(windowCrop)
+                .withLayer(window.prefixOrderIndex)
+                .withCornerRadius(cornerRadius)
+                .withVisibility(true)
+                .build()
 
             transactionApplier.scheduleApply(params)
         }
@@ -474,12 +543,13 @@
 
             val params = SyncRtSurfaceTransactionApplier.SurfaceParams.Builder(navigationBar.leash)
             if (fadeInProgress > 0) {
-                val m = Matrix()
-                m.postTranslate(0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
+                matrix.reset()
+                matrix.setTranslate(
+                    0f, (state.top - navigationBar.sourceContainerBounds.top).toFloat())
                 windowCrop.set(state.left, 0, state.right, state.height)
                 params
                         .withAlpha(NAV_FADE_IN_INTERPOLATOR.getInterpolation(fadeInProgress))
-                        .withMatrix(m)
+                        .withMatrix(matrix)
                         .withWindowCrop(windowCrop)
                         .withVisibility(true)
             } else {
@@ -496,6 +566,7 @@
                 return
             }
 
+            Log.d(TAG, "Remote animation timed out")
             timedOut = true
             controller.onLaunchAnimationCancelled()
         }
@@ -505,6 +576,7 @@
                 return
             }
 
+            Log.d(TAG, "Remote animation was cancelled")
             cancelled = true
             removeTimeout()
             context.mainExecutor.execute {
diff --git a/packages/SystemUI/res/drawable/ic_cake.xml b/packages/SystemUI/res/drawable/ic_cake.xml
new file mode 100644
index 0000000..9c83b43
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_cake.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M19,14v-4c0,-1.1 -0.9,-2 -2,-2h-4L13,6.55c0.15,-0.09 0.29,-0.18 0.41,-0.31 0.39,-0.39 0.59,-0.92 0.59,-1.42s-0.2,-1.02 -0.59,-1.41L12,2l-1.41,1.41c-0.39,0.39 -0.59,0.91 -0.59,1.41s0.2,1.03 0.59,1.42c0.13,0.13 0.27,0.22 0.41,0.31L11,8L7,8c-1.1,0 -2,0.9 -2,2v4c-1.1,0 -2,0.9 -2,2v4c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2v-4c0,-1.1 -0.9,-2 -2,-2zM7,10h10v4L7,14v-4zM19,20L5,20v-4h14v4z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_celebration.xml b/packages/SystemUI/res/drawable/ic_celebration.xml
new file mode 100644
index 0000000..10fe406
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_celebration.xml
@@ -0,0 +1,37 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M2,22l14,-5L7,8L2,22zM12.35,16.18L5.3,18.7l2.52,-7.05L12.35,16.18z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M14.53,12.53l5.59,-5.59c0.49,-0.49 1.28,-0.49 1.77,0l0.59,0.59l1.06,-1.06l-0.59,-0.59c-1.07,-1.07 -2.82,-1.07 -3.89,0l-5.59,5.59L14.53,12.53z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M10.06,6.88L9.47,7.47l1.06,1.06l0.59,-0.59c1.07,-1.07 1.07,-2.82 0,-3.89l-0.59,-0.59L9.47,4.53l0.59,0.59C10.54,5.6 10.54,6.4 10.06,6.88z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M17.06,11.88l-1.59,1.59l1.06,1.06l1.59,-1.59c0.49,-0.49 1.28,-0.49 1.77,0l1.61,1.61l1.06,-1.06l-1.61,-1.61C19.87,10.81 18.13,10.81 17.06,11.88z"
+        android:fillColor="#FFFFFFFF"/>
+    <path
+        android:pathData="M15.06,5.88l-3.59,3.59l1.06,1.06l3.59,-3.59c1.07,-1.07 1.07,-2.82 0,-3.89l-1.59,-1.59l-1.06,1.06l1.59,1.59C15.54,4.6 15.54,5.4 15.06,5.88z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
+
diff --git a/packages/SystemUI/res/drawable/ic_gift.xml b/packages/SystemUI/res/drawable/ic_gift.xml
new file mode 100644
index 0000000..fab36c3
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_gift.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M22,5h-5.18C16.93,4.69 17,4.35 17,4c0,-1.65 -1.35,-3 -3,-3c-0.77,0 -1.47,0.3 -2,0.78C11.47,1.3 10.77,1 10,1C8.35,1 7,2.35 7,4c0,0.35 0.07,0.69 0.18,1H2v6h2v11h16V11h2V5zM14,3c0.55,0 1,0.45 1,1s-0.45,1 -1,1s-1,-0.45 -1,-1S13.45,3 14,3zM9,4c0,-0.55 0.45,-1 1,-1s1,0.45 1,1s-0.45,1 -1,1S9,4.55 9,4zM4,7h7v2H4V7zM6,11h5v9H6V11zM18,20h-5v-9h5V20zM20,9h-7V7h7V9z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_pages.xml b/packages/SystemUI/res/drawable/ic_pages.xml
new file mode 100644
index 0000000..9cd076d
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_pages.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M19,5v14L5,19L5,5h14m0,-2L5,3c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L21,5c0,-1.1 -0.9,-2 -2,-2zM12,17l1.57,-3.43L17,12l-3.43,-1.57L12,7l-1.57,3.43L7,12l3.43,1.57L12,17z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_play_games.xml b/packages/SystemUI/res/drawable/ic_play_games.xml
new file mode 100644
index 0000000..20096f4
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_play_games.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M20.47,8c-0.39,-2.3 -2.4,-4 -4.81,-4L8.34,4C5.93,4 3.93,5.7 3.53,8 3.53,8 2,16.8 2,16.93 2,18.07 2.93,19 4.07,19c0.57,0 1.09,-0.2 1.47,-0.58L9,15h6l3.46,3.42c0.38,0.38 0.89,0.58 1.47,0.58 1.15,0 2.07,-0.93 2.07,-2.07C22,16.8 20.47,8 20.47,8zM11,10L9,10v2L8,12v-2L6,10L6,9h2L8,7h1v2h2v1zM13.8,10.3c-0.44,0 -0.8,-0.36 -0.8,-0.8 0,-0.44 0.36,-0.8 0.8,-0.8 0.44,0 0.8,0.36 0.8,0.8 0,0.44 -0.36,0.8 -0.8,0.8zM15.49,12c-0.44,0 -0.8,-0.36 -0.8,-0.8 0,-0.44 0.36,-0.8 0.8,-0.8 0.44,0 0.8,0.36 0.8,0.8 0,0.44 -0.36,0.8 -0.8,0.8zM15.49,8.6c-0.44,0 -0.8,-0.36 -0.8,-0.8s0.36,-0.8 0.8,-0.8c0.44,0 0.8,0.36 0.8,0.8s-0.36,0.8 -0.8,0.8zM17.2,10.3c-0.44,0 -0.8,-0.36 -0.8,-0.8 0,-0.44 0.36,-0.8 0.8,-0.8s0.8,0.36 0.8,0.8c0,0.44 -0.36,0.8 -0.8,0.8z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/drawable/ic_video.xml b/packages/SystemUI/res/drawable/ic_video.xml
new file mode 100644
index 0000000..3668338
--- /dev/null
+++ b/packages/SystemUI/res/drawable/ic_video.xml
@@ -0,0 +1,24 @@
+<!--
+  ~ Copyright (C) 2021 The Android Open Source Project
+  ~
+  ~ Licensed under the Apache License, Version 2.0 (the "License");
+  ~ you may not use this file except in compliance with the License.
+  ~ You may obtain a copy of the License at
+  ~
+  ~      http://www.apache.org/licenses/LICENSE-2.0
+  ~
+  ~ Unless required by applicable law or agreed to in writing, software
+  ~ distributed under the License is distributed on an "AS IS" BASIS,
+  ~ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+  ~ See the License for the specific language governing permissions and
+  ~ limitations under the License.
+  -->
+<vector xmlns:android="http://schemas.android.com/apk/res/android"
+    android:width="24dp"
+    android:height="24dp"
+    android:viewportWidth="24"
+    android:viewportHeight="24">
+    <path
+        android:pathData="M9,7v8l7,-4zM21,3L3,3c-1.1,0 -2,0.9 -2,2v12c0,1.1 0.9,2 2,2h5v2h8v-2h5c1.1,0 2,-0.9 2,-2L23,5c0,-1.1 -0.9,-2 -2,-2zM21,17L3,17L3,5h18v12z"
+        android:fillColor="#FFFFFFFF"/>
+</vector>
diff --git a/packages/SystemUI/res/layout/people_tile_large_with_content.xml b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
index 4994c69..e294dad 100644
--- a/packages/SystemUI/res/layout/people_tile_large_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_large_with_content.xml
@@ -34,8 +34,6 @@
 
             <ImageView
                 android:id="@+id/person_icon"
-                android:layout_marginStart="-2dp"
-                android:layout_marginTop="-2dp"
                 android:layout_width="wrap_content"
                 android:layout_height="wrap_content"
                 android:layout_weight="1" />
@@ -73,12 +71,12 @@
         <include layout="@layout/people_tile_emoji_background_large" />
 
         <TextView
-            android:layout_gravity="top"
             android:id="@+id/name"
-            android:layout_width="match_parent"
+            android:layout_width="wrap_content"
             android:layout_height="wrap_content"
             android:paddingBottom="@dimen/below_name_text_padding"
-            android:gravity="start|top"
+            android:layout_gravity="start|center_vertical"
+            android:gravity="start|center_vertical"
             android:singleLine="true"
             android:ellipsize="end"
             android:text="@string/empty_user_name"
@@ -103,7 +101,7 @@
 
                 <ImageView
                     android:id="@+id/predefined_icon"
-                    android:tint="?android:attr/colorAccent"
+                    android:tint="?android:attr/textColorTertiary"
                     android:gravity="start|center_vertical"
                     android:layout_width="@dimen/regular_predefined_icon"
                     android:layout_height="@dimen/regular_predefined_icon" />
diff --git a/packages/SystemUI/res/layout/people_tile_medium_empty.xml b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
index bebc872..8b2fddc 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_empty.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_empty.xml
@@ -27,19 +27,23 @@
         android:orientation="horizontal"
         android:layout_width="match_parent"
         android:layout_height="match_parent">
-        <ImageView
-            android:id="@+id/person_icon"
-            android:layout_marginTop="-2dp"
-            android:layout_marginStart="-2dp"
-            android:layout_width="64dp"
-            android:layout_height="64dp" />
-        <ImageView
-            android:id="@+id/availability"
-            android:gravity="top"
-            android:layout_marginStart="-2dp"
-            android:layout_width="10dp"
-            android:layout_height="10dp"
-            android:background="@drawable/availability_dot_10dp" />
+        <LinearLayout
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:orientation="horizontal">
+            <ImageView
+                android:id="@+id/person_icon"
+                android:layout_width="64dp"
+                android:layout_height="64dp" />
+            <ImageView
+                android:id="@+id/availability"
+                android:layout_width="10dp"
+                android:layout_height="10dp"
+                android:gravity="top"
+                android:layout_gravity="top"
+                android:layout_marginStart="-2dp"
+                android:background="@drawable/availability_dot_10dp" />
+        </LinearLayout>
         <LinearLayout
             android:orientation="vertical"
             android:paddingStart="4dp"
diff --git a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
index a7a6354..47cab42 100644
--- a/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
+++ b/packages/SystemUI/res/layout/people_tile_medium_with_content.xml
@@ -47,8 +47,6 @@
                 <ImageView
                     android:gravity="start"
                     android:id="@+id/person_icon"
-                    android:layout_marginStart="-2dp"
-                    android:layout_marginTop="-2dp"
                     android:layout_width="52dp"
                     android:layout_height="52dp" />
 
@@ -112,7 +110,8 @@
                 android:clipToOutline="true">
                 <TextView
                     android:id="@+id/name"
-                    android:gravity="center_vertical"
+                    android:layout_gravity="start|center_vertical"
+                    android:gravity="start|center_vertical"
                     android:layout_weight="1"
                     android:text="@string/empty_user_name"
                     android:textAppearance="@*android:style/TextAppearance.DeviceDefault.ListItem"
@@ -140,7 +139,7 @@
                     />
                 <ImageView
                     android:id="@+id/predefined_icon"
-                    android:tint="?android:attr/colorAccent"
+                    android:tint="?android:attr/textColorTertiary"
                     android:gravity="end|center_vertical"
                     android:layout_width="@dimen/regular_predefined_icon"
                     android:layout_height="@dimen/regular_predefined_icon" />
diff --git a/packages/SystemUI/res/layout/people_tile_small.xml b/packages/SystemUI/res/layout/people_tile_small.xml
index 4e5c04c..7a1371d 100644
--- a/packages/SystemUI/res/layout/people_tile_small.xml
+++ b/packages/SystemUI/res/layout/people_tile_small.xml
@@ -39,7 +39,7 @@
 
         <ImageView
             android:id="@+id/predefined_icon"
-            android:tint="?android:attr/colorAccent"
+            android:tint="?android:attr/textColorTertiary"
             android:layout_gravity="center"
             android:layout_width="18dp"
             android:layout_height="22dp" />
diff --git a/packages/SystemUI/res/layout/status_bar_expanded.xml b/packages/SystemUI/res/layout/status_bar_expanded.xml
index 3543fd1..c16f13e 100644
--- a/packages/SystemUI/res/layout/status_bar_expanded.xml
+++ b/packages/SystemUI/res/layout/status_bar_expanded.xml
@@ -64,10 +64,6 @@
         android:clipToPadding="false"
         android:clipChildren="false">
 
-        <include
-            layout="@layout/keyguard_status_view"
-            android:visibility="gone"/>
-
         <com.android.systemui.scrim.ScrimView
             android:id="@+id/scrim_notifications"
             android:layout_width="0dp"
@@ -78,7 +74,11 @@
             systemui:layout_constraintEnd_toEndOf="parent"
             systemui:layout_constraintTop_toTopOf="parent"
             systemui:layout_constraintBottom_toBottomOf="parent"
-            />
+        />
+
+        <include
+            layout="@layout/keyguard_status_view"
+            android:visibility="gone"/>
 
         <include layout="@layout/dock_info_overlay" />
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 792d2ec..146f430 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
@@ -54,14 +54,16 @@
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.os.SomeArgs;
 import com.android.systemui.SystemUI;
+import com.android.systemui.assist.ui.DisplayUtils;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.doze.DozeReceiver;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.HashSet;
 import java.util.List;
+import java.util.Set;
 
 import javax.inject.Inject;
 import javax.inject.Provider;
@@ -79,13 +81,14 @@
 
     private final Handler mHandler = new Handler(Looper.getMainLooper());
     private final CommandQueue mCommandQueue;
-    private final StatusBarStateController mStatusBarStateController;
     private final ActivityTaskManager mActivityTaskManager;
     @Nullable private final FingerprintManager mFingerprintManager;
     @Nullable private final FaceManager mFaceManager;
     private final Provider<UdfpsController> mUdfpsControllerFactory;
     private final Provider<SidefpsController> mSidefpsControllerFactory;
     @Nullable private final PointF mFaceAuthSensorLocation;
+    @Nullable private final PointF mFingerprintLocation;
+    private final Set<Callback> mCallbacks = new HashSet<>();
 
     // TODO: These should just be saved from onSaveState
     private SomeArgs mCurrentDialogArgs;
@@ -142,6 +145,10 @@
                     if (mSidefpsProps != null) {
                         mSidefpsController = mSidefpsControllerFactory.get();
                     }
+
+                    for (Callback cb : mCallbacks) {
+                        cb.onAllAuthenticatorsRegistered();
+                    }
                 }
             };
 
@@ -195,6 +202,20 @@
         }
     }
 
+    /**
+     * Adds a callback. See {@link Callback}.
+     */
+    public void addCallback(@NonNull Callback callback) {
+        mCallbacks.add(callback);
+    }
+
+    /**
+     * Removes a callback. See {@link Callback}.
+     */
+    public void removeCallback(@NonNull Callback callback) {
+        mCallbacks.remove(callback);
+    }
+
     @Override
     public void dozeTimeTick() {
         if (mUdfpsController != null) {
@@ -335,6 +356,17 @@
     }
 
     /**
+     * @return where the fingerprint sensor exists in pixels in portrait mode. devices without an
+     * overridden value will use the default value even if they don't have a fingerprint sensor
+     */
+    @Nullable public PointF getFingerprintSensorLocation() {
+        if (getUdfpsSensorLocation() != null) {
+            return getUdfpsSensorLocation();
+        }
+        return mFingerprintLocation;
+    }
+
+    /**
      * @return where the face authentication sensor exists relative to the screen in pixels in
      * portrait mode.
      */
@@ -387,7 +419,6 @@
 
     @Inject
     public AuthController(Context context, CommandQueue commandQueue,
-            StatusBarStateController statusBarStateController,
             ActivityTaskManager activityTaskManager,
             @Nullable FingerprintManager fingerprintManager,
             @Nullable FaceManager faceManager,
@@ -395,7 +426,6 @@
             Provider<SidefpsController> sidefpsControllerFactory) {
         super(context);
         mCommandQueue = commandQueue;
-        mStatusBarStateController = statusBarStateController;
         mActivityTaskManager = activityTaskManager;
         mFingerprintManager = fingerprintManager;
         mFaceManager = faceManager;
@@ -414,6 +444,10 @@
                     (float) faceAuthLocation[1]);
         }
 
+        mFingerprintLocation = new PointF(DisplayUtils.getWidth(mContext) / 2,
+                mContext.getResources().getDimensionPixelSize(
+                com.android.systemui.R.dimen.physical_fingerprint_sensor_center_screen_location_y));
+
         IntentFilter filter = new IntentFilter();
         filter.addAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
 
@@ -711,4 +745,12 @@
                 .setMultiSensorConfig(multiSensorConfig)
                 .build(sensorIds, credentialAllowed, mFpProps, mFaceProps);
     }
+
+    interface Callback {
+        /**
+         * Called when authenticators are registered. If authenticators are already
+         * registered before this call, this callback will never be triggered.
+         */
+        void onAllAuthenticatorsRegistered();
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
index 257bd25..cf577a3 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleController.kt
@@ -28,6 +28,7 @@
 import com.android.systemui.statusbar.commandline.Command
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.StatusBar
 import com.android.systemui.statusbar.phone.dagger.StatusBarComponent.StatusBarScope
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.ViewController
@@ -40,6 +41,7 @@
  */
 @StatusBarScope
 class AuthRippleController @Inject constructor(
+    private val statusBar: StatusBar,
     private val sysuiContext: Context,
     private val authController: AuthController,
     private val configurationController: ConfigurationController,
@@ -49,13 +51,14 @@
     private val bypassController: KeyguardBypassController,
     rippleView: AuthRippleView?
 ) : ViewController<AuthRippleView>(rippleView) {
-    private var fingerprintSensorLocation: PointF? = null
+    var fingerprintSensorLocation: PointF? = null
     private var faceSensorLocation: PointF? = null
 
     @VisibleForTesting
     public override fun onViewAttached() {
         updateRippleColor()
         updateSensorLocation()
+        authController.addCallback(authControllerCallback)
         configurationController.addCallback(configurationChangedListener)
         keyguardUpdateMonitor.registerCallback(keyguardUpdateMonitorCallback)
         commandRegistry.registerCommand("auth-ripple") { AuthRippleCommand() }
@@ -63,6 +66,7 @@
 
     @VisibleForTesting
     public override fun onViewDetached() {
+        authController.removeCallback(authControllerCallback)
         keyguardUpdateMonitor.removeCallback(keyguardUpdateMonitorCallback)
         configurationController.removeCallback(configurationChangedListener)
         commandRegistry.unregisterCommand("auth-ripple")
@@ -97,9 +101,10 @@
         })
     }
 
-    private fun updateSensorLocation() {
-        fingerprintSensorLocation = authController.udfpsSensorLocation
+    fun updateSensorLocation() {
+        fingerprintSensorLocation = authController.fingerprintSensorLocation
         faceSensorLocation = authController.faceAuthSensorLocation
+        statusBar.updateCircleReveal()
     }
 
     private fun updateRippleColor() {
@@ -134,6 +139,8 @@
             }
     }
 
+    private val authControllerCallback = AuthController.Callback { updateSensorLocation() }
+
     inner class AuthRippleCommand : Command {
         override fun execute(pw: PrintWriter, args: List<String>) {
             if (args.isEmpty()) {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
index 374ddae..01fbe39 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthRippleView.kt
@@ -23,7 +23,11 @@
 import android.graphics.Canvas
 import android.graphics.Paint
 import android.graphics.PointF
+import android.media.AudioAttributes
+import android.os.VibrationEffect
+import android.os.Vibrator
 import android.util.AttributeSet
+import android.util.MathUtils
 import android.view.View
 import android.view.animation.PathInterpolator
 import com.android.internal.graphics.ColorUtils
@@ -31,15 +35,26 @@
 
 private const val RIPPLE_ANIMATION_DURATION: Long = 1533
 private const val RIPPLE_SPARKLE_STRENGTH: Float = 0.4f
+private const val RIPPLE_VIBRATION_PRIMITIVE: Int = VibrationEffect.Composition.PRIMITIVE_LOW_TICK
+private const val RIPPLE_VIBRATION_SIZE: Int = 60
+private const val RIPPLE_VIBRATION_SCALE_START: Float = 0.6f
+private const val RIPPLE_VIBRATION_SCALE_DECAY: Float = -0.1f
 
 /**
  * Expanding ripple effect on the transition from biometric authentication success to showing
  * launcher.
  */
 class AuthRippleView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
+    private val vibrator: Vibrator? = context?.getSystemService(Vibrator::class.java)
     private var rippleInProgress: Boolean = false
     private val rippleShader = RippleShader()
     private val ripplePaint = Paint()
+    private val rippleVibrationEffect = createVibrationEffect(vibrator)
+    private val rippleVibrationAttrs =
+            AudioAttributes.Builder()
+                    .setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
+                    .setUsage(AudioAttributes.USAGE_ASSISTANCE_SONIFICATION)
+                    .build()
 
     init {
         rippleShader.color = 0xffffffff.toInt() // default color
@@ -95,6 +110,7 @@
                 visibility = GONE
             }
         })
+        vibrate()
         animatorSet.start()
         visibility = VISIBLE
         rippleInProgress = true
@@ -108,4 +124,23 @@
         // draw over the entire screen
         canvas?.drawRect(0f, 0f, width.toFloat(), height.toFloat(), ripplePaint)
     }
+
+    private fun vibrate() {
+        if (rippleVibrationEffect != null) {
+            vibrator?.vibrate(rippleVibrationEffect, rippleVibrationAttrs)
+        }
+    }
+
+    private fun createVibrationEffect(vibrator: Vibrator?): VibrationEffect? {
+        if (vibrator?.areAllPrimitivesSupported(RIPPLE_VIBRATION_PRIMITIVE) == false) {
+            return null
+        }
+        val composition = VibrationEffect.startComposition()
+        for (i in 0 until RIPPLE_VIBRATION_SIZE) {
+            val scale =
+                    RIPPLE_VIBRATION_SCALE_START * MathUtils.exp(RIPPLE_VIBRATION_SCALE_DECAY * i)
+            composition.addPrimitive(RIPPLE_VIBRATION_PRIMITIVE, scale, 0 /* delay */)
+        }
+        return composition.compose()
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
index 3075617..5c360a6 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/UdfpsController.java
@@ -496,7 +496,6 @@
         mSensorProps = findFirstUdfps();
         // At least one UDFPS sensor exists
         checkArgument(mSensorProps != null);
-        mStatusBar.setSensorRect(getSensorLocation());
 
         mCoreLayoutParams = new WindowManager.LayoutParams(
                 WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG,
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
index 98d8866..6a025a7 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleSpaceActivity.java
@@ -184,10 +184,4 @@
         // Refresh tile views to sync new conversations.
         buildActivity();
     }
-
-    @Override
-    protected void onPause() {
-        super.onPause();
-        finish();
-    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
index f3cb359..96aeb60 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleStoryIconFactory.java
@@ -29,6 +29,8 @@
 import android.util.IconDrawableFactory;
 import android.util.Log;
 
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
@@ -58,7 +60,7 @@
         mIconDrawableFactory = iconDrawableFactory;
         mImportantConversationColor = context.getColor(R.color.important_conversation);
         mAccentColor = Utils.getColorAttr(context,
-                com.android.internal.R.attr.colorAccentPrimary).getDefaultColor();
+                com.android.internal.R.attr.colorAccentPrimaryVariant).getDefaultColor();
         mContext = context;
     }
 
@@ -83,7 +85,8 @@
      * Returns a {@link Drawable} for the entire conversation. The shortcut icon will be badged
      * with the launcher icon of the app specified by packageName.
      */
-    public Drawable getPeopleTileDrawable(Drawable headDrawable, String packageName, int userId,
+    public Drawable getPeopleTileDrawable(RoundedBitmapDrawable headDrawable, String packageName,
+            int userId,
             boolean important, boolean newStory) {
         return new PeopleStoryIconDrawable(headDrawable, getAppBadge(packageName, userId),
                 mIconBitmapSize, mImportantConversationColor, important, mIconSize, mDensity,
@@ -96,7 +99,7 @@
      */
     public static class PeopleStoryIconDrawable extends Drawable {
         private float mFullIconSize;
-        private Drawable mAvatar;
+        private RoundedBitmapDrawable mAvatar;
         private Drawable mBadgeIcon;
         private int mIconSize;
         private Paint mPriorityRingPaint;
@@ -105,12 +108,13 @@
         private Paint mStoryPaint;
         private float mDensity;
 
-        PeopleStoryIconDrawable(Drawable avatar,
+        PeopleStoryIconDrawable(RoundedBitmapDrawable avatar,
                 Drawable badgeIcon,
                 int iconSize,
                 @ColorInt int ringColor,
                 boolean showImportantRing, float fullIconSize, float density,
                 @ColorInt int accentColor, boolean showStoryRing) {
+            avatar.setCircular(true);
             mAvatar = avatar;
             mBadgeIcon = badgeIcon;
             mIconSize = iconSize;
diff --git a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
index 59c7fd1..72d382a 100644
--- a/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
+++ b/packages/SystemUI/src/com/android/systemui/people/PeopleTileViewHelper.java
@@ -45,9 +45,6 @@
 import android.graphics.Bitmap;
 import android.graphics.drawable.Drawable;
 import android.graphics.drawable.Icon;
-import android.icu.text.MeasureFormat;
-import android.icu.util.Measure;
-import android.icu.util.MeasureUnit;
 import android.net.Uri;
 import android.os.Bundle;
 import android.os.UserHandle;
@@ -61,6 +58,9 @@
 import android.widget.RemoteViews;
 import android.widget.TextView;
 
+import androidx.core.graphics.drawable.RoundedBitmapDrawable;
+import androidx.core.graphics.drawable.RoundedBitmapDrawableFactory;
+
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.launcher3.icons.FastBitmapDrawable;
 import com.android.systemui.R;
@@ -72,6 +72,7 @@
 import java.time.Duration;
 import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.Comparator;
 import java.util.List;
 import java.util.Locale;
 import java.util.Objects;
@@ -94,6 +95,8 @@
     public static final int LAYOUT_LARGE = 2;
 
     private static final int MIN_CONTENT_MAX_LINES = 2;
+    private static final int NAME_MAX_LINES_WITHOUT_LAST_INTERACTION = 3;
+    private static final int NAME_MAX_LINES_WITH_LAST_INTERACTION = 1;
 
     private static final int FIXED_HEIGHT_DIMENS_FOR_LARGE_NOTIF_CONTENT = 16 + 22 + 8 + 16;
     private static final int FIXED_HEIGHT_DIMENS_FOR_LARGE_STATUS_CONTENT = 16 + 16 + 24 + 4 + 16;
@@ -225,7 +228,9 @@
                 Log.d(TAG,
                         "Create status view for: " + statusesForEntireView.get(0).getActivity());
             }
-            return createStatusRemoteViews(statusesForEntireView.get(0));
+            ConversationStatus mostRecentlyStartedStatus = statusesForEntireView.stream().max(
+                    Comparator.comparing(s -> s.getStartTimeMillis())).get();
+            return createStatusRemoteViews(mostRecentlyStartedStatus);
         }
 
         return createLastInteractionRemoteViews();
@@ -579,11 +584,33 @@
             setMaxLines(views, false);
         }
         setAvailabilityDotPadding(views, R.dimen.availability_dot_status_padding);
-        // TODO: Set status pre-defined icons
-        views.setImageViewResource(R.id.predefined_icon, R.drawable.ic_person);
+        views.setImageViewResource(R.id.predefined_icon, getDrawableForStatus(status));
         return views;
     }
 
+    private int getDrawableForStatus(ConversationStatus status) {
+        switch (status.getActivity()) {
+            case ACTIVITY_NEW_STORY:
+                return R.drawable.ic_pages;
+            case ACTIVITY_ANNIVERSARY:
+                return R.drawable.ic_celebration;
+            case ACTIVITY_UPCOMING_BIRTHDAY:
+                return R.drawable.ic_gift;
+            case ACTIVITY_BIRTHDAY:
+                return R.drawable.ic_cake;
+            case ACTIVITY_LOCATION:
+                return R.drawable.ic_location;
+            case ACTIVITY_GAME:
+                return R.drawable.ic_play_games;
+            case ACTIVITY_VIDEO:
+                return R.drawable.ic_video;
+            case ACTIVITY_AUDIO:
+                return R.drawable.ic_music_note;
+            default:
+                return R.drawable.ic_person;
+        }
+    }
+
     /**
      * Update the padding of the availability dot. The padding on the availability dot decreases
      * on the status layouts compared to all other layouts.
@@ -658,7 +685,6 @@
     }
 
     private RemoteViews decorateBackground(RemoteViews views, CharSequence content) {
-        int visibility = View.GONE;
         CharSequence emoji = getDoubleEmoji(content);
         if (!TextUtils.isEmpty(emoji)) {
             setEmojiBackground(views, emoji);
@@ -768,6 +794,7 @@
     }
 
     private RemoteViews setViewForContentLayout(RemoteViews views) {
+        views = decorateBackground(views, "");
         if (mLayoutSize == LAYOUT_SMALL) {
             views.setViewVisibility(R.id.predefined_icon, View.VISIBLE);
             views.setViewVisibility(R.id.name, View.GONE);
@@ -819,6 +846,7 @@
 
     private RemoteViews createLastInteractionRemoteViews() {
         RemoteViews views = new RemoteViews(mContext.getPackageName(), getEmptyLayout());
+        views.setInt(R.id.name, "setMaxLines", NAME_MAX_LINES_WITH_LAST_INTERACTION);
         if (mLayoutSize == LAYOUT_SMALL) {
             views.setViewVisibility(R.id.name, View.VISIBLE);
             views.setViewVisibility(R.id.predefined_icon, View.GONE);
@@ -836,6 +864,9 @@
         } else {
             if (DEBUG) Log.d(TAG, "Hide last interaction");
             views.setViewVisibility(R.id.last_interaction, View.GONE);
+            if (mLayoutSize == LAYOUT_MEDIUM) {
+                views.setInt(R.id.name, "setMaxLines", NAME_MAX_LINES_WITHOUT_LAST_INTERACTION);
+            }
         }
         return views;
     }
@@ -891,8 +922,9 @@
                 context.getPackageManager(),
                 IconDrawableFactory.newInstance(context, false),
                 maxAvatarSize);
-        Drawable drawable = icon.loadDrawable(context);
-        Drawable personDrawable = storyIcon.getPeopleTileDrawable(drawable,
+        RoundedBitmapDrawable roundedDrawable = RoundedBitmapDrawableFactory.create(
+                context.getResources(), icon.getBitmap());
+        Drawable personDrawable = storyIcon.getPeopleTileDrawable(roundedDrawable,
                 tile.getPackageName(), getUserId(tile), tile.isImportantConversation(),
                 hasNewStory);
         return convertDrawableToBitmap(personDrawable);
@@ -907,14 +939,11 @@
         }
         long now = System.currentTimeMillis();
         Duration durationSinceLastInteraction = Duration.ofMillis(now - lastInteraction);
-        MeasureFormat formatter = MeasureFormat.getInstance(Locale.getDefault(),
-                MeasureFormat.FormatWidth.WIDE);
         if (durationSinceLastInteraction.toDays() <= ONE_DAY) {
             return null;
         } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK) {
-            return context.getString(R.string.days_timestamp, formatter.formatMeasures(
-                    new Measure(durationSinceLastInteraction.toDays(),
-                            MeasureUnit.DAY)));
+            return context.getString(R.string.days_timestamp,
+                    durationSinceLastInteraction.toDays());
         } else if (durationSinceLastInteraction.toDays() == DAYS_IN_A_WEEK) {
             return context.getString(R.string.one_week_timestamp);
         } else if (durationSinceLastInteraction.toDays() < DAYS_IN_A_WEEK * 2) {
diff --git a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
index 9e0dd72..2602d7a 100644
--- a/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
+++ b/packages/SystemUI/src/com/android/systemui/people/widget/PeopleSpaceWidgetManager.java
@@ -667,12 +667,16 @@
         if (icon != null) {
             updatedTile.setUserIcon(icon);
         }
+        if (DEBUG) Log.d(TAG, "Statuses: " + conversation.getStatuses().toString());
+        NotificationChannel channel = conversation.getParentNotificationChannel();
+        if (channel != null) {
+            if (DEBUG) Log.d(TAG, "Important:" + channel.isImportantConversation());
+            updatedTile.setIsImportantConversation(channel.isImportantConversation());
+        }
         updatedTile
                 .setContactUri(uri)
                 .setStatuses(conversation.getStatuses())
-                .setLastInteractionTimestamp(conversation.getLastEventTimestamp())
-                .setIsImportantConversation(conversation.getParentNotificationChannel() != null
-                        && conversation.getParentNotificationChannel().isImportantConversation());
+                .setLastInteractionTimestamp(conversation.getLastEventTimestamp());
         updateAppWidgetOptionsAndView(appWidgetId, updatedTile.build());
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
index 9b2ed3a..b92f7c0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ScrimController.java
@@ -548,8 +548,11 @@
      */
     public void setNotificationsBounds(float left, float top, float right, float bottom) {
         if (mClipsQsScrim) {
-            // "top - 1" to have 1 px of scrims overlap, see: b/186644628
-            mNotificationsScrim.setDrawableBounds(left, top - 1, right, bottom);
+            // notification scrim's rounded corners are anti-aliased, but clipping of the QS scrim
+            // can't be and it's causing jagged corners. That's why notification scrim needs
+            // to overlap QS scrim by one pixel - both vertically (top - 1) and
+            // horizontally (left - 1 and right + 1), see: b/186644628
+            mNotificationsScrim.setDrawableBounds(left - 1, top - 1, right + 1, bottom);
             mScrimBehind.setBottomEdgePosition((int) top);
         } else {
             mNotificationsScrim.setDrawableBounds(left, top, right, bottom);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
index eec896a..1364d47 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBar.java
@@ -73,9 +73,9 @@
 import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ResolveInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Point;
 import android.graphics.PointF;
-import android.graphics.RectF;
 import android.media.AudioAttributes;
 import android.metrics.LogMaker;
 import android.net.Uri;
@@ -150,6 +150,7 @@
 import com.android.systemui.animation.ActivityLaunchAnimator;
 import com.android.systemui.animation.DelegateLaunchAnimatorController;
 import com.android.systemui.assist.AssistManager;
+import com.android.systemui.biometrics.AuthRippleController;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.camera.CameraIntents;
 import com.android.systemui.charging.WirelessChargingAnimation;
@@ -326,9 +327,15 @@
     public static final int FADE_KEYGUARD_DURATION = 300;
     public static final int FADE_KEYGUARD_DURATION_PULSING = 96;
 
+    public static final long[] CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS =
+            new long[]{20, 20, 20, 20, 100, 20};
+    public static final int[] CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES =
+            new int[]{39, 82, 139, 213, 0, 127};
 
-    /** If true, the system is in the half-boot-to-decryption-screen state.
-     * Prudently disable QS and notifications.  */
+    /**
+     * If true, the system is in the half-boot-to-decryption-screen state.
+     * Prudently disable QS and notifications.
+     */
     public static final boolean ONLY_CORE_APPS;
 
     /** If true, the lockscreen will show a distinct wallpaper */
@@ -380,6 +387,7 @@
     protected NotificationShadeWindowView mNotificationShadeWindowView;
     protected StatusBarWindowView mPhoneStatusBarWindow;
     protected PhoneStatusBarView mStatusBarView;
+    private AuthRippleController mAuthRippleController;
     private int mStatusBarWindowState = WINDOW_STATE_SHOWING;
     protected NotificationShadeWindowController mNotificationShadeWindowController;
     protected StatusBarWindowController mStatusBarWindowController;
@@ -600,7 +608,7 @@
     private int mLastCameraLaunchSource;
     protected PowerManager.WakeLock mGestureWakeLock;
     private Vibrator mVibrator;
-    private long[] mCameraLaunchGestureVibePattern;
+    private VibrationEffect mCameraLaunchGestureVibrationEffect;
 
     private final int[] mTmpInt2 = new int[2];
 
@@ -1311,12 +1319,8 @@
         mGestureWakeLock = mPowerManager.newWakeLock(PowerManager.SCREEN_BRIGHT_WAKE_LOCK,
                 "GestureWakeLock");
         mVibrator = mContext.getSystemService(Vibrator.class);
-        int[] pattern = mContext.getResources().getIntArray(
-                R.array.config_cameraLaunchGestureVibePattern);
-        mCameraLaunchGestureVibePattern = new long[pattern.length];
-        for (int i = 0; i < pattern.length; i++) {
-            mCameraLaunchGestureVibePattern[i] = pattern[i];
-        }
+        mCameraLaunchGestureVibrationEffect = getCameraGestureVibrationEffect(
+                mVibrator, context.getResources());
 
         // receive broadcasts
         registerBroadcastReceiver();
@@ -1556,7 +1560,9 @@
         mPhoneStatusBarWindow = mSuperStatusBarViewFactory.getStatusBarWindowView();
         mNotificationPanelViewController = statusBarComponent.getNotificationPanelViewController();
         statusBarComponent.getLockIconViewController().init();
-        statusBarComponent.getAuthRippleController().init();
+
+        mAuthRippleController = statusBarComponent.getAuthRippleController();
+        mAuthRippleController.init();
     }
 
     protected void startKeyguard() {
@@ -2801,7 +2807,7 @@
             int[] result = new int[]{ActivityManager.START_CANCELED};
 
             mActivityLaunchAnimator.startIntentWithAnimation(animController,
-                    areLaunchAnimationsEnabled(), (adapter) -> {
+                    areLaunchAnimationsEnabled(), intent.getPackage(), (adapter) -> {
                         ActivityOptions options = new ActivityOptions(
                                 getActivityOptions(mDisplayId, adapter));
                         options.setDisallowEnterPictureInPictureWhileLaunching(
@@ -3791,7 +3797,8 @@
 
     @Override
     public void onDozeAmountChanged(float linear, float eased) {
-        if (mFeatureFlags.useNewLockscreenAnimations()) {
+        if (mFeatureFlags.useNewLockscreenAnimations()
+                && !mCircleRevealAnimator.isRunning()) {
             mLightRevealScrim.setRevealAmount(1f - linear);
         }
     }
@@ -3828,6 +3835,23 @@
         Trace.endSection();
     }
 
+    /**
+     * Update the parameters for the dozing circle reveal that animates when the user authenticates
+     * from AOD using the fingerprint sensor.
+     */
+    public void updateCircleReveal() {
+        final PointF fpLocation = mAuthRippleController.getFingerprintSensorLocation();
+        if (fpLocation != null) {
+            mCircleReveal =
+                    new CircleReveal(
+                            fpLocation.x,
+                            fpLocation.y,
+                            0,
+                            Math.max(Math.max(fpLocation.x, getDisplayWidth() - fpLocation.x),
+                                    Math.max(fpLocation.y, getDisplayHeight() - fpLocation.y)));
+        }
+    }
+
     private void startCircleReveal() {
         mLightRevealScrim.setRevealEffect(mCircleReveal);
         mCircleRevealAnimator.cancel();
@@ -3840,7 +3864,6 @@
 
     private boolean shouldShowCircleReveal() {
         return mCircleReveal != null && !mCircleRevealAnimator.isRunning()
-                && mKeyguardUpdateMonitor.isUdfpsEnrolled()
                 && mBiometricUnlockController.getBiometricType() == FINGERPRINT;
     }
 
@@ -4062,12 +4085,37 @@
 
     private void vibrateForCameraGesture() {
         // Make sure to pass -1 for repeat so VibratorService doesn't stop us when going to sleep.
-        mVibrator.vibrate(mCameraLaunchGestureVibePattern, -1 /* repeat */);
+        mVibrator.vibrate(mCameraLaunchGestureVibrationEffect);
+    }
+
+    private static VibrationEffect getCameraGestureVibrationEffect(Vibrator vibrator,
+            Resources resources) {
+        if (vibrator.areAllPrimitivesSupported(
+                VibrationEffect.Composition.PRIMITIVE_QUICK_RISE,
+                VibrationEffect.Composition.PRIMITIVE_CLICK)) {
+            return VibrationEffect.startComposition()
+                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_QUICK_RISE)
+                    .addPrimitive(VibrationEffect.Composition.PRIMITIVE_CLICK, 1, 50)
+                    .compose();
+        }
+        if (vibrator.hasAmplitudeControl()) {
+            return VibrationEffect.createWaveform(
+                    CAMERA_LAUNCH_GESTURE_VIBRATION_TIMINGS,
+                    CAMERA_LAUNCH_GESTURE_VIBRATION_AMPLITUDES,
+                    /* repeat= */ -1);
+        }
+
+        int[] pattern = resources.getIntArray(R.array.config_cameraLaunchGestureVibePattern);
+        long[] timings = new long[pattern.length];
+        for (int i = 0; i < pattern.length; i++) {
+            timings[i] = pattern[i];
+        }
+        return VibrationEffect.createWaveform(timings, /* repeat= */ -1);
     }
 
     /**
      * @return true if the screen is currently fully off, i.e. has finished turning off and has
-     *         since not started turning on.
+     * since not started turning on.
      */
     public boolean isScreenFullyOff() {
         return mScreenLifecycle.getScreenState() == ScreenLifecycle.SCREEN_OFF;
@@ -4278,15 +4326,6 @@
         updateScrimController();
     }
 
-    /**
-     * Set the location of the sensor on UDFPS if existent.
-     */
-    public void setSensorRect(RectF rect) {
-        final float startRadius = (rect.right - rect.left) / 2f;
-        mCircleReveal = new CircleReveal(rect.centerX(), rect.centerY(),
-                startRadius, rect.centerY() - startRadius);
-    }
-
     @VisibleForTesting
     public void updateScrimController() {
         Trace.beginSection("StatusBar#updateScrimController");
@@ -4565,7 +4604,7 @@
                                 animationController, this, intent.isActivity()) : null;
 
                 mActivityLaunchAnimator.startPendingIntentWithAnimation(
-                        controller, areLaunchAnimationsEnabled(),
+                        controller, areLaunchAnimationsEnabled(), intent.getCreatorPackage(),
                         (animationAdapter) -> intent.sendAndReturnResult(null, 0, null, null, null,
                                 null, getActivityOptions(mDisplayId, animationAdapter)));
             } catch (PendingIntent.CanceledException e) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
index ab58aae6..5cd4e13 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarter.java
@@ -437,7 +437,7 @@
 
             mActivityLaunchAnimator.startPendingIntentWithAnimation(animationController,
                     !wasOccluded && mStatusBar.areLaunchAnimationsEnabled(),
-                    (adapter) -> {
+                    intent.getCreatorPackage(), (adapter) -> {
                         long eventTime = row.getAndResetLastActionUpTime();
                         Bundle options = eventTime > 0
                                 ? getActivityOptions(
@@ -469,6 +469,7 @@
 
                 mActivityLaunchAnimator.startIntentWithAnimation(
                         animationController, mStatusBar.areLaunchAnimationsEnabled(),
+                        intent.getPackage(),
                         (adapter) -> TaskStackBuilder.create(mContext)
                                 .addNextIntentWithParentStack(intent)
                                 .startActivities(getActivityOptions(
@@ -499,7 +500,7 @@
                                 true /* isActivityIntent */);
 
                 mActivityLaunchAnimator.startIntentWithAnimation(animationController,
-                        mStatusBar.areLaunchAnimationsEnabled(),
+                        mStatusBar.areLaunchAnimationsEnabled(), intent.getPackage(),
                         (adapter) -> tsb.startActivities(
                                 getActivityOptions(mStatusBar.getDisplayId(), adapter),
                                 UserHandle.CURRENT));
diff --git a/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt b/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
index 603d690..8187956 100644
--- a/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
+++ b/packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
@@ -76,29 +76,41 @@
             }
             val linearInterp = LinearInterpolator()
             val scaleInterp = PathInterpolator(0.3f, 0f, 1f, 1f)
-            val sX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f).apply {
+            val viewScaleX = ObjectAnimator.ofFloat(view, "scaleX", 1f, 0.9f).apply {
                 interpolator = scaleInterp
                 duration = 250
             }
-            val sY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f).apply {
+            val viewScaleY = ObjectAnimator.ofFloat(view, "scaleY", 1f, 0.9f).apply {
                 interpolator = scaleInterp
                 duration = 250
             }
-            val vA = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
+            val viewElevation = ObjectAnimator.ofFloat(view, "elevation",
+                view.elevation, 0f).apply {
+                interpolator = linearInterp
+                duration = 40
+                startDelay = 150
+            }
+            val viewAlpha = ObjectAnimator.ofFloat(view, "alpha", 1f, 0f).apply {
                 interpolator = linearInterp
                 duration = 100
                 startDelay = 150
             }
-            val tA = ObjectAnimator.ofFloat(text, "alpha", 1f, 0f).apply {
+            val textAlpha = ObjectAnimator.ofFloat(text, "alpha", 1f, 0f).apply {
                 interpolator = linearInterp
                 duration = 166
             }
-            val iA = ObjectAnimator.ofFloat(icon, "alpha", 1f, 0f).apply {
+            val iconAlpha = ObjectAnimator.ofFloat(icon, "alpha", 1f, 0f).apply {
                 interpolator = linearInterp
                 duration = 166
             }
             return AnimatorSet().apply {
-                playTogether(sX, sY, vA, tA, iA)
+                playTogether(
+                    viewScaleX,
+                    viewScaleY,
+                    viewElevation,
+                    viewAlpha,
+                    textAlpha,
+                    iconAlpha)
             }
         }
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
index 897d78b..f2ef5c3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/animation/ActivityLaunchAnimatorTest.kt
@@ -51,7 +51,11 @@
         // We start in a new thread so that we can ensure that the callbacks are called in the main
         // thread.
         thread {
-            activityLaunchAnimator.startIntentWithAnimation(controller, animate, intentStarter)
+            activityLaunchAnimator.startIntentWithAnimation(
+                    controller = controller,
+                    animate = animate,
+                    intentStarter = intentStarter
+            )
         }.join()
     }
 
@@ -135,11 +139,14 @@
         verify(controller).onLaunchAnimationStart(anyBoolean())
     }
 
-    private fun fakeWindow() = RemoteAnimationTarget(
-            0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
-            Point(), Rect(), Rect(), WindowConfiguration(), false, SurfaceControl(), Rect(),
-            ActivityManager.RunningTaskInfo()
-    )
+    private fun fakeWindow(): RemoteAnimationTarget {
+        val bounds = Rect(10 /* left */, 20 /* top */, 30 /* right */, 40 /* bottom */)
+        return RemoteAnimationTarget(
+                0, RemoteAnimationTarget.MODE_OPENING, SurfaceControl(), false, Rect(), Rect(), 0,
+                Point(), Rect(), bounds, WindowConfiguration(), false, SurfaceControl(), Rect(),
+                ActivityManager.RunningTaskInfo()
+        )
+    }
 }
 
 /**
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
index 711f293..06f9253 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthBiometricViewTest.java
@@ -26,6 +26,7 @@
 import static org.mockito.Mockito.verify;
 
 import android.content.Context;
+import android.hardware.biometrics.BiometricPrompt;
 import android.hardware.biometrics.PromptInfo;
 import android.os.Bundle;
 import android.test.suitebuilder.annotation.SmallTest;
@@ -41,7 +42,6 @@
 import com.android.systemui.SysuiTestCase;
 
 import org.junit.Before;
-import org.junit.Ignore;
 import org.junit.Test;
 import org.junit.runner.RunWith;
 import org.mockito.Mock;
@@ -195,8 +195,6 @@
         assertEquals(AuthBiometricView.STATE_AUTHENTICATING, mBiometricView.mState);
     }
 
-    // TODO: b(/189031816)
-    @Ignore
     @Test
     public void testError_sendsActionError() {
         initDialog(mContext, false /* allowDeviceCredential */, mCallback, new MockInjector());
@@ -205,7 +203,7 @@
         waitForIdleSync();
 
         verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_ERROR);
-        assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState);
+        assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState);
     }
 
     @Test
@@ -241,8 +239,6 @@
         verify(mCallback, never()).onAction(eq(AuthBiometricView.Callback.ACTION_USER_CANCELED));
     }
 
-    // TODO: b(/189031816)
-    @Ignore
     @Test
     public void testRestoresState() {
         final boolean requireConfirmation = true; // set/init from AuthController
@@ -258,6 +254,12 @@
             public TextView getIndicatorView() {
                 return indicatorView;
             }
+
+            @Override
+            public int getDelayAfterError() {
+                // keep a real delay to test saving in the error state
+                return BiometricPrompt.HIDE_DIALOG_DELAY;
+            }
         });
 
         final String failureMessage = "testFailureMessage";
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
index bb2e55f..db5648a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthControllerTest.java
@@ -62,7 +62,6 @@
 
 import com.android.internal.R;
 import com.android.systemui.SysuiTestCase;
-import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.statusbar.CommandQueue;
 
 import org.junit.Before;
@@ -96,8 +95,6 @@
     @Mock
     private CommandQueue mCommandQueue;
     @Mock
-    private StatusBarStateController mStatusBarStateController;
-    @Mock
     private ActivityTaskManager mActivityTaskManager;
     @Mock
     private FingerprintManager mFingerprintManager;
@@ -152,7 +149,7 @@
         when(mFingerprintManager.getSensorPropertiesInternal()).thenReturn(props);
 
         mAuthController = new TestableAuthController(context, mCommandQueue,
-                mStatusBarStateController, mActivityTaskManager, mFingerprintManager, mFaceManager,
+                mActivityTaskManager, mFingerprintManager, mFaceManager,
                 () -> mUdfpsController, () -> mSidefpsController);
 
         mAuthController.start();
@@ -561,13 +558,12 @@
         private PromptInfo mLastBiometricPromptInfo;
 
         TestableAuthController(Context context, CommandQueue commandQueue,
-                StatusBarStateController statusBarStateController,
                 ActivityTaskManager activityTaskManager,
                 FingerprintManager fingerprintManager,
                 FaceManager faceManager,
                 Provider<UdfpsController> udfpsControllerFactory,
                 Provider<SidefpsController> sidefpsControllerFactory) {
-            super(context, commandQueue, statusBarStateController, activityTaskManager,
+            super(context, commandQueue, activityTaskManager,
                     fingerprintManager, faceManager, udfpsControllerFactory,
                     sidefpsControllerFactory);
         }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
index 247748a..240fdf3 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/AuthRippleControllerTest.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.statusbar.NotificationShadeWindowController
 import com.android.systemui.statusbar.commandline.CommandRegistry
 import com.android.systemui.statusbar.phone.KeyguardBypassController
+import com.android.systemui.statusbar.phone.StatusBar
 import com.android.systemui.statusbar.policy.ConfigurationController
 import org.junit.Before
 import org.junit.Test
@@ -44,6 +45,7 @@
 @RunWith(AndroidTestingRunner::class)
 class AuthRippleControllerTest : SysuiTestCase() {
     private lateinit var controller: AuthRippleController
+    @Mock private lateinit var statusBar: StatusBar
     @Mock private lateinit var rippleView: AuthRippleView
     @Mock private lateinit var commandRegistry: CommandRegistry
     @Mock private lateinit var configurationController: ConfigurationController
@@ -56,6 +58,7 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
         controller = AuthRippleController(
+            statusBar,
             context,
             authController,
             configurationController,
@@ -72,7 +75,7 @@
     fun testFingerprintTrigger_Ripple() {
         // GIVEN fp exists, keyguard is visible, user doesn't need strong auth
         val fpsLocation = PointF(5f, 5f)
-        `when`(authController.udfpsSensorLocation).thenReturn(fpsLocation)
+        `when`(authController.fingerprintSensorLocation).thenReturn(fpsLocation)
         controller.onViewAttached()
         `when`(keyguardUpdateMonitor.isKeyguardVisible).thenReturn(true)
         `when`(keyguardUpdateMonitor.userNeedsStrongAuth()).thenReturn(false)
@@ -193,7 +196,7 @@
 
     @Test
     fun testNullFingerprintSensorLocationDoesNothing() {
-        `when`(authController.udfpsSensorLocation).thenReturn(null)
+        `when`(authController.fingerprintSensorLocation).thenReturn(null)
         controller.onViewAttached()
 
         val captor = ArgumentCaptor.forClass(KeyguardUpdateMonitorCallback::class.java)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
index 3b56f22..67505c4 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/people/PeopleTileViewHelperTest.java
@@ -69,6 +69,7 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.time.Duration;
 import java.util.Arrays;
 
 @RunWith(AndroidTestingRunner.class)
@@ -185,6 +186,30 @@
     }
 
     @Test
+    public void testLastInteractionTime() {
+        long now = System.currentTimeMillis();
+        long fiveDaysAgo = now - Duration.ofDays(5).toMillis();
+        String lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+                fiveDaysAgo);
+        assertThat(lastInteractionString).isEqualTo("5 days ago");
+
+        long lessThanOneDayAgo = now - Duration.ofHours(20).toMillis();
+        lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+                lessThanOneDayAgo);
+        assertThat(lastInteractionString).isNull();
+
+        long overOneWeekAgo = now - Duration.ofDays(8).toMillis();
+        lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+                overOneWeekAgo);
+        assertThat(lastInteractionString).isEqualTo("Over 1 week ago");
+
+        long overTwoWeeksAgo = now - Duration.ofDays(15).toMillis();
+        lastInteractionString = PeopleTileViewHelper.getLastInteractionString(mContext,
+                overTwoWeeksAgo);
+        assertThat(lastInteractionString).isEqualTo("Over 2 weeks ago");
+    }
+
+    @Test
     public void testCreateRemoteViewsWithLastInteractionTime() {
         PeopleSpaceTile tileWithLastInteraction =
                 PERSON_TILE_WITHOUT_NOTIFICATION.toBuilder().setLastInteractionTimestamp(
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
index be86af5..407afbe 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarNotificationActivityStarterTest.java
@@ -269,7 +269,7 @@
         verify(mShadeController, atLeastOnce()).collapsePanel();
 
         verify(mActivityLaunchAnimator).startPendingIntentWithAnimation(any(),
-                eq(false) /* animate */, any());
+                eq(false) /* animate */, any(), any());
 
         verify(mAssistManager).hideAssist();
 
diff --git a/services/core/java/com/android/server/PersistentDataBlockService.java b/services/core/java/com/android/server/PersistentDataBlockService.java
index 6e7771d..e336b6b 100644
--- a/services/core/java/com/android/server/PersistentDataBlockService.java
+++ b/services/core/java/com/android/server/PersistentDataBlockService.java
@@ -39,11 +39,9 @@
 import libcore.io.IoUtils;
 
 import java.io.DataInputStream;
-import java.io.DataOutputStream;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.FileNotFoundException;
-import java.io.FileOutputStream;
 import java.io.IOException;
 import java.io.RandomAccessFile;
 import java.nio.ByteBuffer;
@@ -377,11 +375,16 @@
 
         try {
             FileChannel channel = getBlockOutputChannel();
-            ByteBuffer buf = ByteBuffer.allocate(DIGEST_SIZE_BYTES + HEADER_SIZE);
+            int header_size = DIGEST_SIZE_BYTES + HEADER_SIZE;
+            ByteBuffer buf = ByteBuffer.allocate(header_size);
             buf.put(new byte[DIGEST_SIZE_BYTES]);
             buf.putInt(PARTITION_TYPE_MARKER);
             buf.putInt(0);
             channel.write(buf);
+            // corrupt the payload explicitly
+            int payload_size = (int) getBlockDeviceSize() - header_size;
+            buf = ByteBuffer.allocate(payload_size);
+            channel.write(buf);
             channel.force(true);
         } catch (IOException e) {
             Slog.e(TAG, "failed to format block", e);
diff --git a/services/core/java/com/android/server/am/BatteryStatsService.java b/services/core/java/com/android/server/am/BatteryStatsService.java
index 85e8315..6cb374a 100644
--- a/services/core/java/com/android/server/am/BatteryStatsService.java
+++ b/services/core/java/com/android/server/am/BatteryStatsService.java
@@ -139,7 +139,7 @@
                     .onMalformedInput(CodingErrorAction.REPLACE)
                     .onUnmappableCharacter(CodingErrorAction.REPLACE)
                     .replaceWith("?");
-    private static final int MAX_LOW_POWER_STATS_SIZE = 8192;
+    private static final int MAX_LOW_POWER_STATS_SIZE = 16384;
     private static final int POWER_STATS_QUERY_TIMEOUT_MILLIS = 2000;
     private static final String EMPTY = "Empty";
 
diff --git a/services/core/java/com/android/server/am/CoreSettingsObserver.java b/services/core/java/com/android/server/am/CoreSettingsObserver.java
index f32423f..b325ea3 100644
--- a/services/core/java/com/android/server/am/CoreSettingsObserver.java
+++ b/services/core/java/com/android/server/am/CoreSettingsObserver.java
@@ -159,6 +159,10 @@
                 DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.MAGNIFIER_ASPECT_RATIO,
                 WidgetFlags.KEY_MAGNIFIER_ASPECT_RATIO, float.class,
                 WidgetFlags.MAGNIFIER_ASPECT_RATIO_DEFAULT));
+        sDeviceConfigEntries.add(new DeviceConfigEntry<>(
+                DeviceConfig.NAMESPACE_WIDGET, WidgetFlags.ANALOG_CLOCK_SECONDS_HAND_FPS,
+                WidgetFlags.KEY_ANALOG_CLOCK_SECONDS_HAND_FPS, int.class,
+                WidgetFlags.ANALOG_CLOCK_SECONDS_HAND_FPS_DEFAULT));
         // add other device configs here...
     }
 
diff --git a/services/core/java/com/android/server/compat/CompatChange.java b/services/core/java/com/android/server/compat/CompatChange.java
index d29a0c7..0f97b90 100644
--- a/services/core/java/com/android/server/compat/CompatChange.java
+++ b/services/core/java/com/android/server/compat/CompatChange.java
@@ -26,9 +26,7 @@
 import android.compat.annotation.Disabled;
 import android.compat.annotation.EnabledSince;
 import android.compat.annotation.Overridable;
-import android.content.Context;
 import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageManager;
 
 import com.android.internal.compat.AndroidBuildClassifier;
 import com.android.internal.compat.CompatibilityChangeInfo;
@@ -161,15 +159,17 @@
      *
      * @param packageName Package name to tentatively enable the change for.
      * @param override The package override to be set
+     * @param allowedState Whether the override is allowed.
+     * @param versionCode The version code of the package.
      */
     void addPackageOverride(String packageName, PackageOverride override,
-            OverrideAllowedState allowedState, Context context) {
+            OverrideAllowedState allowedState, @Nullable Long versionCode) {
         if (getLoggingOnly()) {
             throw new IllegalArgumentException(
                     "Can't add overrides for a logging only change " + toString());
         }
         mRawOverrides.put(packageName, override);
-        recheckOverride(packageName, allowedState, context);
+        recheckOverride(packageName, allowedState, versionCode);
     }
 
     /**
@@ -179,32 +179,24 @@
      * overrides, check if they need to be demoted to deferred.</p>
      *
      * @param packageName Package name to apply deferred overrides for.
-     * @param allowed Whether the override is allowed.
+     * @param allowedState Whether the override is allowed.
+     * @param versionCode The version code of the package.
      *
      * @return {@code true} if the recheck yielded a result that requires invalidating caches
      *         (a deferred override was consolidated or a regular override was removed).
      */
     boolean recheckOverride(String packageName, OverrideAllowedState allowedState,
-            Context context) {
+            @Nullable Long versionCode) {
         boolean allowed = (allowedState.state == OverrideAllowedState.ALLOWED);
 
-        Long version = null;
-        try {
-            ApplicationInfo applicationInfo = context.getPackageManager().getApplicationInfo(
-                    packageName, 0);
-            version = applicationInfo.longVersionCode;
-        } catch (PackageManager.NameNotFoundException e) {
-            // Do nothing
-        }
-
         // If the app is not installed or no longer has raw overrides, evaluate to false
-        if (version == null || !hasRawOverride(packageName) || !allowed) {
+        if (versionCode == null || !hasRawOverride(packageName) || !allowed) {
             removePackageOverrideInternal(packageName);
             return false;
         }
 
         // Evaluate the override based on its version
-        int overrideValue = mRawOverrides.get(packageName).evaluate(version);
+        int overrideValue = mRawOverrides.get(packageName).evaluate(versionCode);
         switch (overrideValue) {
             case VALUE_UNDEFINED:
                 removePackageOverrideInternal(packageName);
@@ -229,11 +221,13 @@
      * <p>Note, this method is not thread safe so callers must ensure thread safety.
      *
      * @param pname Package name to reset to defaults for.
+     * @param allowedState Whether the override is allowed.
+     * @param versionCode The version code of the package.
      */
     boolean removePackageOverride(String pname, OverrideAllowedState allowedState,
-            Context context) {
+            @Nullable Long versionCode) {
         if (mRawOverrides.remove(pname) != null) {
-            recheckOverride(pname, allowedState, context);
+            recheckOverride(pname, allowedState, versionCode);
             return true;
         }
         return false;
diff --git a/services/core/java/com/android/server/compat/CompatConfig.java b/services/core/java/com/android/server/compat/CompatConfig.java
index 9247568..909ed11 100644
--- a/services/core/java/com/android/server/compat/CompatConfig.java
+++ b/services/core/java/com/android/server/compat/CompatConfig.java
@@ -16,11 +16,13 @@
 
 package com.android.server.compat;
 
+import android.annotation.Nullable;
 import android.app.compat.ChangeIdStateCache;
 import android.app.compat.PackageOverride;
 import android.compat.Compatibility.ChangeConfig;
 import android.content.Context;
 import android.content.pm.ApplicationInfo;
+import android.content.pm.PackageManager;
 import android.os.Environment;
 import android.text.TextUtils;
 import android.util.LongArray;
@@ -51,7 +53,6 @@
 import java.io.IOException;
 import java.io.InputStream;
 import java.io.PrintWriter;
-import java.util.ArrayList;
 import java.util.HashSet;
 import java.util.List;
 import java.util.Set;
@@ -249,6 +250,7 @@
         OverrideAllowedState allowedState =
                 mOverrideValidator.getOverrideAllowedState(changeId, packageName);
         allowedState.enforce(changeId, packageName);
+        Long versionCode = getVersionCodeOrNull(packageName);
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
             if (c == null) {
@@ -256,7 +258,7 @@
                 c = new CompatChange(changeId);
                 addChange(c);
             }
-            c.addPackageOverride(packageName, overrides, allowedState, mContext);
+            c.addPackageOverride(packageName, overrides, allowedState, versionCode);
             invalidateCache();
         }
         return alreadyKnown;
@@ -336,6 +338,7 @@
      * It does not invalidate the cache nor save the overrides.
      */
     private boolean removeOverrideUnsafe(long changeId, String packageName) {
+        Long versionCode = getVersionCodeOrNull(packageName);
         synchronized (mChanges) {
             CompatChange c = mChanges.get(changeId);
             if (c != null) {
@@ -343,7 +346,7 @@
                         mOverrideValidator.getOverrideAllowedState(changeId, packageName);
                 if (c.hasPackageOverride(packageName)) {
                     allowedState.enforce(changeId, packageName);
-                    c.removePackageOverride(packageName, allowedState, mContext);
+                    c.removePackageOverride(packageName, allowedState, versionCode);
                     invalidateCache();
                     return true;
                 }
@@ -653,26 +656,33 @@
      * Rechecks all the existing overrides for a package.
      */
     void recheckOverrides(String packageName) {
-        // Local cache of compat changes. Holding a lock on mChanges for the whole duration of the
-        // method will cause a deadlock.
-        List<CompatChange> changes;
+        Long versionCode = getVersionCodeOrNull(packageName);
         synchronized (mChanges) {
-            changes = new ArrayList<>(mChanges.size());
+            boolean shouldInvalidateCache = false;
             for (int idx = 0; idx < mChanges.size(); ++idx) {
-                changes.add(mChanges.valueAt(idx));
+                CompatChange c = mChanges.valueAt(idx);
+                if (!c.hasPackageOverride(packageName)) {
+                    continue;
+                }
+                OverrideAllowedState allowedState =
+                        mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(),
+                                packageName);
+                shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, versionCode);
+            }
+            if (shouldInvalidateCache) {
+                invalidateCache();
             }
         }
-        boolean shouldInvalidateCache = false;
-        for (CompatChange c: changes) {
-            if (!c.hasPackageOverride(packageName)) {
-                continue;
-            }
-            OverrideAllowedState allowedState =
-                    mOverrideValidator.getOverrideAllowedStateForRecheck(c.getId(), packageName);
-            shouldInvalidateCache |= c.recheckOverride(packageName, allowedState, mContext);
-        }
-        if (shouldInvalidateCache) {
-            invalidateCache();
+    }
+
+    @Nullable
+    private Long getVersionCodeOrNull(String packageName) {
+        try {
+            ApplicationInfo applicationInfo = mContext.getPackageManager().getApplicationInfo(
+                    packageName, 0);
+            return applicationInfo.longVersionCode;
+        } catch (PackageManager.NameNotFoundException e) {
+            return null;
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index 065dc6e..38966b9 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -16,7 +16,6 @@
 
 package com.android.server.wm;
 
-import static android.Manifest.permission.INTERNAL_SYSTEM_WINDOW;
 import static android.app.ActivityManager.LOCK_TASK_MODE_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_IMPORTANT_FOREGROUND;
 import static android.app.ActivityOptions.ANIM_CLIP_REVEAL;
@@ -90,7 +89,6 @@
 import static android.content.pm.ActivityInfo.SIZE_CHANGES_UNSUPPORTED_OVERRIDE;
 import static android.content.pm.ActivityInfo.isFixedOrientationLandscape;
 import static android.content.pm.ActivityInfo.isFixedOrientationPortrait;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.res.Configuration.ASSETS_SEQ_UNDEFINED;
 import static android.content.res.Configuration.EMPTY;
 import static android.content.res.Configuration.ORIENTATION_LANDSCAPE;
@@ -279,7 +277,6 @@
 import android.os.Trace;
 import android.os.UserHandle;
 import android.os.storage.StorageManager;
-import android.permission.PermissionManager;
 import android.service.dreams.DreamActivity;
 import android.service.dreams.DreamManagerInternal;
 import android.service.voice.IVoiceInteractionSession;
@@ -7457,11 +7454,9 @@
 
     @Override
     public boolean providesMaxBounds() {
-        // System and SystemUI should always be able to access the physical display bounds,
-        // so do not provide it with the overridden maximum bounds.
-        // TODO(b/179179513) check WindowState#mOwnerCanAddInternalSystemWindow instead
-        if (getUid() == SYSTEM_UID || PermissionManager.checkPermission(INTERNAL_SYSTEM_WINDOW,
-                getPid(), info.applicationInfo.uid) == PERMISSION_GRANTED) {
+        // System should always be able to access the DisplayArea bounds, so do not provide it with
+        // compat max window bounds.
+        if (getUid() == SYSTEM_UID) {
             return false;
         }
         // Do not sandbox to activity window bounds if the feature is disabled.
diff --git a/services/core/java/com/android/server/wm/BlurController.java b/services/core/java/com/android/server/wm/BlurController.java
index ff10168..0363944 100644
--- a/services/core/java/com/android/server/wm/BlurController.java
+++ b/services/core/java/com/android/server/wm/BlurController.java
@@ -29,6 +29,7 @@
 import android.os.RemoteException;
 import android.provider.Settings;
 import android.view.ICrossWindowBlurEnabledListener;
+import android.view.TunnelModeEnabledListener;
 
 /**
  * Keeps track of the different factors that determine whether cross-window blur is enabled
@@ -45,6 +46,16 @@
     private volatile boolean mBlurEnabled;
     private boolean mInPowerSaveMode;
     private boolean mBlurDisabledSetting;
+    private boolean mTunnelModeEnabled = false;
+
+    private TunnelModeEnabledListener mTunnelModeListener =
+            new TunnelModeEnabledListener(Runnable::run) {
+        @Override
+        public void onTunnelModeEnabledChanged(boolean tunnelModeEnabled) {
+            mTunnelModeEnabled = tunnelModeEnabled;
+            updateBlurEnabled();
+        }
+    };
 
     BlurController(Context context, PowerManager powerManager) {
         mContext = context;
@@ -78,6 +89,8 @@
                 });
         mBlurDisabledSetting = getBlurDisabledSetting();
 
+        TunnelModeEnabledListener.register(mTunnelModeListener);
+
         updateBlurEnabled();
     }
 
@@ -99,7 +112,7 @@
     private void updateBlurEnabled() {
         synchronized (mLock) {
             final boolean newEnabled = CROSS_WINDOW_BLUR_SUPPORTED && !mBlurDisabledSetting
-                    && !mInPowerSaveMode;
+                    && !mInPowerSaveMode && !mTunnelModeEnabled;
             if (mBlurEnabled == newEnabled) {
                 return;
             }
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index 0251537..7df5744 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -8105,11 +8105,10 @@
             // This could prevent if there is no container animation, we still have to apply the
             // pending transaction and exit waiting.
             mAnimator.mNotifyWhenNoAnimation = true;
-            WindowContainer animatingContainer = null;
-            while (mAnimator.isAnimationScheduled() || timeoutRemaining > 0) {
-                animatingContainer = mRoot.getAnimatingContainer(TRANSITION | CHILDREN,
-                        ANIMATION_TYPE_ALL);
-                if (animatingContainer == null) {
+            while (timeoutRemaining > 0) {
+                boolean isAnimating = mAnimator.isAnimationScheduled()
+                        || mRoot.isAnimating(TRANSITION | CHILDREN, ANIMATION_TYPE_ALL);
+                if (!isAnimating) {
                     break;
                 }
                 long startTime = System.currentTimeMillis();
@@ -8121,6 +8120,9 @@
             }
             mAnimator.mNotifyWhenNoAnimation = false;
 
+            WindowContainer animatingContainer;
+            animatingContainer = mRoot.getAnimatingContainer(TRANSITION | CHILDREN,
+                    ANIMATION_TYPE_ALL);
             if (mAnimator.isAnimationScheduled() || animatingContainer != null) {
                 Slog.w(TAG, "Timed out waiting for animations to complete,"
                         + " animatingContainer=" + animatingContainer
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
index 8d43bbb..ce8f6df 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/ActiveAdmin.java
@@ -1190,7 +1190,7 @@
             pw.println(mEnrollmentSpecificId);
         }
 
-        pw.print("mAdminCanGrantSensorsPermissions");
+        pw.print("mAdminCanGrantSensorsPermissions=");
         pw.println(mAdminCanGrantSensorsPermissions);
 
         pw.print("mUsbDataSignaling=");
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 891ed3d..bc130e2 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8579,6 +8579,7 @@
         final DevicePolicyData policyData = getUserData(userId);
         policyData.mCurrentInputMethodSet = false;
         saveSettingsLocked(userId);
+        mPolicyCache.onUserRemoved(userId);
         final DevicePolicyData systemPolicyData = getUserData(UserHandle.USER_SYSTEM);
         systemPolicyData.mLastSecurityLogRetrievalTime = -1;
         systemPolicyData.mLastBugReportRequestTime = -1;
diff --git a/services/midi/java/com/android/server/midi/MidiService.java b/services/midi/java/com/android/server/midi/MidiService.java
index 47505a3..e31be82 100644
--- a/services/midi/java/com/android/server/midi/MidiService.java
+++ b/services/midi/java/com/android/server/midi/MidiService.java
@@ -43,6 +43,7 @@
 import android.os.Process;
 import android.os.RemoteException;
 import android.os.UserHandle;
+import android.util.EventLog;
 import android.util.Log;
 
 import com.android.internal.content.PackageMonitor;
@@ -736,13 +737,19 @@
 
     @Override
     public MidiDeviceInfo getServiceDeviceInfo(String packageName, String className) {
+        int uid = Binder.getCallingUid();
         synchronized (mDevicesByInfo) {
             for (Device device : mDevicesByInfo.values()) {
                  ServiceInfo serviceInfo = device.getServiceInfo();
                  if (serviceInfo != null &&
                         packageName.equals(serviceInfo.packageName) &&
                         className.equals(serviceInfo.name)) {
-                    return device.getDeviceInfo();
+                    if (device.isUidAllowed(uid)) {
+                        return device.getDeviceInfo();
+                    } else {
+                        EventLog.writeEvent(0x534e4554, "185796676", -1, "");
+                        return null;
+                    }
                 }
             }
             return null;
diff --git a/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java b/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
index c631026..49d5e50 100644
--- a/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
+++ b/services/people/java/com/android/server/people/data/ConversationStatusExpirationBroadcastReceiver.java
@@ -20,26 +20,18 @@
 import android.app.ActivityManager;
 import android.app.AlarmManager;
 import android.app.PendingIntent;
-import android.app.job.JobInfo;
-import android.app.job.JobParameters;
-import android.app.job.JobScheduler;
-import android.app.job.JobService;
 import android.app.people.ConversationStatus;
 import android.content.BroadcastReceiver;
-import android.content.ComponentName;
 import android.content.Context;
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.net.Uri;
+import android.os.Binder;
 import android.os.CancellationSignal;
-import android.os.SystemClock;
 
 import com.android.server.LocalServices;
-import com.android.server.notification.NotificationRecord;
 import com.android.server.people.PeopleServiceInternal;
 
-import java.util.concurrent.TimeUnit;
-
 /**
  * If a {@link ConversationStatus} is added to the system with an expiration time, remove that
  * status at that time
@@ -53,18 +45,22 @@
 
     void scheduleExpiration(Context context, @UserIdInt int userId, String pkg,
             String conversationId, ConversationStatus status) {
-
-        final PendingIntent pi = PendingIntent.getBroadcast(context,
-                REQUEST_CODE,
-                new Intent(ACTION)
-                        .setData(new Uri.Builder().scheme(SCHEME)
-                                .appendPath(getKey(userId, pkg, conversationId, status))
-                                .build())
-                        .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
-                        .putExtra(EXTRA_USER_ID, userId),
-                PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
-        context.getSystemService(AlarmManager.class).setExactAndAllowWhileIdle(
-                AlarmManager.RTC_WAKEUP, status.getEndTimeMillis(), pi);
+        final long identity = Binder.clearCallingIdentity();
+        try {
+            final PendingIntent pi = PendingIntent.getBroadcast(context,
+                    REQUEST_CODE,
+                    new Intent(ACTION)
+                            .setData(new Uri.Builder().scheme(SCHEME)
+                                    .appendPath(getKey(userId, pkg, conversationId, status))
+                                    .build())
+                            .addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+                            .putExtra(EXTRA_USER_ID, userId),
+                    PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_IMMUTABLE);
+            context.getSystemService(AlarmManager.class).setExactAndAllowWhileIdle(
+                    AlarmManager.RTC_WAKEUP, status.getEndTimeMillis(), pi);
+        } finally {
+            Binder.restoreCallingIdentity(identity);
+        }
     }
 
     private static String getKey(@UserIdInt int userId, String pkg,
diff --git a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
index 9be1ac4..2206b0a 100644
--- a/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
+++ b/services/voiceinteraction/java/com/android/server/voiceinteraction/VoiceInteractionManagerServiceImpl.java
@@ -22,6 +22,7 @@
 import static android.app.ActivityManager.START_VOICE_NOT_ACTIVE_SESSION;
 import static android.app.WindowConfiguration.ACTIVITY_TYPE_ASSISTANT;
 
+import android.Manifest;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
@@ -36,7 +37,6 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.ServiceConnection;
-import android.content.pm.IPackageManager;
 import android.content.pm.PackageManager;
 import android.content.pm.ServiceInfo;
 import android.hardware.soundtrigger.IRecognitionStatusCallback;
@@ -414,11 +414,31 @@
             Slog.w(TAG, "Hotword detection service name not found");
             throw new IllegalStateException("Hotword detection service name not found");
         }
-        if (!isIsolatedProcessLocked(mHotwordDetectionComponentName)) {
+        ServiceInfo hotwordDetectionServiceInfo = getServiceInfoLocked(
+                mHotwordDetectionComponentName, mUser);
+        if (hotwordDetectionServiceInfo == null) {
+            Slog.w(TAG, "Hotword detection service info not found");
+            throw new IllegalStateException("Hotword detection service info not found");
+        }
+        if (!isIsolatedProcessLocked(hotwordDetectionServiceInfo)) {
             Slog.w(TAG, "Hotword detection service not in isolated process");
             throw new IllegalStateException("Hotword detection service not in isolated process");
         }
-        // TODO : Need to check related permissions for hotword detection service
+        if (!Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE.equals(
+                hotwordDetectionServiceInfo.permission)) {
+            Slog.w(TAG, "Hotword detection service does not require permission "
+                    + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+            throw new SecurityException("Hotword detection service does not require permission "
+                    + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+        }
+        if (mContext.getPackageManager().checkPermission(
+                Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE,
+                mInfo.getServiceInfo().packageName) == PackageManager.PERMISSION_GRANTED) {
+            Slog.w(TAG, "Voice interaction service should not hold permission "
+                    + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+            throw new SecurityException("Voice interaction service should not hold permission "
+                    + Manifest.permission.BIND_HOTWORD_DETECTION_SERVICE);
+        }
 
         if (sharedMemory != null && !sharedMemory.setProtect(OsConstants.PROT_READ)) {
             Slog.w(TAG, "Can't set sharedMemory to be read-only");
@@ -522,23 +542,24 @@
                 mHotwordDetectionConnection);
     }
 
-    boolean isIsolatedProcessLocked(ComponentName componentName) {
-        IPackageManager pm = AppGlobals.getPackageManager();
+    private static ServiceInfo getServiceInfoLocked(@NonNull ComponentName componentName,
+            int userHandle) {
         try {
-            ServiceInfo serviceInfo = pm.getServiceInfo(componentName,
+            return AppGlobals.getPackageManager().getServiceInfo(componentName,
                     PackageManager.GET_META_DATA
                             | PackageManager.MATCH_DIRECT_BOOT_AWARE
-                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, mUser);
-            if (serviceInfo != null) {
-                return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
-                        && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
-            }
+                            | PackageManager.MATCH_DIRECT_BOOT_UNAWARE, userHandle);
         } catch (RemoteException e) {
             if (DEBUG) {
-                Slog.w(TAG, "isIsolatedProcess RemoteException : " + e);
+                Slog.w(TAG, "getServiceInfoLocked RemoteException : " + e);
             }
         }
-        return false;
+        return null;
+    }
+
+    boolean isIsolatedProcessLocked(@NonNull ServiceInfo serviceInfo) {
+        return (serviceInfo.flags & ServiceInfo.FLAG_ISOLATED_PROCESS) != 0
+                && (serviceInfo.flags & ServiceInfo.FLAG_EXTERNAL_SERVICE) == 0;
     }
 
     public void dumpLocked(FileDescriptor fd, PrintWriter pw, String[] args) {