Merge "Refactored some com.android.car.settings.enterprise interfaces." 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 d939438..6f68e3f 100644
--- a/core/api/system-current.txt
+++ b/core/api/system-current.txt
@@ -1458,6 +1458,7 @@
     method public long getTimestampMillis();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.search.Query> CREATOR;
+    field public static final String EXTRA_IME_HEIGHT = "android.app.search.extra.IME_HEIGHT";
   }
 
   public final class SearchAction implements android.os.Parcelable {
@@ -1526,7 +1527,7 @@
     method @Nullable public android.content.pm.ShortcutInfo getShortcutInfo();
     method @Nullable public android.net.Uri getSliceUri();
     method @NonNull public android.os.UserHandle getUserHandle();
-    method public boolean shouldHide();
+    method public boolean isHidden();
     method public void writeToParcel(@NonNull android.os.Parcel, int);
     field @NonNull public static final android.os.Parcelable.Creator<android.app.search.SearchTarget> CREATOR;
     field public static final String LAYOUT_TYPE_ICON = "icon";
@@ -1543,12 +1544,12 @@
     method @NonNull public android.app.search.SearchTarget build();
     method @NonNull public android.app.search.SearchTarget.Builder setAppWidgetProviderInfo(@NonNull android.appwidget.AppWidgetProviderInfo);
     method @NonNull public android.app.search.SearchTarget.Builder setExtras(@NonNull android.os.Bundle);
+    method @NonNull public android.app.search.SearchTarget.Builder setHidden(boolean);
     method @NonNull public android.app.search.SearchTarget.Builder setPackageName(@NonNull String);
     method @NonNull public android.app.search.SearchTarget.Builder setParentId(@NonNull String);
     method @NonNull public android.app.search.SearchTarget.Builder setScore(@FloatRange(from=0.0f, to=1.0f) float);
     method @NonNull public android.app.search.SearchTarget.Builder setSearchAction(@Nullable android.app.search.SearchAction);
     method @NonNull public android.app.search.SearchTarget.Builder setShortcutInfo(@NonNull android.content.pm.ShortcutInfo);
-    method @NonNull public android.app.search.SearchTarget.Builder setShouldHide(boolean);
     method @NonNull public android.app.search.SearchTarget.Builder setSliceUri(@NonNull android.net.Uri);
     method @NonNull public android.app.search.SearchTarget.Builder setUserHandle(@NonNull android.os.UserHandle);
   }
@@ -2246,7 +2247,7 @@
 package android.companion {
 
   public final class CompanionDeviceManager {
-    method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public void associate(@NonNull String, @NonNull android.net.MacAddress);
+    method @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES) public void associate(@NonNull String, @NonNull android.net.MacAddress, @NonNull byte[]);
     method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean canPairWithoutPrompt(@NonNull String, @NonNull String, @NonNull android.os.UserHandle);
     method @RequiresPermission("android.permission.MANAGE_COMPANION_DEVICES") public boolean isDeviceAssociatedForWifiConnection(@NonNull String, @NonNull android.net.MacAddress, @NonNull android.os.UserHandle);
   }
@@ -10416,11 +10417,11 @@
     ctor public TranslationService();
     method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent);
     method public void onConnected();
-    method public void onCreateTranslationSession(@NonNull android.view.translation.TranslationContext, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
+    method public abstract void onCreateTranslationSession(@NonNull android.view.translation.TranslationContext, int, @NonNull java.util.function.Consumer<java.lang.Boolean>);
     method public void onDisconnected();
     method public abstract void onFinishTranslationSession(int);
     method public abstract void onTranslationCapabilitiesRequest(int, int, @NonNull java.util.function.Consumer<java.util.Set<android.view.translation.TranslationCapability>>);
-    method public void onTranslationRequest(@NonNull android.view.translation.TranslationRequest, int, @Nullable android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.view.translation.TranslationResponse>);
+    method public abstract void onTranslationRequest(@NonNull android.view.translation.TranslationRequest, int, @Nullable android.os.CancellationSignal, @NonNull java.util.function.Consumer<android.view.translation.TranslationResponse>);
     method public final void updateTranslationCapability(@NonNull android.view.translation.TranslationCapability);
     field public static final String SERVICE_INTERFACE = "android.service.translation.TranslationService";
     field public static final String SERVICE_META_DATA = "android.translation_service";
@@ -10528,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
@@ -10548,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/api/system-removed.txt b/core/api/system-removed.txt
index 304f4fe..7cf0076 100644
--- a/core/api/system-removed.txt
+++ b/core/api/system-removed.txt
@@ -58,6 +58,14 @@
     method @Deprecated public void destroy();
   }
 
+  public final class SearchTarget implements android.os.Parcelable {
+    method @Deprecated public boolean shouldHide();
+  }
+
+  public static final class SearchTarget.Builder {
+    method @Deprecated @NonNull public android.app.search.SearchTarget.Builder setShouldHide(boolean);
+  }
+
 }
 
 package android.bluetooth {
diff --git a/core/java/android/app/ActivityThread.java b/core/java/android/app/ActivityThread.java
index 92bdda3..eb0a7b4 100644
--- a/core/java/android/app/ActivityThread.java
+++ b/core/java/android/app/ActivityThread.java
@@ -73,8 +73,8 @@
 import android.content.pm.InstrumentationInfo;
 import android.content.pm.PackageInfo;
 import android.content.pm.PackageManager;
-import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.PackageManager.ApplicationInfoFlags;
+import android.content.pm.PackageManager.NameNotFoundException;
 import android.content.pm.ParceledListSlice;
 import android.content.pm.PermissionInfo;
 import android.content.pm.ProviderInfo;
@@ -4108,7 +4108,7 @@
         }
         synchronized (this) {
             if (mSplashScreenGlobal != null) {
-                mSplashScreenGlobal.dispatchOnExitAnimation(r.token, v);
+                mSplashScreenGlobal.handOverSplashScreenView(r.token, v);
             }
         }
     }
diff --git a/core/java/android/app/Notification.java b/core/java/android/app/Notification.java
index 1865141..47ababf 100644
--- a/core/java/android/app/Notification.java
+++ b/core/java/android/app/Notification.java
@@ -22,7 +22,6 @@
 
 import static java.util.Objects.requireNonNull;
 
-import android.annotation.AttrRes;
 import android.annotation.ColorInt;
 import android.annotation.ColorRes;
 import android.annotation.DimenRes;
@@ -36,6 +35,7 @@
 import android.annotation.SdkConstant;
 import android.annotation.SdkConstant.SdkConstantType;
 import android.annotation.StringRes;
+import android.annotation.StyleableRes;
 import android.annotation.SuppressLint;
 import android.annotation.SystemApi;
 import android.annotation.TestApi;
@@ -3750,19 +3750,11 @@
         private boolean mIsLegacyInitialized;
 
         /**
-         * Caches a contrast-enhanced version of {@link #mCachedContrastColorIsFor}.
-         */
-        private int mCachedContrastColor = COLOR_INVALID;
-        private int mCachedContrastColorIsFor = COLOR_INVALID;
-
-        /**
          * Caches an instance of StandardTemplateParams. Note that this may have been used before,
          * so make sure to call {@link StandardTemplateParams#reset()} before using it.
          */
         StandardTemplateParams mParams = new StandardTemplateParams();
-        private int mTextColorsAreForBackground = COLOR_INVALID;
-        private int mPrimaryTextColor = COLOR_INVALID;
-        private int mSecondaryTextColor = COLOR_INVALID;
+        Colors mColors = new Colors();
 
         private boolean mTintActionButtons;
         private boolean mInNightMode;
@@ -4595,22 +4587,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
@@ -5035,7 +5011,7 @@
             contentView.setDrawableTint(
                     R.id.phishing_alert,
                     false /* targetBackground */,
-                    getErrorColor(p),
+                    getColors(p).getErrorColor(),
                     PorterDuff.Mode.SRC_ATOP);
         }
 
@@ -5082,8 +5058,8 @@
             contentView.setDrawableTint(
                     R.id.alerted_icon,
                     false /* targetBackground */,
-                    getHeaderIconColor(p),
-                    PorterDuff.Mode.SRC_ATOP);
+                    getColors(p).getSecondaryTextColor(),
+                    PorterDuff.Mode.SRC_IN);
         }
 
         /**
@@ -5211,8 +5187,7 @@
          */
         @VisibleForTesting
         public @ColorInt int getPrimaryTextColor(StandardTemplateParams p) {
-            ensureColors(p);
-            return mPrimaryTextColor;
+            return getColors(p).getPrimaryTextColor();
         }
 
         /**
@@ -5222,8 +5197,7 @@
          */
         @VisibleForTesting
         public @ColorInt int getSecondaryTextColor(StandardTemplateParams p) {
-            ensureColors(p);
-            return mSecondaryTextColor;
+            return getColors(p).getSecondaryTextColor();
         }
 
         private void setTextViewColorSecondary(RemoteViews contentView, @IdRes int id,
@@ -5231,29 +5205,9 @@
             contentView.setTextColor(id, getSecondaryTextColor(p));
         }
 
-        private void ensureColors(StandardTemplateParams p) {
-            int backgroundColor = getUnresolvedBackgroundColor(p);
-            if (mPrimaryTextColor == COLOR_INVALID
-                    || mSecondaryTextColor == COLOR_INVALID
-                    || mTextColorsAreForBackground != backgroundColor) {
-                mTextColorsAreForBackground = backgroundColor;
-                int defaultPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(mContext,
-                        backgroundColor, mInNightMode);
-                int defaultSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(mContext,
-                        backgroundColor, mInNightMode);
-                boolean colorized = backgroundColor != COLOR_DEFAULT;
-                if (colorized) {
-                    mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
-                            defaultPrimaryTextColor, backgroundColor, 4.5);
-                    mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
-                            defaultSecondaryTextColor, backgroundColor, 4.5);
-                } else {
-                    mPrimaryTextColor = obtainThemeColor(R.attr.textColorPrimary,
-                            defaultPrimaryTextColor);
-                    mSecondaryTextColor = obtainThemeColor(R.attr.textColorSecondary,
-                            defaultSecondaryTextColor);
-                }
-            }
+        private Colors getColors(StandardTemplateParams p) {
+            mColors.resolvePalette(mContext, mN.color, isBackgroundColorized(p), mInNightMode);
+            return mColors;
         }
 
         private void updateBackgroundColor(RemoteViews contentView,
@@ -5278,7 +5232,7 @@
                 contentView.setProgressBar(R.id.progress, max, progress, ind);
                 contentView.setProgressBackgroundTintList(R.id.progress,
                         mContext.getColorStateList(R.color.notification_progress_background_color));
-                ColorStateList progressTint = ColorStateList.valueOf(getAccentColor(p));
+                ColorStateList progressTint = ColorStateList.valueOf(getPrimaryAccentColor(p));
                 contentView.setProgressTintList(R.id.progress, progressTint);
                 contentView.setProgressIndeterminateTintList(R.id.progress, progressTint);
                 return true;
@@ -5412,13 +5366,13 @@
         private void bindExpandButton(RemoteViews contentView, StandardTemplateParams p) {
             // set default colors
             int textColor = getPrimaryTextColor(p);
-            int pillColor = getProtectionColor(p);
+            int pillColor = getColors(p).getProtectionColor();
             contentView.setInt(R.id.expand_button, "setDefaultTextColor", textColor);
             contentView.setInt(R.id.expand_button, "setDefaultPillColor", pillColor);
             // Use different highlighted colors for conversations' unread count
             if (p.mHighlightExpander) {
                 textColor = getBackgroundColor(p);
-                pillColor = getAccentColor(p);
+                pillColor = getPrimaryAccentColor(p);
             }
             contentView.setInt(R.id.expand_button, "setHighlightTextColor", textColor);
             contentView.setInt(R.id.expand_button, "setHighlightPillColor", pillColor);
@@ -5731,7 +5685,7 @@
                         showSpinner ? View.VISIBLE : View.GONE);
                 big.setProgressIndeterminateTintList(
                         R.id.notification_material_reply_progress,
-                        ColorStateList.valueOf(getAccentColor(p)));
+                        ColorStateList.valueOf(getPrimaryAccentColor(p)));
 
                 if (replyText.length > 1 && !TextUtils.isEmpty(replyText[1].getText())
                         && p.maxRemoteInputHistory > 1) {
@@ -6126,7 +6080,7 @@
                 // change the background bgColor
                 CharSequence title = action.title;
                 ColorStateList[] outResultColor = new ColorStateList[1];
-                int background = getSecondaryAccentColor(p);
+                int background = getColors(p).getSecondaryAccentColor();
                 if (isLegacy()) {
                     title = ContrastColorUtil.clearColorSpans(title);
                 } else {
@@ -6286,7 +6240,7 @@
             if (largeIcon != null && isLegacy()
                     && getColorUtil().isGrayscaleIcon(mContext, largeIcon)) {
                 // resolve color will fall back to the default when legacy
-                int color = getContrastColor(p);
+                int color = getSmallIconColor(p);
                 contentView.setInt(R.id.icon, "setOriginalIconColor", color);
             }
         }
@@ -6302,14 +6256,7 @@
          */
         private @ColorInt int getStandardActionColor(Notification.StandardTemplateParams p) {
             return mTintActionButtons || isBackgroundColorized(p)
-                    ? getAccentColor(p) : getNeutralColor(p);
-        }
-
-        /**
-         * Gets a neutral color that can be used for icons or similar that should not stand out.
-         */
-        private @ColorInt int getHeaderIconColor(StandardTemplateParams p) {
-            return isBackgroundColorized(p) ? getSecondaryTextColor(p) : getNeutralColor(p);
+                    ? getPrimaryAccentColor(p) : getSecondaryTextColor(p);
         }
 
         /**
@@ -6317,134 +6264,12 @@
          * is the primary text color, otherwise it's the contrast-adjusted app-provided color.
          */
         private @ColorInt int getSmallIconColor(StandardTemplateParams p) {
-            return getContrastColor(p);
+            return getColors(p).getContrastColor();
         }
 
-        /**
-         * Gets the accent color for colored UI elements.  If we're tinting with the theme
-         * accent, this is the theme accent color, otherwise this would be identical to
-         * {@link #getSmallIconColor(StandardTemplateParams)}.
-         */
-        private @ColorInt int getAccentColor(StandardTemplateParams p) {
-            if (isBackgroundColorized(p)) {
-                return getPrimaryTextColor(p);
-            }
-            int color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
-            if (color != COLOR_INVALID) {
-                return color;
-            }
-            return getContrastColor(p);
-        }
-
-        /**
-         * Gets the secondary accent color for colored UI elements.  If we're tinting with the theme
-         * accent, this is the theme accent color, otherwise this would be identical to
-         * {@link #getSmallIconColor(StandardTemplateParams)}.
-         */
-        private @ColorInt int getSecondaryAccentColor(StandardTemplateParams p) {
-            if (isBackgroundColorized(p)) {
-                return getSecondaryTextColor(p);
-            }
-            int color = obtainThemeColor(R.attr.colorAccentSecondary, COLOR_INVALID);
-            if (color != COLOR_INVALID) {
-                return color;
-            }
-            return getContrastColor(p);
-        }
-
-        /**
-         * Gets the "surface protection" color from the theme, or a variant of the normal background
-         * color when colorized, or when not using theme color tints.
-         */
-        private @ColorInt int getProtectionColor(StandardTemplateParams p) {
-            if (!isBackgroundColorized(p)) {
-                int color = obtainThemeColor(R.attr.colorBackgroundFloating, COLOR_INVALID);
-                if (color != COLOR_INVALID) {
-                    return color;
-                }
-            }
-            // TODO(b/181048615): What color should we use for the expander pill when colorized
-            return ColorUtils.blendARGB(getPrimaryTextColor(p), getBackgroundColor(p), 0.8f);
-        }
-
-        /**
-         * Gets the theme's error color, or the primary text color for colorized notifications.
-         */
-        private @ColorInt int getErrorColor(StandardTemplateParams p) {
-            if (!isBackgroundColorized(p)) {
-                int color = obtainThemeColor(R.attr.colorError, COLOR_INVALID);
-                if (color != COLOR_INVALID) {
-                    return color;
-                }
-            }
-            return getPrimaryTextColor(p);
-        }
-
-        /**
-         * Gets the theme's background color
-         */
-        private @ColorInt int getDefaultBackgroundColor() {
-            return obtainThemeColor(R.attr.colorSurface,
-                    mInNightMode ? Color.BLACK : Color.WHITE);
-        }
-
-        /**
-         * Gets the contrast-adjusted version of the color provided by the app.
-         */
-        private @ColorInt int getContrastColor(StandardTemplateParams p) {
-            if (isBackgroundColorized(p)) {
-                return getPrimaryTextColor(p);
-            }
-            int rawColor = getRawColor(p);
-            if (mCachedContrastColorIsFor == rawColor && mCachedContrastColor != COLOR_INVALID) {
-                return mCachedContrastColor;
-            }
-
-            int color;
-            // TODO: Maybe use getBackgroundColor(p) instead -- but doing so could break the cache
-            int background = getDefaultBackgroundColor();
-            if (rawColor == COLOR_DEFAULT) {
-                ensureColors(p);
-                color = obtainThemeColor(R.attr.colorAccent, COLOR_INVALID);
-                if (color == COLOR_INVALID) {
-                    color = ContrastColorUtil.resolveDefaultColor(mContext, background,
-                            mInNightMode);
-                }
-            } else {
-                color = ContrastColorUtil.resolveContrastColor(mContext, rawColor,
-                        background, mInNightMode);
-            }
-            if (Color.alpha(color) < 255) {
-                // alpha doesn't go well for color filters, so let's blend it manually
-                color = ContrastColorUtil.compositeColors(color, background);
-            }
-            mCachedContrastColorIsFor = rawColor;
-            return mCachedContrastColor = color;
-        }
-
-        /**
-         * Return the raw color of this Notification, which doesn't necessarily satisfy contrast.
-         *
-         * @see #getContrastColor(StandardTemplateParams) for the contrasted color
-         * @param p the template params to inflate this with
-         */
-        private @ColorInt int getRawColor(StandardTemplateParams p) {
-            return mN.color;
-        }
-
-        /**
-         * Gets a neutral palette color; this is a contrast-satisfied version of the default color.
-         * @param p the template params to inflate this with
-         */
-        private @ColorInt int getNeutralColor(StandardTemplateParams p) {
-            int background = getBackgroundColor(p);
-            int neutralColor = ContrastColorUtil.resolveDefaultColor(mContext, background,
-                    mInNightMode);
-            if (Color.alpha(neutralColor) < 255) {
-                // alpha doesn't go well for color filters, so let's blend it manually
-                neutralColor = ContrastColorUtil.compositeColors(neutralColor, background);
-            }
-            return neutralColor;
+        /** @return the theme's accent color for colored UI elements. */
+        private @ColorInt int getPrimaryAccentColor(StandardTemplateParams p) {
+            return getColors(p).getPrimaryAccentColor();
         }
 
         /**
@@ -6590,23 +6415,6 @@
         }
 
         /**
-         * Returns the color for the given Theme.DeviceDefault.DayNight attribute, or
-         * defValue if that could not be completed
-         */
-        private @ColorInt int obtainThemeColor(@AttrRes int attrRes, @ColorInt int defaultColor) {
-            Resources.Theme theme = mContext.getTheme();
-            if (theme == null) {
-                // Running unit tests with mocked context
-                return defaultColor;
-            }
-            theme = new ContextThemeWrapper(mContext, R.style.Theme_DeviceDefault_DayNight)
-                    .getTheme();
-            try (TypedArray ta = theme.obtainStyledAttributes(new int[]{attrRes})) {
-                return ta == null ? defaultColor : ta.getColor(0, defaultColor);
-            }
-        }
-
-        /**
          * Apply this Builder to an existing {@link Notification} object.
          *
          * @hide
@@ -6716,24 +6524,8 @@
             return R.layout.notification_material_action_tombstone;
         }
 
-        /**
-         * Gets the background color, with {@link #COLOR_DEFAULT} being a valid return value,
-         * which must be resolved by the caller before being used.
-         */
-        private @ColorInt int getUnresolvedBackgroundColor(StandardTemplateParams p) {
-            return isBackgroundColorized(p) ? getRawColor(p) : COLOR_DEFAULT;
-        }
-
-        /**
-         * Same as {@link #getUnresolvedBackgroundColor(StandardTemplateParams)} except that it
-         * also resolves the default color to the background.
-         */
         private @ColorInt int getBackgroundColor(StandardTemplateParams p) {
-            int backgroundColor = getUnresolvedBackgroundColor(p);
-            if (backgroundColor == COLOR_DEFAULT) {
-                backgroundColor = getDefaultBackgroundColor();
-            }
-            return backgroundColor;
+            return getColors(p).getBackgroundColor();
         }
 
         private boolean textColorsNeedInversion() {
@@ -9115,8 +8907,7 @@
             container.setDrawableTint(buttonId, false, tintColor,
                     PorterDuff.Mode.SRC_ATOP);
 
-            int rippleAlpha = Color.alpha(mBuilder.obtainThemeColor(
-                    android.R.attr.colorControlHighlight, COLOR_DEFAULT));
+            int rippleAlpha = mBuilder.getColors(p).getRippleAlpha();
             int rippleColor = Color.argb(rippleAlpha, Color.red(tintColor), Color.green(tintColor),
                     Color.blue(tintColor));
             container.setRippleDrawableColor(buttonId, ColorStateList.valueOf(rippleColor));
@@ -12447,4 +12238,219 @@
             return this;
         }
     }
+
+    /**
+     * A utility which stores and calculates the palette of colors used to color notifications.
+     * @hide
+     */
+    @VisibleForTesting
+    public static class Colors {
+        private int mPaletteIsForRawColor = COLOR_INVALID;
+        private boolean mPaletteIsForColorized = false;
+        private boolean mPaletteIsForNightMode = false;
+        // The following colors are the palette
+        private int mBackgroundColor = COLOR_INVALID;
+        private int mProtectionColor = COLOR_INVALID;
+        private int mPrimaryTextColor = COLOR_INVALID;
+        private int mSecondaryTextColor = COLOR_INVALID;
+        private int mPrimaryAccentColor = COLOR_INVALID;
+        private int mSecondaryAccentColor = COLOR_INVALID;
+        private int mErrorColor = COLOR_INVALID;
+        private int mContrastColor = COLOR_INVALID;
+        private int mRippleAlpha = 0x33;
+
+        /**
+         * A utility for obtaining a TypedArray of the given DayNight-styled attributes, which
+         * returns null when the context is a mock with no theme.
+         *
+         * NOTE: Calling this method is expensive, as creating a new ContextThemeWrapper
+         * instances can allocate as much as 5MB of memory, so its important to call this method
+         * only when necessary, getting as many attributes as possible from each call.
+         *
+         * @see Resources.Theme#obtainStyledAttributes(int[])
+         */
+        @Nullable
+        private static TypedArray obtainDayNightAttributes(@NonNull Context ctx,
+                @NonNull @StyleableRes int[] attrs) {
+            // when testing, the mock context may have no theme
+            if (ctx.getTheme() == null) {
+                return null;
+            }
+            Resources.Theme theme = new ContextThemeWrapper(ctx,
+                    R.style.Theme_DeviceDefault_DayNight).getTheme();
+            return theme.obtainStyledAttributes(attrs);
+        }
+
+        /** A null-safe wrapper of TypedArray.getColor because mocks return null */
+        private static @ColorInt int getColor(@Nullable TypedArray ta, int index,
+                @ColorInt int defValue) {
+            return ta == null ? defValue : ta.getColor(index, defValue);
+        }
+
+        /**
+         * Resolve the palette.  If the inputs have not changed, this will be a no-op.
+         * This does not handle invalidating the resolved colors when the context itself changes,
+         * because that case does not happen in the current notification inflation pipeline; we will
+         * recreate a new builder (and thus a new palette) when reinflating notifications for a new
+         * theme (admittedly, we do the same for night mode, but that's easy to check).
+         *
+         * @param ctx the builder context.
+         * @param rawColor the notification's color; may be COLOR_DEFAULT, but may never have alpha.
+         * @param isColorized whether the notification is colorized.
+         * @param nightMode whether the UI is in night mode.
+         */
+        public void resolvePalette(Context ctx, int rawColor,
+                boolean isColorized, boolean nightMode) {
+            if (mPaletteIsForRawColor == rawColor
+                    && mPaletteIsForColorized == isColorized
+                    && mPaletteIsForNightMode == nightMode) {
+                return;
+            }
+            mPaletteIsForRawColor = rawColor;
+            mPaletteIsForColorized = isColorized;
+            mPaletteIsForNightMode = nightMode;
+
+            if (isColorized) {
+                if (rawColor == COLOR_DEFAULT) {
+                    int[] attrs = {R.attr.colorAccentTertiary};
+                    try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
+                        mBackgroundColor = getColor(ta, 0, Color.WHITE);
+                    }
+                } else {
+                    mBackgroundColor = rawColor;
+                }
+                mProtectionColor = COLOR_INVALID;  // filled in at the end
+                mPrimaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+                        ContrastColorUtil.resolvePrimaryColor(ctx, mBackgroundColor, nightMode),
+                        mBackgroundColor, 4.5);
+                mSecondaryTextColor = ContrastColorUtil.findAlphaToMeetContrast(
+                        ContrastColorUtil.resolveSecondaryColor(ctx, mBackgroundColor, nightMode),
+                        mBackgroundColor, 4.5);
+                mContrastColor = mPrimaryTextColor;
+                mPrimaryAccentColor = mPrimaryTextColor;
+                mSecondaryAccentColor = mSecondaryTextColor;
+                mErrorColor = mPrimaryTextColor;
+                mRippleAlpha = 0x33;
+            } else {
+                int[] attrs = {
+                        R.attr.colorBackground,
+                        R.attr.colorBackgroundFloating,
+                        R.attr.textColorPrimary,
+                        R.attr.textColorSecondary,
+                        R.attr.colorAccent,
+                        R.attr.colorAccentSecondary,
+                        R.attr.colorError,
+                        R.attr.colorControlHighlight
+                };
+                try (TypedArray ta = obtainDayNightAttributes(ctx, attrs)) {
+                    mBackgroundColor = getColor(ta, 0, nightMode ? Color.BLACK : Color.WHITE);
+                    mProtectionColor = getColor(ta, 1, COLOR_INVALID);
+                    mPrimaryTextColor = getColor(ta, 2, COLOR_INVALID);
+                    mSecondaryTextColor = getColor(ta, 3, COLOR_INVALID);
+                    mPrimaryAccentColor = getColor(ta, 4, COLOR_INVALID);
+                    mSecondaryAccentColor = getColor(ta, 5, COLOR_INVALID);
+                    mErrorColor = getColor(ta, 6, COLOR_INVALID);
+                    mRippleAlpha = Color.alpha(getColor(ta, 7, 0x33ffffff));
+                }
+                mContrastColor = calculateContrastColor(ctx, rawColor, mPrimaryAccentColor,
+                        mBackgroundColor, nightMode);
+
+                // make sure every color has a valid value
+                if (mPrimaryTextColor == COLOR_INVALID) {
+                    mPrimaryTextColor = ContrastColorUtil.resolvePrimaryColor(
+                            ctx, mBackgroundColor, nightMode);
+                }
+                if (mSecondaryTextColor == COLOR_INVALID) {
+                    mSecondaryTextColor = ContrastColorUtil.resolveSecondaryColor(
+                            ctx, mBackgroundColor, nightMode);
+                }
+                if (mPrimaryAccentColor == COLOR_INVALID) {
+                    mPrimaryAccentColor = mContrastColor;
+                }
+                if (mSecondaryAccentColor == COLOR_INVALID) {
+                    mSecondaryAccentColor = mContrastColor;
+                }
+                if (mErrorColor == COLOR_INVALID) {
+                    mErrorColor = mPrimaryTextColor;
+                }
+            }
+            // make sure every color has a valid value
+            if (mProtectionColor == COLOR_INVALID) {
+                mProtectionColor = ColorUtils.blendARGB(mPrimaryTextColor, mBackgroundColor, 0.8f);
+            }
+        }
+
+        /** calculates the contrast color for the non-colorized notifications */
+        private static @ColorInt int calculateContrastColor(Context ctx, @ColorInt int rawColor,
+                @ColorInt int accentColor, @ColorInt int backgroundColor, boolean nightMode) {
+            int color;
+            if (rawColor == COLOR_DEFAULT) {
+                color = accentColor;
+                if (color == COLOR_INVALID) {
+                    color = ContrastColorUtil.resolveDefaultColor(ctx, backgroundColor, nightMode);
+                }
+            } else {
+                color = ContrastColorUtil.resolveContrastColor(ctx, rawColor, backgroundColor,
+                        nightMode);
+            }
+            return flattenAlpha(color, backgroundColor);
+        }
+
+        /** remove any alpha by manually blending it with the given background. */
+        private static @ColorInt int flattenAlpha(@ColorInt int color, @ColorInt int background) {
+            return Color.alpha(color) == 0xff ? color
+                    : ContrastColorUtil.compositeColors(color, background);
+        }
+
+        /** @return the notification's background color */
+        public @ColorInt int getBackgroundColor() {
+            return mBackgroundColor;
+        }
+
+        /**
+         * @return the "surface protection" color from the theme,
+         * or a variant of the normal background color when colorized.
+         */
+        public @ColorInt int getProtectionColor() {
+            return mProtectionColor;
+        }
+
+        /** @return the color for the most prominent text */
+        public @ColorInt int getPrimaryTextColor() {
+            return mPrimaryTextColor;
+        }
+
+        /** @return the color for less prominent text */
+        public @ColorInt int getSecondaryTextColor() {
+            return mSecondaryTextColor;
+        }
+
+        /** @return the theme's accent color for colored UI elements. */
+        public @ColorInt int getPrimaryAccentColor() {
+            return mPrimaryAccentColor;
+        }
+
+        /** @return the theme's secondary accent color for colored UI elements. */
+        public @ColorInt int getSecondaryAccentColor() {
+            return mSecondaryAccentColor;
+        }
+
+        /**
+         * @return the contrast-adjusted version of the color provided by the app, or the
+         * primary text color when colorized.
+         */
+        public @ColorInt int getContrastColor() {
+            return mContrastColor;
+        }
+
+        /** @return the theme's error color, or the primary text color when colorized. */
+        public @ColorInt int getErrorColor() {
+            return mErrorColor;
+        }
+
+        /** @return the alpha component of the current theme's control highlight color. */
+        public int getRippleAlpha() {
+            return mRippleAlpha;
+        }
+    }
 }
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/app/search/Query.java b/core/java/android/app/search/Query.java
index 34ace48..c64e107 100644
--- a/core/java/android/app/search/Query.java
+++ b/core/java/android/app/search/Query.java
@@ -37,6 +37,14 @@
 public final class Query implements Parcelable {
 
     /**
+     * The lookup key for a integer that indicates what the height of the soft keyboard
+     * (e.g., IME, also known as Input Method Editor) was on the client window
+     * in dp (density-independent pixels). This information is to be used by the consumer
+     * of the API in estimating how many search results will be visible above the keyboard.
+     */
+    public static final String EXTRA_IME_HEIGHT = "android.app.search.extra.IME_HEIGHT";
+
+    /**
      * string typed from the client.
      */
     @NonNull
@@ -45,7 +53,7 @@
     private final long mTimestampMillis;
 
     /**
-     * Contains other client UI constraints related data
+     * Contains other client UI constraints related data (e.g., {@link #EXTRA_IME_HEIGHT}.
      */
     @NonNull
     private final Bundle mExtras;
diff --git a/core/java/android/app/search/SearchTarget.java b/core/java/android/app/search/SearchTarget.java
index 6d638d4..a590a5d 100644
--- a/core/java/android/app/search/SearchTarget.java
+++ b/core/java/android/app/search/SearchTarget.java
@@ -50,7 +50,7 @@
  * can recommend which layout this target should be rendered in.
  *
  * The service can also use fields such as {@link #getScore()} to indicate
- * how confidence the search result is and {@link #shouldHide()} to indicate
+ * how confidence the search result is and {@link #isHidden()} to indicate
  * whether it is recommended to be shown by default.
  *
  * Finally, {@link #getId()} is the unique identifier of this search target and a single
@@ -125,7 +125,7 @@
 
     private final float mScore;
 
-    private final boolean mShouldHide;
+    private final boolean mHidden;
 
     @NonNull
     private final String mPackageName;
@@ -149,7 +149,7 @@
         mId = parcel.readString();
         mParentId = parcel.readString();
         mScore = parcel.readFloat();
-        mShouldHide = parcel.readBoolean();
+        mHidden = parcel.readBoolean();
 
         mPackageName = parcel.readString();
         mUserHandle = UserHandle.of(parcel.readInt());
@@ -165,7 +165,7 @@
             @NonNull String layoutType,
             @NonNull String id,
             @Nullable String parentId,
-            float score, boolean shouldHide,
+            float score, boolean hidden,
             @NonNull String packageName,
             @NonNull UserHandle userHandle,
             @Nullable SearchAction action,
@@ -178,7 +178,7 @@
         mId = Objects.requireNonNull(id);
         mParentId = parentId;
         mScore = score;
-        mShouldHide = shouldHide;
+        mHidden = hidden;
         mPackageName = Objects.requireNonNull(packageName);
         mUserHandle = Objects.requireNonNull(userHandle);
         mSearchAction = action;
@@ -238,9 +238,20 @@
 
     /**
      * Indicates whether this object should be hidden and shown only on demand.
+     *
+     * @deprecated will be removed once SDK drops
+     * @removed
      */
+    @Deprecated
     public boolean shouldHide() {
-        return mShouldHide;
+        return mHidden;
+    }
+
+    /**
+     * Indicates whether this object should be hidden and shown only on demand.
+     */
+    public boolean isHidden() {
+        return mHidden;
     }
 
     /**
@@ -311,7 +322,7 @@
         parcel.writeString(mId);
         parcel.writeString(mParentId);
         parcel.writeFloat(mScore);
-        parcel.writeBoolean(mShouldHide);
+        parcel.writeBoolean(mHidden);
         parcel.writeString(mPackageName);
         parcel.writeInt(mUserHandle.getIdentifier());
         parcel.writeTypedObject(mSearchAction, flags);
@@ -351,7 +362,7 @@
         @Nullable
         private String mParentId;
         private float mScore;
-        private boolean mShouldHide;
+        private boolean mHidden;
         @NonNull
         private String mPackageName;
         @NonNull
@@ -374,7 +385,7 @@
             mLayoutType = Objects.requireNonNull(layoutType);
             mResultType = resultType;
             mScore = 1f;
-            mShouldHide = false;
+            mHidden = false;
         }
 
         /**
@@ -473,8 +484,20 @@
          * Sets whether the result should be hidden (e.g. not visible) by default inside client.
          */
         @NonNull
+        public Builder setHidden(boolean hidden) {
+            mHidden = hidden;
+            return this;
+        }
+
+        /**
+         * Sets whether the result should be hidden by default inside client.
+         * @deprecated will be removed once SDK drops
+         * @removed
+         */
+        @NonNull
+        @Deprecated
         public Builder setShouldHide(boolean shouldHide) {
-            mShouldHide = shouldHide;
+            mHidden = shouldHide;
             return this;
         }
 
@@ -485,7 +508,7 @@
          */
         @NonNull
         public SearchTarget build() {
-            return new SearchTarget(mResultType, mLayoutType, mId, mParentId, mScore, mShouldHide,
+            return new SearchTarget(mResultType, mLayoutType, mId, mParentId, mScore, mHidden,
                     mPackageName, mUserHandle,
                     mSearchAction, mShortcutInfo, mSliceUri, mAppWidgetProviderInfo,
                     mExtras);
diff --git a/core/java/android/companion/CompanionDeviceManager.java b/core/java/android/companion/CompanionDeviceManager.java
index e6ffded..b99ad51 100644
--- a/core/java/android/companion/CompanionDeviceManager.java
+++ b/core/java/android/companion/CompanionDeviceManager.java
@@ -442,13 +442,18 @@
     /**
      * Associates given device with given app for the given user directly, without UI prompt.
      *
+     * @param packageName package name of the companion app
+     * @param macAddress mac address of the device to associate
+     * @param certificate The SHA256 digest of the companion app's signing certificate
+     *
      * @hide
      */
     @SystemApi
     @RequiresPermission(android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES)
     public void associate(
             @NonNull String packageName,
-            @NonNull MacAddress macAddress) {
+            @NonNull MacAddress macAddress,
+            @NonNull byte[] certificate) {
         if (!checkFeaturePresent()) {
             return;
         }
@@ -458,7 +463,7 @@
         UserHandle user = android.os.Process.myUserHandle();
         try {
             mService.createAssociation(
-                    packageName, macAddress.toString(), user.getIdentifier());
+                    packageName, macAddress.toString(), user.getIdentifier(), certificate);
         } catch (RemoteException e) {
             throw e.rethrowFromSystemServer();
         }
diff --git a/core/java/android/companion/ICompanionDeviceManager.aidl b/core/java/android/companion/ICompanionDeviceManager.aidl
index cc3749c..d113b92 100644
--- a/core/java/android/companion/ICompanionDeviceManager.aidl
+++ b/core/java/android/companion/ICompanionDeviceManager.aidl
@@ -52,5 +52,6 @@
 
     boolean canPairWithoutPrompt(in String packageName, in String deviceMacAddress, int userId);
 
-    void createAssociation(in String packageName, in String macAddress, int userId);
+    void createAssociation(in String packageName, in String macAddress, int userId,
+        in byte[] certificate);
 }
diff --git a/core/java/android/content/Intent.java b/core/java/android/content/Intent.java
index a436fa4..688483a 100644
--- a/core/java/android/content/Intent.java
+++ b/core/java/android/content/Intent.java
@@ -1983,7 +1983,7 @@
      * activities that are not properly protected.
      *
      * <p>
-     * Input: {@link android.Manifest.permission_group} specifies the permission group
+     * Input: {@link #EXTRA_PERMISSION_GROUP_NAME} specifies the permission group
      * for which the launched UI would be targeted.
      * </p>
      * <p>
@@ -2013,12 +2013,12 @@
      * Input: {@link #EXTRA_ATTRIBUTION_TAGS} specifies the attribution tags for the usage entry.
      * </p>
      * <p>
-     * Input: {@link #EXTRA_START_TIME} specifies the start time of the period. Both start time and
-     * end time are needed and start time must be <= end time.
+     * Input: {@link #EXTRA_START_TIME} specifies the start time of the period (epoch time in
+     * millis). Both start time and end time are needed and start time must be <= end time.
      * </p>
      * <p>
-     * Input: {@link #EXTRA_END_TIME} specifies the end time of the period. Both start time and end
-     * time are needed and start time must be <= end time.
+     * Input: {@link #EXTRA_END_TIME} specifies the end time of the period (epoch time in
+     * millis). Both start time and end time are needed and start time must be <= end time.
      * </p>
      * <p>
      * Output: Nothing.
diff --git a/core/java/android/hardware/biometrics/BiometricTestSession.java b/core/java/android/hardware/biometrics/BiometricTestSession.java
index 41672b7..c62680f 100644
--- a/core/java/android/hardware/biometrics/BiometricTestSession.java
+++ b/core/java/android/hardware/biometrics/BiometricTestSession.java
@@ -23,7 +23,6 @@
 import android.annotation.RequiresPermission;
 import android.annotation.TestApi;
 import android.content.Context;
-import android.hardware.fingerprint.FingerprintManager;
 import android.os.RemoteException;
 import android.util.ArraySet;
 import android.util.Log;
@@ -248,6 +247,12 @@
             }
         }
 
+        if (!mUsersCleaningUp.isEmpty()) {
+            // TODO(b/186600837): this seems common on multi sensor devices
+            Log.e(getTag(), "Cleanup not finished before shutdown - pending: "
+                    + mUsersCleaningUp.size());
+        }
+
         // Disable the test HAL after the sensor becomes idle.
         setTestHalEnabled(false);
     }
diff --git a/core/java/android/service/translation/TranslationService.java b/core/java/android/service/translation/TranslationService.java
index 2f704f4..e1d4a56 100644
--- a/core/java/android/service/translation/TranslationService.java
+++ b/core/java/android/service/translation/TranslationService.java
@@ -230,12 +230,8 @@
      */
     // TODO(b/176464808): the session id won't be unique cross client/server process. Need to find
     // solution to make it's safe.
-    // TODO: make abstract once aiai is implemented.
-    public void onCreateTranslationSession(@NonNull TranslationContext translationContext,
-            int sessionId, @NonNull Consumer<Boolean> callback) {
-        onCreateTranslationSession(translationContext, sessionId);
-        callback.accept(true);
-    }
+    public abstract void onCreateTranslationSession(@NonNull TranslationContext translationContext,
+            int sessionId, @NonNull Consumer<Boolean> callback);
 
     /**
      * TODO: fill in javadoc.
@@ -285,23 +281,9 @@
      * @param callback
      * @param cancellationSignal
      */
-    //TODO: make abstract once aiai transitions.
-    public void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
+    public abstract void onTranslationRequest(@NonNull TranslationRequest request, int sessionId,
             @Nullable CancellationSignal cancellationSignal,
-            @NonNull Consumer<TranslationResponse> callback) {
-        onTranslationRequest(request, sessionId, cancellationSignal,
-                new OnTranslationResultCallback() {
-                    @Override
-                    public void onTranslationSuccess(@NonNull TranslationResponse response) {
-                        callback.accept(response);
-                    }
-
-                    @Override
-                    public void onError() {
-                        // null-op
-                    }
-                });
-    }
+            @NonNull Consumer<TranslationResponse> callback);
 
     /**
      * TODO: fill in javadoc
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/InsetsAnimationControlImpl.java b/core/java/android/view/InsetsAnimationControlImpl.java
index 3255dd6..b3caac0 100644
--- a/core/java/android/view/InsetsAnimationControlImpl.java
+++ b/core/java/android/view/InsetsAnimationControlImpl.java
@@ -28,6 +28,8 @@
 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
 import static android.view.InsetsController.AnimationType;
 import static android.view.InsetsController.DEBUG;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
+import static android.view.InsetsController.LayoutInsetsDuringAnimation;
 import static android.view.InsetsState.ISIDE_BOTTOM;
 import static android.view.InsetsState.ISIDE_FLOATING;
 import static android.view.InsetsState.ISIDE_LEFT;
@@ -85,6 +87,7 @@
     private final Matrix mTmpMatrix = new Matrix();
     private final InsetsState mInitialInsetsState;
     private final @AnimationType int mAnimationType;
+    private final @LayoutInsetsDuringAnimation int mLayoutInsetsDuringAnimation;
     private final @InsetsType int mTypes;
     private @InsetsType int mControllingTypes;
     private final InsetsAnimationControlCallbacks mController;
@@ -107,9 +110,10 @@
     @VisibleForTesting
     public InsetsAnimationControlImpl(SparseArray<InsetsSourceControl> controls,
             @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
-            @InsetsType int types,
-            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
-            @AnimationType int animationType, CompatibilityInfo.Translator translator) {
+            @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs,
+            Interpolator interpolator, @AnimationType int animationType,
+            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+            CompatibilityInfo.Translator translator) {
         mControls = controls;
         mListener = listener;
         mTypes = types;
@@ -145,6 +149,7 @@
                 durationMs);
         mAnimation.setAlpha(getCurrentAlpha());
         mAnimationType = animationType;
+        mLayoutInsetsDuringAnimation = layoutInsetsDuringAnimation;
         mTranslator = translator;
         mController.startAnimation(this, listener, types, mAnimation,
                 new Bounds(mHiddenInsets, mShownInsets));
@@ -299,6 +304,10 @@
         if (mFinished) {
             return;
         }
+        mPendingInsets = mLayoutInsetsDuringAnimation == LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+                ? mShownInsets : mHiddenInsets;
+        mPendingAlpha = 1f;
+        applyChangeInsets(null);
         mCancelled = true;
         mListener.onCancelled(mReadyDispatched ? this : null);
         if (DEBUG) Log.d(TAG, "notify Control request cancelled for types: " + mTypes);
diff --git a/core/java/android/view/InsetsAnimationThreadControlRunner.java b/core/java/android/view/InsetsAnimationThreadControlRunner.java
index 436a17c..c6ebc9e 100644
--- a/core/java/android/view/InsetsAnimationThreadControlRunner.java
+++ b/core/java/android/view/InsetsAnimationThreadControlRunner.java
@@ -29,6 +29,7 @@
 import android.util.SparseArray;
 import android.util.proto.ProtoOutputStream;
 import android.view.InsetsController.AnimationType;
+import android.view.InsetsController.LayoutInsetsDuringAnimation;
 import android.view.SyncRtSurfaceTransactionApplier.SurfaceParams;
 import android.view.WindowInsets.Type.InsetsType;
 import android.view.WindowInsetsAnimation.Bounds;
@@ -103,14 +104,15 @@
     @UiThread
     public InsetsAnimationThreadControlRunner(SparseArray<InsetsSourceControl> controls,
             @Nullable Rect frame, InsetsState state, WindowInsetsAnimationControlListener listener,
-            @InsetsType int types,
-            InsetsAnimationControlCallbacks controller, long durationMs, Interpolator interpolator,
-            @AnimationType int animationType, CompatibilityInfo.Translator translator,
-            Handler mainThreadHandler) {
+            @InsetsType int types, InsetsAnimationControlCallbacks controller, long durationMs,
+            Interpolator interpolator, @AnimationType int animationType,
+            @LayoutInsetsDuringAnimation int layoutInsetsDuringAnimation,
+            CompatibilityInfo.Translator translator, Handler mainThreadHandler) {
         mMainThreadHandler = mainThreadHandler;
         mOuterCallbacks = controller;
-        mControl = new InsetsAnimationControlImpl(controls, frame, state, listener,
-                types, mCallbacks, durationMs, interpolator, animationType, translator);
+        mControl = new InsetsAnimationControlImpl(controls, frame, state, listener, types,
+                mCallbacks, durationMs, interpolator, animationType, layoutInsetsDuringAnimation,
+                translator);
         InsetsAnimationThread.getHandler().post(() -> {
             if (mControl.isCancelled()) {
                 return;
diff --git a/core/java/android/view/InsetsController.java b/core/java/android/view/InsetsController.java
index d17b42e..d339c04 100644
--- a/core/java/android/view/InsetsController.java
+++ b/core/java/android/view/InsetsController.java
@@ -1053,10 +1053,11 @@
         final InsetsAnimationControlRunner runner = useInsetsAnimationThread
                 ? new InsetsAnimationThreadControlRunner(controls,
                         frame, mState, listener, typesReady, this, durationMs, interpolator,
-                        animationType, mHost.getTranslator(), mHost.getHandler())
+                        animationType, layoutInsetsDuringAnimation, mHost.getTranslator(),
+                        mHost.getHandler())
                 : new InsetsAnimationControlImpl(controls,
                         frame, mState, listener, typesReady, this, durationMs, interpolator,
-                        animationType, mHost.getTranslator());
+                        animationType, layoutInsetsDuringAnimation, mHost.getTranslator());
         if ((typesReady & WindowInsets.Type.ime()) != 0) {
             ImeTracing.getInstance().triggerClientDump("InsetsAnimationControlImpl",
                     mHost.getInputMethodManager(), null /* icProto */);
diff --git a/core/java/android/view/SurfaceView.java b/core/java/android/view/SurfaceView.java
index 2fce434..6b0bb9d 100644
--- a/core/java/android/view/SurfaceView.java
+++ b/core/java/android/view/SurfaceView.java
@@ -571,7 +571,10 @@
         // recreate this Surface, so only release it when we are fully
         // detached.
         if (mSurfacePackage != null) {
-            mTmpTransaction.reparent(mSurfacePackage.getSurfaceControl(), null).apply();
+            final SurfaceControl sc = mSurfacePackage.getSurfaceControl();
+            if (sc != null && sc.isValid()) {
+                mTmpTransaction.reparent(sc, null).apply();
+            }
             mSurfacePackage.release();
             mSurfacePackage = null;
         }
@@ -1826,7 +1829,7 @@
      */
     public void setChildSurfacePackage(@NonNull SurfaceControlViewHost.SurfacePackage p) {
         final SurfaceControl lastSc = mSurfacePackage != null ?
-            mSurfacePackage.getSurfaceControl() : null;
+                mSurfacePackage.getSurfaceControl() : null;
         if (mSurfaceControl != null && lastSc != null) {
             mTmpTransaction.reparent(lastSc, null).apply();
             mSurfacePackage.release();
@@ -1839,8 +1842,11 @@
 
     private void reparentSurfacePackage(SurfaceControl.Transaction t,
             SurfaceControlViewHost.SurfacePackage p) {
-        initEmbeddedHierarchyForAccessibility(p);
         final SurfaceControl sc = p.getSurfaceControl();
+        if (sc == null || !sc.isValid()) {
+            return;
+        }
+        initEmbeddedHierarchyForAccessibility(p);
         final SurfaceControl parent;
         if (mUseBlastAdapter) {
             parent = mBlastSurfaceControl;
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/SpellChecker.java b/core/java/android/widget/SpellChecker.java
index 7c04b1c..6b3a698 100644
--- a/core/java/android/widget/SpellChecker.java
+++ b/core/java/android/widget/SpellChecker.java
@@ -375,6 +375,13 @@
         final int sequenceNumber = suggestionsInfo.getSequence();
         for (int k = 0; k < mLength; ++k) {
             if (sequenceNumber == mIds[k]) {
+                final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[k];
+                final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan);
+                if (spellCheckSpanStart < 0) {
+                    // Skips the suggestion if the matched span has been removed.
+                    return null;
+                }
+
                 final int attributes = suggestionsInfo.getSuggestionsAttributes();
                 final boolean isInDictionary =
                         ((attributes & SuggestionsInfo.RESULT_ATTR_IN_THE_DICTIONARY) > 0);
@@ -383,7 +390,11 @@
                 final boolean looksLikeGrammarError =
                         ((attributes & SuggestionsInfo.RESULT_ATTR_LOOKS_LIKE_GRAMMAR_ERROR) > 0);
 
-                final SpellCheckSpan spellCheckSpan = mSpellCheckSpans[k];
+                // Validates the suggestions range in case the SpellCheckSpan is out-of-date but not
+                // removed as expected.
+                if (spellCheckSpanStart + offset + length > editable.length()) {
+                    return spellCheckSpan;
+                }
                 //TODO: we need to change that rule for results from a sentence-level spell
                 // checker that will probably be in dictionary.
                 if (!isInDictionary && (looksLikeTypo || looksLikeGrammarError)) {
@@ -393,7 +404,6 @@
                     // Valid word -- isInDictionary || !looksLikeTypo
                     // Allow the spell checker to remove existing misspelled span by
                     // overwriting the span over the same place
-                    final int spellCheckSpanStart = editable.getSpanStart(spellCheckSpan);
                     final int spellCheckSpanEnd = editable.getSpanEnd(spellCheckSpan);
                     final int start;
                     final int end;
@@ -461,7 +471,6 @@
     @Override
     public void onGetSentenceSuggestions(SentenceSuggestionsInfo[] results) {
         final Editable editable = (Editable) mTextView.getText();
-        final int sentenceLength = editable.length();
         for (int i = 0; i < results.length; ++i) {
             final SentenceSuggestionsInfo ssi = results[i];
             if (ssi == null) {
@@ -475,9 +484,6 @@
                 }
                 final int offset = ssi.getOffsetAt(j);
                 final int length = ssi.getLengthAt(j);
-                if (offset < 0 || offset + length > sentenceLength) {
-                    continue;
-                }
                 final SpellCheckSpan scs = onGetSuggestionsInternal(
                         suggestionsInfo, offset, length);
                 if (spellCheckSpan == null && scs != null) {
@@ -821,7 +827,7 @@
             // The offset should be rounded up to word boundary.
             int uncheckedLength = sentenceEnd - textChangeStart;
             if (uncheckedLength > MAX_SENTENCE_LENGTH) {
-                sentenceEnd = findSeparator(sequence, sentenceStart + MAX_SENTENCE_LENGTH,
+                sentenceEnd = findSeparator(sequence, textChangeStart + MAX_SENTENCE_LENGTH,
                         sentenceEnd);
                 sentenceStart = roundUpToWordStart(sequence, textChangeStart, sentenceStart);
             } else {
@@ -829,7 +835,7 @@
                         sentenceStart);
             }
         }
-        return new Range(sentenceStart, sentenceEnd);
+        return new Range<>(sentenceStart, Math.max(sentenceStart, sentenceEnd));
     }
 
     private int roundUpToWordStart(CharSequence sequence, int position, int frontBoundary) {
diff --git a/core/java/android/widget/TextView.java b/core/java/android/widget/TextView.java
index 9959510..3c4fd5e 100644
--- a/core/java/android/widget/TextView.java
+++ b/core/java/android/widget/TextView.java
@@ -10750,12 +10750,15 @@
         Editable text = (Editable) mText;
 
         T[] spans = text.getSpans(start, end, type);
-        final int length = spans.length;
-        for (int i = 0; i < length; i++) {
-            final int spanStart = text.getSpanStart(spans[i]);
-            final int spanEnd = text.getSpanEnd(spans[i]);
-            if (spanEnd == start || spanStart == end) break;
-            text.removeSpan(spans[i]);
+        ArrayList<T> spansToRemove = new ArrayList<>();
+        for (T span : spans) {
+            final int spanStart = text.getSpanStart(span);
+            final int spanEnd = text.getSpanEnd(span);
+            if (spanEnd == start || spanStart == end) continue;
+            spansToRemove.add(span);
+        }
+        for (T span : spansToRemove) {
+            text.removeSpan(span);
         }
     }
 
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/java/android/window/SplashScreen.java b/core/java/android/window/SplashScreen.java
index 7d222db..42a58fb 100644
--- a/core/java/android/window/SplashScreen.java
+++ b/core/java/android/window/SplashScreen.java
@@ -220,7 +220,13 @@
             }
         }
 
-        public void dispatchOnExitAnimation(IBinder token, SplashScreenView view) {
+        public void handOverSplashScreenView(@NonNull IBinder token,
+                @NonNull SplashScreenView splashScreenView) {
+            transferSurface(splashScreenView);
+            dispatchOnExitAnimation(token, splashScreenView);
+        }
+
+        private void dispatchOnExitAnimation(IBinder token, SplashScreenView view) {
             synchronized (mGlobalLock) {
                 final SplashScreenImpl impl = findImpl(token);
                 if (impl == null) {
@@ -240,5 +246,9 @@
                 return impl != null && impl.mExitAnimationListener != null;
             }
         }
+
+        private void transferSurface(@NonNull SplashScreenView splashScreenView) {
+            splashScreenView.transferSurface();
+        }
     }
 }
diff --git a/core/java/android/window/SplashScreenView.java b/core/java/android/window/SplashScreenView.java
index 6d71639..000dfb2 100644
--- a/core/java/android/window/SplashScreenView.java
+++ b/core/java/android/window/SplashScreenView.java
@@ -30,6 +30,7 @@
 import android.graphics.Bitmap;
 import android.graphics.Canvas;
 import android.graphics.Color;
+import android.graphics.PixelFormat;
 import android.graphics.Rect;
 import android.graphics.drawable.BitmapDrawable;
 import android.graphics.drawable.Drawable;
@@ -38,13 +39,17 @@
 import android.os.Trace;
 import android.util.AttributeSet;
 import android.util.Log;
+import android.view.Gravity;
 import android.view.LayoutInflater;
+import android.view.SurfaceControlViewHost;
+import android.view.SurfaceView;
 import android.view.View;
 import android.view.ViewGroup;
 import android.view.Window;
 import android.view.WindowInsetsController;
 import android.view.WindowManager;
 import android.widget.FrameLayout;
+import android.widget.ImageView;
 
 import com.android.internal.R;
 import com.android.internal.policy.DecorView;
@@ -92,6 +97,14 @@
 
     // The host activity when transfer view to it.
     private Activity mHostActivity;
+
+    @Nullable
+    private SurfaceControlViewHost.SurfacePackage mSurfacePackageCopy;
+    @Nullable
+    private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+    @Nullable
+    private SurfaceView mSurfaceView;
+
     // cache original window and status
     private Window mWindow;
     private int mAppWindowFlags;
@@ -114,6 +127,7 @@
         private @ColorInt int mIconBackground;
         private Bitmap mParceledIconBitmap;
         private Drawable mIconDrawable;
+        private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
         private int mBrandingImageWidth;
         private int mBrandingImageHeight;
         private Drawable mBrandingDrawable;
@@ -133,7 +147,10 @@
             mIconSize = parcelable.getIconSize();
             mBackgroundColor = parcelable.getBackgroundColor();
             mIconBackground = parcelable.getIconBackground();
-            if (parcelable.mIconBitmap != null) {
+            mSurfacePackage = parcelable.mSurfacePackage;
+            if (mSurfacePackage == null && parcelable.mIconBitmap != null) {
+                // We only create a Bitmap copies of immobile icons since animated icon are using
+                // a surface view
                 mIconDrawable = new BitmapDrawable(mContext.getResources(), parcelable.mIconBitmap);
                 mParceledIconBitmap = parcelable.mIconBitmap;
             }
@@ -145,6 +162,9 @@
             }
             mIconAnimationStart = Instant.ofEpochMilli(parcelable.mIconAnimationStartMillis);
             mIconAnimationDuration = Duration.ofMillis(parcelable.mIconAnimationDurationMillis);
+            if (DEBUG) {
+                Log.d(TAG, String.format("Building from parcel drawable: %s", mIconDrawable));
+            }
             return this;
         }
 
@@ -167,7 +187,7 @@
         /**
          * Set the Drawable object to fill the center view.
          */
-        public Builder setCenterViewDrawable(Drawable drawable) {
+        public Builder setCenterViewDrawable(@Nullable Drawable drawable) {
             mIconDrawable = drawable;
             return this;
         }
@@ -191,7 +211,7 @@
         /**
          * Set the Drawable object and size for the branding view.
          */
-        public Builder setBrandingDrawable(Drawable branding, int width, int height) {
+        public Builder setBrandingDrawable(@Nullable Drawable branding, int width, int height) {
             mBrandingDrawable = branding;
             mBrandingImageWidth = width;
             mBrandingImageHeight = height;
@@ -209,22 +229,30 @@
             view.mInitBackgroundColor = mBackgroundColor;
             view.mInitIconBackgroundColor = mIconBackground;
             view.setBackgroundColor(mBackgroundColor);
-            view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
+
             view.mBrandingImageView = view.findViewById(R.id.splashscreen_branding_view);
+
             // center icon
-            if (mIconSize != 0) {
-                final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
-                params.width = mIconSize;
-                params.height = mIconSize;
-                view.mIconView.setLayoutParams(params);
-            }
-            if (mIconDrawable != null) {
-                view.mIconView.setBackground(mIconDrawable);
+            if (mIconDrawable instanceof SplashScreenView.IconAnimateListener
+                    || mSurfacePackage != null) {
+                view.mIconView = createSurfaceView(view);
                 view.initIconAnimation(mIconDrawable,
                         mIconAnimationDuration != null ? mIconAnimationDuration.toMillis() : 0);
+                view.mIconAnimationStart = mIconAnimationStart;
+                view.mIconAnimationDuration = mIconAnimationDuration;
+            } else {
+                view.mIconView = view.findViewById(R.id.splashscreen_icon_view);
+                if (mIconSize != 0) {
+                    final ViewGroup.LayoutParams params = view.mIconView.getLayoutParams();
+                    params.width = mIconSize;
+                    params.height = mIconSize;
+                    view.mIconView.setLayoutParams(params);
+                    if (mIconDrawable != null) {
+                        view.mIconView.setBackground(mIconDrawable);
+                    }
+                }
             }
-            view.mIconAnimationStart = mIconAnimationStart;
-            view.mIconAnimationDuration = mIconAnimationDuration;
+
             if (mParceledIconBitmap != null) {
                 view.mParceledIconBitmap = mParceledIconBitmap;
             }
@@ -242,14 +270,60 @@
                 view.mParceledBrandingBitmap = mParceledBrandingBitmap;
             }
             if (DEBUG) {
-                Log.d(TAG, " build " + view + " Icon: view: " + view.mIconView + " drawable: "
-                        + mIconDrawable + " size: " + mIconSize + "\n Branding: view: "
-                        + view.mBrandingImageView + " drawable: " + mBrandingDrawable
-                        + " size w: " + mBrandingImageWidth + " h: " + mBrandingImageHeight);
+                Log.d(TAG, "Build " + view
+                        + "\nIcon: view: " + view.mIconView + " drawable: "
+                        + mIconDrawable + " size: " + mIconSize
+                        + "\nBranding: view: " + view.mBrandingImageView + " drawable: "
+                        + mBrandingDrawable + " size w: " + mBrandingImageWidth + " h: "
+                        + mBrandingImageHeight);
             }
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
             return view;
         }
+
+        private SurfaceView createSurfaceView(@NonNull SplashScreenView view) {
+            final SurfaceView surfaceView = new SurfaceView(view.getContext());
+            if (mSurfacePackage == null) {
+                if (DEBUG) {
+                    Log.d(TAG,
+                            "Creating Original SurfacePackage. SurfaceView: " + surfaceView);
+                }
+
+                SurfaceControlViewHost viewHost = new SurfaceControlViewHost(mContext,
+                        mContext.getDisplay(),
+                        surfaceView.getHostToken());
+                ImageView imageView = new ImageView(mContext);
+                imageView.setBackground(mIconDrawable);
+                viewHost.setView(imageView, mIconSize, mIconSize);
+                SurfaceControlViewHost.SurfacePackage surfacePackage = viewHost.getSurfacePackage();
+                surfaceView.setChildSurfacePackage(surfacePackage);
+                view.mSurfacePackage = surfacePackage;
+                view.mSurfacePackageCopy = new SurfaceControlViewHost.SurfacePackage(
+                        surfacePackage);
+            } else {
+                if (DEBUG) {
+                    Log.d(TAG, "Using copy of SurfacePackage in the client");
+                }
+                view.mSurfacePackage = mSurfacePackage;
+            }
+            if (mIconSize != 0) {
+                LayoutParams lp = new FrameLayout.LayoutParams(mIconSize, mIconSize);
+                lp.gravity = Gravity.CENTER;
+                surfaceView.setLayoutParams(lp);
+                if (DEBUG) {
+                    Log.d(TAG, "Icon size " + mIconSize);
+                }
+            }
+
+            // We ensure that we can blend the alpha of the surface view with the SplashScreenView
+            surfaceView.setUseAlpha();
+            surfaceView.setZOrderOnTop(true);
+            surfaceView.getHolder().setFormat(PixelFormat.TRANSLUCENT);
+
+            view.addView(surfaceView);
+            view.mSurfaceView = surfaceView;
+            return surfaceView;
+        }
     }
 
     /** @hide */
@@ -298,6 +372,35 @@
     }
 
     /**
+     * Called when this {@link SplashScreenView} has been copied to be transferred to the client.
+     *
+     * @hide
+     */
+    public void onCopied() {
+        if (mSurfaceView == null) {
+            return;
+        }
+        if (DEBUG) {
+            Log.d(TAG, "Setting SurfaceView's SurfacePackage to null.");
+        }
+        // If we don't release the surface package, the surface will be reparented to this
+        // surface view. So once it's copied into the client process, we release it.
+        mSurfacePackage.release();
+        mSurfacePackage = null;
+    }
+
+    @Override
+    public void setAlpha(float alpha) {
+        super.setAlpha(alpha);
+
+        // The surface view's alpha is not multiplied with the containing view's alpha, so we
+        // manually do it here
+        if (mSurfaceView != null) {
+            mSurfaceView.setAlpha(mSurfaceView.getAlpha() * alpha);
+        }
+    }
+
+    /**
      * Returns the duration of the icon animation if icon is animatable.
      *
      * @see android.R.attr#windowSplashScreenAnimatedIcon
@@ -316,6 +419,22 @@
         return mIconAnimationStart;
     }
 
+
+    void transferSurface() {
+        if (mSurfacePackage == null) {
+            return;
+        }
+        if (DEBUG) {
+            mSurfacePackage.getSurfaceControl().addOnReparentListener(
+                    (transaction, parent) -> Log.e(TAG,
+                            String.format("SurfacePackage'surface reparented.\n Parent: %s",
+                                    parent), new Throwable()));
+            Log.d(TAG, "Transferring surface " + mSurfaceView.toString());
+        }
+        mSurfaceView.setChildSurfacePackage(mSurfacePackage);
+
+    }
+
     void initIconAnimation(Drawable iconDrawable, long duration) {
         if (!(iconDrawable instanceof IconAnimateListener)) {
             return;
@@ -477,7 +596,7 @@
         private int mBackgroundColor;
         private int mIconBackground;
 
-        private Bitmap mIconBitmap;
+        private Bitmap mIconBitmap = null;
         private int mBrandingWidth;
         private int mBrandingHeight;
         private Bitmap mBrandingBitmap;
@@ -485,14 +604,20 @@
         private long mIconAnimationStartMillis;
         private long mIconAnimationDurationMillis;
 
+        private SurfaceControlViewHost.SurfacePackage mSurfacePackage;
+
         public SplashScreenViewParcelable(SplashScreenView view) {
-            ViewGroup.LayoutParams params = view.getIconView().getLayoutParams();
-            mIconSize = params.height;
+            mIconSize = view.mIconView.getWidth();
             mBackgroundColor = view.getInitBackgroundColor();
             mIconBackground = view.getIconBackgroundColor();
-            mIconBitmap = copyDrawable(view.getIconView().getBackground());
+            mSurfacePackage = view.mSurfacePackageCopy;
+            if (mSurfacePackage == null) {
+                // We only need to copy the drawable if we are not using a SurfaceView
+                mIconBitmap = copyDrawable(view.getIconView().getBackground());
+            }
             mBrandingBitmap = copyDrawable(view.getBrandingView().getBackground());
-            params = view.getBrandingView().getLayoutParams();
+
+            ViewGroup.LayoutParams params = view.getBrandingView().getLayoutParams();
             mBrandingWidth = params.width;
             mBrandingHeight = params.height;
 
@@ -535,6 +660,7 @@
             mIconAnimationStartMillis = source.readLong();
             mIconAnimationDurationMillis = source.readLong();
             mIconBackground = source.readInt();
+            mSurfacePackage = source.readTypedObject(SurfaceControlViewHost.SurfacePackage.CREATOR);
         }
 
         @Override
@@ -553,6 +679,7 @@
             dest.writeLong(mIconAnimationStartMillis);
             dest.writeLong(mIconAnimationDurationMillis);
             dest.writeInt(mIconBackground);
+            dest.writeTypedObject(mSurfacePackage, flags);
         }
 
         public static final @NonNull Parcelable.Creator<SplashScreenViewParcelable> CREATOR =
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index 862c900..28c2774 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -1093,6 +1093,7 @@
                     "",
                     -1);
 
+            setResult(RESULT_OK);
             finish();
         }
     }
diff --git a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
index d4d6125..3aaccdd 100644
--- a/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
+++ b/core/java/com/android/internal/os/BatteryUsageStatsProvider.java
@@ -180,29 +180,28 @@
     }
 
     private long getProcessForegroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
-        final long topStateDurationMs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
-                realtimeUs, BatteryStats.STATS_SINCE_CHARGED) / 1000;
-
-        long foregroundActivityDurationMs = 0;
+        final long topStateDurationUs = uid.getProcessStateTime(BatteryStats.Uid.PROCESS_STATE_TOP,
+                realtimeUs, BatteryStats.STATS_SINCE_CHARGED);
+        long foregroundActivityDurationUs = 0;
         final BatteryStats.Timer foregroundActivityTimer = uid.getForegroundActivityTimer();
         if (foregroundActivityTimer != null) {
-            foregroundActivityDurationMs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
-                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
+            foregroundActivityDurationUs = foregroundActivityTimer.getTotalTimeLocked(realtimeUs,
+                    BatteryStats.STATS_SINCE_CHARGED);
         }
 
         // Use the min value of STATE_TOP time and foreground activity time, since both of these
         // times are imprecise
-        final long foregroundDurationMs = Math.min(topStateDurationMs,
-                foregroundActivityDurationMs);
+        long totalForegroundDurationUs = Math.min(topStateDurationUs, foregroundActivityDurationUs);
 
-        long foregroundServiceDurationMs = 0;
-        final BatteryStats.Timer foregroundServiceTimer = uid.getForegroundServiceTimer();
-        if (foregroundServiceTimer != null) {
-            foregroundServiceDurationMs = foregroundServiceTimer.getTotalTimeLocked(realtimeUs,
-                    BatteryStats.STATS_SINCE_CHARGED) / 1000;
-        }
+        totalForegroundDurationUs += uid.getProcessStateTime(
+                BatteryStats.Uid.PROCESS_STATE_FOREGROUND, realtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
 
-        return foregroundDurationMs + foregroundServiceDurationMs;
+        totalForegroundDurationUs += uid.getProcessStateTime(
+                BatteryStats.Uid.PROCESS_STATE_FOREGROUND_SERVICE, realtimeUs,
+                BatteryStats.STATS_SINCE_CHARGED);
+
+        return totalForegroundDurationUs / 1000;
     }
 
     private long getProcessBackgroundTimeMs(BatteryStats.Uid uid, long realtimeUs) {
diff --git a/core/java/com/android/internal/util/ContrastColorUtil.java b/core/java/com/android/internal/util/ContrastColorUtil.java
index 8508a8d..8b3c133 100644
--- a/core/java/com/android/internal/util/ContrastColorUtil.java
+++ b/core/java/com/android/internal/util/ContrastColorUtil.java
@@ -595,7 +595,9 @@
         if (backgroundColor == Notification.COLOR_DEFAULT) {
             return !defaultBackgroundIsDark;
         }
-        return ColorUtilsFromCompat.calculateLuminance(backgroundColor) > 0.5;
+        // Color contrast ratio luminance midpoint, X: 1.05 / (X + 0.05) = (X + 0.05) / 0.05
+        // Solved as X = sqrt(.05 * 1.05) - 0.05 = 0.17912878474
+        return ColorUtilsFromCompat.calculateLuminance(backgroundColor) > 0.17912878474;
     }
 
     public static double calculateLuminance(int backgroundColor) {
@@ -619,6 +621,7 @@
     }
 
     public static boolean isColorLight(int backgroundColor) {
+        // TODO(b/188947832): Use 0.17912878474 instead of 0.5 to ensure better contrast
         return calculateLuminance(backgroundColor) > 0.5f;
     }
 
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-night/colors.xml b/core/res/res/values-night/colors.xml
index baffa5a..816ddd4 100644
--- a/core/res/res/values-night/colors.xml
+++ b/core/res/res/values-night/colors.xml
@@ -17,14 +17,6 @@
   NOTE: You might also want to edit: packages/SystemUI/res/values-night/colors.xml
   -->
 <resources>
-    <!-- The primary text color if the text is on top of a dark background.
-    This is also affects colorized notifications with dark backgrounds. -->
-    <color name="notification_primary_text_color_dark">#ddffffff</color>
-
-    <!-- The secondary text color if the text is on top of a dark background. -->
-    <color name="notification_secondary_text_color_dark">#b2ffffff</color>
-
-    <color name="notification_default_color_dark">#ddffffff</color>
 
     <color name="notification_primary_text_color_current">@color/notification_primary_text_color_dark</color>
     <color name="notification_secondary_text_color_current">@color/notification_secondary_text_color_dark</color>
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/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
index c207135..0c7218e 100644
--- a/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
+++ b/core/tests/batterystatstests/BatteryStatsViewer/src/com/android/frameworks/core/batterystatsviewer/BatteryConsumerData.java
@@ -124,7 +124,8 @@
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
             final String metricTitle = getPowerMetricTitle(component);
             final int powerModel = requestedBatteryConsumer.getPowerModel(component);
-            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE
+                    || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
                 addEntry(metricTitle, EntryType.UID_POWER_MODELED,
                         requestedBatteryConsumer.getConsumedPower(component),
                         totalPowerByComponentMah[component]
@@ -202,7 +203,8 @@
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
             final String metricTitle = getPowerMetricTitle(component);
             final int powerModel = deviceBatteryConsumer.getPowerModel(component);
-            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+            if (powerModel == BatteryConsumer.POWER_MODEL_POWER_PROFILE
+                    || powerModel == BatteryConsumer.POWER_MODEL_UNDEFINED) {
                 addEntry(metricTitle, EntryType.DEVICE_POWER_MODELED,
                         deviceBatteryConsumer.getConsumedPower(component),
                         appsBatteryConsumer.getConsumedPower(component));
@@ -237,8 +239,9 @@
 
     private boolean isPowerProfileModelsOnly(BatteryConsumer batteryConsumer) {
         for (int component = 0; component < BatteryConsumer.POWER_COMPONENT_COUNT; component++) {
-            if (batteryConsumer.getPowerModel(component)
-                    != BatteryConsumer.POWER_MODEL_POWER_PROFILE) {
+            final int powerModel = batteryConsumer.getPowerModel(component);
+            if (powerModel != BatteryConsumer.POWER_MODEL_POWER_PROFILE
+                    && powerModel != BatteryConsumer.POWER_MODEL_UNDEFINED) {
                 return false;
             }
         }
diff --git a/core/tests/coretests/Android.bp b/core/tests/coretests/Android.bp
index 415b1f2..93e4a29 100644
--- a/core/tests/coretests/Android.bp
+++ b/core/tests/coretests/Android.bp
@@ -41,6 +41,7 @@
         "frameworks-core-util-lib",
         "mockwebserver",
         "guava",
+        "androidx.core_core",
         "androidx.test.espresso.core",
         "androidx.test.ext.junit",
         "androidx.test.runner",
diff --git a/core/tests/coretests/AndroidManifest.xml b/core/tests/coretests/AndroidManifest.xml
index 520d2f1..14a3a01 100644
--- a/core/tests/coretests/AndroidManifest.xml
+++ b/core/tests/coretests/AndroidManifest.xml
@@ -156,6 +156,9 @@
     <!-- Allow use of PendingIntent.getIntent() -->
     <uses-permission android:name="android.permission.GET_INTENT_SENDER_INTENT" />
 
+    <!-- ChooserActivityTest permissions-->
+    <uses-permission android:name="android.permission.SET_CLIP_SOURCE" />
+
     <application android:theme="@style/Theme" android:supportsRtl="true">
         <uses-library android:name="android.test.runner" />
         <uses-library android:name="org.apache.http.legacy" android:required="false" />
diff --git a/core/tests/coretests/src/android/app/NotificationTest.java b/core/tests/coretests/src/android/app/NotificationTest.java
index 0f8c9e2..cd07d46 100644
--- a/core/tests/coretests/src/android/app/NotificationTest.java
+++ b/core/tests/coretests/src/android/app/NotificationTest.java
@@ -16,6 +16,14 @@
 
 package android.app;
 
+import static androidx.core.graphics.ColorUtils.calculateContrast;
+
+import static com.android.compatibility.common.util.SystemUtil.runShellCommand;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static junit.framework.Assert.fail;
+
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertFalse;
 import static org.junit.Assert.assertNotSame;
@@ -27,10 +35,10 @@
 import android.content.Context;
 import android.content.Intent;
 import android.content.LocusId;
+import android.content.res.Configuration;
 import android.graphics.BitmapFactory;
 import android.graphics.Color;
 import android.graphics.drawable.Icon;
-import android.media.session.MediaSession;
 import android.os.Build;
 import android.os.Parcel;
 import android.os.Parcelable;
@@ -325,13 +333,142 @@
         assertNull(clone.getLocusId());
     }
 
-    private Notification.Builder getMediaNotification() {
-        MediaSession session = new MediaSession(mContext, "test");
-        return new Notification.Builder(mContext, "color")
-                .setSmallIcon(com.android.internal.R.drawable.emergency_icon)
-                .setContentTitle("Title")
-                .setContentText("Text")
-                .setStyle(new Notification.MediaStyle().setMediaSession(session.getSessionToken()));
+    @Test
+    public void testColors_ensureColors_dayMode_producesValidPalette() {
+        Notification.Colors c = new Notification.Colors();
+        boolean colorized = false;
+        boolean nightMode = false;
+        resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized);
+        assertValid(c);
+    }
+
+    @Test
+    public void testColors_ensureColors_nightMode_producesValidPalette() {
+        Notification.Colors c = new Notification.Colors();
+        boolean colorized = false;
+        boolean nightMode = true;
+        resolveColorsInNightMode(nightMode, c, Color.BLUE, colorized);
+        assertValid(c);
+    }
+
+    @Test
+    public void testColors_ensureColors_colorized_producesValidPalette_default() {
+        validateColorizedPaletteForColor(Notification.COLOR_DEFAULT);
+    }
+
+    @Test
+    public void testColors_ensureColors_colorized_producesValidPalette_blue() {
+        validateColorizedPaletteForColor(Color.BLUE);
+    }
+
+    @Test
+    public void testColors_ensureColors_colorized_producesValidPalette_red() {
+        validateColorizedPaletteForColor(Color.RED);
+    }
+
+    @Test
+    public void testColors_ensureColors_colorized_producesValidPalette_white() {
+        validateColorizedPaletteForColor(Color.WHITE);
+    }
+
+    @Test
+    public void testColors_ensureColors_colorized_producesValidPalette_black() {
+        validateColorizedPaletteForColor(Color.BLACK);
+    }
+
+    public void validateColorizedPaletteForColor(int rawColor) {
+        Notification.Colors cDay = new Notification.Colors();
+        Notification.Colors cNight = new Notification.Colors();
+        boolean colorized = true;
+
+        resolveColorsInNightMode(false, cDay, rawColor, colorized);
+        resolveColorsInNightMode(true, cNight, rawColor, colorized);
+
+        if (rawColor != Notification.COLOR_DEFAULT) {
+            assertEquals(rawColor, cDay.getBackgroundColor());
+            assertEquals(rawColor, cNight.getBackgroundColor());
+        }
+
+        assertValid(cDay);
+        assertValid(cNight);
+
+        if (rawColor != Notification.COLOR_DEFAULT) {
+            // When a color is provided, night mode should have no effect on the notification
+            assertEquals(cDay.getBackgroundColor(), cNight.getBackgroundColor());
+            assertEquals(cDay.getPrimaryTextColor(), cNight.getPrimaryTextColor());
+            assertEquals(cDay.getSecondaryTextColor(), cNight.getSecondaryTextColor());
+            assertEquals(cDay.getPrimaryAccentColor(), cNight.getPrimaryAccentColor());
+            assertEquals(cDay.getSecondaryAccentColor(), cNight.getSecondaryAccentColor());
+            assertEquals(cDay.getProtectionColor(), cNight.getProtectionColor());
+            assertEquals(cDay.getContrastColor(), cNight.getContrastColor());
+            assertEquals(cDay.getRippleAlpha(), cNight.getRippleAlpha());
+        }
+    }
+
+    private void assertValid(Notification.Colors c) {
+        // Assert that all colors are populated
+        assertThat(c.getBackgroundColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getProtectionColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getPrimaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getSecondaryTextColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getPrimaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getSecondaryAccentColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getErrorColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getContrastColor()).isNotEqualTo(Notification.COLOR_INVALID);
+        assertThat(c.getRippleAlpha()).isAtLeast(0x00);
+        assertThat(c.getRippleAlpha()).isAtMost(0xff);
+
+        // Assert that various colors have sufficient contrast
+        assertContrastIsAtLeast(c.getPrimaryTextColor(), c.getBackgroundColor(), 4.5);
+        assertContrastIsAtLeast(c.getSecondaryTextColor(), c.getBackgroundColor(), 4.5);
+        assertContrastIsAtLeast(c.getPrimaryAccentColor(), c.getBackgroundColor(), 4.5);
+        assertContrastIsAtLeast(c.getErrorColor(), c.getBackgroundColor(), 4.5);
+        assertContrastIsAtLeast(c.getContrastColor(), c.getBackgroundColor(), 4.5);
+
+        // This accent color is only used for emphasized buttons
+        assertContrastIsAtLeast(c.getSecondaryAccentColor(), c.getBackgroundColor(), 1);
+    }
+
+    private void assertContrastIsAtLeast(int foreground, int background, double minContrast) {
+        try {
+            assertThat(calculateContrast(foreground, background)).isAtLeast(minContrast);
+        } catch (AssertionError e) {
+            throw new AssertionError(
+                    String.format("Insufficient contrast: foreground=#%08x background=#%08x",
+                            foreground, background), e);
+        }
+    }
+
+    private void resolveColorsInNightMode(boolean nightMode, Notification.Colors c, int rawColor,
+            boolean colorized) {
+        runInNightMode(nightMode,
+                () -> c.resolvePalette(mContext, rawColor, colorized, nightMode));
+    }
+
+    private void runInNightMode(boolean nightMode, Runnable task) {
+        final String initialNightMode = changeNightMode(nightMode);
+        try {
+            Configuration currentConfig = mContext.getResources().getConfiguration();
+            boolean isNightMode = (currentConfig.uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                    == Configuration.UI_MODE_NIGHT_YES;
+            assertEquals(nightMode, isNightMode);
+            task.run();
+        } finally {
+            runShellCommand("cmd uimode night " + initialNightMode);
+        }
+    }
+
+
+    // Change the night mode and return the previous mode
+    private String changeNightMode(boolean nightMode) {
+        final String nightModeText = runShellCommand("cmd uimode night");
+        final String[] nightModeSplit = nightModeText.split(":");
+        if (nightModeSplit.length != 2) {
+            fail("Failed to get initial night mode value from " + nightModeText);
+        }
+        String previousMode = nightModeSplit[1].trim();
+        runShellCommand("cmd uimode night " + (nightMode ? "yes" : "no"));
+        return previousMode;
     }
 
     /**
diff --git a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
index 613232f..8fd1af8 100644
--- a/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
+++ b/core/tests/coretests/src/android/view/InsetsAnimationControlImplTest.java
@@ -110,7 +110,7 @@
         mController = new InsetsAnimationControlImpl(controls,
                 new Rect(0, 0, 500, 500), mInsetsState, mMockListener, systemBars(),
                 mMockController, 10 /* durationMs */, new LinearInterpolator(),
-                0 /* animationType */, null /* translator */);
+                0 /* animationType */, 0 /* layoutInsetsDuringAnimation */, null /* translator */);
         mController.mReadyDispatched = true;
     }
 
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/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
index 1633d28..19c2763 100644
--- a/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
+++ b/core/tests/coretests/src/com/android/internal/app/ChooserActivityTest.java
@@ -16,6 +16,8 @@
 
 package com.android.internal.app;
 
+import static android.app.Activity.RESULT_OK;
+
 import static androidx.test.espresso.Espresso.onView;
 import static androidx.test.espresso.action.ViewActions.click;
 import static androidx.test.espresso.action.ViewActions.swipeUp;
@@ -558,6 +560,8 @@
 
         ClipDescription clipDescription = clipData.getDescription();
         assertThat("text/plain", is(clipDescription.getMimeType(0)));
+
+        assertEquals(mActivityRule.getActivityResult().getResultCode(), RESULT_OK);
     }
 
     @Test
diff --git a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
index 7f0449b..d83645d 100644
--- a/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
+++ b/core/tests/coretests/src/com/android/internal/os/BatteryUsageStatsProviderTest.java
@@ -59,8 +59,14 @@
                 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
         batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_SERVICE,
                 30 * MINUTE_IN_MS, 30 * MINUTE_IN_MS);
-        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+        batteryStats.noteUidProcessStateLocked(APP_UID,
+                ActivityManager.PROCESS_STATE_FOREGROUND_SERVICE,
                 40 * MINUTE_IN_MS, 40 * MINUTE_IN_MS);
+        batteryStats.noteUidProcessStateLocked(APP_UID,
+                ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE,
+                50 * MINUTE_IN_MS, 50 * MINUTE_IN_MS);
+        batteryStats.noteUidProcessStateLocked(APP_UID, ActivityManager.PROCESS_STATE_CACHED_EMPTY,
+                80 * MINUTE_IN_MS, 80 * MINUTE_IN_MS);
 
         mStatsRule.setCurrentTime(54321);
 
@@ -74,7 +80,7 @@
                 batteryUsageStats.getUidBatteryConsumers();
         final UidBatteryConsumer uidBatteryConsumer = uidBatteryConsumers.get(0);
         assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_FOREGROUND))
-                .isEqualTo(20 * MINUTE_IN_MS);
+                .isEqualTo(60 * MINUTE_IN_MS);
         assertThat(uidBatteryConsumer.getTimeInStateMs(UidBatteryConsumer.STATE_BACKGROUND))
                 .isEqualTo(10 * MINUTE_IN_MS);
 
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/graphics/java/android/graphics/drawable/RippleAnimationSession.java b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
index ee867dd..55fb83c 100644
--- a/graphics/java/android/graphics/drawable/RippleAnimationSession.java
+++ b/graphics/java/android/graphics/drawable/RippleAnimationSession.java
@@ -40,9 +40,9 @@
 public final class RippleAnimationSession {
     private static final String TAG = "RippleAnimationSession";
     private static final int ENTER_ANIM_DURATION = 450;
-    private static final int EXIT_ANIM_DURATION = 225;
+    private static final int EXIT_ANIM_DURATION = 375;
     private static final long NOISE_ANIMATION_DURATION = 7000;
-    private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 120;
+    private static final long MAX_NOISE_PHASE = NOISE_ANIMATION_DURATION / 214;
     private static final TimeInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
     private static final Interpolator FAST_OUT_SLOW_IN =
             new PathInterpolator(0.4f, 0f, 0.2f, 1f);
@@ -61,12 +61,12 @@
     }
 
     @NonNull RippleAnimationSession enter(Canvas canvas) {
+        mStartTime = AnimationUtils.currentAnimationTimeMillis();
         if (isHwAccelerated(canvas)) {
             enterHardware((RecordingCanvas) canvas);
         } else {
             enterSoftware();
         }
-        mStartTime = AnimationUtils.currentAnimationTimeMillis();
         return this;
     }
 
@@ -160,7 +160,8 @@
         RenderNodeAnimator expand =
                 new RenderNodeAnimator(props.getProgress(), .5f);
         expand.setTarget(canvas);
-        RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(), MAX_NOISE_PHASE);
+        RenderNodeAnimator loop = new RenderNodeAnimator(props.getNoisePhase(),
+                mStartTime + MAX_NOISE_PHASE);
         loop.setTarget(canvas);
         startAnimation(expand, loop);
     }
@@ -190,7 +191,7 @@
             notifyUpdate();
             mProperties.getShader().setProgress((float) expand.getAnimatedValue());
         });
-        ValueAnimator loop = ValueAnimator.ofFloat(0f, MAX_NOISE_PHASE);
+        ValueAnimator loop = ValueAnimator.ofFloat(mStartTime, mStartTime + MAX_NOISE_PHASE);
         loop.addUpdateListener(updatedAnimation -> {
             notifyUpdate();
             mProperties.getShader().setNoisePhase((float) loop.getAnimatedValue());
diff --git a/graphics/java/android/graphics/drawable/RippleDrawable.java b/graphics/java/android/graphics/drawable/RippleDrawable.java
index 518fceb..be45f18 100644
--- a/graphics/java/android/graphics/drawable/RippleDrawable.java
+++ b/graphics/java/android/graphics/drawable/RippleDrawable.java
@@ -50,6 +50,7 @@
 import android.graphics.Shader;
 import android.os.Build;
 import android.util.AttributeSet;
+import android.view.animation.AnimationUtils;
 import android.view.animation.LinearInterpolator;
 
 import com.android.internal.R;
@@ -151,7 +152,7 @@
     /** The maximum number of ripples supported. */
     private static final int MAX_RIPPLES = 10;
     private static final LinearInterpolator LINEAR_INTERPOLATOR = new LinearInterpolator();
-    private static final int DEFAULT_EFFECT_COLOR = 0x80ffffff;
+    private static final int DEFAULT_EFFECT_COLOR = 0x8dffffff;
     /** Temporary flag for teamfood. **/
     private static final boolean FORCE_PATTERNED_STYLE = true;
 
@@ -970,15 +971,16 @@
                 ? mState.mColor.getColorForState(getState(), Color.BLACK)
                 : mMaskColorFilter.getColor());
         final int effectColor = mState.mEffectColor.getColorForState(getState(), Color.MAGENTA);
+        final float noisePhase = AnimationUtils.currentAnimationTimeMillis();
         shader.setColor(color, effectColor);
         shader.setOrigin(cx, cy);
         shader.setTouch(x, y);
         shader.setResolution(w, h, mState.mDensity);
-        shader.setNoisePhase(0);
+        shader.setNoisePhase(noisePhase);
         shader.setRadius(radius);
         shader.setProgress(.0f);
         properties = new RippleAnimationSession.AnimationProperties<>(
-                cx, cy, radius, 0f, p, 0f, color, shader);
+                cx, cy, radius, noisePhase, p, 0f, color, shader);
         if (mMaskShader == null) {
             shader.setShader(null);
         } else {
diff --git a/graphics/java/android/graphics/drawable/RippleShader.java b/graphics/java/android/graphics/drawable/RippleShader.java
index e5651e0..eb726c1 100644
--- a/graphics/java/android/graphics/drawable/RippleShader.java
+++ b/graphics/java/android/graphics/drawable/RippleShader.java
@@ -58,7 +58,7 @@
             + "  float s = 0.0;\n"
             + "  for (float i = 0; i < 4; i += 1) {\n"
             + "    float l = i * 0.1;\n"
-            + "    float h = l + 0.025;\n"
+            + "    float h = l + 0.05;\n"
             + "    float o = sin(PI * (t + 0.35 * i));\n"
             + "    s += threshold(n + o, l, h);\n"
             + "  }\n"
@@ -70,7 +70,7 @@
             + "  return 1. - smoothstep(1. - blurHalf, 1. + blurHalf, d / radius);\n"
             + "}\n"
             + "float softRing(vec2 uv, vec2 xy, float radius, float progress, float blur) {\n"
-            + "  float thickness = 0.3 * radius;\n"
+            + "  float thickness = 0.05 * radius;\n"
             + "  float currentRadius = radius * progress;\n"
             + "  float circle_outer = softCircle(uv, xy, currentRadius + thickness, blur);\n"
             + "  float circle_inner = softCircle(uv, xy, max(currentRadius - thickness, 0.), "
@@ -93,7 +93,7 @@
             + "  return softCircle(coord, vec2(normal_radius), radius, radius * 50.0);\n"
             + "}\n"
             + "float turbulence(vec2 uv, float t) {\n"
-            + "  const vec2 scale = vec2(1.5);\n"
+            + "  const vec2 scale = vec2(0.8);\n"
             + "  uv = uv * scale;\n"
             + "  float g1 = circle_grid(scale, uv, t, in_tCircle1, in_tRotation1, 0.17);\n"
             + "  float g2 = circle_grid(scale, uv, t, in_tCircle2, in_tRotation2, 0.2);\n"
@@ -102,12 +102,12 @@
             + "  return saturate(0.45 + 0.8 * v);\n"
             + "}\n";
     private static final String SHADER_MAIN = "vec4 main(vec2 p) {\n"
-            + "    float fadeIn = subProgress(0., 0.1, in_progress);\n"
-            + "    float scaleIn = subProgress(0., 0.45, in_progress);\n"
-            + "    float fadeOutNoise = subProgress(0.5, 0.95, in_progress);\n"
-            + "    float fadeOutRipple = subProgress(0.5, 1., in_progress);\n"
-            + "    vec2 center = mix(in_touch, in_origin, scaleIn);\n"
-            + "    float ring = softRing(p, center, in_maxRadius, scaleIn, 0.45);\n"
+            + "    float fadeIn = subProgress(0., 0.13, in_progress);\n"
+            + "    float scaleIn = subProgress(0., 1.0, in_progress);\n"
+            + "    float fadeOutNoise = subProgress(0.4, 0.5, in_progress);\n"
+            + "    float fadeOutRipple = subProgress(0.4, 1., in_progress);\n"
+            + "    vec2 center = mix(in_touch, in_origin, saturate(in_progress * 2.0));\n"
+            + "    float ring = softRing(p, center, in_maxRadius, scaleIn, 1.);\n"
             + "    float alpha = min(fadeIn, 1. - fadeOutNoise);\n"
             + "    vec2 uv = p * in_resolutionScale;\n"
             + "    vec2 densityUv = uv - mod(uv, in_noiseScale);\n"
@@ -115,7 +115,7 @@
             + "    float sparkleAlpha = sparkles(densityUv, in_noisePhase) * ring * alpha "
             + "* turbulence;\n"
             + "    float fade = min(fadeIn, 1. - fadeOutRipple);\n"
-            + "    float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 0.2) * fade "
+            + "    float waveAlpha = softCircle(p, center, in_maxRadius * scaleIn, 1.) * fade "
             + "* in_color.a;\n"
             + "    vec4 waveColor = vec4(in_color.rgb * waveAlpha, waveAlpha);\n"
             + "    vec4 sparkleColor = vec4(in_sparkleColor.rgb * in_sparkleColor.a, "
@@ -139,7 +139,7 @@
     }
 
     public void setRadius(float radius) {
-        setUniform("in_maxRadius", radius);
+        setUniform("in_maxRadius", radius * 2.3f);
     }
 
     public void setOrigin(float x, float y) {
@@ -205,7 +205,7 @@
     }
 
     public void setResolution(float w, float h, int density) {
-        final float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE;
+        final float densityScale = density * DisplayMetrics.DENSITY_DEFAULT_SCALE * 0.8f;
         setUniform("in_resolutionScale", new float[] {1f / w, 1f / h});
         setUniform("in_noiseScale", new float[] {densityScale / w, densityScale / h});
     }
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..1a03ebd 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);
     }
 
@@ -372,6 +375,7 @@
         if (preView != null && preView.mContentView != null
                 && preView.mContentView.isCopyable()) {
             parcelable = new SplashScreenViewParcelable(preView.mContentView);
+            preView.mContentView.onCopied();
         } else {
             parcelable = null;
         }
@@ -382,7 +386,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 +405,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 +473,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/libs/hwui/HardwareBitmapUploader.cpp b/libs/hwui/HardwareBitmapUploader.cpp
index 859a555..db3a108 100644
--- a/libs/hwui/HardwareBitmapUploader.cpp
+++ b/libs/hwui/HardwareBitmapUploader.cpp
@@ -24,10 +24,10 @@
 #include <GrDirectContext.h>
 #include <SkCanvas.h>
 #include <SkImage.h>
+#include <gui/TraceUtils.h>
 #include <utils/GLUtils.h>
 #include <utils/NdkUtils.h>
 #include <utils/Trace.h>
-#include <utils/TraceUtils.h>
 
 #include <thread>
 
diff --git a/libs/hwui/Readback.cpp b/libs/hwui/Readback.cpp
index a9b129f..8a8b418 100644
--- a/libs/hwui/Readback.cpp
+++ b/libs/hwui/Readback.cpp
@@ -19,6 +19,7 @@
 #include <sync/sync.h>
 #include <system/window.h>
 
+#include <gui/TraceUtils.h>
 #include "DeferredLayerUpdater.h"
 #include "Properties.h"
 #include "hwui/Bitmap.h"
@@ -28,7 +29,6 @@
 #include "utils/Color.h"
 #include "utils/MathUtils.h"
 #include "utils/NdkUtils.h"
-#include "utils/TraceUtils.h"
 
 using namespace android::uirenderer::renderthread;
 
diff --git a/libs/hwui/RenderNode.cpp b/libs/hwui/RenderNode.cpp
index ded7994..9a9e6d4 100644
--- a/libs/hwui/RenderNode.cpp
+++ b/libs/hwui/RenderNode.cpp
@@ -27,9 +27,9 @@
 #include "DamageAccumulator.h"
 #include "pipeline/skia/SkiaDisplayList.h"
 #endif
+#include <gui/TraceUtils.h>
 #include "utils/MathUtils.h"
 #include "utils/StringUtils.h"
-#include "utils/TraceUtils.h"
 
 #include <SkPathOps.h>
 #include <algorithm>
diff --git a/libs/hwui/VectorDrawable.cpp b/libs/hwui/VectorDrawable.cpp
index 4a21ad6..55f434f 100644
--- a/libs/hwui/VectorDrawable.cpp
+++ b/libs/hwui/VectorDrawable.cpp
@@ -30,8 +30,8 @@
 #include "renderthread/RenderThread.h"
 #endif
 
+#include <gui/TraceUtils.h>
 #include "utils/Macros.h"
-#include "utils/TraceUtils.h"
 #include "utils/VectorDrawableUtils.h"
 
 namespace android {
diff --git a/libs/hwui/hwui/AnimatedImageDrawable.cpp b/libs/hwui/hwui/AnimatedImageDrawable.cpp
index 0d3d3e3..876f5c8 100644
--- a/libs/hwui/hwui/AnimatedImageDrawable.cpp
+++ b/libs/hwui/hwui/AnimatedImageDrawable.cpp
@@ -19,7 +19,7 @@
 #include "AnimatedImageThread.h"
 #endif
 
-#include "utils/TraceUtils.h"
+#include <gui/TraceUtils.h>
 #include "pipeline/skia/SkiaUtils.h"
 
 #include <SkPicture.h>
diff --git a/libs/hwui/jni/Typeface.cpp b/libs/hwui/jni/Typeface.cpp
index f928baa..ee7b260 100644
--- a/libs/hwui/jni/Typeface.cpp
+++ b/libs/hwui/jni/Typeface.cpp
@@ -15,19 +15,19 @@
  */
 
 #define ATRACE_TAG ATRACE_TAG_VIEW
-#include "FontUtils.h"
-#include "GraphicsJNI.h"
-#include "fonts/Font.h"
-#include <nativehelper/ScopedPrimitiveArray.h>
-#include <nativehelper/ScopedUtfChars.h>
-#include "SkData.h"
-#include "SkTypeface.h"
+#include <gui/TraceUtils.h>
 #include <hwui/Typeface.h>
 #include <minikin/FontCollection.h>
 #include <minikin/FontFamily.h>
 #include <minikin/FontFileParser.h>
 #include <minikin/SystemFonts.h>
-#include <utils/TraceUtils.h>
+#include <nativehelper/ScopedPrimitiveArray.h>
+#include <nativehelper/ScopedUtfChars.h>
+#include "FontUtils.h"
+#include "GraphicsJNI.h"
+#include "SkData.h"
+#include "SkTypeface.h"
+#include "fonts/Font.h"
 
 #include <mutex>
 #include <unordered_map>
@@ -37,7 +37,6 @@
 #endif
 
 using namespace android;
-using android::uirenderer::TraceUtils;
 
 static inline Typeface* toTypeface(jlong ptr) {
     return reinterpret_cast<Typeface*>(ptr);
diff --git a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
index 82bc5a1..4289c45 100644
--- a/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
+++ b/libs/hwui/jni/android_graphics_HardwareRenderer.cpp
@@ -24,6 +24,7 @@
 #include <Properties.h>
 #include <RootRenderNode.h>
 #include <dlfcn.h>
+#include <gui/TraceUtils.h>
 #include <inttypes.h>
 #include <media/NdkImage.h>
 #include <media/NdkImageReader.h>
@@ -39,7 +40,6 @@
 #include <utils/RefBase.h>
 #include <utils/StrongPointer.h>
 #include <utils/Timers.h>
-#include <utils/TraceUtils.h>
 
 #include <pthread.h>
 
diff --git a/libs/hwui/jni/android_graphics_RenderNode.cpp b/libs/hwui/jni/android_graphics_RenderNode.cpp
index 002bd83..e1da169 100644
--- a/libs/hwui/jni/android_graphics_RenderNode.cpp
+++ b/libs/hwui/jni/android_graphics_RenderNode.cpp
@@ -26,8 +26,8 @@
 #endif
 #include <TreeInfo.h>
 #include <effects/StretchEffect.h>
+#include <gui/TraceUtils.h>
 #include <hwui/Paint.h>
-#include <utils/TraceUtils.h>
 
 namespace android {
 
diff --git a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
index c8247e7..d7546d8 100644
--- a/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
+++ b/libs/hwui/pipeline/skia/RenderNodeDrawable.cpp
@@ -16,11 +16,11 @@
 
 #include "RenderNodeDrawable.h"
 #include <SkPaintFilterCanvas.h>
-#include "StretchMask.h"
+#include <gui/TraceUtils.h>
 #include "RenderNode.h"
 #include "SkiaDisplayList.h"
+#include "StretchMask.h"
 #include "TransformCanvas.h"
-#include "utils/TraceUtils.h"
 
 #include <include/effects/SkImageFilters.h>
 
diff --git a/libs/hwui/pipeline/skia/ShaderCache.cpp b/libs/hwui/pipeline/skia/ShaderCache.cpp
index 3baff7e..c482fc1 100644
--- a/libs/hwui/pipeline/skia/ShaderCache.cpp
+++ b/libs/hwui/pipeline/skia/ShaderCache.cpp
@@ -16,6 +16,7 @@
 
 #include "ShaderCache.h"
 #include <GrDirectContext.h>
+#include <gui/TraceUtils.h>
 #include <log/log.h>
 #include <openssl/sha.h>
 #include <algorithm>
@@ -23,7 +24,6 @@
 #include <thread>
 #include "FileBlobCache.h"
 #include "Properties.h"
-#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
index 50eea31..a78cd83 100644
--- a/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaOpenGLPipeline.cpp
@@ -16,6 +16,7 @@
 
 #include "SkiaOpenGLPipeline.h"
 
+#include <gui/TraceUtils.h>
 #include "DeferredLayerUpdater.h"
 #include "LayerDrawable.h"
 #include "LightingInfo.h"
@@ -27,7 +28,6 @@
 #include "renderthread/EglManager.h"
 #include "renderthread/Frame.h"
 #include "utils/GLUtils.h"
-#include "utils/TraceUtils.h"
 
 #include <GLES3/gl3.h>
 
diff --git a/libs/hwui/pipeline/skia/SkiaPipeline.cpp b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
index 1f73ac9..039b0f9 100644
--- a/libs/hwui/pipeline/skia/SkiaPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaPipeline.cpp
@@ -31,13 +31,13 @@
 
 #include <sstream>
 
+#include <gui/TraceUtils.h>
 #include "LightingInfo.h"
 #include "VectorDrawable.h"
 #include "thread/CommonPool.h"
 #include "tools/SkSharingProc.h"
 #include "utils/Color.h"
 #include "utils/String8.h"
-#include "utils/TraceUtils.h"
 
 using namespace android::uirenderer::renderthread;
 
diff --git a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
index 30a3fc5..0e4a1f9 100644
--- a/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
+++ b/libs/hwui/pipeline/skia/SkiaVulkanPipeline.cpp
@@ -16,6 +16,7 @@
 
 #include "SkiaVulkanPipeline.h"
 
+#include <gui/TraceUtils.h>
 #include "DeferredLayerUpdater.h"
 #include "LightingInfo.h"
 #include "Readback.h"
@@ -25,7 +26,6 @@
 #include "VkInteropFunctorDrawable.h"
 #include "renderstate/RenderState.h"
 #include "renderthread/Frame.h"
-#include "utils/TraceUtils.h"
 
 #include <SkSurface.h>
 #include <SkTypes.h>
diff --git a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
index 6efe176..8abf4534 100644
--- a/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkFunctorDrawable.cpp
@@ -21,9 +21,9 @@
 #include <SkAndroidFrameworkUtils.h>
 #include <SkImage.h>
 #include <SkM44.h>
+#include <gui/TraceUtils.h>
 #include <utils/Color.h>
 #include <utils/Trace.h>
-#include <utils/TraceUtils.h>
 #include <vk/GrVkTypes.h>
 #include <thread>
 #include "renderthread/RenderThread.h"
diff --git a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
index bae11f7..ddfb66f 100644
--- a/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
+++ b/libs/hwui/pipeline/skia/VkInteropFunctorDrawable.cpp
@@ -21,11 +21,11 @@
 #include <GLES2/gl2.h>
 #include <GLES2/gl2ext.h>
 #include <GLES3/gl3.h>
+#include <gui/TraceUtils.h>
 #include <private/hwui/DrawGlInfo.h>
 #include <utils/Color.h>
 #include <utils/GLUtils.h>
 #include <utils/Trace.h>
-#include <utils/TraceUtils.h>
 
 #include <thread>
 
diff --git a/libs/hwui/renderthread/CanvasContext.cpp b/libs/hwui/renderthread/CanvasContext.cpp
index c1f61e08..d317305 100644
--- a/libs/hwui/renderthread/CanvasContext.cpp
+++ b/libs/hwui/renderthread/CanvasContext.cpp
@@ -26,6 +26,7 @@
 #include <cstdlib>
 #include <functional>
 
+#include <gui/TraceUtils.h>
 #include "../Properties.h"
 #include "AnimationContext.h"
 #include "Frame.h"
@@ -39,7 +40,6 @@
 #include "thread/CommonPool.h"
 #include "utils/GLUtils.h"
 #include "utils/TimeUtils.h"
-#include "utils/TraceUtils.h"
 
 #define TRIM_MEMORY_COMPLETE 80
 #define TRIM_MEMORY_UI_HIDDEN 20
diff --git a/libs/hwui/renderthread/DrawFrameTask.cpp b/libs/hwui/renderthread/DrawFrameTask.cpp
index 8448b87..5c4b901 100644
--- a/libs/hwui/renderthread/DrawFrameTask.cpp
+++ b/libs/hwui/renderthread/DrawFrameTask.cpp
@@ -16,8 +16,8 @@
 
 #include "DrawFrameTask.h"
 
+#include <gui/TraceUtils.h>
 #include <utils/Log.h>
-#include <utils/TraceUtils.h>
 #include <algorithm>
 
 #include "../DeferredLayerUpdater.h"
diff --git a/libs/hwui/renderthread/RenderProxy.cpp b/libs/hwui/renderthread/RenderProxy.cpp
index 95aa29d..ac19a15 100644
--- a/libs/hwui/renderthread/RenderProxy.cpp
+++ b/libs/hwui/renderthread/RenderProxy.cpp
@@ -16,6 +16,7 @@
 
 #include "RenderProxy.h"
 
+#include <gui/TraceUtils.h>
 #include "DeferredLayerUpdater.h"
 #include "DisplayList.h"
 #include "Properties.h"
@@ -27,7 +28,6 @@
 #include "renderthread/RenderThread.h"
 #include "utils/Macros.h"
 #include "utils/TimeUtils.h"
-#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/renderthread/RenderThread.cpp b/libs/hwui/renderthread/RenderThread.cpp
index a648f98..4ba7748 100644
--- a/libs/hwui/renderthread/RenderThread.cpp
+++ b/libs/hwui/renderthread/RenderThread.cpp
@@ -16,6 +16,7 @@
 
 #include "RenderThread.h"
 
+#include <gui/TraceUtils.h>
 #include "../HardwareBitmapUploader.h"
 #include "CanvasContext.h"
 #include "DeviceInfo.h"
@@ -29,7 +30,6 @@
 #include "pipeline/skia/SkiaVulkanPipeline.h"
 #include "renderstate/RenderState.h"
 #include "utils/TimeUtils.h"
-#include "utils/TraceUtils.h"
 
 #include <GrContextOptions.h>
 #include <gl/GrGLInterface.h>
diff --git a/libs/hwui/renderthread/VulkanManager.cpp b/libs/hwui/renderthread/VulkanManager.cpp
index 07146e8..5a71833 100644
--- a/libs/hwui/renderthread/VulkanManager.cpp
+++ b/libs/hwui/renderthread/VulkanManager.cpp
@@ -29,11 +29,11 @@
 
 #include <cstring>
 
+#include <gui/TraceUtils.h>
 #include "Properties.h"
 #include "RenderThread.h"
 #include "pipeline/skia/ShaderCache.h"
 #include "renderstate/RenderState.h"
-#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/renderthread/VulkanSurface.cpp b/libs/hwui/renderthread/VulkanSurface.cpp
index c559425..01a2ec5 100644
--- a/libs/hwui/renderthread/VulkanSurface.cpp
+++ b/libs/hwui/renderthread/VulkanSurface.cpp
@@ -20,9 +20,9 @@
 #include <SkSurface.h>
 #include <algorithm>
 
+#include <gui/TraceUtils.h>
 #include "VulkanManager.h"
 #include "utils/Color.h"
-#include "utils/TraceUtils.h"
 
 namespace android {
 namespace uirenderer {
diff --git a/libs/hwui/tests/macrobench/TestSceneRunner.cpp b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
index b640b90..de2c621 100644
--- a/libs/hwui/tests/macrobench/TestSceneRunner.cpp
+++ b/libs/hwui/tests/macrobench/TestSceneRunner.cpp
@@ -14,6 +14,7 @@
  * limitations under the License.
  */
 
+#include <gui/TraceUtils.h>
 #include "AnimationContext.h"
 #include "RenderNode.h"
 #include "renderthread/RenderProxy.h"
@@ -21,7 +22,6 @@
 #include "tests/common/TestContext.h"
 #include "tests/common/TestScene.h"
 #include "tests/common/scenes/TestSceneBase.h"
-#include "utils/TraceUtils.h"
 
 #include <benchmark/benchmark.h>
 #include <gui/Surface.h>
diff --git a/libs/hwui/utils/TraceUtils.h b/libs/hwui/utils/TraceUtils.h
deleted file mode 100644
index e61b4be..0000000
--- a/libs/hwui/utils/TraceUtils.h
+++ /dev/null
@@ -1,57 +0,0 @@
-/*
- * Copyright (C) 2014 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-#ifndef TRACE_UTILS_H
-#define TRACE_UTILS_H
-
-#include <cutils/trace.h>
-#include <utils/Trace.h>
-
-#define ATRACE_FORMAT(fmt, ...)           \
-    TraceUtils::TraceEnder __traceEnder = \
-            (TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__), TraceUtils::TraceEnder())
-
-#define ATRACE_FORMAT_BEGIN(fmt, ...) TraceUtils::atraceFormatBegin(fmt, ##__VA_ARGS__)
-
-namespace android {
-namespace uirenderer {
-
-class TraceUtils {
-public:
-    class TraceEnder {
-    public:
-        ~TraceEnder() { ATRACE_END(); }
-    };
-
-    static void atraceFormatBegin(const char* fmt, ...) {
-        if (CC_LIKELY(!ATRACE_ENABLED())) return;
-
-        const int BUFFER_SIZE = 256;
-        va_list ap;
-        char buf[BUFFER_SIZE];
-
-        va_start(ap, fmt);
-        vsnprintf(buf, BUFFER_SIZE, fmt, ap);
-        va_end(ap);
-
-        ATRACE_BEGIN(buf);
-    }
-
-};  // class TraceUtils
-
-} /* namespace uirenderer */
-} /* namespace android */
-
-#endif /* TRACE_UTILS_H */
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/res/values-ar/strings.xml b/packages/SettingsLib/res/values-ar/strings.xml
index 4e30f38..8b703f6 100644
--- a/packages/SettingsLib/res/values-ar/strings.xml
+++ b/packages/SettingsLib/res/values-ar/strings.xml
@@ -515,7 +515,7 @@
     <string name="alarms_and_reminders_footer_title" product="device" msgid="349578867821273761">"يمكنك السماح لهذا التطبيق بضبط المنبّهات وجدولة الإجراءات الأخرى. قد يتم استخدام هذا التطبيق عند عدم استخدامك للجهاز، مما قد يستهلك المزيد من شحن البطارية. إذا كان هذا الإذن غير مفعّل، قد لا يعمل هذا التطبيق بشكل طبيعي ولن تعمل المنبّهات فيه كما هو مقرر."</string>
     <string name="keywords_alarms_and_reminders" msgid="6633360095891110611">"جدول زمني، جدولة، منبّه، تذكير، ساعة"</string>
     <string name="zen_mode_enable_dialog_turn_on" msgid="6418297231575050426">"تفعيل"</string>
-    <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل وضع \"الرجاء عدم الإزعاج\""</string>
+    <string name="zen_mode_settings_turn_on_dialog_title" msgid="2760567063190790696">"تفعيل ميزة \"عدم الإزعاج\""</string>
     <string name="zen_mode_settings_summary_off" msgid="3832876036123504076">"مطلقًا"</string>
     <string name="zen_interruption_level_priority" msgid="5392140786447823299">"الأولوية فقط"</string>
     <string name="zen_mode_and_condition" msgid="8877086090066332516">"<xliff:g id="ZEN_MODE">%1$s</xliff:g>. <xliff:g id="EXIT_CONDITION">%2$s</xliff:g>"</string>
diff --git a/packages/SettingsLib/res/values-fr-rCA/strings.xml b/packages/SettingsLib/res/values-fr-rCA/strings.xml
index 36bdf47..e5aa95d 100644
--- a/packages/SettingsLib/res/values-fr-rCA/strings.xml
+++ b/packages/SettingsLib/res/values-fr-rCA/strings.xml
@@ -284,7 +284,7 @@
     <string name="wifi_display_certification_summary" msgid="8111151348106907513">"Afficher les options pour la certification d\'affichage sans fil"</string>
     <string name="wifi_verbose_logging_summary" msgid="4993823188807767892">"Détailler davantage les données Wi-Fi, afficher par SSID RSSI dans sélect. Wi-Fi"</string>
     <string name="wifi_scan_throttling_summary" msgid="2577105472017362814">"Réduit l\'utilisation de la pile et améliore les performances réseau"</string>
-    <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecter à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
+    <string name="wifi_enhanced_mac_randomization_summary" msgid="1210663439867489931">"Lorsque ce mode est activé, l\'adresse MAC de cet appareil pourrait changer chaque fois qu\'il se connecte à un réseau sur lequel la sélection aléatoire des adresses MAC est activée."</string>
     <string name="wifi_metered_label" msgid="8737187690304098638">"Facturé à l\'usage"</string>
     <string name="wifi_unmetered_label" msgid="6174142840934095093">"Non mesuré"</string>
     <string name="select_logd_size_title" msgid="1604578195914595173">"Tailles des mémoires tampons d\'enregistreur"</string>
@@ -376,7 +376,7 @@
     <string name="force_allow_on_external" msgid="9187902444231637880">"Forcer l\'autor. d\'applis sur stockage externe"</string>
     <string name="force_allow_on_external_summary" msgid="8525425782530728238">"Rend possible l\'enregistrement de toute application sur un espace de stockage externe, indépendamment des valeurs du fichier manifeste"</string>
     <string name="force_resizable_activities" msgid="7143612144399959606">"Forcer les activités à être redimensionnables"</string>
-    <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multifenêtre, indépendamment des valeurs du fichier manifeste."</string>
+    <string name="force_resizable_activities_summary" msgid="2490382056981583062">"Permet de redimensionner toutes les activités pour le mode multi-fenêtre, indépendamment des valeurs du fichier manifeste."</string>
     <string name="enable_freeform_support" msgid="7599125687603914253">"Activer les fenêtres de forme libre"</string>
     <string name="enable_freeform_support_summary" msgid="1822862728719276331">"Activer la compatibilité avec les fenêtres de forme libre expérimentales."</string>
     <string name="local_backup_password_title" msgid="4631017948933578709">"Mot de passe sauvegarde PC"</string>
diff --git a/packages/SettingsLib/res/values-zh-rCN/strings.xml b/packages/SettingsLib/res/values-zh-rCN/strings.xml
index da62ded..2dc05f4 100644
--- a/packages/SettingsLib/res/values-zh-rCN/strings.xml
+++ b/packages/SettingsLib/res/values-zh-rCN/strings.xml
@@ -474,7 +474,7 @@
     <item msgid="7529124349186240216">"100%"</item>
   </string-array>
     <string name="charge_length_format" msgid="6941645744588690932">"<xliff:g id="ID_1">%1$s</xliff:g>前"</string>
-    <string name="remaining_length_format" msgid="4310625772926171089">"还需 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
+    <string name="remaining_length_format" msgid="4310625772926171089">"还可以使用 <xliff:g id="ID_1">%1$s</xliff:g>"</string>
     <string name="screen_zoom_summary_small" msgid="6050633151263074260">"小"</string>
     <string name="screen_zoom_summary_default" msgid="1888865694033865408">"默认"</string>
     <string name="screen_zoom_summary_large" msgid="4706951482598978984">"大"</string>
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/animation/src/com/android/systemui/animation/Interpolators.java b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
index 044b5ed..e1f72c1 100644
--- a/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
+++ b/packages/SystemUI/animation/src/com/android/systemui/animation/Interpolators.java
@@ -96,13 +96,18 @@
     /**
      * Interpolate alpha for notifications background scrim during shade expansion.
      * @param fraction Shade expansion fraction
+     * @param forNotification If we want the alpha of the notification shade or the scrim.
      */
-    public static float getNotificationScrimAlpha(float fraction) {
+    public static float getNotificationScrimAlpha(float fraction, boolean forNotification) {
+        if (!forNotification) {
+            fraction = MathUtils.saturate(1.7f * fraction);
+        }
         fraction = fraction * 1.2f - 0.2f;
         if (fraction <= 0) {
             return 0;
         } else {
-            return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * Math.pow(1f - fraction, 2f))));
+            final float oneMinusFrac = 1f - fraction;
+            return (float) (1f - 0.5f * (1f - Math.cos(3.14159f * oneMinusFrac * oneMinusFrac)));
         }
     }
 }
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-land/volume_dialog.xml b/packages/SystemUI/res/layout-land/volume_dialog.xml
index 237dc02..1a4e812 100644
--- a/packages/SystemUI/res/layout-land/volume_dialog.xml
+++ b/packages/SystemUI/res/layout-land/volume_dialog.xml
@@ -16,6 +16,7 @@
 <FrameLayout
     xmlns:android="http://schemas.android.com/apk/res/android"
     xmlns:sysui="http://schemas.android.com/apk/res-auto"
+    xmlns:androidprv="http://schemas.android.com/apk/prv/res/android"
     android:id="@+id/volume_dialog_container"
     android:layout_width="wrap_content"
     android:layout_height="wrap_content"
@@ -24,64 +25,29 @@
     android:background="@android:color/transparent"
     android:theme="@style/volume_dialog_theme">
 
-    <FrameLayout
+    <!-- right-aligned to be physically near volume button -->
+    <LinearLayout
         android:id="@+id/volume_dialog"
-        android:minWidth="@dimen/volume_dialog_panel_width"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
         android:gravity="right"
         android:layout_gravity="right"
-        android:background="@android:color/transparent"
-        android:paddingRight="@dimen/volume_dialog_stream_padding"
-        android:paddingLeft="@dimen/volume_dialog_panel_transparent_padding"
-        android:clipToPadding="false">
+        android:layout_marginRight="@dimen/volume_dialog_panel_transparent_padding_right"
+        android:orientation="vertical"
+        android:clipToPadding="false"
+        android:clipChildren="false">
 
-        <!--
-            Container for a) the ringer drawer and the caption button next to b) the volume rows.
-        -->
+
         <LinearLayout
+            android:id="@+id/volume_dialog_ringer_and_rows_container"
             android:layout_width="wrap_content"
             android:layout_height="wrap_content"
-            android:orientation="horizontal"
+            android:orientation="vertical"
+            android:padding="7dp"
             android:clipChildren="false"
-            android:clipToPadding="false">
+            android:background="@drawable/volume_background">
 
-            <!-- The ringer drawer and the caption button. -->
-            <FrameLayout
-                android:layout_width="wrap_content"
-                android:layout_height="match_parent"
-                android:paddingRight="@dimen/volume_dialog_stream_padding"
-                android:clipChildren="false"
-                android:clipToPadding="false"
-                android:orientation="vertical">
-
-                <include layout="@layout/volume_ringer_drawer"
-                    android:layout_gravity="top|right"/>
-
-                <FrameLayout
-                    android:id="@+id/odi_captions"
-                    android:layout_width="@dimen/volume_dialog_caption_size"
-                    android:layout_height="@dimen/volume_dialog_caption_size"
-                    android:gravity="center"
-                    android:layout_gravity="bottom|right"
-                    android:layout_marginBottom="@dimen/volume_dialog_tap_target_size"
-                    android:clipToPadding="false">
-
-                    <com.android.systemui.volume.CaptionsToggleImageButton
-                        android:id="@+id/odi_captions_icon"
-                        android:src="@drawable/ic_volume_odi_captions_disabled"
-                        style="@style/VolumeButtons"
-                        android:background="@drawable/rounded_ripple"
-                        android:layout_width="match_parent"
-                        android:layout_height="match_parent"
-                        android:tint="@color/caption_tint_color_selector"
-                        android:layout_gravity="center"
-                        android:soundEffectsEnabled="false"
-                        sysui:optedOut="false"/>
-
-                </FrameLayout>
-
-            </FrameLayout>
+            <include layout="@layout/volume_ringer_drawer" />
 
             <FrameLayout
                 android:visibility="gone"
@@ -102,34 +68,33 @@
                     android:layout_height="match_parent"
                     android:scaleType="fitCenter"
                     android:padding="@dimen/volume_dialog_ringer_icon_padding"
-                    android:tint="@color/accent_tint_color_selector"
+                    android:tint="?android:attr/textColorPrimary"
                     android:layout_gravity="center"
                     android:soundEffectsEnabled="false" />
 
                 <include layout="@layout/volume_dnd_icon"
-                         android:layout_width="match_parent"
-                         android:layout_height="wrap_content"
-                         android:layout_marginRight="@dimen/volume_dialog_stream_padding"
-                         android:layout_marginTop="6dp"/>
+                    android:layout_width="match_parent"
+                    android:layout_height="wrap_content"
+                    android:layout_marginRight="@dimen/volume_dialog_stream_padding"
+                    android:layout_marginTop="6dp"/>
             </FrameLayout>
 
             <LinearLayout
                 android:id="@+id/main"
                 android:layout_width="wrap_content"
-                android:minWidth="@dimen/volume_dialog_panel_width"
                 android:layout_height="wrap_content"
                 android:gravity="right"
                 android:layout_gravity="right"
                 android:orientation="vertical"
                 android:clipChildren="false"
-                android:clipToPadding="false">
+                android:clipToPadding="false" >
                 <LinearLayout
                     android:id="@+id/volume_dialog_rows"
                     android:layout_width="wrap_content"
                     android:layout_height="wrap_content"
-                    android:minWidth="@dimen/volume_dialog_panel_width"
                     android:gravity="center"
-                    android:orientation="horizontal">
+                    android:orientation="horizontal"
+                    android:layout_marginTop="@dimen/volume_row_slider_padding_start">
                     <!-- volume rows added and removed here! :-) -->
                 </LinearLayout>
                 <FrameLayout
@@ -144,23 +109,41 @@
                         android:layout_gravity="center"
                         android:contentDescription="@string/accessibility_volume_settings"
                         android:background="@drawable/ripple_drawable_20dp"
-                        android:tint="?android:attr/colorBackgroundFloating"
+                        android:tint="?androidprv:attr/colorAccent"
                         android:soundEffectsEnabled="false" />
                 </FrameLayout>
             </LinearLayout>
 
         </LinearLayout>
 
-        <ViewStub
-            android:id="@+id/odi_captions_tooltip_stub"
-            android:inflatedId="@+id/odi_captions_tooltip_view"
-            android:layout="@layout/volume_tool_tip_view"
-            android:layout_width="wrap_content"
-            android:layout_height="wrap_content"
-            android:layout_marginRight="@dimen/volume_tool_tip_right_margin"
-            android:layout_marginTop="@dimen/volume_tool_tip_top_margin"
-            android:layout_gravity="right"/>
+        <FrameLayout
+            android:id="@+id/odi_captions"
+            android:layout_width="@dimen/volume_dialog_caption_size"
+            android:layout_height="@dimen/volume_dialog_caption_size"
+            android:layout_marginTop="@dimen/volume_dialog_row_margin_bottom"
+            android:gravity="right"
+            android:layout_gravity="right"
+            android:clipToPadding="false"
+            android:background="@drawable/volume_background">
+            <com.android.systemui.volume.CaptionsToggleImageButton
+                android:id="@+id/odi_captions_icon"
+                android:src="@drawable/ic_volume_odi_captions_disabled"
+                style="@style/VolumeButtons"
+                android:layout_width="match_parent"
+                android:layout_height="match_parent"
+                android:tint="?android:attr/colorAccent"
+                android:layout_gravity="center"
+                android:soundEffectsEnabled="false"
+                sysui:optedOut="false"/>
+        </FrameLayout>
+    </LinearLayout>
 
-    </FrameLayout>
+    <ViewStub
+        android:id="@+id/odi_captions_tooltip_stub"
+        android:inflatedId="@+id/odi_captions_tooltip_view"
+        android:layout="@layout/volume_tool_tip_view"
+        android:layout_width="wrap_content"
+        android:layout_height="wrap_content"
+        android:layout_gravity="bottom | right"/>
 
 </FrameLayout>
\ No newline at end of file
diff --git a/packages/SystemUI/res/layout/long_screenshot.xml b/packages/SystemUI/res/layout/long_screenshot.xml
index 9430862..de33846 100644
--- a/packages/SystemUI/res/layout/long_screenshot.xml
+++ b/packages/SystemUI/res/layout/long_screenshot.xml
@@ -33,7 +33,7 @@
         android:layout_marginStart="8dp"
         android:layout_marginTop="4dp"
         android:backgroundTint="?androidprv:attr/colorAccentSecondary"
-        android:textColor="?android:textColorPrimary"
+        android:textColor="?android:textColorSecondary"
         app:layout_constraintStart_toStartOf="parent"
         app:layout_constraintTop_toTopOf="parent"
         app:layout_constraintBottom_toTopOf="@id/preview" />
@@ -117,7 +117,7 @@
         android:backgroundTint="?androidprv:attr/colorAccentSecondary"
         android:src="@drawable/ic_screenshot_edit"
         android:contentDescription="@string/screenshot_edit_label"
-        android:tint="?android:textColorPrimary"
+        android:tint="?android:textColorSecondary"
         android:padding="16dp"
         android:scaleType="fitCenter"
         app:layout_constraintBottom_toBottomOf="parent"
diff --git a/packages/SystemUI/res/layout/ongoing_call_chip.xml b/packages/SystemUI/res/layout/ongoing_call_chip.xml
index f8175d4..5389d9b 100644
--- a/packages/SystemUI/res/layout/ongoing_call_chip.xml
+++ b/packages/SystemUI/res/layout/ongoing_call_chip.xml
@@ -23,6 +23,7 @@
     android:layout_gravity="center_vertical|start"
 >
     <LinearLayout
+        android:id="@+id/ongoing_call_chip_background"
         android:layout_width="wrap_content"
         android:layout_height="@dimen/ongoing_appops_chip_height"
         android:layout_gravity="center_vertical"
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/res/values-land/dimens.xml b/packages/SystemUI/res/values-land/dimens.xml
index c6931e8..215698d 100644
--- a/packages/SystemUI/res/values-land/dimens.xml
+++ b/packages/SystemUI/res/values-land/dimens.xml
@@ -45,6 +45,7 @@
 
     <dimen name="volume_tool_tip_right_margin">136dp</dimen>
     <dimen name="volume_tool_tip_top_margin">12dp</dimen>
+    <dimen name="volume_row_slider_height">128dp</dimen>
 
     <dimen name="controls_activity_view_top_offset">25dp</dimen>
 
diff --git a/packages/SystemUI/res/values-night/styles.xml b/packages/SystemUI/res/values-night/styles.xml
index f10a564..e6165ee 100644
--- a/packages/SystemUI/res/values-night/styles.xml
+++ b/packages/SystemUI/res/values-night/styles.xml
@@ -35,7 +35,7 @@
         <item name="android:windowLightStatusBar">false</item>
         <item name="android:windowLightNavigationBar">false</item>
         <item name="android:navigationBarColor">?android:attr/colorBackgroundFloating</item>
-        <item name="android:textColorPrimary">?android:attr/textColorPrimaryInverse</item>
+        <item name="android:textColorSecondary">?android:attr/textColorPrimaryInverse</item>
     </style>
 
     <style name="Screenshot" parent="@android:style/Theme.DeviceDefault.DayNight">
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index ee7eb4b..964b135 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -16,6 +16,7 @@
 
 package com.android.systemui.accessibility;
 
+import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
 
 import android.annotation.NonNull;
@@ -70,7 +71,7 @@
     private final ImageView mImageView;
     private final Runnable mWindowInsetChangeRunnable;
     private final SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
-    private int mMagnificationMode = Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN;
+    private int mMagnificationMode = ACCESSIBILITY_MAGNIFICATION_MODE_NONE;
     private final LayoutParams mParams;
     @VisibleForTesting
     final Rect mDraggableWindowBounds = new Rect();
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthController.java
index 9871b4e..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);
 
@@ -481,14 +515,24 @@
      */
     @Override
     public void onBiometricAuthenticated() {
-        mCurrentDialog.onAuthenticationSucceeded();
+        if (DEBUG) Log.d(TAG, "onBiometricAuthenticated: ");
+
+        if (mCurrentDialog != null) {
+            mCurrentDialog.onAuthenticationSucceeded();
+        } else {
+            Log.w(TAG, "onBiometricAuthenticated callback but dialog gone");
+        }
     }
 
     @Override
     public void onBiometricHelp(String message) {
         if (DEBUG) Log.d(TAG, "onBiometricHelp: " + message);
 
-        mCurrentDialog.onHelp(message);
+        if (mCurrentDialog != null) {
+            mCurrentDialog.onHelp(message);
+        } else {
+            Log.w(TAG, "onBiometricHelp callback but dialog gone");
+        }
     }
 
     @Nullable
@@ -527,19 +571,23 @@
         final boolean isSoftError = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED
                 || error == BiometricConstants.BIOMETRIC_ERROR_TIMEOUT);
 
-        if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
-            if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
-            mCurrentDialog.animateToCredentialUI();
-        } else if (isSoftError) {
-            final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
-                    ? mContext.getString(R.string.biometric_not_recognized)
-                    : getErrorString(modality, error, vendorCode);
-            if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
-            mCurrentDialog.onAuthenticationFailed(errorMessage);
+        if (mCurrentDialog != null) {
+            if (mCurrentDialog.isAllowDeviceCredentials() && isLockout) {
+                if (DEBUG) Log.d(TAG, "onBiometricError, lockout");
+                mCurrentDialog.animateToCredentialUI();
+            } else if (isSoftError) {
+                final String errorMessage = (error == BiometricConstants.BIOMETRIC_PAUSED_REJECTED)
+                        ? mContext.getString(R.string.biometric_not_recognized)
+                        : getErrorString(modality, error, vendorCode);
+                if (DEBUG) Log.d(TAG, "onBiometricError, soft error: " + errorMessage);
+                mCurrentDialog.onAuthenticationFailed(errorMessage);
+            } else {
+                final String errorMessage = getErrorString(modality, error, vendorCode);
+                if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
+                mCurrentDialog.onError(errorMessage);
+            }
         } else {
-            final String errorMessage = getErrorString(modality, error, vendorCode);
-            if (DEBUG) Log.d(TAG, "onBiometricError, hard error: " + errorMessage);
-            mCurrentDialog.onError(errorMessage);
+            Log.w(TAG, "onBiometricError callback but dialog is gone");
         }
 
         onCancelUdfps();
@@ -697,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/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index b93da4b..99c0f4e 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -31,8 +31,8 @@
 import android.view.accessibility.AccessibilityNodeInfo;
 
 import com.android.internal.annotations.VisibleForTesting;
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
 import com.android.systemui.statusbar.notification.NotificationUtils;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -180,7 +180,7 @@
 
             if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
                 viewState.alpha = Interpolators.getNotificationScrimAlpha(
-                        ambientState.getExpansionFraction());
+                        ambientState.getExpansionFraction(), true /* notification */);
             } else {
                 viewState.alpha = 1f - ambientState.getHideAmount();
             }
@@ -255,7 +255,6 @@
         int backgroundTop = 0;
         int clipTopAmount = 0;
         float firstElementRoundness = 0.0f;
-        ActivatableNotificationView previousAnv = null;
 
         for (int i = 0; i < mHostLayoutController.getChildCount(); i++) {
             ExpandableView child = mHostLayoutController.getChildAt(i);
@@ -327,52 +326,10 @@
                 notGoneIndex++;
             }
 
-            final float viewEnd = viewStart + child.getActualHeight();
-            final float cornerAnimationDistance = mCornerAnimationDistance
-                    * mAmbientState.getExpansionFraction();
-            final float cornerAnimationTop = shelfStart - cornerAnimationDistance;
-
             if (child instanceof ActivatableNotificationView) {
                 ActivatableNotificationView anv =
                         (ActivatableNotificationView) child;
-
-                final boolean isUnlockedHeadsUp = !mAmbientState.isOnKeyguard()
-                        && !mAmbientState.isShadeExpanded()
-                        && child instanceof ExpandableView
-                        && ((ExpandableNotificationRow) child).isHeadsUp();
-                if (viewStart < shelfStart
-                        && !mHostLayoutController.isViewAffectedBySwipe(anv)
-                        && !isUnlockedHeadsUp
-                        && !mAmbientState.isPulsing()
-                        && !mAmbientState.isDozing()) {
-
-                    if (viewEnd >= cornerAnimationTop) {
-                        // Round bottom corners within animation bounds
-                        final float changeFraction = MathUtils.saturate(
-                                (viewEnd - cornerAnimationTop) / cornerAnimationDistance);
-                        final float roundness = anv.isLastInSection() ? 1f : changeFraction * 1f;
-                        anv.setBottomRoundness(roundness, false);
-
-                    } else if (viewEnd < cornerAnimationTop) {
-                        // Fast scroll skips frames and leaves corners with unfinished rounding.
-                        // Reset top and bottom corners outside of animation bounds.
-                        anv.setBottomRoundness(anv.isLastInSection() ? 1f : 0f, false);
-                    }
-
-                    if (viewStart >= cornerAnimationTop) {
-                        // Round top corners within animation bounds
-                        final float changeFraction = MathUtils.saturate(
-                                (viewStart - cornerAnimationTop) / cornerAnimationDistance);
-                        final float roundness = anv.isFirstInSection() ? 1f : changeFraction * 1f;
-                        anv.setTopRoundness(roundness, false);
-
-                    } else if (viewStart < cornerAnimationTop) {
-                        // Fast scroll skips frames and leaves corners with unfinished rounding.
-                        // Reset top and bottom corners outside of animation bounds.
-                        anv.setTopRoundness(anv.isFirstInSection() ? 1f : 0f, false);
-                    }
-                }
-                previousAnv = anv;
+                updateCornerRoundnessOnScroll(anv, viewStart, shelfStart);
             }
         }
 
@@ -408,6 +365,58 @@
         }
     }
 
+    private void updateCornerRoundnessOnScroll(ActivatableNotificationView anv, float viewStart,
+            float shelfStart) {
+
+        final boolean isUnlockedHeadsUp = !mAmbientState.isOnKeyguard()
+                && !mAmbientState.isShadeExpanded()
+                && anv instanceof ExpandableNotificationRow
+                && ((ExpandableNotificationRow) anv).isHeadsUp();
+
+        final boolean shouldUpdateCornerRoundness = viewStart < shelfStart
+                && !mHostLayoutController.isViewAffectedBySwipe(anv)
+                && !isUnlockedHeadsUp
+                && !mAmbientState.isPulsing()
+                && !mAmbientState.isDozing();
+
+        if (!shouldUpdateCornerRoundness) {
+            return;
+        }
+
+        final float viewEnd = viewStart + anv.getActualHeight();
+        final float cornerAnimationDistance = mCornerAnimationDistance
+                * mAmbientState.getExpansionFraction();
+        final float cornerAnimationTop = shelfStart - cornerAnimationDistance;
+
+        if (viewEnd >= cornerAnimationTop) {
+            // Round bottom corners within animation bounds
+            final float changeFraction = MathUtils.saturate(
+                    (viewEnd - cornerAnimationTop) / cornerAnimationDistance);
+            anv.setBottomRoundness(anv.isLastInSection() ? 1f : changeFraction,
+                    false /* animate */);
+
+        } else if (viewEnd < cornerAnimationTop) {
+            // Fast scroll skips frames and leaves corners with unfinished rounding.
+            // Reset top and bottom corners outside of animation bounds.
+            anv.setBottomRoundness(anv.isLastInSection() ? 1f : 0f,
+                    false /* animate */);
+        }
+
+        if (viewStart >= cornerAnimationTop) {
+            // Round top corners within animation bounds
+            final float changeFraction = MathUtils.saturate(
+                    (viewStart - cornerAnimationTop) / cornerAnimationDistance);
+            anv.setTopRoundness(anv.isFirstInSection() ? 1f : changeFraction,
+                    false /* animate */);
+
+        } else if (viewStart < cornerAnimationTop) {
+            // Fast scroll skips frames and leaves corners with unfinished rounding.
+            // Reset top and bottom corners outside of animation bounds.
+            anv.setTopRoundness(anv.isFirstInSection() ? 1f : 0f,
+                    false /* animate */);
+        }
+    }
+
     /**
      * Clips transient views to the top of the shelf - Transient views are only used for
      * disappearing views/animations and need to be clipped correctly by the shelf to ensure they
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
index c0fbf68..7afb015 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/NotificationWakeUpCoordinator.kt
@@ -393,6 +393,11 @@
     override fun onDozingChanged(isDozing: Boolean) {
         if (isDozing) {
             setNotificationsVisible(visible = false, animate = false, increaseSpeed = false)
+        } else {
+            // We only unset the flag once we fully went asleep. If the user interrupts the
+            // animation in the middle, we have to abort the animation as well to make sure
+            // the notifications are visible again.
+            animatingScreenOff = false
         }
     }
 
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
index e931ec4..0d34e90 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithm.java
@@ -24,8 +24,8 @@
 import android.view.View;
 import android.view.ViewGroup;
 
-import com.android.systemui.animation.Interpolators;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.NotificationShelf;
 import com.android.systemui.statusbar.notification.dagger.SilentHeader;
 import com.android.systemui.statusbar.notification.row.ActivatableNotificationView;
@@ -382,7 +382,7 @@
 
         if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
             viewState.alpha = Interpolators.getNotificationScrimAlpha(
-                    ambientState.getExpansionFraction());
+                    ambientState.getExpansionFraction(), true /* notification */);
         } else {
             viewState.alpha = 1f - ambientState.getHideAmount();
         }
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 7c63763..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);
@@ -883,7 +886,7 @@
     }
 
     private float getInterpolatedFraction() {
-        return Interpolators.getNotificationScrimAlpha(mPanelExpansion);
+        return Interpolators.getNotificationScrimAlpha(mPanelExpansion, false /* notification */);
     }
 
     private void setScrimAlpha(ScrimView scrim, float alpha) {
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..ba2340e 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(
@@ -3609,10 +3615,16 @@
 
         boolean visibleNotOccluded = mStatusBarKeyguardViewManager.isShowing()
                 && !mStatusBarKeyguardViewManager.isOccluded();
+        // If we're dozing and we'll be animating the screen off, the keyguard isn't currently
+        // visible but will be shortly for the animation, so we should proceed as if it's visible.
+        boolean visibleNotOccludedOrWillBe =
+                visibleNotOccluded || (mDozing && mDozeParameters.shouldControlUnlockedScreenOff());
+
         boolean wakeAndUnlock = mBiometricUnlockController.getMode()
                 == BiometricUnlockController.MODE_WAKE_AND_UNLOCK;
         boolean animate = (!mDozing && mDozeServiceHost.shouldAnimateWakeup() && !wakeAndUnlock)
-                || (mDozing && mDozeServiceHost.shouldAnimateScreenOff() && visibleNotOccluded);
+                || (mDozing && mDozeServiceHost.shouldAnimateScreenOff()
+                && visibleNotOccludedOrWillBe);
 
         mNotificationPanelViewController.setDozing(mDozing, animate, mWakeUpTouchLocation);
         updateQsExpansionEnabled();
@@ -3791,7 +3803,8 @@
 
     @Override
     public void onDozeAmountChanged(float linear, float eased) {
-        if (mFeatureFlags.useNewLockscreenAnimations()) {
+        if (mFeatureFlags.useNewLockscreenAnimations()
+                && !mCircleRevealAnimator.isRunning()) {
             mLightRevealScrim.setRevealAmount(1f - linear);
         }
     }
@@ -3828,6 +3841,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 +3870,6 @@
 
     private boolean shouldShowCircleReveal() {
         return mCircleReveal != null && !mCircleRevealAnimator.isRunning()
-                && mKeyguardUpdateMonitor.isUdfpsEnrolled()
                 && mBiometricUnlockController.getBiometricType() == FINGERPRINT;
     }
 
@@ -4062,12 +4091,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 +4332,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 +4610,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/statusbar/phone/ongoingcall/OngoingCallController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
index 9bf13b8..7dccf01 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/ongoingcall/OngoingCallController.kt
@@ -150,9 +150,11 @@
 
         val currentChipView = chipView
         val timeView =
-                currentChipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+            currentChipView?.findViewById<Chronometer>(R.id.ongoing_call_chip_time)
+        val backgroundView =
+            currentChipView?.findViewById<View>(R.id.ongoing_call_chip_background)
 
-        if (currentChipView != null && timeView != null) {
+        if (currentChipView != null && timeView != null && backgroundView != null) {
             timeView.base = currentOngoingCallInfo.callStartTime -
                     System.currentTimeMillis() +
                     systemClock.elapsedRealtime()
@@ -162,7 +164,7 @@
                 logger.logChipClicked()
                 activityStarter.postStartActivityDismissingKeyguard(
                         currentOngoingCallInfo.intent, 0,
-                        ActivityLaunchAnimator.Controller.fromView(it))
+                        ActivityLaunchAnimator.Controller.fromView(backgroundView))
             }
 
             setUpUidObserver(currentOngoingCallInfo)
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/src/com/android/systemui/volume/VolumeDialogImpl.java b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
index b9f896e..98d8b29 100644
--- a/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/volume/VolumeDialogImpl.java
@@ -1752,7 +1752,21 @@
         }
 
         final Rect bounds = mRingerAndRowsContainerBackground.copyBounds();
-        bounds.top = (int) (drawerClosedAmount * getRingerDrawerOpenExtraSize());
+
+        if (!isLandscape()) {
+            // In portrait, the background should fill the full width, but only go up to the ringer
+            // icon's top. We'll extend it all the way to the top of the container when the ringer
+            // drawer opens.
+            bounds.left = 0;
+            bounds.top = (int) (drawerClosedAmount * getRingerDrawerOpenExtraSize());
+        } else {
+            // In landscape, the background should be inset by the size of the open drawer, since it
+            // opens sideways. It should extend to the top of the container since we haven't left
+            // space for the drawer to open upward.
+            bounds.left = getRingerDrawerOpenExtraSize();
+            bounds.top = 0;
+        }
+
         mRingerAndRowsContainerBackground.setBounds(bounds);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index d9a240f..936ec80 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -100,8 +100,6 @@
     private AccessibilityManager mAccessibilityManager;
     @Mock
     private SfVsyncFrameCallbackProvider mSfVsyncFrameProvider;
-    @Mock
-    private Handler mHandler;
     private TestableWindowManager mWindowManager;
     private ViewPropertyAnimator mViewPropertyAnimator;
     private MagnificationModeSwitch mMagnificationModeSwitch;
@@ -152,12 +150,12 @@
     }
 
     @Test
-    public void showWindowModeButton_fullscreenMode_addViewAndSetImageResource() {
-        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW);
+    public void showFullscreenModeButton_addViewAndSetImageResource() {
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
 
         verify(mSpyImageView).setImageResource(
-                getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW));
-        verify(mWindowManager).addView(eq(mSpyImageView), any(WindowManager.LayoutParams.class));
+                getIconResId(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN));
+        assertEquals(mSpyImageView, mWindowManager.getAttachedView());
         assertShowFadingAnimation(FADE_IN_ALPHA);
         assertShowFadingAnimation(FADE_OUT_ALPHA);
     }
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 36a031a..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;
@@ -202,7 +203,7 @@
         waitForIdleSync();
 
         verify(mCallback).onAction(AuthBiometricView.Callback.ACTION_ERROR);
-        assertEquals(AuthBiometricView.STATE_ERROR, mBiometricView.mState);
+        assertEquals(AuthBiometricView.STATE_IDLE, mBiometricView.mState);
     }
 
     @Test
@@ -253,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/ScrimControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
index a431a78..8b0b579 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/ScrimControllerTest.java
@@ -1118,7 +1118,7 @@
     public void testNotificationTransparency_inKeyguardState() {
         mScrimController.transitionTo(ScrimState.KEYGUARD);
 
-        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.8f);
+        assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.2f, /* expansion */ 0.4f);
         assertAlphaAfterExpansion(mNotificationsScrim, /* alpha */ 0.8f, /* expansion */ 0.2f);
     }
 
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/Android.bp b/services/Android.bp
index 1dd2192..f2e0b20 100644
--- a/services/Android.bp
+++ b/services/Android.bp
@@ -141,7 +141,6 @@
     libs: [
         "android.hidl.manager-V1.0-java",
         "framework-tethering.stubs.module_lib",
-        "service-art.stubs.system_server",
     ],
 
     // Uncomment to enable output of certain warnings (deprecated, unchecked)
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index ab85b5e..83dfe8e 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -20,6 +20,7 @@
 import static android.bluetooth.le.ScanSettings.CALLBACK_TYPE_ALL_MATCHES;
 import static android.bluetooth.le.ScanSettings.SCAN_MODE_BALANCED;
 import static android.content.Context.BIND_IMPORTANT;
+import static android.content.pm.PackageManager.CERT_INPUT_SHA256;
 import static android.content.pm.PackageManager.MATCH_ALL;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 
@@ -657,7 +658,14 @@
         }
 
         @Override
-        public void createAssociation(String packageName, String macAddress, int userId) {
+        public void createAssociation(String packageName, String macAddress, int userId,
+                byte[] certificate) {
+            if (!getContext().getPackageManager().hasSigningCertificate(
+                    packageName, certificate, CERT_INPUT_SHA256)) {
+                Slog.e(LOG_TAG, "Given certificate doesn't match the package certificate.");
+                return;
+            }
+
             getContext().enforceCallingOrSelfPermission(
                     android.Manifest.permission.ASSOCIATE_COMPANION_DEVICES, "createAssociation");
 
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/VcnManagementService.java b/services/core/java/com/android/server/VcnManagementService.java
index e7e3ce9..57adcb6 100644
--- a/services/core/java/com/android/server/VcnManagementService.java
+++ b/services/core/java/com/android/server/VcnManagementService.java
@@ -148,6 +148,7 @@
 // TODO(b/180451994): ensure all incoming + outgoing calls have a cleared calling identity
 public class VcnManagementService extends IVcnManagementService.Stub {
     @NonNull private static final String TAG = VcnManagementService.class.getSimpleName();
+    private static final long DUMP_TIMEOUT_MILLIS = TimeUnit.SECONDS.toMillis(5);
 
     public static final boolean VDBG = false; // STOPSHIP: if true
 
@@ -997,48 +998,38 @@
     protected void dump(FileDescriptor fd, PrintWriter writer, String[] args) {
         mContext.enforceCallingOrSelfPermission(DUMP, TAG);
 
-        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "  ");
+        final IndentingPrintWriter pw = new IndentingPrintWriter(writer, "| ");
 
-        pw.println("VcnManagementService dump:");
-        pw.increaseIndent();
-
-        pw.println("mNetworkProvider:");
-        pw.increaseIndent();
-        mNetworkProvider.dump(pw);
-        pw.decreaseIndent();
-        pw.println();
-
-        pw.println("mTrackingNetworkCallback:");
-        pw.increaseIndent();
-        mTrackingNetworkCallback.dump(pw);
-        pw.decreaseIndent();
-        pw.println();
-
-        synchronized (mLock) {
-            pw.println("mLastSnapshot:");
-            pw.increaseIndent();
-            mLastSnapshot.dump(pw);
-            pw.decreaseIndent();
+        // Post to handler thread to prevent ConcurrentModificationExceptions, and avoid lock-hell.
+        mHandler.runWithScissors(() -> {
+            mNetworkProvider.dump(pw);
             pw.println();
 
-            pw.println("mConfigs:");
-            pw.increaseIndent();
-            for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
-                pw.println(entry.getKey() + ": " + entry.getValue().getProvisioningPackageName());
+            mTrackingNetworkCallback.dump(pw);
+            pw.println();
+
+            synchronized (mLock) {
+                mLastSnapshot.dump(pw);
+                pw.println();
+
+                pw.println("mConfigs:");
+                pw.increaseIndent();
+                for (Entry<ParcelUuid, VcnConfig> entry : mConfigs.entrySet()) {
+                    pw.println(entry.getKey() + ": "
+                            + entry.getValue().getProvisioningPackageName());
+                }
+                pw.decreaseIndent();
+                pw.println();
+
+                pw.println("mVcns:");
+                pw.increaseIndent();
+                for (Vcn vcn : mVcns.values()) {
+                    vcn.dump(pw);
+                }
+                pw.decreaseIndent();
+                pw.println();
             }
-            pw.decreaseIndent();
-            pw.println();
-
-            pw.println("mVcns:");
-            pw.increaseIndent();
-            for (Vcn vcn : mVcns.values()) {
-                vcn.dump(pw);
-            }
-            pw.decreaseIndent();
-            pw.println();
-        }
-
-        pw.decreaseIndent();
+        }, DUMP_TIMEOUT_MILLIS);
     }
 
     // TODO(b/180452282): Make name more generic and implement directly with VcnManagementService
diff --git a/services/core/java/com/android/server/am/ActiveServices.java b/services/core/java/com/android/server/am/ActiveServices.java
index 0f3aa65..0408309 100644
--- a/services/core/java/com/android/server/am/ActiveServices.java
+++ b/services/core/java/com/android/server/am/ActiveServices.java
@@ -21,38 +21,40 @@
 import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
 import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
 import static android.app.ActivityManager.PROCESS_STATE_HEAVY_WEIGHT;
+import static android.app.ActivityManager.PROCESS_STATE_PERSISTENT_UI;
 import static android.app.ActivityManager.PROCESS_STATE_RECEIVER;
 import static android.app.ActivityManager.PROCESS_STATE_TOP;
 import static android.content.pm.PackageManager.PERMISSION_GRANTED;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MANIFEST;
+import static android.os.PowerExemptionManager.REASON_ACTIVITY_STARTER;
 import static android.os.PowerExemptionManager.REASON_ACTIVITY_VISIBILITY_GRACE_PERIOD;
+import static android.os.PowerExemptionManager.REASON_ALLOWLISTED_PACKAGE;
+import static android.os.PowerExemptionManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_BACKGROUND_FGS_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_COMPANION_DEVICE_MANAGER;
+import static android.os.PowerExemptionManager.REASON_DENIED;
+import static android.os.PowerExemptionManager.REASON_DEVICE_DEMO_MODE;
+import static android.os.PowerExemptionManager.REASON_DEVICE_OWNER;
+import static android.os.PowerExemptionManager.REASON_FGS_BINDING;
+import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
 import static android.os.PowerExemptionManager.REASON_OPT_OUT_REQUESTED;
 import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_PLATFORM_VPN;
 import static android.os.PowerExemptionManager.REASON_OP_ACTIVATE_VPN;
+import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT;
+import static android.os.PowerExemptionManager.REASON_PROC_STATE_PERSISTENT_UI;
+import static android.os.PowerExemptionManager.REASON_PROC_STATE_TOP;
+import static android.os.PowerExemptionManager.REASON_PROFILE_OWNER;
+import static android.os.PowerExemptionManager.REASON_SERVICE_LAUNCH;
+import static android.os.PowerExemptionManager.REASON_START_ACTIVITY_FLAG;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_ALLOW_LISTED;
+import static android.os.PowerExemptionManager.REASON_SYSTEM_UID;
 import static android.os.PowerExemptionManager.REASON_TEMP_ALLOWED_WHILE_IN_USE;
-import static android.os.PowerWhitelistManager.REASON_ACTIVITY_STARTER;
-import static android.os.PowerWhitelistManager.REASON_ALLOWLISTED_PACKAGE;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_COMPANION_DEVICE_MANAGER;
-import static android.os.PowerWhitelistManager.REASON_DENIED;
-import static android.os.PowerWhitelistManager.REASON_DEVICE_DEMO_MODE;
-import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_FGS_BINDING;
-import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_ACTIVITY_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_INSTR_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT;
-import static android.os.PowerWhitelistManager.REASON_PROC_STATE_PERSISTENT_UI;
-import static android.os.PowerWhitelistManager.REASON_PROC_STATE_TOP;
-import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_START_ACTIVITY_FLAG;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
-import static android.os.PowerWhitelistManager.REASON_UID_VISIBLE;
-import static android.os.PowerWhitelistManager.TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
-import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
-import static android.os.PowerWhitelistManager.reasonCodeToString;
+import static android.os.PowerExemptionManager.REASON_UID_VISIBLE;
+import static android.os.PowerExemptionManager.TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED;
+import static android.os.PowerExemptionManager.getReasonCodeFromProcState;
+import static android.os.PowerExemptionManager.reasonCodeToString;
 import static android.os.Process.INVALID_UID;
 import static android.os.Process.NFC_UID;
 import static android.os.Process.ROOT_UID;
@@ -118,8 +120,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
-import android.os.PowerWhitelistManager;
-import android.os.PowerWhitelistManager.ReasonCode;
+import android.os.PowerExemptionManager.ReasonCode;
 import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
@@ -135,6 +136,7 @@
 import android.util.ArrayMap;
 import android.util.ArraySet;
 import android.util.EventLog;
+import android.util.Pair;
 import android.util.PrintWriterPrinter;
 import android.util.Slog;
 import android.util.SparseArray;
@@ -1704,14 +1706,6 @@
                         +  String.format("0x%08X", manifestType)
                         + " in service element of manifest file");
                 }
-                // If the foreground service is not started from TOP process, do not allow it to
-                // have while-in-use location/camera/microphone access.
-                if (!r.mAllowWhileInUsePermissionInFgs) {
-                    Slog.w(TAG,
-                            "Foreground service started from background can not have "
-                                    + "location/camera/microphone access: service "
-                                    + r.shortInstanceName);
-                }
             }
 
             boolean alreadyStartedOp = false;
@@ -1800,6 +1794,14 @@
                                     r.appInfo.uid, r.intent.getIntent(), r, r.userId,false);
                         }
                     }
+                    // If the foreground service is not started from TOP process, do not allow it to
+                    // have while-in-use location/camera/microphone access.
+                    if (!r.mAllowWhileInUsePermissionInFgs) {
+                        Slog.w(TAG,
+                                "Foreground service started from background can not have "
+                                        + "location/camera/microphone access: service "
+                                        + r.shortInstanceName);
+                    }
                     logFgsBackgroundStart(r);
                     if (r.mAllowStartForeground == REASON_DENIED && isBgFgsRestrictionEnabled(r)) {
                         final String msg = "Service.startForeground() not allowed due to "
@@ -3614,8 +3616,9 @@
                         + " for fg-service launch");
             }
             mAm.tempAllowlistUidLocked(r.appInfo.uid,
-                    SERVICE_START_FOREGROUND_TIMEOUT, PowerWhitelistManager.REASON_SERVICE_LAUNCH,
-                    "fg-service-launch", TEMPORARY_ALLOWLIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
+                    SERVICE_START_FOREGROUND_TIMEOUT, REASON_SERVICE_LAUNCH,
+                    "fg-service-launch",
+                    TEMPORARY_ALLOW_LIST_TYPE_FOREGROUND_SERVICE_ALLOWED,
                     r.mRecentCallingUid);
         }
 
@@ -5740,6 +5743,66 @@
         int ret = shouldAllowFgsStartForegroundLocked(allowWhileInUse, callingPid, callingUid,
                 callingPackage, r);
 
+        String bindFromPackage = null;
+        if (ret == REASON_DENIED) {
+            // If the callingUid is not allowed to start FGS, check if the callingUid has any
+            // service that is bound by a clientUid, the clientUid can propagate its BG-FGS-start
+            // capability down to the callingUid.
+            final ArraySet<Integer> checkedClientUids = new ArraySet<>();
+            final Pair<Integer, String> isAllowed = mAm.mProcessList.searchEachLruProcessesLOSP(
+                    false, pr -> {
+                if (pr.uid == callingUid) {
+                    final ProcessServiceRecord psr = pr.mServices;
+                    final int serviceCount = psr.mServices.size();
+                    for (int svc = 0; svc < serviceCount; svc++) {
+                        final ArrayMap<IBinder, ArrayList<ConnectionRecord>> conns =
+                                psr.mServices.valueAt(svc).getConnections();
+                        final int size = conns.size();
+                        for (int conni = 0; conni < size; conni++) {
+                            final ArrayList<ConnectionRecord> crs = conns.valueAt(conni);
+                            for (int con = 0; con < crs.size(); con++) {
+                                final ConnectionRecord cr = crs.get(con);
+                                final ProcessRecord clientPr = cr.binding.client;
+                                // Persistent process does not propagate BG-FGS-start capability
+                                // down to service over binding.
+                                if (clientPr.mState.getCurProcState()
+                                        <= PROCESS_STATE_PERSISTENT_UI) {
+                                    continue;
+                                }
+                                final int clientPid = clientPr.mPid;
+                                final int clientUid = clientPr.uid;
+                                // An UID can bind to itself, do not check on itself again.
+                                // Also skip already checked clientUid.
+                                if (clientUid == callingUid
+                                        || checkedClientUids.contains(clientUid)) {
+                                    continue;
+                                }
+                                final String clientPackageName = cr.clientPackageName;
+                                final @ReasonCode int allowWhileInUse2 =
+                                        shouldAllowFgsWhileInUsePermissionLocked(clientPackageName,
+                                                clientPid, clientUid, null /* serviceRecord */,
+                                                false /* allowBackgroundActivityStarts */);
+                                final @ReasonCode int allowStartFgs =
+                                        shouldAllowFgsStartForegroundLocked(allowWhileInUse2,
+                                                clientPid, clientUid, clientPackageName, null /* targetService */);
+                                if (allowStartFgs != REASON_DENIED) {
+                                    return new Pair<>(allowStartFgs, clientPackageName);
+                                } else {
+                                    checkedClientUids.add(clientUid);
+                                }
+
+                            }
+                        }
+                    }
+                }
+                return null;
+            });
+            if (isAllowed != null) {
+                ret = REASON_FGS_BINDING;
+                bindFromPackage = isAllowed.second;
+            }
+        }
+
         final int uidState = mAm.getUidStateLocked(callingUid);
         int callerTargetSdkVersion = INVALID_UID;
         try {
@@ -5765,6 +5828,7 @@
                         + "; targetSdkVersion:" + r.appInfo.targetSdkVersion
                         + "; callerTargetSdkVersion:" + callerTargetSdkVersion
                         + "; startForegroundCount:" + r.mStartForegroundCount
+                        + "; bindFromPackage:" + bindFromPackage
                         + "]";
         if (!debugInfo.equals(r.mInfoAllowStartForeground)) {
             r.mLoggedInfoAllowStartForeground = false;
@@ -5790,9 +5854,7 @@
             final Integer allowedType = mAm.mProcessList.searchEachLruProcessesLOSP(false, app -> {
                 if (app.uid == callingUid) {
                     final ProcessStateRecord state = app.mState;
-                    if (state.getAllowedStartFgs() != REASON_DENIED) {
-                        return state.getAllowedStartFgs();
-                    } else if (state.isAllowedStartFgsState()) {
+                    if (state.isAllowedStartFgsState()) {
                         return getReasonCodeFromProcState(state.getAllowStartFgsState());
                     } else if (state.areBackgroundFgsStartsAllowedByToken()) {
                         return REASON_FGS_BINDING;
@@ -5891,6 +5953,7 @@
         }
         if (ret == REASON_DENIED) {
             if (mAm.mConstants.mFgsAllowOptOut
+                    && targetService != null
                     && targetService.appInfo.hasRequestForegroundServiceExemption()) {
                 ret = REASON_OPT_OUT_REQUESTED;
             }
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/am/OomAdjuster.java b/services/core/java/com/android/server/am/OomAdjuster.java
index 2e2a297..661e0b8 100644
--- a/services/core/java/com/android/server/am/OomAdjuster.java
+++ b/services/core/java/com/android/server/am/OomAdjuster.java
@@ -42,7 +42,6 @@
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_CAMERA;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_LOCATION;
 import static android.content.pm.ServiceInfo.FOREGROUND_SERVICE_TYPE_MICROPHONE;
-import static android.os.PowerWhitelistManager.REASON_DENIED;
 import static android.os.Process.SCHED_OTHER;
 import static android.os.Process.THREAD_GROUP_BACKGROUND;
 import static android.os.Process.THREAD_GROUP_DEFAULT;
@@ -1574,8 +1573,7 @@
         state.setAdjTarget(null);
         state.setEmpty(false);
         state.setCached(false);
-        state.setAllowStartFgsState(PROCESS_STATE_NONEXISTENT);
-        state.resetAllowStartFgs();
+        state.resetAllowStartFgsState();
         app.mOptRecord.setShouldNotFreeze(false);
 
         final int appUid = app.info.uid;
@@ -1630,7 +1628,6 @@
             state.setCurAdj(state.getMaxAdj());
             state.setCompletedAdjSeq(state.getAdjSeq());
             state.bumpAllowStartFgsState(state.getCurProcState());
-            state.setAllowStartFgs();
             // if curAdj is less than prevAppAdj, then this process was promoted
             return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState;
         }
@@ -2028,12 +2025,6 @@
 
                     final boolean clientIsSystem = clientProcState < PROCESS_STATE_TOP;
 
-                    // pass client's mAllowStartFgs to the app if client is not persistent process.
-                    if (cstate.getAllowedStartFgs() != REASON_DENIED
-                            && cstate.getMaxAdj() >= ProcessList.FOREGROUND_APP_ADJ) {
-                        state.setAllowStartFgs(cstate.getAllowedStartFgs());
-                    }
-
                     if ((cr.flags & Context.BIND_WAIVE_PRIORITY) == 0) {
                         if (shouldSkipDueToCycle(state, cstate, procState, adj, cycleReEval)) {
                             continue;
@@ -2524,7 +2515,6 @@
         state.updateLastInvisibleTime(hasVisibleActivities);
         state.setHasForegroundActivities(foregroundActivities);
         state.setCompletedAdjSeq(mAdjSeq);
-        state.setAllowStartFgs();
 
         // if curAdj or curProcState improved, then this process was promoted
         return state.getCurAdj() < prevAppAdj || state.getCurProcState() < prevProcState
diff --git a/services/core/java/com/android/server/am/ProcessServiceRecord.java b/services/core/java/com/android/server/am/ProcessServiceRecord.java
index 5c3bf60..8f77b87 100644
--- a/services/core/java/com/android/server/am/ProcessServiceRecord.java
+++ b/services/core/java/com/android/server/am/ProcessServiceRecord.java
@@ -89,7 +89,7 @@
     /**
      * All ServiceRecord running in this process.
      */
-    private final ArraySet<ServiceRecord> mServices = new ArraySet<>();
+    final ArraySet<ServiceRecord> mServices = new ArraySet<>();
 
     /**
      * Services that are currently executing code (need to remain foreground).
diff --git a/services/core/java/com/android/server/am/ProcessStateRecord.java b/services/core/java/com/android/server/am/ProcessStateRecord.java
index 801e382..d83e13c 100644
--- a/services/core/java/com/android/server/am/ProcessStateRecord.java
+++ b/services/core/java/com/android/server/am/ProcessStateRecord.java
@@ -16,28 +16,9 @@
 
 package com.android.server.am;
 
-import static android.Manifest.permission.START_ACTIVITIES_FROM_BACKGROUND;
-import static android.Manifest.permission.START_FOREGROUND_SERVICES_FROM_BACKGROUND;
-import static android.Manifest.permission.SYSTEM_ALERT_WINDOW;
 import static android.app.ActivityManager.PROCESS_CAPABILITY_NONE;
 import static android.app.ActivityManager.PROCESS_STATE_BOUND_FOREGROUND_SERVICE;
 import static android.app.ActivityManager.PROCESS_STATE_NONEXISTENT;
-import static android.content.pm.PackageManager.PERMISSION_GRANTED;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_ACTIVITY_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_BACKGROUND_FGS_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_DENIED;
-import static android.os.PowerWhitelistManager.REASON_DEVICE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_PROFILE_OWNER;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_ALLOW_LISTED;
-import static android.os.PowerWhitelistManager.REASON_SYSTEM_UID;
-import static android.os.PowerWhitelistManager.ReasonCode;
-import static android.os.PowerWhitelistManager.getReasonCodeFromProcState;
-import static android.os.PowerWhitelistManager.reasonCodeToString;
-import static android.os.Process.NFC_UID;
-import static android.os.Process.ROOT_UID;
-import static android.os.Process.SHELL_UID;
-import static android.os.Process.SYSTEM_UID;
 
 import static com.android.server.am.ActivityManagerDebugConfig.DEBUG_OOM_ADJ;
 import static com.android.server.am.ProcessRecord.TAG;
@@ -47,7 +28,6 @@
 import android.content.ComponentName;
 import android.os.Binder;
 import android.os.SystemClock;
-import android.os.UserHandle;
 import android.util.ArraySet;
 import android.util.Slog;
 import android.util.TimeUtils;
@@ -56,7 +36,6 @@
 import com.android.internal.annotations.GuardedBy;
 import com.android.internal.util.FrameworkStatsLog;
 
-
 import java.io.PrintWriter;
 
 /**
@@ -327,20 +306,6 @@
     private final ArraySet<Binder> mBackgroundFgsStartTokens = new ArraySet<>();
 
     /**
-     * Does the process has permission to start FGS from background.
-     */
-    @GuardedBy("mService")
-    private @ReasonCode int mAllowStartFgsByPermission = REASON_DENIED;
-
-    /**
-     * Can this process start FGS from background?
-     * If this process has the ability to start FGS from background, this ability can be passed to
-     * another process through service binding.
-     */
-    @GuardedBy("mService")
-    private @ReasonCode int mAllowStartFgs = REASON_DENIED;
-
-    /**
      * Whether or not this process has been in forced-app-standby state.
      */
     @GuardedBy("mService")
@@ -435,7 +400,6 @@
         mApp = app;
         mService = app.mService;
         mProcLock = mService.mProcLock;
-        setAllowStartFgsByPermission();
     }
 
     void init(long now) {
@@ -1152,9 +1116,8 @@
     }
 
     @GuardedBy("mService")
-    void resetAllowStartFgs() {
+    void resetAllowStartFgsState() {
         mAllowStartFgsState = PROCESS_STATE_NONEXISTENT;
-        mAllowStartFgs = mAllowStartFgsByPermission;
     }
 
     @GuardedBy("mService")
@@ -1165,11 +1128,6 @@
     }
 
     @GuardedBy("mService")
-    void setAllowStartFgsState(int allowStartFgsState) {
-        mAllowStartFgsState = allowStartFgsState;
-    }
-
-    @GuardedBy("mService")
     int getAllowStartFgsState() {
         return mAllowStartFgsState;
     }
@@ -1180,98 +1138,6 @@
     }
 
     @GuardedBy("mService")
-    void setAllowStartFgsByPermission() {
-        int ret = REASON_DENIED;
-        boolean isSystem = false;
-        final int uid = UserHandle.getAppId(mApp.info.uid);
-        switch (uid) {
-            case ROOT_UID:
-            case SYSTEM_UID:
-            case NFC_UID:
-            case SHELL_UID:
-                isSystem = true;
-                break;
-            default:
-                isSystem = false;
-                break;
-        }
-
-        if (isSystem) {
-            ret = REASON_SYSTEM_UID;
-        }
-
-        if (ret == REASON_DENIED) {
-            if (ActivityManager.checkComponentPermission(START_ACTIVITIES_FROM_BACKGROUND,
-                    mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
-                ret = REASON_BACKGROUND_ACTIVITY_PERMISSION;
-            } else if (ActivityManager.checkComponentPermission(
-                    START_FOREGROUND_SERVICES_FROM_BACKGROUND,
-                    mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
-                ret = REASON_BACKGROUND_FGS_PERMISSION;
-            } else if (ActivityManager.checkComponentPermission(SYSTEM_ALERT_WINDOW,
-                    mApp.info.uid, -1, true) == PERMISSION_GRANTED) {
-                ret = REASON_SYSTEM_ALERT_WINDOW_PERMISSION;
-            }
-        }
-        mAllowStartFgs = mAllowStartFgsByPermission = ret;
-    }
-
-    // TODO(b/188063200) Clean up this method. Why do we need to duplicate only some of the checks?
-    @GuardedBy("mService")
-    void setAllowStartFgs() {
-        if (mAllowStartFgs != REASON_DENIED) {
-            return;
-        }
-        if (mAllowStartFgs == REASON_DENIED) {
-            if (isAllowedStartFgsState()) {
-                mAllowStartFgs = getReasonCodeFromProcState(mAllowStartFgsState);
-            }
-        }
-
-        if (mAllowStartFgs == REASON_DENIED) {
-            // Is the calling UID a device owner app?
-            if (mService.mInternal != null) {
-                if (mService.mInternal.isDeviceOwner(mApp.info.uid)) {
-                    mAllowStartFgs = REASON_DEVICE_OWNER;
-                }
-            }
-        }
-
-        if (mAllowStartFgs == REASON_DENIED) {
-            // Is the calling UID a profile owner app?
-            if (mService.mInternal != null) {
-                if (mService.mInternal.isProfileOwner(mApp.info.uid)) {
-                    mAllowStartFgs = REASON_PROFILE_OWNER;
-                }
-            }
-        }
-
-        if (mAllowStartFgs == REASON_DENIED) {
-            // uid is on DeviceIdleController's user/system allowlist
-            // or AMS's FgsStartTempAllowList.
-            ActivityManagerService.FgsTempAllowListItem item =
-                    mService.isAllowlistedForFgsStartLOSP(mApp.info.uid);
-            if (item != null) {
-                if (item == ActivityManagerService.FAKE_TEMP_ALLOW_LIST_ITEM) {
-                    mAllowStartFgs = REASON_SYSTEM_ALLOW_LISTED;
-                } else {
-                    mAllowStartFgs = item.mReasonCode;
-                }
-            }
-        }
-    }
-
-    @GuardedBy("mService")
-    void setAllowStartFgs(@ReasonCode int allowStartFgs) {
-        mAllowStartFgs = allowStartFgs;
-    }
-
-    @GuardedBy("mService")
-    @ReasonCode int getAllowedStartFgs() {
-        return mAllowStartFgs;
-    }
-
-    @GuardedBy("mService")
     void setForcedAppStandby(boolean standby) {
         mForcedAppStandby = standby;
     }
@@ -1334,10 +1200,6 @@
         pw.println();
         pw.print(prefix); pw.print("allowStartFgsState=");
         pw.println(mAllowStartFgsState);
-        if (mAllowStartFgs != REASON_DENIED) {
-            pw.print(prefix); pw.print("allowStartFgs=");
-            pw.println(reasonCodeToString(mAllowStartFgs));
-        }
         if (mHasShownUi || mApp.mProfile.hasPendingUiClean()) {
             pw.print(prefix); pw.print("hasShownUi="); pw.print(mHasShownUi);
             pw.print(" pendingUiClean="); pw.println(mApp.mProfile.hasPendingUiClean());
diff --git a/services/core/java/com/android/server/biometrics/BiometricStrengthController.java b/services/core/java/com/android/server/biometrics/BiometricStrengthController.java
index 270621c..768dc36 100644
--- a/services/core/java/com/android/server/biometrics/BiometricStrengthController.java
+++ b/services/core/java/com/android/server/biometrics/BiometricStrengthController.java
@@ -48,16 +48,9 @@
      */
     private static final String KEY_BIOMETRIC_STRENGTHS = "biometric_strengths";
 
-    /**
-     * Default (no-op) value of the flag KEY_BIOMETRIC_STRENGTHS
-     */
-    public static final String DEFAULT_BIOMETRIC_STRENGTHS = null;
-
     private DeviceConfig.OnPropertiesChangedListener mDeviceConfigListener = properties -> {
-        for (String name : properties.getKeyset()) {
-            if (KEY_BIOMETRIC_STRENGTHS.equals(name)) {
-                updateStrengths();
-            }
+        if (properties.getKeyset().contains(KEY_BIOMETRIC_STRENGTHS)) {
+            updateStrengths();
         }
     };
 
@@ -75,7 +68,17 @@
      * has been changed.
      */
     public void updateStrengths() {
-        final Map<Integer, Integer> idToStrength = getIdToStrengthMap();
+        final String newValue = DeviceConfig.getString(DeviceConfig.NAMESPACE_BIOMETRICS,
+                KEY_BIOMETRIC_STRENGTHS, "null");
+        if ("null".equals(newValue) || newValue.isEmpty()) {
+            revertStrengths();
+        } else {
+            updateStrengths(newValue);
+        }
+    }
+
+    private void updateStrengths(String flags) {
+        final Map<Integer, Integer> idToStrength = getIdToStrengthMap(flags);
         if (idToStrength == null) {
             return;
         }
@@ -91,12 +94,18 @@
         }
     }
 
+    private void revertStrengths() {
+        for (BiometricSensor sensor : mService.mSensors) {
+            Slog.d(TAG, "updateStrengths: revert sensorId=" + sensor.id + " to oemStrength="
+                    + sensor.oemStrength);
+            sensor.updateStrength(sensor.oemStrength);
+        }
+    }
+
     /**
      * @return a map of <ID, Strength>
      */
-    private Map<Integer, Integer> getIdToStrengthMap() {
-        final String flags = DeviceConfig.getString(DeviceConfig.NAMESPACE_BIOMETRICS,
-                KEY_BIOMETRIC_STRENGTHS, DEFAULT_BIOMETRIC_STRENGTHS);
+    private static Map<Integer, Integer> getIdToStrengthMap(String flags) {
         if (flags == null || flags.isEmpty()) {
             Slog.d(TAG, "Flags are null or empty");
             return null;
diff --git a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
index 6482a2e..99f4e2c 100644
--- a/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
+++ b/services/core/java/com/android/server/biometrics/sensors/BaseClientMonitor.java
@@ -82,7 +82,20 @@
     private final int mCookie;
     boolean mAlreadyDone;
 
-    @NonNull protected Callback mCallback;
+    // Use an empty callback by default since delayed operations can receive events
+    // before they are started and cause NPE in subclasses that access this field directly.
+    @NonNull protected Callback mCallback = new Callback() {
+        @Override
+        public void onClientStarted(@NonNull BaseClientMonitor clientMonitor) {
+            Slog.e(TAG, "mCallback onClientStarted: called before set (should not happen)");
+        }
+
+        @Override
+        public void onClientFinished(@NonNull BaseClientMonitor clientMonitor,
+                boolean success) {
+            Slog.e(TAG, "mCallback onClientFinished: called before set (should not happen)");
+        }
+    };
 
     /**
      * @return A ClientMonitorEnum constant defined in biometrics.proto
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/pm/AppsFilter.java b/services/core/java/com/android/server/pm/AppsFilter.java
index 7b1fa14..06ff691 100644
--- a/services/core/java/com/android/server/pm/AppsFilter.java
+++ b/services/core/java/com/android/server/pm/AppsFilter.java
@@ -58,10 +58,12 @@
 import com.android.server.om.OverlayReferenceMapper;
 import com.android.server.pm.parsing.pkg.AndroidPackage;
 import com.android.server.utils.Snappable;
+import com.android.server.utils.SnapshotCache;
 import com.android.server.utils.Snapshots;
 import com.android.server.utils.Watchable;
 import com.android.server.utils.WatchableImpl;
 import com.android.server.utils.WatchedArrayMap;
+import com.android.server.utils.WatchedSparseBooleanMatrix;
 import com.android.server.utils.Watcher;
 
 import java.io.PrintWriter;
@@ -158,12 +160,21 @@
      * initial scam and is null until {@link #onSystemReady()} is called.
      */
     @GuardedBy("mCacheLock")
-    private volatile SparseArray<SparseBooleanArray> mShouldFilterCache;
+    private volatile WatchedSparseBooleanMatrix mShouldFilterCache;
 
     /**
      * A cached snapshot.
      */
-    private volatile AppsFilter mSnapshot = null;
+    private final SnapshotCache<AppsFilter> mSnapshot;
+
+    private SnapshotCache<AppsFilter> makeCache() {
+        return new SnapshotCache<AppsFilter>(this, this) {
+            @Override
+            public AppsFilter createSnapshot() {
+                AppsFilter s = new AppsFilter(mSource);
+                return s;
+            }};
+    }
 
     /**
      * Watchable machinery
@@ -211,7 +222,6 @@
      */
     @Override
     public void dispatchChange(@Nullable Watchable what) {
-        mSnapshot = null;
         mWatchable.dispatchChange(what);
     }
 
@@ -236,6 +246,7 @@
                 overlayProvider);
         mStateProvider = stateProvider;
         mBackgroundExecutor = backgroundExecutor;
+        mSnapshot = makeCache();
     }
 
     /**
@@ -258,8 +269,14 @@
         mSystemSigningDetails = orig.mSystemSigningDetails;
         mProtectedBroadcasts = orig.mProtectedBroadcasts;
         mShouldFilterCache = orig.mShouldFilterCache;
+        if (mShouldFilterCache != null) {
+            synchronized (orig.mCacheLock) {
+                mShouldFilterCache = mShouldFilterCache.snapshot();
+            }
+        }
 
         mBackgroundExecutor = null;
+        mSnapshot = new SnapshotCache.Sealed<>();
     }
 
     /**
@@ -268,13 +285,7 @@
      * condition causes the cached snapshot to be cleared asynchronously to this method.
      */
     public AppsFilter snapshot() {
-        AppsFilter s = mSnapshot;
-        if (s == null) {
-            s = new AppsFilter(this);
-            s.mWatchable.seal();
-            mSnapshot = s;
-        }
-        return s;
+        return mSnapshot.snapshot();
     }
 
     /**
@@ -636,12 +647,7 @@
             if (mShouldFilterCache != null) {
                 // update the cache in a one-off manner since we've got all the information we
                 // need.
-                SparseBooleanArray visibleUids = mShouldFilterCache.get(recipientUid);
-                if (visibleUids == null) {
-                    visibleUids = new SparseBooleanArray();
-                    mShouldFilterCache.put(recipientUid, visibleUids);
-                }
-                visibleUids.put(visibleUid, false);
+                mShouldFilterCache.put(recipientUid, visibleUid, false);
             }
         }
         if (changed) {
@@ -813,23 +819,21 @@
         if (mShouldFilterCache == null) {
             return;
         }
-        for (int i = mShouldFilterCache.size() - 1; i >= 0; i--) {
+        for (int i = 0; i < mShouldFilterCache.size(); i++) {
             if (UserHandle.getAppId(mShouldFilterCache.keyAt(i)) == appId) {
                 mShouldFilterCache.removeAt(i);
-                continue;
-            }
-            SparseBooleanArray targetSparseArray = mShouldFilterCache.valueAt(i);
-            for (int j = targetSparseArray.size() - 1; j >= 0; j--) {
-                if (UserHandle.getAppId(targetSparseArray.keyAt(j)) == appId) {
-                    targetSparseArray.removeAt(j);
-                }
+                // The key was deleted so the list of keys has shifted left.  That means i
+                // is now pointing at the next key to be examined.  The decrement here and
+                // the loop increment together mean that i will be unchanged in the need
+                // iteration and will correctly point to the next key to be examined.
+                i--;
             }
         }
     }
 
     private void updateEntireShouldFilterCache() {
         mStateProvider.runWithState((settings, users) -> {
-            SparseArray<SparseBooleanArray> cache =
+            WatchedSparseBooleanMatrix cache =
                     updateEntireShouldFilterCacheInner(settings, users);
             synchronized (mCacheLock) {
                 mShouldFilterCache = cache;
@@ -837,10 +841,10 @@
         });
     }
 
-    private SparseArray<SparseBooleanArray> updateEntireShouldFilterCacheInner(
+    private WatchedSparseBooleanMatrix updateEntireShouldFilterCacheInner(
             ArrayMap<String, PackageSetting> settings, UserInfo[] users) {
-        SparseArray<SparseBooleanArray> cache =
-                new SparseArray<>(users.length * settings.size());
+        WatchedSparseBooleanMatrix cache =
+                new WatchedSparseBooleanMatrix(users.length * settings.size());
         for (int i = settings.size() - 1; i >= 0; i--) {
             updateShouldFilterCacheForPackage(cache,
                     null /*skipPackage*/, settings.valueAt(i), settings, users, i);
@@ -864,7 +868,7 @@
                     packagesCache.put(settings.keyAt(i), pkg);
                 }
             });
-            SparseArray<SparseBooleanArray> cache =
+            WatchedSparseBooleanMatrix cache =
                     updateEntireShouldFilterCacheInner(settingsCopy, usersRef[0]);
             boolean[] changed = new boolean[1];
             // We have a cache, let's make sure the world hasn't changed out from under us.
@@ -916,7 +920,7 @@
         }
     }
 
-    private void updateShouldFilterCacheForPackage(SparseArray<SparseBooleanArray> cache,
+    private void updateShouldFilterCacheForPackage(WatchedSparseBooleanMatrix cache,
             @Nullable String skipPackageName, PackageSetting subjectSetting, ArrayMap<String,
             PackageSetting> allSettings, UserInfo[] allUsers, int maxIndex) {
         for (int i = Math.min(maxIndex, allSettings.size() - 1); i >= 0; i--) {
@@ -935,17 +939,11 @@
                 for (int ou = 0; ou < userCount; ou++) {
                     int otherUser = allUsers[ou].id;
                     int subjectUid = UserHandle.getUid(subjectUser, subjectSetting.appId);
-                    if (!cache.contains(subjectUid)) {
-                        cache.put(subjectUid, new SparseBooleanArray(appxUidCount));
-                    }
                     int otherUid = UserHandle.getUid(otherUser, otherSetting.appId);
-                    if (!cache.contains(otherUid)) {
-                        cache.put(otherUid, new SparseBooleanArray(appxUidCount));
-                    }
-                    cache.get(subjectUid).put(otherUid,
+                    cache.put(subjectUid, otherUid,
                             shouldFilterApplicationInternal(
                                     subjectUid, subjectSetting, otherSetting, otherUser));
-                    cache.get(otherUid).put(subjectUid,
+                    cache.put(otherUid, subjectUid,
                             shouldFilterApplicationInternal(
                                     otherUid, otherSetting, subjectSetting, subjectUser));
                 }
@@ -1198,22 +1196,20 @@
             }
             synchronized (mCacheLock) {
                 if (mShouldFilterCache != null) { // use cache
-                    SparseBooleanArray shouldFilterTargets = mShouldFilterCache.get(callingUid);
-                    final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId);
-                    if (shouldFilterTargets == null) {
+                    final int callingIndex = mShouldFilterCache.indexOfKey(callingUid);
+                    if (callingIndex < 0) {
                         Slog.wtf(TAG, "Encountered calling uid with no cached rules: "
                                 + callingUid);
                         return true;
                     }
-                    int indexOfTargetUid = shouldFilterTargets.indexOfKey(targetUid);
-                    if (indexOfTargetUid < 0) {
+                    final int targetUid = UserHandle.getUid(userId, targetPkgSetting.appId);
+                    final int targetIndex = mShouldFilterCache.indexOfKey(targetUid);
+                    if (targetIndex < 0) {
                         Slog.w(TAG, "Encountered calling -> target with no cached rules: "
                                 + callingUid + " -> " + targetUid);
                         return true;
                     }
-                    if (!shouldFilterTargets.valueAt(indexOfTargetUid)) {
-                        return false;
-                    }
+                    return mShouldFilterCache.valueAt(callingIndex, targetIndex);
                 } else {
                     if (!shouldFilterApplicationInternal(
                             callingUid, callingSetting, targetPkgSetting, userId)) {
diff --git a/services/core/java/com/android/server/pm/PackageManagerService.java b/services/core/java/com/android/server/pm/PackageManagerService.java
index c947463..14861c2d 100644
--- a/services/core/java/com/android/server/pm/PackageManagerService.java
+++ b/services/core/java/com/android/server/pm/PackageManagerService.java
@@ -780,7 +780,6 @@
     private static final String COMPANION_PACKAGE_NAME = "com.android.companiondevicemanager";
 
     // Compilation reasons.
-    public static final int REASON_UNKNOWN = -1;
     public static final int REASON_FIRST_BOOT = 0;
     public static final int REASON_BOOT_AFTER_OTA = 1;
     public static final int REASON_POST_BOOT = 2;
@@ -793,7 +792,8 @@
     public static final int REASON_BACKGROUND_DEXOPT = 9;
     public static final int REASON_AB_OTA = 10;
     public static final int REASON_INACTIVE_PACKAGE_DOWNGRADE = 11;
-    public static final int REASON_SHARED = 12;
+    public static final int REASON_CMDLINE = 12;
+    public static final int REASON_SHARED = 13;
 
     public static final int REASON_LAST = REASON_SHARED;
 
@@ -8472,7 +8472,7 @@
                             libInfo.getPackageName(), libInfo.getAllCodePaths(),
                             libInfo.getName(), libInfo.getLongVersion(),
                             libInfo.getType(), libInfo.getDeclaringPackage(),
-                            getPackagesUsingSharedLibraryLPr(libInfo, flags, userId),
+                            getPackagesUsingSharedLibraryLPr(libInfo, flags, callingUid, userId),
                             (libInfo.getDependencies() == null
                                     ? null
                                     : new ArrayList<>(libInfo.getDependencies())),
@@ -8544,9 +8544,11 @@
                             libraryInfo.getPath(), libraryInfo.getPackageName(),
                             libraryInfo.getAllCodePaths(), libraryInfo.getName(),
                             libraryInfo.getLongVersion(), libraryInfo.getType(),
-                            libraryInfo.getDeclaringPackage(), getPackagesUsingSharedLibraryLPr(
-                            libraryInfo, flags, userId), libraryInfo.getDependencies() == null
-                            ? null : new ArrayList<>(libraryInfo.getDependencies()),
+                            libraryInfo.getDeclaringPackage(),
+                            getPackagesUsingSharedLibraryLPr(
+                                    libraryInfo, flags, callingUid, userId),
+                            libraryInfo.getDependencies() == null
+                                    ? null : new ArrayList<>(libraryInfo.getDependencies()),
                             libraryInfo.isNative());
 
                     if (result == null) {
@@ -8562,7 +8564,7 @@
 
     @GuardedBy("mLock")
     private List<VersionedPackage> getPackagesUsingSharedLibraryLPr(
-            SharedLibraryInfo libInfo, int flags, int userId) {
+            SharedLibraryInfo libInfo, int flags, int callingUid, int userId) {
         List<VersionedPackage> versionedPackages = null;
         final int packageCount = mSettings.getPackagesLocked().size();
         for (int i = 0; i < packageCount; i++) {
@@ -8585,6 +8587,9 @@
                 if (ps.usesStaticLibrariesVersions[libIdx] != libInfo.getLongVersion()) {
                     continue;
                 }
+                if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                    continue;
+                }
                 if (versionedPackages == null) {
                     versionedPackages = new ArrayList<>();
                 }
@@ -8597,6 +8602,9 @@
             } else if (ps.pkg != null) {
                 if (ArrayUtils.contains(ps.pkg.getUsesLibraries(), libName)
                         || ArrayUtils.contains(ps.pkg.getUsesOptionalLibraries(), libName)) {
+                    if (shouldFilterApplicationLocked(ps, callingUid, userId)) {
+                        continue;
+                    }
                     if (versionedPackages == null) {
                         versionedPackages = new ArrayList<>();
                     }
@@ -11942,7 +11950,7 @@
         int flags = (checkProfiles ? DexoptOptions.DEXOPT_CHECK_FOR_PROFILES_UPDATES : 0) |
                 (force ? DexoptOptions.DEXOPT_FORCE : 0) |
                 (bootComplete ? DexoptOptions.DEXOPT_BOOT_COMPLETE : 0);
-        return performDexOpt(new DexoptOptions(packageName, REASON_UNKNOWN,
+        return performDexOpt(new DexoptOptions(packageName, REASON_CMDLINE,
                 targetCompilerFilter, splitName, flags));
     }
 
@@ -14321,7 +14329,7 @@
         // Remove the shared library overlays from its dependent packages.
         for (int currentUserId : UserManagerService.getInstance().getUserIds()) {
             final List<VersionedPackage> dependents = getPackagesUsingSharedLibraryLPr(
-                    libraryInfo, 0, currentUserId);
+                    libraryInfo, 0, Process.SYSTEM_UID, currentUserId);
             if (dependents == null) {
                 continue;
             }
@@ -20684,7 +20692,7 @@
                             continue;
                         }
                         List<VersionedPackage> libClientPackages = getPackagesUsingSharedLibraryLPr(
-                                libraryInfo, MATCH_KNOWN_PACKAGES, currUserId);
+                                libraryInfo, MATCH_KNOWN_PACKAGES, Process.SYSTEM_UID, currUserId);
                         if (!ArrayUtils.isEmpty(libClientPackages)) {
                             Slog.w(TAG, "Not removing package " + pkg.getManifestPackageName()
                                     + " hosting lib " + libraryInfo.getName() + " version "
@@ -26795,7 +26803,7 @@
                             continue;
                         }
                         final List<VersionedPackage> dependents = getPackagesUsingSharedLibraryLPr(
-                                info, 0, userId);
+                                info, 0, Process.SYSTEM_UID, userId);
                         if (dependents == null) {
                             continue;
                         }
diff --git a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
index 636db11..7c1f054 100644
--- a/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
+++ b/services/core/java/com/android/server/pm/PackageManagerServiceCompilerMapping.java
@@ -40,6 +40,7 @@
         "bg-dexopt",
         "ab-ota",
         "inactive",
+        "cmdline",
         // "shared" must be the last entry
         "shared"
     };
@@ -141,9 +142,6 @@
     }
 
     public static String getReasonName(int reason) {
-        if (reason == PackageManagerService.REASON_UNKNOWN) {
-            return "unknown";
-        }
         if (reason < 0 || reason >= REASON_STRINGS.length) {
             throw new IllegalArgumentException("reason " + reason + " invalid");
         }
diff --git a/services/core/java/com/android/server/pm/dex/ArtManagerService.java b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
index 3576950..1859b4c 100644
--- a/services/core/java/com/android/server/pm/dex/ArtManagerService.java
+++ b/services/core/java/com/android/server/pm/dex/ArtManagerService.java
@@ -607,6 +607,7 @@
             TRON_COMPILATION_REASON_INSTALL_BULK_SECONDARY_DOWNGRADED_WITH_DM = 19;
     private static final int TRON_COMPILATION_REASON_BOOT_AFTER_OTA = 20;
     private static final int TRON_COMPILATION_REASON_POST_BOOT = 21;
+    private static final int TRON_COMPILATION_REASON_CMDLINE = 22;
 
     // The annotation to add as a suffix to the compilation reason when dexopt was
     // performed with dex metadata.
@@ -617,7 +618,7 @@
      */
     private static int getCompilationReasonTronValue(String compilationReason) {
         switch (compilationReason) {
-            case "unknown" : return TRON_COMPILATION_REASON_UNKNOWN;
+            case "cmdline" : return TRON_COMPILATION_REASON_CMDLINE;
             case "error" : return TRON_COMPILATION_REASON_ERROR;
             case "first-boot" : return TRON_COMPILATION_REASON_FIRST_BOOT;
             case "boot-after-ota": return TRON_COMPILATION_REASON_BOOT_AFTER_OTA;
diff --git a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
index 091d820..946f8d5 100644
--- a/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
+++ b/services/core/java/com/android/server/pm/dex/ArtStatsLogUtils.java
@@ -58,8 +58,6 @@
     private static final Map<Integer, Integer> COMPILATION_REASON_MAP = new HashMap();
 
     static {
-        COMPILATION_REASON_MAP.put(PackageManagerService.REASON_UNKNOWN, ArtStatsLog.
-                ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_UNKNOWN);
         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_FIRST_BOOT, ArtStatsLog.
                 ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_FIRST_BOOT);
         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_BOOT_AFTER_OTA, ArtStatsLog.
@@ -85,6 +83,8 @@
         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_INACTIVE_PACKAGE_DOWNGRADE,
                 ArtStatsLog.
                         ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_INACTIVE);
+        COMPILATION_REASON_MAP.put(PackageManagerService.REASON_CMDLINE,
+                ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_CMDLINE);
         COMPILATION_REASON_MAP.put(PackageManagerService.REASON_SHARED,
                 ArtStatsLog.ART_DATUM_REPORTED__COMPILATION_REASON__ART_COMPILATION_REASON_SHARED);
     }
diff --git a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
index 35aff8d..a582914 100644
--- a/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
+++ b/services/core/java/com/android/server/rotationresolver/RemoteRotationResolverService.java
@@ -126,14 +126,12 @@
 
 
         void cancelInternal() {
-            synchronized (mLock) {
-                if (mIsFulfilled) {
-                    return;
-                }
-                mIsFulfilled = true;
-            }
             Handler.getMain().post(() -> {
                 synchronized (mLock) {
+                    if (mIsFulfilled) {
+                        return;
+                    }
+                    mIsFulfilled = true;
                     try {
                         if (mCancellation != null) {
                             mCancellation.cancel();
diff --git a/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
new file mode 100644
index 0000000..42a2f81
--- /dev/null
+++ b/services/core/java/com/android/server/utils/WatchedSparseBooleanMatrix.java
@@ -0,0 +1,562 @@
+/*
+ * 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.
+ */
+
+package com.android.server.utils;
+
+import android.annotation.Nullable;
+import android.annotation.Size;
+
+import com.android.internal.util.ArrayUtils;
+import com.android.internal.util.GrowingArrayUtils;
+
+import java.util.Arrays;
+
+/**
+ * A {@link WatchedSparseBooleanMatrix} is an compact NxN array of booleans.  The rows and
+ * columns of the array are indexed by integers, which need not be contiguous.  The matrix
+ * is square and the row and column indices are identical.  This matrix is intended to be
+ * very memory efficient.
+ *
+ * The matrix contains a map from indices to columns: this map requires 2*N integers.  The
+ * boolean array is bit-packed and requires N*N/8 bytes.  The memory required for an
+ * order-N matrix is therefore 2*N*4 + N*N bytes.
+ *
+ * See {@link SparseBooleanArray} for a discussion of sparse arrays.
+ */
+public class WatchedSparseBooleanMatrix extends WatchableImpl implements Snappable {
+
+    /**
+     * The matrix is implemented through four arrays.  The matrix of booleans is stored in
+     * a one-dimensional {@code mValues} array.  {@code mValues} is always of size
+     * {@code mOrder * mOrder}.  Elements of {@code mValues} are addressed with
+     * arithmetic: the offset of the element {@code {row, col}} is at
+     * {@code row * mOrder + col}.  The term "storage index" applies to {@code mValues}.
+     * A storage index designates a row (column) in the underlying storage.  This is not
+     * the same as the row seen by client code.
+     *
+     * Client code addresses the matrix through indices.  These are integers that need not
+     * be contiguous.  Client indices are mapped to storage indices through two linear
+     * integer arrays.  {@code mKeys} is a sorted list of client indices.
+     * {@code mIndices} is a parallel array that contains storage indices.  The storage
+     * index of a client index {@code k} is {@code mIndices[i]}, where
+     * {@code mKeys[i] == k}.
+     *
+     * A final array, {@code mInUse} records if storage indices are free or in use.  This
+     * array is of size {@code mOrder}.  A client index is deleted by removing it from
+     * {@code mKeys} and {@code mIndices} and then setting the original storage index
+     * false in {@code mInUse}.
+     *
+     * Some notes:
+     * <ul>
+     * <li> The matrix never shrinks.
+     * <li> Equality is a very, very expesive operation.
+     * </ul>
+     */
+
+    /**
+     * mOrder is always a multiple of this value.  A  minimal matrix therefore holds 2^12
+     * values and requires 1024 bytes.
+     */
+    private static final int STEP = 64;
+
+    /**
+     * The order of the matrix storage, including any padding.  The matrix is always
+     * square.  mOrder is always greater than or equal to mSize.
+     */
+    private int mOrder;
+
+    /**
+     * The number of client keys.  This is always less than or equal to mOrder.  It is the
+     * order of the matrix as seen by the client.
+     */
+    private int mSize;
+
+    /**
+     * The in-use list.
+     */
+    private boolean[] mInUse;
+
+    /**
+     * The array of client keys (indices), in sorted order.
+     */
+    private int[] mKeys;
+
+    /**
+     * The mapping from a client key to an storage index.  If client key K is at index N
+     * in mKeys, then the storage index for K is at mMap[N].
+     */
+    private int[] mMap;
+
+    /**
+     * The boolean array.  This array is always {@code mOrder x mOrder} in size.
+     */
+    private boolean[] mValues;
+
+    /**
+     * A convenience function called when the elements are added to or removed from the storage.
+     * The watchable is always {@link this}.
+     */
+    private void onChanged() {
+        dispatchChange(this);
+    }
+
+    /**
+     * Creates a new WatchedSparseBooleanMatrix containing no mappings.
+     */
+    public WatchedSparseBooleanMatrix() {
+        this(STEP);
+    }
+
+    /**
+     * Creates a new SparseBooleanMatrix containing no mappings that will not require any
+     * additional memory allocation to store the specified number of mappings.  The
+     * capacity is always rounded up to a non-zero multiple of STEP.
+     */
+    public WatchedSparseBooleanMatrix(int initialCapacity) {
+        mOrder = initialCapacity;
+        if (mOrder < STEP) {
+            mOrder = STEP;
+        }
+        if (mOrder % STEP != 0) {
+            mOrder = ((initialCapacity / STEP) + 1) * STEP;
+        }
+        if (mOrder < STEP || (mOrder % STEP != 0)) {
+            throw new RuntimeException("mOrder is " + mOrder + " initCap is " + initialCapacity);
+        }
+
+        mInUse = new boolean[mOrder];
+        mKeys = ArrayUtils.newUnpaddedIntArray(mOrder);
+        mMap = ArrayUtils.newUnpaddedIntArray(mOrder);
+        mValues = new boolean[mOrder * mOrder];
+        mSize = 0;
+    }
+
+    /**
+     * A copy constructor that can be used for snapshotting.
+     */
+    private WatchedSparseBooleanMatrix(WatchedSparseBooleanMatrix r) {
+        mOrder = r.mOrder;
+        mSize = r.mSize;
+        mKeys = r.mKeys.clone();
+        mMap = r.mMap.clone();
+        mInUse = r.mInUse.clone();
+        mValues = r.mValues.clone();
+    }
+
+    /**
+     * Return a copy of this object.
+     */
+    public WatchedSparseBooleanMatrix snapshot() {
+        return new WatchedSparseBooleanMatrix(this);
+    }
+
+    /**
+     * Gets the boolean mapped from the specified key, or <code>false</code>
+     * if no such mapping has been made.
+     */
+    public boolean get(int row, int col) {
+        return get(row, col, false);
+    }
+
+    /**
+     * Gets the boolean mapped from the specified key, or the specified value
+     * if no such mapping has been made.
+     */
+    public boolean get(int row, int col, boolean valueIfKeyNotFound) {
+        int r = indexOfKey(row, false);
+        int c = indexOfKey(col, false);
+        if (r >= 0 && c >= 0) {
+            return valueAt(r, c);
+        } else {
+            return valueIfKeyNotFound;
+        }
+    }
+
+    /**
+     * Adds a mapping from the specified keys to the specified value, replacing the
+     * previous mapping from the specified keys if there was one.
+     */
+    public void put(int row, int col, boolean value) {
+        int r = indexOfKey(row);
+        int c = indexOfKey(col);
+        if (r < 0 || c < 0) {
+            // One or both of the keys has not be installed yet.  Install them now.
+            // Installing either key may shift the other key.  The safest course is to
+            // install the keys that are not present and then recompute both indices.
+            if (r < 0) {
+                r = indexOfKey(row, true);
+            }
+            if (c < 0) {
+                c = indexOfKey(col, true);
+            }
+            r = indexOfKey(row);
+            c = indexOfKey(col);
+        }
+        if (r >= 0 && c >= 0) {
+            setValueAt(r, c, value);
+            onChanged();
+        } else {
+            throw new RuntimeException("matrix overflow");
+        }
+    }
+
+    /**
+     * Removes the mapping from the specified key, if there was any.  Note that deletion
+     * applies to a single index, not to an element.  The matrix never shrinks but the
+     * space will be reused the next time an index is added.
+     */
+    public void deleteKey(int key) {
+        int i = indexOfKey(key, false);
+        if (i >= 0) {
+            removeAt(i);
+        }
+    }
+
+    /**
+     * Removes the mapping at the specified index.  The matrix does not shrink.  This
+     * throws ArrayIndexOutOfBounds if the index out outside the range {@code 0..size()-1}.
+     */
+    public void removeAt(int index) {
+        validateIndex(index);
+        mInUse[mMap[index]] = false;
+        System.arraycopy(mKeys, index + 1, mKeys, index, mSize - (index + 1));
+        System.arraycopy(mMap, index + 1, mMap, index, mSize - (index + 1));
+        mSize--;
+        onChanged();
+    }
+
+    /**
+     * Returns the number of key-value mappings that this WatchedSparseBooleanMatrix
+     * currently stores.
+     */
+    public int size() {
+        return mSize;
+    }
+
+    /**
+     * Removes all key-value mappings from this WatchedSparseBooleanMatrix.
+     */
+    public void clear() {
+        mSize = 0;
+        Arrays.fill(mInUse, false);
+        onChanged();
+    }
+
+    /**
+     * Given an index in the range <code>0...size()-1</code>, returns the key from the
+     * <code>index</code>th key-value mapping that this WatchedSparseBooleanMatrix stores.
+     *
+     * <p>The keys corresponding to indices in ascending order are guaranteed to be in
+     * ascending order, e.g., <code>keyAt(0)</code> will return the smallest key and
+     * <code>keyAt(size()-1)</code> will return the largest key.</p>
+     *
+     * <p>{@link ArrayIndexOutOfBoundsException} is thrown for indices outside of the
+     * range <code>0...size()-1</code></p>
+     */
+    public int keyAt(int index) {
+        validateIndex(index);
+        return mKeys[index];
+    }
+
+    /**
+     * Given a row and column, each in the range <code>0...size()-1</code>, returns the
+     * value from the <code>index</code>th key-value mapping that this WatchedSparseBooleanMatrix
+     * stores.
+     */
+    public boolean valueAt(int rowIndex, int colIndex) {
+        validateIndex(rowIndex, colIndex);
+        int r = mMap[rowIndex];
+        int c = mMap[colIndex];
+        int element = r * mOrder + c;
+        return mValues[element];
+    }
+
+    /**
+     * Directly set the value at a particular index.
+     */
+    public void setValueAt(int rowIndex, int colIndex, boolean value) {
+        validateIndex(rowIndex, colIndex);
+        int r = mMap[rowIndex];
+        int c = mMap[colIndex];
+        int element = r * mOrder + c;
+        mValues[element] = value;
+        onChanged();
+    }
+
+    /**
+     * Returns the index for which {@link #keyAt} would return the specified key, or a
+     * negative number if the specified key is not mapped.
+     */
+    public int indexOfKey(int key) {
+        return binarySearch(mKeys, mSize, key);
+    }
+
+    /**
+     * Return true if the matrix knows the user index.
+     */
+    public boolean contains(int key) {
+        return indexOfKey(key) >= 0;
+    }
+
+    /**
+     * Fetch the index of a key.  If the key does not exist and grow is true, then add the
+     * key.  If the does not exist and grow is false, return -1.
+     */
+    private int indexOfKey(int key, boolean grow) {
+        int i = binarySearch(mKeys, mSize, key);
+        if (i < 0 && grow) {
+            i = ~i;
+            if (mSize >= mOrder) {
+                // Preemptively grow the matrix, which also grows the free list.
+                growMatrix();
+            }
+            int newIndex = nextFree();
+            mKeys = GrowingArrayUtils.insert(mKeys, mSize, i, key);
+            mMap = GrowingArrayUtils.insert(mMap, mSize, i, newIndex);
+            mSize++;
+            // Initialize the row and column corresponding to the new index.
+            for (int n = 0; n < mSize; n++) {
+                mValues[n * mOrder + newIndex] = false;
+                mValues[newIndex * mOrder + n] = false;
+            }
+            onChanged();
+        }
+        return i;
+    }
+
+    /**
+     * Validate the index.  This can throw.
+     */
+    private void validateIndex(int index) {
+        if (index >= mSize) {
+            // The array might be slightly bigger than mSize, in which case, indexing won't fail.
+            throw new ArrayIndexOutOfBoundsException(index);
+        }
+    }
+
+    /**
+     * Validate two indices.
+     */
+    private void validateIndex(int row, int col) {
+        validateIndex(row);
+        validateIndex(col);
+    }
+
+    /**
+     * Find an unused storage index, mark it in-use, and return it.
+     */
+    private int nextFree() {
+        for (int i = 0; i < mInUse.length; i++) {
+            if (!mInUse[i]) {
+                mInUse[i] = true;
+                return i;
+            }
+        }
+        throw new RuntimeException();
+    }
+
+    /**
+     * Expand the 2D array.  This also extends the free list.
+     */
+    private void growMatrix() {
+        int newOrder = mOrder + STEP;
+
+        boolean[] newInuse = Arrays.copyOf(mInUse, newOrder);
+
+        boolean[] newValues = new boolean[newOrder * newOrder];
+        for (int i = 0; i < mOrder; i++) {
+            int row = mOrder * i;
+            int newRow = newOrder * i;
+            for (int j = 0; j < mOrder; j++) {
+                int index = row + j;
+                int newIndex = newRow + j;
+                newValues[newIndex] = mValues[index];
+            }
+        }
+
+        mInUse = newInuse;
+        mValues = newValues;
+        mOrder = newOrder;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public int hashCode() {
+        int hashCode = mSize;
+        for (int i = 0; i < mSize; i++) {
+            hashCode = 31 * hashCode + mKeys[i];
+            hashCode = 31 * hashCode + mMap[i];
+        }
+        for (int i = 0; i < mSize; i++) {
+            int row = mMap[i] * mOrder;
+            for (int j = 0; j < mSize; j++) {
+                int element = mMap[j] + row;
+                hashCode = 31 * hashCode + (mValues[element] ? 1 : 0);
+            }
+        }
+        return hashCode;
+    }
+
+    /**
+     * {@inheritDoc}
+     */
+    @Override
+    public boolean equals(@Nullable Object that) {
+        if (this == that) {
+            return true;
+        }
+
+        if (!(that instanceof WatchedSparseBooleanMatrix)) {
+            return false;
+        }
+
+        WatchedSparseBooleanMatrix other = (WatchedSparseBooleanMatrix) that;
+        if (mSize != other.mSize) {
+            return false;
+        }
+
+        for (int i = 0; i < mSize; i++) {
+            if (mKeys[i] != other.mKeys[i]) {
+                return false;
+            }
+            if (mMap[i] != other.mMap[i]) {
+                return false;
+            }
+        }
+        for (int i = 0; i < mSize; i++) {
+            int row = mMap[i] * mOrder;
+            for (int j = 0; j < mSize; j++) {
+                int element = mMap[j] + row;
+                if (mValues[element] != other.mValues[element]) {
+                    return false;
+                }
+            }
+        }
+        return true;
+    }
+
+    /**
+     * Return the matrix meta information.  This is always three strings long.
+     */
+    private @Size(3) String[] matrixToStringMeta() {
+        String[] result = new String[3];
+
+        StringBuilder k = new StringBuilder();
+        for (int i = 0; i < mSize; i++) {
+            k.append(mKeys[i]);
+            if (i < mSize - 1) {
+                k.append(" ");
+            }
+        }
+        result[0] = k.substring(0);
+
+        StringBuilder m = new StringBuilder();
+        for (int i = 0; i < mSize; i++) {
+            m.append(mMap[i]);
+            if (i < mSize - 1) {
+                m.append(" ");
+            }
+        }
+        result[1] = m.substring(0);
+
+        StringBuilder u = new StringBuilder();
+        for (int i = 0; i < mOrder; i++) {
+            u.append(mInUse[i] ? "1" : "0");
+        }
+        result[2] = u.substring(0);
+        return result;
+    }
+
+    /**
+     * Return the matrix as an array of strings.  There is one string per row.  Each
+     * string has a '1' or a '0' in the proper column.
+     */
+    private String[] matrixToStringRaw() {
+        String[] result = new String[mOrder];
+        for (int i = 0; i < mOrder; i++) {
+            int row = i * mOrder;
+            StringBuilder line = new StringBuilder(mOrder);
+            for (int j = 0; j < mOrder; j++) {
+                int element = row + j;
+                line.append(mValues[element] ? "1" : "0");
+            }
+            result[i] = line.substring(0);
+        }
+        return result;
+    }
+
+    private String[] matrixToStringCooked() {
+        String[] result = new String[mSize];
+        for (int i = 0; i < mSize; i++) {
+            int row = mMap[i] * mOrder;
+            StringBuilder line = new StringBuilder(mSize);
+            for (int j = 0; j < mSize; j++) {
+                int element = row + mMap[j];
+                line.append(mValues[element] ? "1" : "0");
+            }
+            result[i] = line.substring(0);
+        }
+        return result;
+    }
+
+    public String[] matrixToString(boolean raw) {
+        String[] meta = matrixToStringMeta();
+        String[] data;
+        if (raw) {
+            data = matrixToStringRaw();
+        } else {
+            data = matrixToStringCooked();
+        }
+        String[] result = new String[meta.length + data.length];
+        System.arraycopy(meta, 0, result, 0, meta.length);
+        System.arraycopy(data, 0, result, meta.length, data.length);
+        return result;
+    }
+
+    /**
+     * {@inheritDoc}
+     *
+     * <p>This implementation creates a string that describes the size of the array.  A
+     * string with all the values could easily exceed 1Mb.
+     */
+    @Override
+    public String toString() {
+        return "{" + mSize + "x" + mSize + "}";
+    }
+
+    // Copied from android.util.ContainerHelpers, which is not visible outside the
+    // android.util package.
+    private static int binarySearch(int[] array, int size, int value) {
+        int lo = 0;
+        int hi = size - 1;
+
+        while (lo <= hi) {
+            final int mid = (lo + hi) >>> 1;
+            final int midVal = array[mid];
+
+            if (midVal < value) {
+                lo = mid + 1;
+            } else if (midVal > value) {
+                hi = mid - 1;
+            } else {
+                return mid;  // value found
+            }
+        }
+        return ~lo;  // value not present
+    }
+}
diff --git a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
index fb4c623..5414a52 100644
--- a/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
+++ b/services/core/java/com/android/server/vcn/UnderlyingNetworkTracker.java
@@ -40,6 +40,7 @@
 import android.telephony.TelephonyManager;
 import android.util.ArrayMap;
 import android.util.Slog;
+import android.util.SparseArray;
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.annotations.VisibleForTesting.Visibility;
@@ -106,6 +107,17 @@
     @VisibleForTesting(visibility = Visibility.PRIVATE)
     static final int PRIORITY_ANY = Integer.MAX_VALUE;
 
+    private static final SparseArray<String> PRIORITY_TO_STRING_MAP = new SparseArray<>();
+
+    static {
+        PRIORITY_TO_STRING_MAP.put(
+                PRIORITY_OPPORTUNISTIC_CELLULAR, "PRIORITY_OPPORTUNISTIC_CELLULAR");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_IN_USE, "PRIORITY_WIFI_IN_USE");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_WIFI_PROSPECTIVE, "PRIORITY_WIFI_PROSPECTIVE");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_MACRO_CELLULAR, "PRIORITY_MACRO_CELLULAR");
+        PRIORITY_TO_STRING_MAP.put(PRIORITY_ANY, "PRIORITY_ANY");
+    }
+
     @NonNull private final VcnContext mVcnContext;
     @NonNull private final ParcelUuid mSubscriptionGroup;
     @NonNull private final Set<Integer> mRequiredUnderlyingNetworkCapabilities;
@@ -403,12 +415,12 @@
     }
 
     private void reevaluateNetworks() {
-        TreeSet<UnderlyingNetworkRecord> sorted =
-                new TreeSet<>(
-                        UnderlyingNetworkRecord.getComparator(
-                                mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig));
-        sorted.addAll(mRouteSelectionCallback.getUnderlyingNetworks());
+        if (mRouteSelectionCallback == null) {
+            return; // UnderlyingNetworkTracker has quit.
+        }
 
+        TreeSet<UnderlyingNetworkRecord> sorted =
+                mRouteSelectionCallback.getSortedUnderlyingNetworks();
         UnderlyingNetworkRecord candidate = sorted.isEmpty() ? null : sorted.first();
         if (Objects.equals(mCurrentRecord, candidate)) {
             return;
@@ -454,17 +466,23 @@
         private final Map<Network, UnderlyingNetworkRecord.Builder>
                 mUnderlyingNetworkRecordBuilders = new ArrayMap<>();
 
-        private List<UnderlyingNetworkRecord> getUnderlyingNetworks() {
-            final List<UnderlyingNetworkRecord> records = new ArrayList<>();
+        private TreeSet<UnderlyingNetworkRecord> getSortedUnderlyingNetworks() {
+            TreeSet<UnderlyingNetworkRecord> sorted =
+                    new TreeSet<>(
+                            UnderlyingNetworkRecord.getComparator(
+                                    mSubscriptionGroup,
+                                    mLastSnapshot,
+                                    mCurrentRecord,
+                                    mCarrierConfig));
 
             for (UnderlyingNetworkRecord.Builder builder :
                     mUnderlyingNetworkRecordBuilders.values()) {
                 if (builder.isValid()) {
-                    records.add(builder.build());
+                    sorted.add(builder.build());
                 }
             }
 
-            return records;
+            return sorted;
         }
 
         @Override
@@ -668,10 +686,21 @@
         }
 
         /** Dumps the state of this record for logging and debugging purposes. */
-        public void dump(IndentingPrintWriter pw) {
+        private void dump(
+                IndentingPrintWriter pw,
+                ParcelUuid subscriptionGroup,
+                TelephonySubscriptionSnapshot snapshot,
+                UnderlyingNetworkRecord currentlySelected,
+                PersistableBundle carrierConfig) {
             pw.println("UnderlyingNetworkRecord:");
             pw.increaseIndent();
 
+            final int priorityClass =
+                    calculatePriorityClass(
+                            subscriptionGroup, snapshot, currentlySelected, carrierConfig);
+            pw.println(
+                    "Priority class: " + PRIORITY_TO_STRING_MAP.get(priorityClass) + " ("
+                            + priorityClass + ")");
             pw.println("mNetwork: " + network);
             pw.println("mNetworkCapabilities: " + networkCapabilities);
             pw.println("mLinkProperties: " + linkProperties);
@@ -741,6 +770,30 @@
         }
     }
 
+    /** Dumps the state of this record for logging and debugging purposes. */
+    public void dump(IndentingPrintWriter pw) {
+        pw.println("UnderlyingNetworkTracker:");
+        pw.increaseIndent();
+
+        pw.println("Carrier WiFi Entry Threshold: " + getWifiEntryRssiThreshold(mCarrierConfig));
+        pw.println("Carrier WiFi Exit Threshold: " + getWifiExitRssiThreshold(mCarrierConfig));
+        pw.println(
+                "Currently selected: " + (mCurrentRecord == null ? null : mCurrentRecord.network));
+
+        pw.println("Underlying networks:");
+        pw.increaseIndent();
+        if (mRouteSelectionCallback != null) {
+            for (UnderlyingNetworkRecord record :
+                    mRouteSelectionCallback.getSortedUnderlyingNetworks()) {
+                record.dump(pw, mSubscriptionGroup, mLastSnapshot, mCurrentRecord, mCarrierConfig);
+            }
+        }
+        pw.decreaseIndent();
+        pw.println();
+
+        pw.decreaseIndent();
+    }
+
     private class VcnActiveDataSubscriptionIdListener extends TelephonyCallback
             implements ActiveDataSubscriptionIdListener {
         @Override
diff --git a/services/core/java/com/android/server/vcn/Vcn.java b/services/core/java/com/android/server/vcn/Vcn.java
index f918827..6b4ee69 100644
--- a/services/core/java/com/android/server/vcn/Vcn.java
+++ b/services/core/java/com/android/server/vcn/Vcn.java
@@ -557,11 +557,14 @@
 
         pw.println("mCurrentStatus: " + mCurrentStatus);
         pw.println("mIsMobileDataEnabled: " + mIsMobileDataEnabled);
+        pw.println();
 
         pw.println("mVcnGatewayConnections:");
+        pw.increaseIndent();
         for (VcnGatewayConnection gw : mVcnGatewayConnections.values()) {
             gw.dump(pw);
         }
+        pw.decreaseIndent();
         pw.println();
 
         pw.decreaseIndent();
diff --git a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
index 5cecff6..fbbae97 100644
--- a/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
+++ b/services/core/java/com/android/server/vcn/VcnGatewayConnection.java
@@ -1970,6 +1970,9 @@
             }
             builder.setAdministratorUids(adminUids);
 
+            builder.setLinkUpstreamBandwidthKbps(underlyingCaps.getLinkUpstreamBandwidthKbps());
+            builder.setLinkDownstreamBandwidthKbps(underlyingCaps.getLinkDownstreamBandwidthKbps());
+
             // Set TransportInfo for SysUI use (never parcelled out of SystemServer).
             if (underlyingCaps.hasTransport(TRANSPORT_WIFI)
                     && underlyingCaps.getTransportInfo() instanceof WifiInfo) {
@@ -1986,6 +1989,11 @@
                         "Unknown transport type or missing TransportInfo/NetworkSpecifier for"
                                 + " non-null underlying network");
             }
+        } else {
+            Slog.wtf(
+                    TAG,
+                    "No underlying network while building network capabilities",
+                    new IllegalStateException());
         }
 
         return builder.build();
@@ -2013,7 +2021,18 @@
         lp.addRoute(new RouteInfo(new IpPrefix(Inet6Address.ANY, 0), null /*gateway*/,
                 null /*iface*/, RouteInfo.RTN_UNICAST));
 
-        final int underlyingMtu = (underlying == null) ? 0 : underlying.linkProperties.getMtu();
+        int underlyingMtu = 0;
+        if (underlying != null) {
+            final LinkProperties underlyingLp = underlying.linkProperties;
+
+            lp.setTcpBufferSizes(underlyingLp.getTcpBufferSizes());
+            underlyingMtu = underlyingLp.getMtu();
+        } else {
+            Slog.wtf(
+                    TAG,
+                    "No underlying network while building link properties",
+                    new IllegalStateException());
+        }
         lp.setMtu(
                 MtuUtils.getMtu(
                         ikeTunnelParams.getTunnelModeChildSessionParams().getSaProposals(),
@@ -2169,15 +2188,9 @@
         pw.println(
                 "mNetworkAgent.getNetwork(): "
                         + (mNetworkAgent == null ? null : mNetworkAgent.getNetwork()));
+        pw.println();
 
-        pw.println("mUnderlying:");
-        pw.increaseIndent();
-        if (mUnderlying != null) {
-            mUnderlying.dump(pw);
-        } else {
-            pw.println("null");
-        }
-        pw.decreaseIndent();
+        mUnderlyingNetworkTracker.dump(pw);
         pw.println();
 
         pw.decreaseIndent();
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/InsetsPolicy.java b/services/core/java/com/android/server/wm/InsetsPolicy.java
index c387d33..f2f1926 100644
--- a/services/core/java/com/android/server/wm/InsetsPolicy.java
+++ b/services/core/java/com/android/server/wm/InsetsPolicy.java
@@ -22,6 +22,8 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_SPLIT_SCREEN_PRIMARY;
 import static android.view.InsetsController.ANIMATION_TYPE_HIDE;
 import static android.view.InsetsController.ANIMATION_TYPE_SHOW;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_HIDDEN;
+import static android.view.InsetsController.LAYOUT_INSETS_DURING_ANIMATION_SHOWN;
 import static android.view.InsetsState.ITYPE_IME;
 import static android.view.InsetsState.ITYPE_NAVIGATION_BAR;
 import static android.view.InsetsState.ITYPE_STATUS_BAR;
@@ -522,7 +524,10 @@
                 mAnimationControl = new InsetsAnimationControlImpl(controls,
                         null /* frame */, state, mListener, typesReady, this,
                         mListener.getDurationMs(), getInsetsInterpolator(),
-                        show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, null /* translator */);
+                        show ? ANIMATION_TYPE_SHOW : ANIMATION_TYPE_HIDE, show
+                                ? LAYOUT_INSETS_DURING_ANIMATION_SHOWN
+                                : LAYOUT_INSETS_DURING_ANIMATION_HIDDEN,
+                        null /* translator */);
                 SurfaceAnimationThread.getHandler().post(
                         () -> mListener.onReady(mAnimationControl, typesReady));
             }
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/java/com/android/server/SystemServer.java b/services/java/com/android/server/SystemServer.java
index ad89e96..d487483 100644
--- a/services/java/com/android/server/SystemServer.java
+++ b/services/java/com/android/server/SystemServer.java
@@ -103,7 +103,6 @@
 import com.android.internal.widget.ILockSettings;
 import com.android.server.am.ActivityManagerService;
 import com.android.server.appbinding.AppBindingService;
-import com.android.server.art.ArtManagerLocal;
 import com.android.server.attention.AttentionManagerService;
 import com.android.server.audio.AudioService;
 import com.android.server.biometrics.AuthService;
@@ -2632,10 +2631,6 @@
         mSystemServiceManager.startService(GAME_MANAGER_SERVICE_CLASS);
         t.traceEnd();
 
-        t.traceBegin("ArtManagerLocal");
-        LocalManagerRegistry.addManager(ArtManagerLocal.class, new ArtManagerLocal());
-        t.traceEnd();
-
         if (context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_UWB)) {
             t.traceBegin("UwbService");
             mSystemServiceManager.startService(UWB_SERVICE_CLASS);
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/tests/servicestests/src/com/android/server/utils/WatcherTest.java b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
index 9679e58..5db9492 100644
--- a/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
+++ b/services/tests/servicestests/src/com/android/server/utils/WatcherTest.java
@@ -22,6 +22,7 @@
 
 import android.util.ArrayMap;
 import android.util.ArraySet;
+import android.util.Log;
 import android.util.LongSparseArray;
 import android.util.SparseArray;
 import android.util.SparseBooleanArray;
@@ -34,9 +35,12 @@
 import org.junit.Test;
 
 import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Random;
 
 /**
- * Test class for {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
+ * Test class for various utility classes that support the Watchable or Snappable
+ * features.  This covers {@link Watcher}, {@link Watchable}, {@link WatchableImpl},
  * {@link WatchedArrayMap}, {@link WatchedSparseArray}, and
  * {@link WatchedSparseBooleanArray}.
  *
@@ -858,6 +862,93 @@
         }
     }
 
+    private static class IndexGenerator {
+        private final int mSeed;
+        private final Random mRandom;
+        public IndexGenerator(int seed) {
+            mSeed = seed;
+            mRandom = new Random(mSeed);
+        }
+        public int index() {
+            return mRandom.nextInt(50000);
+        }
+        public void reset() {
+            mRandom.setSeed(mSeed);
+        }
+    }
+
+    // Return a value based on the row and column.  The algorithm tries to avoid simple
+    // patterns like checkerboard.
+    private final boolean cellValue(int row, int col) {
+        return (((row * 4 + col) % 3)& 1) == 1;
+    }
+
+    // This is an inefficient way to know if a value appears in an array.
+    private final boolean contains(int[] s, int length, int k) {
+        for (int i = 0; i < length; i++) {
+            if (s[i] == k) {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    private void matrixTest(WatchedSparseBooleanMatrix matrix, int size, IndexGenerator indexer) {
+        indexer.reset();
+        int[] indexes = new int[size];
+        for (int i = 0; i < size; i++) {
+            int key = indexer.index();
+            // Ensure the list of indices are unique.
+            while (contains(indexes, i, key)) {
+                key = indexer.index();
+            }
+            indexes[i] = key;
+        }
+        // Set values in the matrix.
+        for (int i = 0; i < size; i++) {
+            int row = indexes[i];
+            for (int j = 0; j < size; j++) {
+                int col = indexes[j];
+                boolean want = cellValue(i, j);
+                matrix.put(row, col, want);
+            }
+        }
+
+        assertEquals(matrix.size(), size);
+
+        // Read back and verify
+        for (int i = 0; i < matrix.size(); i++) {
+            int row = indexes[i];
+            for (int j = 0; j < matrix.size(); j++) {
+                int col = indexes[j];
+                boolean want = cellValue(i, j);
+                boolean actual = matrix.get(row, col);
+                String msg = String.format("matrix(%d:%d, %d:%d) == %s, expected %s",
+                                           i, row, j, col, actual, want);
+                assertEquals(msg, actual, want);
+            }
+        }
+
+        // Test the keyAt/indexOfKey methods
+        for (int i = 0; i < matrix.size(); i++) {
+            int key = indexes[i];
+            assertEquals(matrix.keyAt(matrix.indexOfKey(key)), key);
+        }
+    }
+
+    @Test
+    public void testWatchedSparseBooleanMatrix() {
+        final String name = "WatchedSparseBooleanMatrix";
+
+        // The first part of this method tests the core matrix functionality.  The second
+        // part tests the watchable behavior.  The third part tests the snappable
+        // behavior.
+        IndexGenerator indexer = new IndexGenerator(3);
+        matrixTest(new WatchedSparseBooleanMatrix(), 10, indexer);
+        matrixTest(new WatchedSparseBooleanMatrix(1000), 500, indexer);
+        matrixTest(new WatchedSparseBooleanMatrix(1000), 2000, indexer);
+    }
+
     @Test
     public void testNestedArrays() {
         final String name = "NestedArrays";
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) {
diff --git a/telecomm/java/android/telecom/CallDiagnosticService.java b/telecomm/java/android/telecom/CallDiagnosticService.java
index 011dc17..336a8ea 100644
--- a/telecomm/java/android/telecom/CallDiagnosticService.java
+++ b/telecomm/java/android/telecom/CallDiagnosticService.java
@@ -294,6 +294,10 @@
         CallDiagnostics callDiagnostics;
         synchronized (mLock) {
             callDiagnostics = mDiagnosticCallByTelecomCallId.get(telecomCallId);
+            if (callDiagnostics == null) {
+                // Possible to get a call update after a call is removed.
+                return;
+            }
             mCallByTelecomCallId.put(telecomCallId, newCallDetails);
         }
         getExecutor().execute(() -> callDiagnostics.handleCallUpdated(newCallDetails));
@@ -306,12 +310,12 @@
     private void handleCallRemoved(@NonNull String telecomCallId) {
         Log.i(this, "handleCallRemoved: callId=%s - removed", telecomCallId);
 
-        if (mCallByTelecomCallId.containsKey(telecomCallId)) {
-            mCallByTelecomCallId.remove(telecomCallId);
-        }
-
         CallDiagnostics callDiagnostics;
         synchronized (mLock) {
+            if (mCallByTelecomCallId.containsKey(telecomCallId)) {
+                mCallByTelecomCallId.remove(telecomCallId);
+            }
+
             if (mDiagnosticCallByTelecomCallId.containsKey(telecomCallId)) {
                 callDiagnostics = mDiagnosticCallByTelecomCallId.remove(telecomCallId);
             } else {
@@ -353,7 +357,10 @@
     private void handleCallDisconnected(@NonNull String callId,
             @NonNull DisconnectCause disconnectCause) {
         Log.i(this, "handleCallDisconnected: call=%s; cause=%s", callId, disconnectCause);
-        CallDiagnostics callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+        CallDiagnostics callDiagnostics;
+        synchronized (mLock) {
+            callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+        }
         CharSequence message;
         if (disconnectCause.getImsReasonInfo() != null) {
             message = callDiagnostics.onCallDisconnected(disconnectCause.getImsReasonInfo());
@@ -391,7 +398,9 @@
             @NonNull CallQuality callQuality) {
         Log.i(this, "handleCallQualityChanged; call=%s, cq=%s", callId, callQuality);
         CallDiagnostics callDiagnostics;
-        callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+        synchronized(mLock) {
+            callDiagnostics = mDiagnosticCallByTelecomCallId.get(callId);
+        }
         if (callDiagnostics != null) {
             callDiagnostics.onCallQualityReceived(callQuality);
         }
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
index 39f7386..9c93f81 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionConnectedStateTest.java
@@ -200,6 +200,9 @@
     public void testMigration() throws Exception {
         triggerChildOpened();
 
+        mGatewayConnection
+                .getUnderlyingNetworkTrackerCallback()
+                .onSelectedUnderlyingNetworkChanged(TEST_UNDERLYING_NETWORK_RECORD_2);
         getChildSessionCallback()
                 .onIpSecTransformsMigrated(makeDummyIpSecTransform(), makeDummyIpSecTransform());
         mTestLooper.dispatchAll();
@@ -207,7 +210,7 @@
         verify(mIpSecSvc, times(2))
                 .setNetworkForTunnelInterface(
                         eq(TEST_IPSEC_TUNNEL_RESOURCE_ID),
-                        eq(TEST_UNDERLYING_NETWORK_RECORD_1.network),
+                        eq(TEST_UNDERLYING_NETWORK_RECORD_2.network),
                         any());
 
         for (int direction : new int[] {DIRECTION_IN, DIRECTION_OUT}) {
@@ -226,8 +229,10 @@
                 MtuUtils.getMtu(
                         saProposals,
                         mConfig.getMaxMtu(),
-                        TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.getMtu());
-        verify(mNetworkAgent).sendLinkProperties(argThat(lp -> expectedMtu == lp.getMtu()));
+                        TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.getMtu());
+        verify(mNetworkAgent).sendLinkProperties(
+                argThat(lp -> expectedMtu == lp.getMtu()
+                        && TEST_TCP_BUFFER_SIZES_2.equals(lp.getTcpBufferSizes())));
     }
 
     private void triggerChildOpened() {
@@ -297,6 +302,7 @@
         final LinkProperties lp = lpCaptor.getValue();
         assertEquals(Collections.singletonList(TEST_INTERNAL_ADDR), lp.getLinkAddresses());
         assertEquals(Collections.singletonList(TEST_DNS_ADDR), lp.getDnsServers());
+        assertEquals(TEST_TCP_BUFFER_SIZES_1, lp.getTcpBufferSizes());
 
         final NetworkCapabilities nc = ncCaptor.getValue();
         assertTrue(nc.hasTransport(TRANSPORT_CELLULAR));
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
index 9705f0f..a4f95e0 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTest.java
@@ -74,6 +74,9 @@
     private static final SubscriptionInfo TEST_SUBINFO_2 = mock(SubscriptionInfo.class);
     private static final Map<Integer, ParcelUuid> TEST_SUBID_TO_GROUP_MAP;
 
+    private static final int TEST_UPSTREAM_BANDWIDTH = 1234;
+    private static final int TEST_DOWNSTREAM_BANDWIDTH = 2345;
+
     static {
         final Map<Integer, ParcelUuid> subIdToGroupMap = new HashMap<>();
         subIdToGroupMap.put(TEST_SUBSCRIPTION_ID_1, TEST_PARCEL_UUID);
@@ -106,6 +109,8 @@
             capBuilder.setNetworkSpecifier(
                     new TelephonyNetworkSpecifier(TEST_SUBSCRIPTION_ID_1));
         }
+        capBuilder.setLinkUpstreamBandwidthKbps(TEST_UPSTREAM_BANDWIDTH);
+        capBuilder.setLinkDownstreamBandwidthKbps(TEST_DOWNSTREAM_BANDWIDTH);
         capBuilder.setAdministratorUids(new int[] {TEST_UID});
         UnderlyingNetworkRecord record = new UnderlyingNetworkRecord(
                 mock(Network.class, CALLS_REAL_METHODS),
@@ -130,6 +135,8 @@
 
         assertArrayEquals(new int[] {TEST_UID}, vcnCaps.getAdministratorUids());
         assertTrue(vcnCaps.getTransportInfo() instanceof VcnTransportInfo);
+        assertEquals(TEST_UPSTREAM_BANDWIDTH, vcnCaps.getLinkUpstreamBandwidthKbps());
+        assertEquals(TEST_DOWNSTREAM_BANDWIDTH, vcnCaps.getLinkDownstreamBandwidthKbps());
 
         final VcnTransportInfo info = (VcnTransportInfo) vcnCaps.getTransportInfo();
         if (transportType == TRANSPORT_WIFI) {
diff --git a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
index c747bc0..0a4fcbc 100644
--- a/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
+++ b/tests/vcn/java/com/android/server/vcn/VcnGatewayConnectionTestBase.java
@@ -99,6 +99,7 @@
     protected static final long ELAPSED_REAL_TIME = 123456789L;
     protected static final String TEST_IPSEC_TUNNEL_IFACE = "IPSEC_IFACE";
 
+    protected static final String TEST_TCP_BUFFER_SIZES_1 = "1,2,3,4";
     protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_1 =
             new UnderlyingNetworkRecord(
                     mock(Network.class, CALLS_REAL_METHODS),
@@ -108,8 +109,10 @@
 
     static {
         TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setMtu(1500);
+        TEST_UNDERLYING_NETWORK_RECORD_1.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_1);
     }
 
+    protected static final String TEST_TCP_BUFFER_SIZES_2 = "2,3,4,5";
     protected static final UnderlyingNetworkRecord TEST_UNDERLYING_NETWORK_RECORD_2 =
             new UnderlyingNetworkRecord(
                     mock(Network.class, CALLS_REAL_METHODS),
@@ -119,6 +122,7 @@
 
     static {
         TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setMtu(1460);
+        TEST_UNDERLYING_NETWORK_RECORD_2.linkProperties.setTcpBufferSizes(TEST_TCP_BUFFER_SIZES_2);
     }
 
     protected static final TelephonySubscriptionSnapshot TEST_SUBSCRIPTION_SNAPSHOT =