Merge "Add ABS_MT_SLOT config to virtual touch screen." into tm-qpr-dev
diff --git a/core/java/android/app/ActivityTransitionState.java b/core/java/android/app/ActivityTransitionState.java
index 877e7d3..6f4bb45 100644
--- a/core/java/android/app/ActivityTransitionState.java
+++ b/core/java/android/app/ActivityTransitionState.java
@@ -145,7 +145,10 @@
      * that it is preserved through activty destroy and restore.
      */
     private ArrayList<String> getPendingExitNames() {
-        if (mPendingExitNames == null && mEnterTransitionCoordinator != null) {
+        if (mPendingExitNames == null
+                && mEnterTransitionCoordinator != null
+                && !mEnterTransitionCoordinator.isReturning()
+        ) {
             mPendingExitNames = mEnterTransitionCoordinator.getPendingExitSharedElementNames();
         }
         return mPendingExitNames;
@@ -202,6 +205,7 @@
             restoreExitedViews();
             activity.getWindow().getDecorView().setVisibility(View.VISIBLE);
         }
+        getPendingExitNames(); // Set mPendingExitNames before resetting mEnterTransitionCoordinator
         mEnterTransitionCoordinator = new EnterTransitionCoordinator(activity,
                 resultReceiver, sharedElementNames, mEnterActivityOptions.isReturning(),
                 mEnterActivityOptions.isCrossTask());
@@ -250,6 +254,7 @@
     public void onStop(Activity activity) {
         restoreExitedViews();
         if (mEnterTransitionCoordinator != null) {
+            getPendingExitNames(); // Set mPendingExitNames before clearing
             mEnterTransitionCoordinator.stop();
             mEnterTransitionCoordinator = null;
         }
@@ -275,6 +280,7 @@
                         restoreReenteringViews();
                     } else if (mEnterTransitionCoordinator.isReturning()) {
                         mEnterTransitionCoordinator.runAfterTransitionsComplete(() -> {
+                            getPendingExitNames(); // Set mPendingExitNames before clearing
                             mEnterTransitionCoordinator = null;
                         });
                     }
@@ -374,6 +380,7 @@
     }
 
     public void startExitOutTransition(Activity activity, Bundle options) {
+        getPendingExitNames(); // Set mPendingExitNames before clearing mEnterTransitionCoordinator
         mEnterTransitionCoordinator = null;
         if (!activity.getWindow().hasFeature(Window.FEATURE_ACTIVITY_TRANSITIONS) ||
                 mExitTransitionCoordinators == null) {
diff --git a/core/java/android/service/trust/TrustAgentService.java b/core/java/android/service/trust/TrustAgentService.java
index 559313a..41345e0 100644
--- a/core/java/android/service/trust/TrustAgentService.java
+++ b/core/java/android/service/trust/TrustAgentService.java
@@ -141,7 +141,9 @@
      *
      * Without this flag, the message passed to {@code grantTrust} is only used for debugging
      * purposes. With the flag, it may be displayed to the user as the reason why the device is
-     * unlocked.
+     * unlocked. If this flag isn't set OR the message is set to null, the device will display
+     * its own default message for trust granted. If the TrustAgent intentionally doesn't want to
+     * show any message, then it can set this flag AND set the message to an empty string.
      */
     public static final int FLAG_GRANT_TRUST_DISPLAY_MESSAGE = 1 << 3;
 
diff --git a/core/java/android/view/View.java b/core/java/android/view/View.java
index ba6ba63..b0d4657 100644
--- a/core/java/android/view/View.java
+++ b/core/java/android/view/View.java
@@ -12709,7 +12709,6 @@
         if (mViewTranslationCallback != null) {
             mViewTranslationCallback.onClearTranslation(this);
         }
-        clearViewTranslationCallback();
         clearViewTranslationResponse();
         if (hasTranslationTransientState()) {
             setHasTransientState(false);
diff --git a/core/java/android/view/WindowManager.java b/core/java/android/view/WindowManager.java
index 2195b83..218ca58 100644
--- a/core/java/android/view/WindowManager.java
+++ b/core/java/android/view/WindowManager.java
@@ -285,12 +285,18 @@
     int TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER = 21;
 
     /**
-     * Keyguard is being occluded.
+     * Keyguard is being occluded by non-Dream.
      * @hide
      */
     int TRANSIT_OLD_KEYGUARD_OCCLUDE = 22;
 
     /**
+     * Keyguard is being occluded by Dream.
+     * @hide
+     */
+    int TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM = 33;
+
+    /**
      * Keyguard is being unoccluded.
      * @hide
      */
diff --git a/core/java/com/android/internal/app/ChooserActivity.java b/core/java/com/android/internal/app/ChooserActivity.java
index a66b405..cb30021 100644
--- a/core/java/com/android/internal/app/ChooserActivity.java
+++ b/core/java/com/android/internal/app/ChooserActivity.java
@@ -142,6 +142,7 @@
 import java.net.URISyntaxException;
 import java.text.Collator;
 import java.util.ArrayList;
+import java.util.Arrays;
 import java.util.Collections;
 import java.util.Comparator;
 import java.util.HashMap;
@@ -3708,6 +3709,7 @@
             this.mRows = rows;
             this.mCellCountPerRow = cellCountPerRow;
             this.mCellVisibility = new boolean[rows.size() * cellCountPerRow];
+            Arrays.fill(mCellVisibility, true);
             this.mListAdapterSupplier = listAdapterSupplier;
         }
 
diff --git a/core/java/com/android/internal/app/ChooserListAdapter.java b/core/java/com/android/internal/app/ChooserListAdapter.java
index e57b90a..1ec5325 100644
--- a/core/java/com/android/internal/app/ChooserListAdapter.java
+++ b/core/java/com/android/internal/app/ChooserListAdapter.java
@@ -43,7 +43,6 @@
 import android.widget.TextView;
 
 import com.android.internal.R;
-import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.app.ResolverActivity.ResolvedComponentInfo;
 import com.android.internal.app.chooser.ChooserTargetInfo;
 import com.android.internal.app.chooser.DisplayResolveInfo;
@@ -87,7 +86,7 @@
     private final ChooserActivityLogger mChooserActivityLogger;
 
     private int mNumShortcutResults = 0;
-    private final Map<TargetInfo, AsyncTask> mIconLoaders = new HashMap<>();
+    private Map<DisplayResolveInfo, LoadIconTask> mIconLoaders = new HashMap<>();
     private boolean mApplySharingAppLimits;
 
     // Reserve spots for incoming direct share targets by adding placeholders
@@ -105,8 +104,6 @@
     private AppPredictor mAppPredictor;
     private AppPredictor.Callback mAppPredictorCallback;
 
-    private LoadDirectShareIconTaskProvider mTestLoadDirectShareTaskProvider;
-
     // For pinned direct share labels, if the text spans multiple lines, the TextView will consume
     // the full width, even if the characters actually take up less than that. Measure the actual
     // line widths and constrain the View's width based upon that so that the pin doesn't end up
@@ -243,6 +240,7 @@
         mListViewDataChanged = false;
     }
 
+
     private void createPlaceHolders() {
         mNumShortcutResults = 0;
         mServiceTargets.clear();
@@ -267,25 +265,31 @@
             return;
         }
 
-        if (info instanceof DisplayResolveInfo) {
-            DisplayResolveInfo dri = (DisplayResolveInfo) info;
-            holder.bindLabel(dri.getDisplayLabel(), dri.getExtendedInfo(), alwaysShowSubLabel());
-            startDisplayResolveInfoIconLoading(holder, dri);
-        } else {
+        if (!(info instanceof DisplayResolveInfo)) {
             holder.bindLabel(info.getDisplayLabel(), info.getExtendedInfo(), alwaysShowSubLabel());
+            holder.bindIcon(info);
 
             if (info instanceof SelectableTargetInfo) {
-                SelectableTargetInfo selectableInfo = (SelectableTargetInfo) info;
                 // direct share targets should append the application name for a better readout
-                DisplayResolveInfo rInfo = selectableInfo.getDisplayResolveInfo();
+                DisplayResolveInfo rInfo = ((SelectableTargetInfo) info).getDisplayResolveInfo();
                 CharSequence appName = rInfo != null ? rInfo.getDisplayLabel() : "";
-                CharSequence extendedInfo = selectableInfo.getExtendedInfo();
-                String contentDescription = String.join(" ", selectableInfo.getDisplayLabel(),
+                CharSequence extendedInfo = info.getExtendedInfo();
+                String contentDescription = String.join(" ", info.getDisplayLabel(),
                         extendedInfo != null ? extendedInfo : "", appName);
                 holder.updateContentDescription(contentDescription);
-                startSelectableTargetInfoIconLoading(holder, selectableInfo);
+            }
+        } else {
+            DisplayResolveInfo dri = (DisplayResolveInfo) info;
+            holder.bindLabel(dri.getDisplayLabel(), dri.getExtendedInfo(), alwaysShowSubLabel());
+            LoadIconTask task = mIconLoaders.get(dri);
+            if (task == null) {
+                task = new LoadIconTask(dri, holder);
+                mIconLoaders.put(dri, task);
+                task.execute();
             } else {
-                holder.bindIcon(info);
+                // The holder was potentially changed as the underlying items were
+                // reshuffled, so reset the target holder
+                task.setViewHolder(holder);
             }
         }
 
@@ -326,32 +330,6 @@
         }
     }
 
-    private void startDisplayResolveInfoIconLoading(ViewHolder holder, DisplayResolveInfo info) {
-        LoadIconTask task = (LoadIconTask) mIconLoaders.get(info);
-        if (task == null) {
-            task = new LoadIconTask(info, holder);
-            mIconLoaders.put(info, task);
-            task.execute();
-        } else {
-            // The holder was potentially changed as the underlying items were
-            // reshuffled, so reset the target holder
-            task.setViewHolder(holder);
-        }
-    }
-
-    private void startSelectableTargetInfoIconLoading(
-            ViewHolder holder, SelectableTargetInfo info) {
-        LoadDirectShareIconTask task = (LoadDirectShareIconTask) mIconLoaders.get(info);
-        if (task == null) {
-            task = mTestLoadDirectShareTaskProvider == null
-                    ? new LoadDirectShareIconTask(info)
-                    : mTestLoadDirectShareTaskProvider.get();
-            mIconLoaders.put(info, task);
-            task.loadIcon();
-        }
-        task.setViewHolder(holder);
-    }
-
     void updateAlphabeticalList() {
         new AsyncTask<Void, Void, List<DisplayResolveInfo>>() {
             @Override
@@ -366,7 +344,7 @@
                 Map<String, DisplayResolveInfo> consolidated = new HashMap<>();
                 for (DisplayResolveInfo info : allTargets) {
                     String resolvedTarget = info.getResolvedComponentName().getPackageName()
-                            + '#' + info.getDisplayLabel();
+                        + '#' + info.getDisplayLabel();
                     DisplayResolveInfo multiDri = consolidated.get(resolvedTarget);
                     if (multiDri == null) {
                         consolidated.put(resolvedTarget, info);
@@ -375,7 +353,7 @@
                     } else {
                         // create consolidated target from the single DisplayResolveInfo
                         MultiDisplayResolveInfo multiDisplayResolveInfo =
-                                new MultiDisplayResolveInfo(resolvedTarget, multiDri);
+                            new MultiDisplayResolveInfo(resolvedTarget, multiDri);
                         multiDisplayResolveInfo.addTarget(info);
                         consolidated.put(resolvedTarget, multiDisplayResolveInfo);
                     }
@@ -762,24 +740,10 @@
     }
 
     /**
-     * An alias for onBindView to use with unit tests.
-     */
-    @VisibleForTesting
-    public void testViewBind(View view, TargetInfo info, int position) {
-        onBindView(view, info, position);
-    }
-
-    @VisibleForTesting
-    public void setTestLoadDirectShareTaskProvider(LoadDirectShareIconTaskProvider provider) {
-        mTestLoadDirectShareTaskProvider = provider;
-    }
-
-    /**
      * Necessary methods to communicate between {@link ChooserListAdapter}
      * and {@link ChooserActivity}.
      */
-    @VisibleForTesting
-    public interface ChooserListCommunicator extends ResolverListCommunicator {
+    interface ChooserListCommunicator extends ResolverListCommunicator {
 
         int getMaxRankedTargets();
 
@@ -787,59 +751,4 @@
 
         boolean isSendAction(Intent targetIntent);
     }
-
-    /**
-     * Loads direct share targets icons.
-     */
-    @VisibleForTesting
-    public class LoadDirectShareIconTask extends AsyncTask<Void, Void, Void> {
-        private final SelectableTargetInfo mTargetInfo;
-        private ViewHolder mViewHolder;
-
-        private LoadDirectShareIconTask(SelectableTargetInfo targetInfo) {
-            mTargetInfo = targetInfo;
-        }
-
-        @Override
-        protected Void doInBackground(Void... voids) {
-            mTargetInfo.loadIcon();
-            return null;
-        }
-
-        @Override
-        protected void onPostExecute(Void arg) {
-            if (mViewHolder != null) {
-                mViewHolder.bindIcon(mTargetInfo);
-                notifyDataSetChanged();
-            }
-        }
-
-        /**
-         * Specifies a view holder that will be updated when the task is completed.
-         */
-        public void setViewHolder(ViewHolder viewHolder) {
-            mViewHolder = viewHolder;
-            mViewHolder.bindIcon(mTargetInfo);
-            notifyDataSetChanged();
-        }
-
-        /**
-         * An alias for execute to use with unit tests.
-         */
-        public void loadIcon() {
-            execute();
-        }
-    }
-
-    /**
-     * An interface for the unit tests to override icon loading task creation
-     */
-    @VisibleForTesting
-    public interface LoadDirectShareIconTaskProvider {
-        /**
-         * Provides an instance of the task.
-         * @return
-         */
-        LoadDirectShareIconTask get();
-    }
 }
diff --git a/core/java/com/android/internal/app/ResolverListAdapter.java b/core/java/com/android/internal/app/ResolverListAdapter.java
index 3a3baa7..66fff5c 100644
--- a/core/java/com/android/internal/app/ResolverListAdapter.java
+++ b/core/java/com/android/internal/app/ResolverListAdapter.java
@@ -834,11 +834,7 @@
         void onHandlePackagesChanged(ResolverListAdapter listAdapter);
     }
 
-    /**
-     * A view holder.
-     */
-    @VisibleForTesting
-    public static class ViewHolder {
+    static class ViewHolder {
         public View itemView;
         public Drawable defaultItemViewBackground;
 
@@ -846,8 +842,7 @@
         public TextView text2;
         public ImageView icon;
 
-        @VisibleForTesting
-        public ViewHolder(View view) {
+        ViewHolder(View view) {
             itemView = view;
             defaultItemViewBackground = view.getBackground();
             text = (TextView) view.findViewById(com.android.internal.R.id.text1);
diff --git a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
index 37eab40..264e4f7 100644
--- a/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
+++ b/core/java/com/android/internal/app/chooser/SelectableTargetInfo.java
@@ -37,7 +37,6 @@
 import android.text.SpannableStringBuilder;
 import android.util.Log;
 
-import com.android.internal.annotations.GuardedBy;
 import com.android.internal.app.ChooserActivity;
 import com.android.internal.app.ResolverActivity;
 import com.android.internal.app.ResolverListAdapter.ActivityInfoPresentationGetter;
@@ -60,11 +59,8 @@
     private final String mDisplayLabel;
     private final PackageManager mPm;
     private final SelectableTargetInfoCommunicator mSelectableTargetInfoCommunicator;
-    @GuardedBy("this")
-    private ShortcutInfo mShortcutInfo;
     private Drawable mBadgeIcon = null;
     private CharSequence mBadgeContentDescription;
-    @GuardedBy("this")
     private Drawable mDisplayIcon;
     private final Intent mFillInIntent;
     private final int mFillInFlags;
@@ -82,7 +78,6 @@
         mModifiedScore = modifiedScore;
         mPm = mContext.getPackageManager();
         mSelectableTargetInfoCommunicator = selectableTargetInfoComunicator;
-        mShortcutInfo = shortcutInfo;
         mIsPinned = shortcutInfo != null && shortcutInfo.isPinned();
         if (sourceInfo != null) {
             final ResolveInfo ri = sourceInfo.getResolveInfo();
@@ -97,6 +92,8 @@
                 }
             }
         }
+        // TODO(b/121287224): do this in the background thread, and only for selected targets
+        mDisplayIcon = getChooserTargetIconDrawable(chooserTarget, shortcutInfo);
 
         if (sourceInfo != null) {
             mBackupResolveInfo = null;
@@ -121,10 +118,7 @@
         mChooserTarget = other.mChooserTarget;
         mBadgeIcon = other.mBadgeIcon;
         mBadgeContentDescription = other.mBadgeContentDescription;
-        synchronized (other) {
-            mShortcutInfo = other.mShortcutInfo;
-            mDisplayIcon = other.mDisplayIcon;
-        }
+        mDisplayIcon = other.mDisplayIcon;
         mFillInIntent = fillInIntent;
         mFillInFlags = flags;
         mModifiedScore = other.mModifiedScore;
@@ -147,25 +141,6 @@
         return mSourceInfo;
     }
 
-    /**
-     * Load display icon, if needed.
-     */
-    public void loadIcon() {
-        ShortcutInfo shortcutInfo;
-        Drawable icon;
-        synchronized (this) {
-            shortcutInfo = mShortcutInfo;
-            icon = mDisplayIcon;
-        }
-        if (icon == null && shortcutInfo != null) {
-            icon = getChooserTargetIconDrawable(mChooserTarget, shortcutInfo);
-            synchronized (this) {
-                mDisplayIcon = icon;
-                mShortcutInfo = null;
-            }
-        }
-    }
-
     private Drawable getChooserTargetIconDrawable(ChooserTarget target,
             @Nullable ShortcutInfo shortcutInfo) {
         Drawable directShareIcon = null;
@@ -295,7 +270,7 @@
     }
 
     @Override
-    public synchronized Drawable getDisplayIcon(Context context) {
+    public Drawable getDisplayIcon(Context context) {
         return mDisplayIcon;
     }
 
diff --git a/core/java/com/android/internal/widget/ConversationLayout.java b/core/java/com/android/internal/widget/ConversationLayout.java
index 4706aff..5f8acff 100644
--- a/core/java/com/android/internal/widget/ConversationLayout.java
+++ b/core/java/com/android/internal/widget/ConversationLayout.java
@@ -111,6 +111,7 @@
     private Icon mLargeIcon;
     private View mExpandButtonContainer;
     private ViewGroup mExpandButtonAndContentContainer;
+    private ViewGroup mExpandButtonContainerA11yContainer;
     private NotificationExpandButton mExpandButton;
     private MessagingLinearLayout mImageMessageContainer;
     private int mBadgeProtrusion;
@@ -234,6 +235,8 @@
         });
         mConversationText = findViewById(R.id.conversation_text);
         mExpandButtonContainer = findViewById(R.id.expand_button_container);
+        mExpandButtonContainerA11yContainer =
+                findViewById(R.id.expand_button_a11y_container);
         mConversationHeader = findViewById(R.id.conversation_header);
         mContentContainer = findViewById(R.id.notification_action_list_margin_target);
         mExpandButtonAndContentContainer = findViewById(R.id.expand_button_and_content_container);
@@ -1091,7 +1094,7 @@
             newContainer = mExpandButtonAndContentContainer;
         } else {
             buttonGravity = Gravity.CENTER_HORIZONTAL | Gravity.TOP;
-            newContainer = this;
+            newContainer = mExpandButtonContainerA11yContainer;
         }
         mExpandButton.setExpanded(!mIsCollapsed);
 
diff --git a/core/res/res/layout/notification_template_material_conversation.xml b/core/res/res/layout/notification_template_material_conversation.xml
index 42fb4a2..ce8a904 100644
--- a/core/res/res/layout/notification_template_material_conversation.xml
+++ b/core/res/res/layout/notification_template_material_conversation.xml
@@ -89,45 +89,62 @@
         <include layout="@layout/notification_material_action_list" />
     </com.android.internal.widget.RemeasuringLinearLayout>
 
-    <!--This is dynamically placed between here and at the end of the layout. It starts here since
-        only FrameLayout layout params have gravity-->
+    <!--expand_button_a11y_container ensures talkback focus order is correct when view is expanded.
+    The -1px of marginTop and 1px of paddingTop make sure expand_button_a11y_container is prior to
+    its sibling view in accessibility focus order.
+    {see android.view.ViewGroup.addChildrenForAccessibility()}
+    expand_button_container will be moved under expand_button_and_content_container when collapsed,
+    this dynamic movement ensures message can flow under expand button when expanded-->
     <FrameLayout
-        android:id="@+id/expand_button_container"
-        android:layout_width="wrap_content"
+        android:id="@+id/expand_button_a11y_container"
+        android:layout_width="match_parent"
         android:layout_height="match_parent"
         android:layout_gravity="end|top"
         android:clipChildren="false"
-        android:clipToPadding="false">
-        <!--This layout makes sure that we can nicely center the expand content in the
-            collapsed layout while the parent makes sure that we're never laid out bigger
-            than the messaging content.-->
-        <LinearLayout
-            android:id="@+id/expand_button_touch_container"
+        android:clipToPadding="false"
+        android:layout_marginTop="-1px"
+        android:paddingTop="1px"
+        >
+        <!--expand_button_container is dynamically placed between here and at the end of the
+        layout. It starts here since only FrameLayout layout params have gravity-->
+        <FrameLayout
+            android:id="@+id/expand_button_container"
             android:layout_width="wrap_content"
-            android:layout_height="@dimen/conversation_expand_button_height"
-            android:orientation="horizontal"
+            android:layout_height="match_parent"
             android:layout_gravity="end|top"
-            android:paddingEnd="0dp"
-            android:clipToPadding="false"
             android:clipChildren="false"
-            >
-            <!-- Images -->
-            <com.android.internal.widget.MessagingLinearLayout
-                android:id="@+id/conversation_image_message_container"
-                android:forceHasOverlappingRendering="false"
-                android:layout_width="40dp"
-                android:layout_height="40dp"
-                android:layout_marginStart="@dimen/conversation_image_start_margin"
-                android:spacing="0dp"
-                android:layout_gravity="center"
+            android:clipToPadding="false">
+            <!--expand_button_touch_container makes sure that we can nicely center the expand
+            content in the collapsed layout while the parent makes sure that we're never laid out
+            bigger than the messaging content.-->
+            <LinearLayout
+                android:id="@+id/expand_button_touch_container"
+                android:layout_width="wrap_content"
+                android:layout_height="@dimen/conversation_expand_button_height"
+                android:orientation="horizontal"
+                android:layout_gravity="end|top"
+                android:paddingEnd="0dp"
                 android:clipToPadding="false"
                 android:clipChildren="false"
-                />
-            <include layout="@layout/notification_expand_button"
-                android:layout_width="wrap_content"
-                android:layout_height="wrap_content"
-                android:layout_gravity="center"
-                />
-        </LinearLayout>
+                >
+                <!-- Images -->
+                <com.android.internal.widget.MessagingLinearLayout
+                    android:id="@+id/conversation_image_message_container"
+                    android:forceHasOverlappingRendering="false"
+                    android:layout_width="40dp"
+                    android:layout_height="40dp"
+                    android:layout_marginStart="@dimen/conversation_image_start_margin"
+                    android:spacing="0dp"
+                    android:layout_gravity="center"
+                    android:clipToPadding="false"
+                    android:clipChildren="false"
+                    />
+                <include layout="@layout/notification_expand_button"
+                    android:layout_width="wrap_content"
+                    android:layout_height="wrap_content"
+                    android:layout_gravity="center"
+                    />
+            </LinearLayout>
+        </FrameLayout>
     </FrameLayout>
 </com.android.internal.widget.ConversationLayout>
diff --git a/core/res/res/values/strings.xml b/core/res/res/values/strings.xml
index aad32b1..f0ba5ff 100644
--- a/core/res/res/values/strings.xml
+++ b/core/res/res/values/strings.xml
@@ -1804,7 +1804,7 @@
     <!-- Message shown during face acquisition when the image is too bright [CHAR LIMIT=50] -->
     <string name="face_acquired_too_bright">Too bright. Try gentler lighting.</string>
     <!-- Message shown during face acquisition when the image is too dark [CHAR LIMIT=50] -->
-    <string name="face_acquired_too_dark">Try brighter lighting</string>
+    <string name="face_acquired_too_dark">Not enough light</string>
     <!-- Message shown during face acquisition when the user is too close to sensor [CHAR LIMIT=50] -->
     <string name="face_acquired_too_close">Move phone farther away</string>
     <!-- Message shown during face acquisition when the user is too far from sensor [CHAR LIMIT=50] -->
diff --git a/core/res/res/values/symbols.xml b/core/res/res/values/symbols.xml
index e773a9c..a6174e1 100644
--- a/core/res/res/values/symbols.xml
+++ b/core/res/res/values/symbols.xml
@@ -4279,6 +4279,7 @@
   <java-symbol type="id" name="conversation_icon_badge_ring" />
   <java-symbol type="id" name="conversation_icon_badge_bg" />
   <java-symbol type="id" name="expand_button_container" />
+  <java-symbol type="id" name="expand_button_a11y_container" />
   <java-symbol type="id" name="expand_button_touch_container" />
   <java-symbol type="id" name="messaging_group_content_container" />
   <java-symbol type="id" name="expand_button_and_content_container" />
diff --git a/core/tests/coretests/src/com/android/internal/app/ChooserListAdapterTest.kt b/core/tests/coretests/src/com/android/internal/app/ChooserListAdapterTest.kt
deleted file mode 100644
index f027e0b..0000000
--- a/core/tests/coretests/src/com/android/internal/app/ChooserListAdapterTest.kt
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (C) 2022 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.internal.app
-
-import android.content.ComponentName
-import android.content.pm.PackageManager
-import android.os.Bundle
-import android.service.chooser.ChooserTarget
-import android.view.View
-import android.widget.FrameLayout
-import android.widget.ImageView
-import android.widget.TextView
-import androidx.test.ext.junit.runners.AndroidJUnit4
-import androidx.test.platform.app.InstrumentationRegistry
-import com.android.internal.R
-import com.android.internal.app.chooser.SelectableTargetInfo
-import com.android.internal.app.chooser.SelectableTargetInfo.SelectableTargetInfoCommunicator
-import com.android.server.testutils.any
-import com.android.server.testutils.mock
-import com.android.server.testutils.whenever
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mockito.anyInt
-import org.mockito.Mockito.doNothing
-import org.mockito.Mockito.times
-import org.mockito.Mockito.verify
-
-@RunWith(AndroidJUnit4::class)
-class ChooserListAdapterTest {
-    private val packageManager = mock<PackageManager> {
-        whenever(resolveActivity(any(), anyInt())).thenReturn(mock())
-    }
-    private val context = InstrumentationRegistry.getInstrumentation().getContext()
-    private val resolverListController = mock<ResolverListController>()
-    private val chooserListCommunicator = mock<ChooserListAdapter.ChooserListCommunicator> {
-        whenever(maxRankedTargets).thenReturn(0)
-    }
-    private val selectableTargetInfoCommunicator =
-        mock<SelectableTargetInfoCommunicator> {
-            whenever(targetIntent).thenReturn(mock())
-        }
-    private val chooserActivityLogger = mock<ChooserActivityLogger>()
-
-    private val testSubject = ChooserListAdapter(
-        context,
-        emptyList(),
-        emptyArray(),
-        emptyList(),
-        false,
-        resolverListController,
-        chooserListCommunicator,
-        selectableTargetInfoCommunicator,
-        packageManager,
-        chooserActivityLogger
-    )
-
-    @Test
-    fun testDirectShareTargetLoadingIconIsStarted() {
-        val view = createView()
-        val viewHolder = ResolverListAdapter.ViewHolder(view)
-        view.tag = viewHolder
-        val targetInfo = createSelectableTargetInfo()
-        val iconTask = mock<ChooserListAdapter.LoadDirectShareIconTask> {
-            doNothing().whenever(this).loadIcon()
-        }
-        testSubject.setTestLoadDirectShareTaskProvider(
-            mock {
-                whenever(get()).thenReturn(iconTask)
-            }
-        )
-        testSubject.testViewBind(view, targetInfo, 0)
-
-        verify(iconTask, times(1)).loadIcon()
-        verify(iconTask, times(1)).setViewHolder(viewHolder)
-    }
-
-    @Test
-    fun testOnlyOneTaskPerTarget() {
-        val view = createView()
-        val viewHolderOne = ResolverListAdapter.ViewHolder(view)
-        view.tag = viewHolderOne
-        val targetInfo = createSelectableTargetInfo()
-        val iconTaskOne = mock<ChooserListAdapter.LoadDirectShareIconTask> {
-            doNothing().whenever(this).loadIcon()
-        }
-        val testTaskProvider = mock<ChooserListAdapter.LoadDirectShareIconTaskProvider> {
-            whenever(get()).thenReturn(iconTaskOne)
-        }
-        testSubject.setTestLoadDirectShareTaskProvider(
-            testTaskProvider
-        )
-        testSubject.testViewBind(view, targetInfo, 0)
-
-        val viewHolderTwo = ResolverListAdapter.ViewHolder(view)
-        view.tag = viewHolderTwo
-        whenever(testTaskProvider.get()).thenReturn(mock())
-
-        testSubject.testViewBind(view, targetInfo, 0)
-
-        verify(iconTaskOne, times(1)).loadIcon()
-        verify(iconTaskOne, times(1)).setViewHolder(viewHolderOne)
-        verify(iconTaskOne, times(1)).setViewHolder(viewHolderTwo)
-        verify(testTaskProvider, times(1)).get()
-    }
-
-    private fun createSelectableTargetInfo(): SelectableTargetInfo =
-        SelectableTargetInfo(
-            context,
-            null,
-            createChooserTarget(),
-            1f,
-            selectableTargetInfoCommunicator,
-            null
-        )
-
-    private fun createChooserTarget(): ChooserTarget =
-        ChooserTarget(
-            "Title",
-            null,
-            1f,
-            ComponentName("package", "package.Class"),
-            Bundle()
-        )
-
-    private fun createView(): View {
-        val view = FrameLayout(context)
-        TextView(context).apply {
-            id = R.id.text1
-            view.addView(this)
-        }
-        TextView(context).apply {
-            id = R.id.text2
-            view.addView(this)
-        }
-        ImageView(context).apply {
-            id = R.id.icon
-            view.addView(this)
-        }
-        return view
-    }
-}
diff --git a/graphics/java/android/graphics/RuntimeShader.java b/graphics/java/android/graphics/RuntimeShader.java
index 6abe34b..9c36fc3 100644
--- a/graphics/java/android/graphics/RuntimeShader.java
+++ b/graphics/java/android/graphics/RuntimeShader.java
@@ -214,7 +214,7 @@
  * uniform shader myShader;
  * vec4 main(vec2 canvas_coordinates) {
  *     // swap the red and blue color channels when sampling from myShader
- *     return myShader.sample(canvas_coordinates).bgra;
+ *     return myShader.eval(canvas_coordinates).bgra;
  * }</pre>
  *
  * <p>After creating a {@link RuntimeShader} with that program the shader uniform can
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
index b5409b7..4367936 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/ShellTaskOrganizer.java
@@ -876,8 +876,12 @@
                     pkg = info.getTaskInfo().baseActivity.getPackageName();
                 }
                 Rect bounds = info.getTaskInfo().getConfiguration().windowConfiguration.getBounds();
+                boolean running = info.getTaskInfo().isRunning;
+                boolean visible = info.getTaskInfo().isVisible;
+                boolean focused = info.getTaskInfo().isFocused;
                 pw.println(innerPrefix + "#" + i + " task=" + key + " listener=" + listener
-                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds);
+                        + " wmMode=" + windowingMode + " pkg=" + pkg + " bounds=" + bounds
+                        + " running=" + running + " visible=" + visible + " focused=" + focused);
             }
 
             pw.println();
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
index 99b8885..b5a5754 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubble.java
@@ -170,7 +170,8 @@
     @VisibleForTesting(visibility = PRIVATE)
     public Bubble(@NonNull final String key, @NonNull final ShortcutInfo shortcutInfo,
             final int desiredHeight, final int desiredHeightResId, @Nullable final String title,
-            int taskId, @Nullable final String locus, Executor mainExecutor) {
+            int taskId, @Nullable final String locus, Executor mainExecutor,
+            final Bubbles.BubbleMetadataFlagListener listener) {
         Objects.requireNonNull(key);
         Objects.requireNonNull(shortcutInfo);
         mMetadataShortcutId = shortcutInfo.getId();
@@ -188,11 +189,12 @@
         mShowBubbleUpdateDot = false;
         mMainExecutor = mainExecutor;
         mTaskId = taskId;
+        mBubbleMetadataFlagListener = listener;
     }
 
     @VisibleForTesting(visibility = PRIVATE)
     public Bubble(@NonNull final BubbleEntry entry,
-            @Nullable final Bubbles.BubbleMetadataFlagListener listener,
+            final Bubbles.BubbleMetadataFlagListener listener,
             final Bubbles.PendingIntentCanceledListener intentCancelListener,
             Executor mainExecutor) {
         mKey = entry.getKey();
@@ -830,6 +832,7 @@
         pw.print("  desiredHeight: "); pw.println(getDesiredHeightString());
         pw.print("  suppressNotif: "); pw.println(shouldSuppressNotification());
         pw.print("  autoExpand:    "); pw.println(shouldAutoExpand());
+        pw.print("  bubbleMetadataFlagListener null: " + (mBubbleMetadataFlagListener == null));
         if (mExpandedView != null) {
             mExpandedView.dump(pw);
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
index d63c25d..0dfba34 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java
@@ -309,6 +309,7 @@
     protected void onInit() {
         mBubbleData.setListener(mBubbleDataListener);
         mBubbleData.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged);
+        mDataRepository.setSuppressionChangedListener(this::onBubbleMetadataFlagChanged);
 
         mBubbleData.setPendingIntentCancelledListener(bubble -> {
             if (bubble.getBubbleIntent() == null) {
@@ -1336,19 +1337,7 @@
                         }
                         mSysuiProxy.updateNotificationBubbleButton(bubble.getKey());
                     }
-
                 }
-                mSysuiProxy.getPendingOrActiveEntry(bubble.getKey(), (entry) -> {
-                    mMainExecutor.execute(() -> {
-                        if (entry != null) {
-                            final String groupKey = entry.getStatusBarNotification().getGroupKey();
-                            if (getBubblesInGroup(groupKey).isEmpty()) {
-                                // Time to potentially remove the summary
-                                mSysuiProxy.notifyMaybeCancelSummary(bubble.getKey());
-                            }
-                        }
-                    });
-                });
             }
             mDataRepository.removeBubbles(mCurrentUserId, bubblesToBeRemovedFromRepository);
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
index c64133f..af31391 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleData.java
@@ -158,7 +158,6 @@
     @Nullable
     private Listener mListener;
 
-    @Nullable
     private Bubbles.BubbleMetadataFlagListener mBubbleMetadataFlagListener;
     private Bubbles.PendingIntentCanceledListener mCancelledListener;
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
index 97560f4..3a59614 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleDataRepository.kt
@@ -25,6 +25,7 @@
 import android.content.pm.UserInfo
 import android.os.UserHandle
 import android.util.Log
+import com.android.wm.shell.bubbles.Bubbles.BubbleMetadataFlagListener
 import com.android.wm.shell.bubbles.storage.BubbleEntity
 import com.android.wm.shell.bubbles.storage.BubblePersistentRepository
 import com.android.wm.shell.bubbles.storage.BubbleVolatileRepository
@@ -47,6 +48,13 @@
     private val ioScope = CoroutineScope(Dispatchers.IO)
     private var job: Job? = null
 
+    // For use in Bubble construction.
+    private lateinit var bubbleMetadataFlagListener: BubbleMetadataFlagListener
+
+    fun setSuppressionChangedListener(listener: BubbleMetadataFlagListener) {
+        bubbleMetadataFlagListener = listener
+    }
+
     /**
      * Adds the bubble in memory, then persists the snapshot after adding the bubble to disk
      * asynchronously.
@@ -197,7 +205,8 @@
                                 entity.title,
                                 entity.taskId,
                                 entity.locus,
-                                mainExecutor
+                                mainExecutor,
+                                bubbleMetadataFlagListener
                         )
                     }
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
index 453b34e..b3104b5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java
@@ -276,8 +276,6 @@
 
         void notifyInvalidateNotifications(String reason);
 
-        void notifyMaybeCancelSummary(String key);
-
         void updateNotificationBubbleButton(String key);
 
         void onStackExpandChanged(boolean shouldExpand);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
index 47f1e2e..96efeeb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/common/DisplayLayout.java
@@ -96,7 +96,8 @@
 
     /**
      * Different from {@link #equals(Object)}, this method compares the basic geometry properties
-     * of two {@link DisplayLayout} objects including width, height, rotation, density and cutout.
+     * of two {@link DisplayLayout} objects including width, height, rotation, density, cutout and
+     * insets.
      * @return {@code true} if the given {@link DisplayLayout} is identical geometry wise.
      */
     public boolean isSameGeometry(@NonNull DisplayLayout other) {
@@ -104,7 +105,8 @@
                 && mHeight == other.mHeight
                 && mRotation == other.mRotation
                 && mDensityDpi == other.mDensityDpi
-                && Objects.equals(mCutout, other.mCutout);
+                && Objects.equals(mCutout, other.mCutout)
+                && Objects.equals(mStableInsets, other.mStableInsets);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
index b7656de..18ce364 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java
@@ -82,7 +82,7 @@
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellController;
 import com.android.wm.shell.sysui.ShellInit;
-import com.android.wm.shell.transition.SplitscreenPipMixedHandler;
+import com.android.wm.shell.transition.DefaultMixedHandler;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.unfold.ShellUnfoldProgressProvider;
 import com.android.wm.shell.unfold.UnfoldAnimationController;
@@ -220,13 +220,14 @@
             Context context,
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
+            Optional<RecentTasksController> recentTasksController,
             WindowDecorViewModel<?> windowDecorViewModel) {
         // TODO(b/238217847): Temporarily add this check here until we can remove the dynamic
         //                    override for this controller from the base module
         ShellInit init = FreeformComponents.isFreeformEnabled(context)
                 ? shellInit
                 : null;
-        return new FreeformTaskListener<>(init, shellTaskOrganizer,
+        return new FreeformTaskListener<>(init, shellTaskOrganizer, recentTasksController,
                 windowDecorViewModel);
     }
 
@@ -332,6 +333,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             @ShellMainThread ShellExecutor mainExecutor) {
         return Optional.ofNullable(PipController.create(
@@ -340,7 +342,7 @@
                 pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
                 pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                oneHandedController, mainExecutor));
+                displayInsetsController, oneHandedController, mainExecutor));
     }
 
     @WMSingleton
@@ -483,13 +485,13 @@
 
     @WMSingleton
     @Provides
-    static SplitscreenPipMixedHandler provideSplitscreenPipMixedHandler(
+    static DefaultMixedHandler provideDefaultMixedHandler(
             ShellInit shellInit,
             Optional<SplitScreenController> splitScreenOptional,
             Optional<PipTouchHandler> pipTouchHandlerOptional,
             Transitions transitions) {
-        return new SplitscreenPipMixedHandler(shellInit, splitScreenOptional,
-                pipTouchHandlerOptional, transitions);
+        return new DefaultMixedHandler(shellInit, transitions, splitScreenOptional,
+                pipTouchHandlerOptional);
     }
 
     //
@@ -618,7 +620,7 @@
     @ShellCreateTriggerOverride
     @Provides
     static Object provideIndependentShellComponentsToCreate(
-            SplitscreenPipMixedHandler splitscreenPipMixedHandler,
+            DefaultMixedHandler defaultMixedHandler,
             Optional<DesktopModeController> desktopModeController) {
         return new Object();
     }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
index 64cec2a..8993d54 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/desktopmode/DesktopMode.java
@@ -50,7 +50,7 @@
                     Settings.System.DESKTOP_MODE, UserHandle.USER_CURRENT);
             ProtoLog.d(WM_SHELL_DESKTOP_MODE, "isDesktopModeEnabled=%s", result);
             return result != 0;
-        } catch (Settings.SettingNotFoundException e) {
+        } catch (Exception e) {
             ProtoLog.e(WM_SHELL_DESKTOP_MODE, "Failed to read DESKTOP_MODE setting %s", e);
             return false;
         }
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
index 4697a01..b59fe18 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java
@@ -258,12 +258,12 @@
                 break;
             case ACTION_DRAG_ENTERED:
                 pd.dragLayout.show();
-                pd.dragLayout.update(event);
                 break;
             case ACTION_DRAG_LOCATION:
                 pd.dragLayout.update(event);
                 break;
             case ACTION_DROP: {
+                pd.dragLayout.update(event);
                 return handleDrop(event, pd);
             }
             case ACTION_DRAG_EXITED: {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
index 8dcdda1..1baac71 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/freeform/FreeformTaskListener.java
@@ -28,12 +28,15 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.ShellTaskOrganizer;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.recents.RecentTasksController;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.transition.Transitions;
 import com.android.wm.shell.windowdecor.WindowDecorViewModel;
 
 import java.io.PrintWriter;
+import java.util.Optional;
 
 /**
  * {@link ShellTaskOrganizer.TaskListener} for {@link
@@ -46,6 +49,7 @@
     private static final String TAG = "FreeformTaskListener";
 
     private final ShellTaskOrganizer mShellTaskOrganizer;
+    private final Optional<RecentTasksController> mRecentTasksOptional;
     private final WindowDecorViewModel<T> mWindowDecorationViewModel;
 
     private final SparseArray<State<T>> mTasks = new SparseArray<>();
@@ -60,9 +64,11 @@
     public FreeformTaskListener(
             ShellInit shellInit,
             ShellTaskOrganizer shellTaskOrganizer,
+            Optional<RecentTasksController> recentTasksController,
             WindowDecorViewModel<T> windowDecorationViewModel) {
         mShellTaskOrganizer = shellTaskOrganizer;
         mWindowDecorationViewModel = windowDecorationViewModel;
+        mRecentTasksOptional = recentTasksController;
         if (shellInit != null) {
             shellInit.addInitCallback(this::onInit, this);
         }
@@ -83,6 +89,12 @@
                     mWindowDecorationViewModel.createWindowDecoration(taskInfo, leash, t, t);
             t.apply();
         }
+
+        if (DesktopMode.IS_SUPPORTED && taskInfo.isVisible) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+                    "Adding active freeform task: #%d", taskInfo.taskId);
+            mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+        }
     }
 
     private State<T> createOrUpdateTaskState(RunningTaskInfo taskInfo, SurfaceControl leash) {
@@ -111,6 +123,12 @@
                 taskInfo.taskId);
         mTasks.remove(taskInfo.taskId);
 
+        if (DesktopMode.IS_SUPPORTED) {
+            ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+                    "Removing active freeform task: #%d", taskInfo.taskId);
+            mRecentTasksOptional.ifPresent(rt -> rt.removeActiveFreeformTask(taskInfo.taskId));
+        }
+
         if (Transitions.ENABLE_SHELL_TRANSITIONS) {
             // Save window decorations of closing tasks so that we can hand them over to the
             // transition system if this method happens before the transition. In case where the
@@ -131,6 +149,14 @@
         if (state.mWindowDecoration != null) {
             mWindowDecorationViewModel.onTaskInfoChanged(state.mTaskInfo, state.mWindowDecoration);
         }
+
+        if (DesktopMode.IS_SUPPORTED) {
+            if (taskInfo.isVisible) {
+                ProtoLog.v(ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE,
+                        "Adding active freeform task: #%d", taskInfo.taskId);
+                mRecentTasksOptional.ifPresent(rt -> rt.addActiveFreeformTask(taskInfo.taskId));
+            }
+        }
     }
 
     private State<T> updateTaskInfo(RunningTaskInfo taskInfo) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
index 297c79e..f170e77 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/PipTaskOrganizer.java
@@ -966,7 +966,7 @@
         // Re-set the PIP bounds to none.
         mPipBoundsState.setBounds(new Rect());
         mPipUiEventLoggerLogger.setTaskInfo(null);
-        mMainExecutor.executeDelayed(() -> mPipMenuController.detach(), 0);
+        mPipMenuController.detach();
         mLeash = null;
 
         if (info.displayId != Display.DEFAULT_DISPLAY && mOnDisplayIdChangeCallback != null) {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
index 6c9a6b6..61fafb5 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java
@@ -49,6 +49,7 @@
 import android.util.Pair;
 import android.util.Size;
 import android.view.DisplayInfo;
+import android.view.InsetsState;
 import android.view.SurfaceControl;
 import android.view.WindowManagerGlobal;
 import android.window.WindowContainerTransaction;
@@ -64,6 +65,7 @@
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayChangeController;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.RemoteCallable;
 import com.android.wm.shell.common.ShellExecutor;
@@ -135,6 +137,7 @@
     private PipTransitionController mPipTransitionController;
     private TaskStackListenerImpl mTaskStackListener;
     private PipParamsChangedForwarder mPipParamsChangedForwarder;
+    private DisplayInsetsController mDisplayInsetsController;
     private Optional<OneHandedController> mOneHandedController;
     private final ShellCommandHandler mShellCommandHandler;
     private final ShellController mShellController;
@@ -338,6 +341,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor) {
         if (!context.getPackageManager().hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)) {
@@ -351,7 +355,7 @@
                 pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController,
                 pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController,
                 windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder,
-                oneHandedController, mainExecutor)
+                displayInsetsController, oneHandedController, mainExecutor)
                 .mImpl;
     }
 
@@ -374,6 +378,7 @@
             WindowManagerShellWrapper windowManagerShellWrapper,
             TaskStackListenerImpl taskStackListener,
             PipParamsChangedForwarder pipParamsChangedForwarder,
+            DisplayInsetsController displayInsetsController,
             Optional<OneHandedController> oneHandedController,
             ShellExecutor mainExecutor
     ) {
@@ -407,6 +412,7 @@
         mEnterAnimationDuration = mContext.getResources()
                 .getInteger(R.integer.config_pipEnterAnimationDuration);
         mPipParamsChangedForwarder = pipParamsChangedForwarder;
+        mDisplayInsetsController = displayInsetsController;
 
         shellInit.addInitCallback(this::onInit, this);
     }
@@ -549,6 +555,16 @@
                     }
                 });
 
+        mDisplayInsetsController.addInsetsChangedListener(mPipBoundsState.getDisplayId(),
+                new DisplayInsetsController.OnInsetsChangedListener() {
+                    @Override
+                    public void insetsChanged(InsetsState insetsState) {
+                        onDisplayChanged(
+                                mDisplayController.getDisplayLayout(mPipBoundsState.getDisplayId()),
+                                false /* saveRestoreSnapFraction */);
+                    }
+                });
+
         mOneHandedController.ifPresent(controller -> {
             controller.registerTransitionCallback(
                     new OneHandedTransitionCallback() {
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
index 7b42350..27bc1a1 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/recents/RecentTasksController.java
@@ -43,6 +43,7 @@
 import com.android.wm.shell.common.TaskStackListenerImpl;
 import com.android.wm.shell.common.annotations.ExternalThread;
 import com.android.wm.shell.common.annotations.ShellMainThread;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
@@ -52,6 +53,7 @@
 import java.io.PrintWriter;
 import java.util.ArrayList;
 import java.util.HashMap;
+import java.util.HashSet;
 import java.util.List;
 import java.util.Map;
 
@@ -82,6 +84,15 @@
     private final Map<Integer, SplitBounds> mTaskSplitBoundsMap = new HashMap<>();
 
     /**
+     * Set of taskId's that have been launched in freeform mode.
+     * This includes tasks that are currently running, visible and in freeform mode. And also
+     * includes tasks that are running in the background, are no longer visible, but at some point
+     * were visible to the user.
+     * This is used to decide which freeform apps belong to the user's desktop.
+     */
+    private final HashSet<Integer> mActiveFreeformTasks = new HashSet<>();
+
+    /**
      * Creates {@link RecentTasksController}, returns {@code null} if the feature is not
      * supported.
      */
@@ -206,6 +217,22 @@
         notifyRecentTasksChanged();
     }
 
+    /**
+     * Mark a task with given {@code taskId} as active in freeform
+     */
+    public void addActiveFreeformTask(int taskId) {
+        mActiveFreeformTasks.add(taskId);
+        notifyRecentTasksChanged();
+    }
+
+    /**
+     * Remove task with given {@code taskId} from active freeform tasks
+     */
+    public void removeActiveFreeformTask(int taskId) {
+        mActiveFreeformTasks.remove(taskId);
+        notifyRecentTasksChanged();
+    }
+
     @VisibleForTesting
     void notifyRecentTasksChanged() {
         ProtoLog.v(ShellProtoLogGroup.WM_SHELL_RECENT_TASKS, "Notify recent tasks changed");
@@ -273,6 +300,9 @@
             rawMapping.put(taskInfo.taskId, taskInfo);
         }
 
+        boolean desktopModeActive = DesktopMode.isActive(mContext);
+        ArrayList<ActivityManager.RecentTaskInfo> freeformTasks = new ArrayList<>();
+
         // Pull out the pairs as we iterate back in the list
         ArrayList<GroupedRecentTaskInfo> recentTasks = new ArrayList<>();
         for (int i = 0; i < rawList.size(); i++) {
@@ -282,16 +312,31 @@
                 continue;
             }
 
+            if (desktopModeActive && mActiveFreeformTasks.contains(taskInfo.taskId)) {
+                // Freeform tasks will be added as a separate entry
+                freeformTasks.add(taskInfo);
+                continue;
+            }
+
             final int pairedTaskId = mSplitTasks.get(taskInfo.taskId);
-            if (pairedTaskId != INVALID_TASK_ID && rawMapping.contains(pairedTaskId)) {
+            if (!desktopModeActive && pairedTaskId != INVALID_TASK_ID && rawMapping.contains(
+                    pairedTaskId)) {
                 final ActivityManager.RecentTaskInfo pairedTaskInfo = rawMapping.get(pairedTaskId);
                 rawMapping.remove(pairedTaskId);
-                recentTasks.add(new GroupedRecentTaskInfo(taskInfo, pairedTaskInfo,
+                recentTasks.add(GroupedRecentTaskInfo.forSplitTasks(taskInfo, pairedTaskInfo,
                         mTaskSplitBoundsMap.get(pairedTaskId)));
             } else {
-                recentTasks.add(new GroupedRecentTaskInfo(taskInfo));
+                recentTasks.add(GroupedRecentTaskInfo.forSingleTask(taskInfo));
             }
         }
+
+        // Add a special entry for freeform tasks
+        if (!freeformTasks.isEmpty()) {
+            // First task is added separately
+            recentTasks.add(0, GroupedRecentTaskInfo.forFreeformTasks(
+                    freeformTasks.toArray(new ActivityManager.RecentTaskInfo[0])));
+        }
+
         return recentTasks;
     }
 
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
index 169e17b..9206afb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/SplitScreenController.java
@@ -147,7 +147,6 @@
     private final DragAndDropController mDragAndDropController;
     private final Transitions mTransitions;
     private final TransactionPool mTransactionPool;
-    private final SplitscreenEventLogger mLogger;
     private final IconProvider mIconProvider;
     private final Optional<RecentTasksController> mRecentTasksOptional;
     private final SplitScreenShellCommandHandler mSplitScreenShellCommandHandler;
@@ -186,7 +185,6 @@
         mDragAndDropController = dragAndDropController;
         mTransitions = transitions;
         mTransactionPool = transactionPool;
-        mLogger = new SplitscreenEventLogger();
         mIconProvider = iconProvider;
         mRecentTasksOptional = recentTasks;
         mSplitScreenShellCommandHandler = new SplitScreenShellCommandHandler(this);
@@ -213,14 +211,18 @@
         mShellController.addKeyguardChangeListener(this);
         if (mStageCoordinator == null) {
             // TODO: Multi-display
-            mStageCoordinator = new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
-                    mTaskOrganizer, mDisplayController, mDisplayImeController,
-                    mDisplayInsetsController, mTransitions, mTransactionPool, mLogger,
-                    mIconProvider, mMainExecutor, mRecentTasksOptional);
+            mStageCoordinator = createStageCoordinator();
         }
         mDragAndDropController.setSplitScreenController(this);
     }
 
+    protected StageCoordinator createStageCoordinator() {
+        return new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
+                mTaskOrganizer, mDisplayController, mDisplayImeController,
+                mDisplayInsetsController, mTransitions, mTransactionPool,
+                mIconProvider, mMainExecutor, mRecentTasksOptional);
+    }
+
     @Override
     public Context getContext() {
         return mContext;
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
index dcfe08d..9c9841f 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/splitscreen/StageCoordinator.java
@@ -69,6 +69,7 @@
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.ActivityManager;
+import android.app.IActivityTaskManager;
 import android.app.PendingIntent;
 import android.app.WindowConfiguration;
 import android.content.Context;
@@ -81,6 +82,7 @@
 import android.os.Debug;
 import android.os.IBinder;
 import android.os.RemoteException;
+import android.os.ServiceManager;
 import android.util.Log;
 import android.util.Slog;
 import android.view.Choreographer;
@@ -244,18 +246,18 @@
         }
     };
 
-    StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
+    protected StageCoordinator(Context context, int displayId, SyncTransactionQueue syncQueue,
             ShellTaskOrganizer taskOrganizer, DisplayController displayController,
             DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, Transitions transitions,
-            TransactionPool transactionPool, SplitscreenEventLogger logger,
+            TransactionPool transactionPool,
             IconProvider iconProvider, ShellExecutor mainExecutor,
             Optional<RecentTasksController> recentTasks) {
         mContext = context;
         mDisplayId = displayId;
         mSyncQueue = syncQueue;
         mTaskOrganizer = taskOrganizer;
-        mLogger = logger;
+        mLogger = new SplitscreenEventLogger();
         mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
 
@@ -299,7 +301,7 @@
             DisplayController displayController, DisplayImeController displayImeController,
             DisplayInsetsController displayInsetsController, SplitLayout splitLayout,
             Transitions transitions, TransactionPool transactionPool,
-            SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+            ShellExecutor mainExecutor,
             Optional<RecentTasksController> recentTasks) {
         mContext = context;
         mDisplayId = displayId;
@@ -314,7 +316,7 @@
         mSplitLayout = splitLayout;
         mSplitTransitions = new SplitScreenTransitions(transactionPool, transitions,
                 this::onTransitionAnimationComplete, this);
-        mLogger = logger;
+        mLogger = new SplitscreenEventLogger();
         mMainExecutor = mainExecutor;
         mRecentTasks = recentTasks;
         mDisplayController.addDisplayWindowListener(this);
@@ -880,6 +882,8 @@
             WindowContainerTransaction wct, @ExitReason int exitReason) {
         if (!mMainStage.isActive() || mIsExiting) return;
 
+        onSplitScreenExit();
+
         mRecentTasks.ifPresent(recentTasks -> {
             // Notify recents if we are exiting in a way that breaks the pair, and disable further
             // updates to splits in the recents until we enter split again
@@ -949,6 +953,47 @@
     }
 
     /**
+     * Overridden by child classes.
+     */
+    protected void onSplitScreenEnter() {
+    }
+
+    /**
+     * Overridden by child classes.
+     */
+    protected void onSplitScreenExit() {
+    }
+
+    /**
+     * Exits the split screen by finishing one of the tasks.
+     */
+    protected void exitStage(@SplitPosition int stageToClose) {
+        if (ENABLE_SHELL_TRANSITIONS) {
+            StageTaskListener stageToTop = mSideStagePosition == stageToClose
+                    ? mMainStage
+                    : mSideStage;
+            exitSplitScreen(stageToTop, EXIT_REASON_APP_FINISHED);
+        } else {
+            boolean toEnd = stageToClose == SPLIT_POSITION_BOTTOM_OR_RIGHT;
+            mSplitLayout.flingDividerToDismiss(toEnd, EXIT_REASON_APP_FINISHED);
+        }
+    }
+
+    /**
+     * Grants focus to the main or the side stages.
+     */
+    protected void grantFocusToStage(@SplitPosition int stageToFocus) {
+        IActivityTaskManager activityTaskManagerService = IActivityTaskManager.Stub.asInterface(
+                ServiceManager.getService(Context.ACTIVITY_TASK_SERVICE));
+        try {
+            activityTaskManagerService.setFocusedTask(getTaskId(stageToFocus));
+        } catch (RemoteException | NullPointerException e) {
+            ProtoLog.e(ShellProtoLogGroup.WM_SHELL_SPLIT_SCREEN,
+                    "%s: Unable to update focus on the chosen stage, %s", TAG, e);
+        }
+    }
+
+    /**
      * Returns whether the split pair in the recent tasks list should be broken.
      */
     private boolean shouldBreakPairedTaskInRecents(@ExitReason int exitReason) {
@@ -995,6 +1040,7 @@
             @Nullable ActivityManager.RunningTaskInfo taskInfo, @SplitPosition int startPosition) {
         if (mMainStage.isActive()) return;
 
+        onSplitScreenEnter();
         if (taskInfo != null) {
             setSideStagePosition(startPosition, wct);
             mSideStage.addTask(taskInfo, wct);
@@ -1388,6 +1434,7 @@
             }
         } else if (isSideStage && hasChildren && !mMainStage.isActive()) {
             // TODO (b/238697912) : Add the validation to prevent entering non-recovered status
+            onSplitScreenEnter();
             final WindowContainerTransaction wct = new WindowContainerTransaction();
             mSplitLayout.init();
             mSplitLayout.setDividerAtBorder(mSideStagePosition == SPLIT_POSITION_TOP_OR_LEFT);
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
index e26c259..bcf4fbd 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/DefaultMixedHandler.java
@@ -35,10 +35,14 @@
 
 import com.android.internal.protolog.common.ProtoLog;
 import com.android.wm.shell.pip.PipTransitionController;
+import com.android.wm.shell.pip.phone.PipTouchHandler;
 import com.android.wm.shell.protolog.ShellProtoLogGroup;
+import com.android.wm.shell.splitscreen.SplitScreenController;
 import com.android.wm.shell.splitscreen.StageCoordinator;
+import com.android.wm.shell.sysui.ShellInit;
 
 import java.util.ArrayList;
+import java.util.Optional;
 
 /**
  * A handler for dealing with transitions involving multiple other handlers. For example: an
@@ -47,8 +51,8 @@
 public class DefaultMixedHandler implements Transitions.TransitionHandler {
 
     private final Transitions mPlayer;
-    private final PipTransitionController mPipHandler;
-    private final StageCoordinator mSplitHandler;
+    private PipTransitionController mPipHandler;
+    private StageCoordinator mSplitHandler;
 
     private static class MixedTransition {
         static final int TYPE_ENTER_PIP_FROM_SPLIT = 1;
@@ -77,13 +81,22 @@
             mTransition = transition;
         }
     }
+
     private final ArrayList<MixedTransition> mActiveTransitions = new ArrayList<>();
 
-    public DefaultMixedHandler(@NonNull Transitions player,
-            @NonNull PipTransitionController pipHandler, @NonNull StageCoordinator splitHandler) {
+    public DefaultMixedHandler(@NonNull ShellInit shellInit, @NonNull Transitions player,
+            Optional<SplitScreenController> splitScreenControllerOptional,
+            Optional<PipTouchHandler> pipTouchHandlerOptional) {
         mPlayer = player;
-        mPipHandler = pipHandler;
-        mSplitHandler = splitHandler;
+        if (Transitions.ENABLE_SHELL_TRANSITIONS && pipTouchHandlerOptional.isPresent()
+                && splitScreenControllerOptional.isPresent()) {
+            // Add after dependencies because it is higher priority
+            shellInit.addInitCallback(() -> {
+                mPipHandler = pipTouchHandlerOptional.get().getTransitionHandler();
+                mSplitHandler = splitScreenControllerOptional.get().getTransitionHandler();
+                mPlayer.addHandler(this);
+            }, this);
+        }
     }
 
     @Nullable
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
deleted file mode 100644
index 678e91f..0000000
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/SplitscreenPipMixedHandler.java
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- * Copyright (C) 2022 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.wm.shell.transition;
-
-import com.android.wm.shell.pip.phone.PipTouchHandler;
-import com.android.wm.shell.splitscreen.SplitScreenController;
-import com.android.wm.shell.sysui.ShellInit;
-
-import java.util.Optional;
-
-/**
- * Handles transitions between the Splitscreen and PIP components.
- */
-public class SplitscreenPipMixedHandler {
-
-    private final Optional<SplitScreenController> mSplitScreenOptional;
-    private final Optional<PipTouchHandler> mPipTouchHandlerOptional;
-    private final Transitions mTransitions;
-
-    public SplitscreenPipMixedHandler(ShellInit shellInit,
-            Optional<SplitScreenController> splitScreenControllerOptional,
-            Optional<PipTouchHandler> pipTouchHandlerOptional,
-            Transitions transitions) {
-        mSplitScreenOptional = splitScreenControllerOptional;
-        mPipTouchHandlerOptional = pipTouchHandlerOptional;
-        mTransitions = transitions;
-        if (Transitions.ENABLE_SHELL_TRANSITIONS
-                && mSplitScreenOptional.isPresent() && mPipTouchHandlerOptional.isPresent()) {
-            shellInit.addInitCallback(this::onInit, this);
-        }
-    }
-
-    private void onInit() {
-        // Special handling for initializing based on multiple components
-        final DefaultMixedHandler mixedHandler = new DefaultMixedHandler(mTransitions,
-                mPipTouchHandlerOptional.get().getTransitionHandler(),
-                mSplitScreenOptional.get().getTransitionHandler());
-        // Added at end so that it has highest priority.
-        mTransitions.addHandler(mixedHandler);
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
index 2cff171..c045ceb 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/util/GroupedRecentTaskInfo.java
@@ -16,6 +16,7 @@
 
 package com.android.wm.shell.util;
 
+import android.annotation.IntDef;
 import android.app.ActivityManager;
 import android.app.WindowConfiguration;
 import android.os.Parcel;
@@ -24,40 +25,143 @@
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
 
+import java.util.Arrays;
+import java.util.List;
+
 /**
  * Simple container for recent tasks.  May contain either a single or pair of tasks.
  */
 public class GroupedRecentTaskInfo implements Parcelable {
-    public @NonNull ActivityManager.RecentTaskInfo mTaskInfo1;
-    public @Nullable ActivityManager.RecentTaskInfo mTaskInfo2;
-    public @Nullable SplitBounds mSplitBounds;
 
-    public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1) {
-        this(task1, null, null);
+    public static final int TYPE_SINGLE = 1;
+    public static final int TYPE_SPLIT = 2;
+    public static final int TYPE_FREEFORM = 3;
+
+    @IntDef(prefix = {"TYPE_"}, value = {
+            TYPE_SINGLE,
+            TYPE_SPLIT,
+            TYPE_FREEFORM
+    })
+    public @interface GroupType {}
+
+    @NonNull
+    private final ActivityManager.RecentTaskInfo[] mTasks;
+    @Nullable
+    private final SplitBounds mSplitBounds;
+    @GroupType
+    private final int mType;
+
+    /**
+     * Create new for a single task
+     */
+    public static GroupedRecentTaskInfo forSingleTask(
+            @NonNull ActivityManager.RecentTaskInfo task) {
+        return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task}, null,
+                TYPE_SINGLE);
     }
 
-    public GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo task1,
-            @Nullable ActivityManager.RecentTaskInfo task2,
-            @Nullable SplitBounds splitBounds) {
-        mTaskInfo1 = task1;
-        mTaskInfo2 = task2;
+    /**
+     * Create new for a pair of tasks in split screen
+     */
+    public static GroupedRecentTaskInfo forSplitTasks(@NonNull ActivityManager.RecentTaskInfo task1,
+            @NonNull ActivityManager.RecentTaskInfo task2, @Nullable SplitBounds splitBounds) {
+        return new GroupedRecentTaskInfo(new ActivityManager.RecentTaskInfo[]{task1, task2},
+                splitBounds, TYPE_SPLIT);
+    }
+
+    /**
+     * Create new for a group of freeform tasks
+     */
+    public static GroupedRecentTaskInfo forFreeformTasks(
+            @NonNull ActivityManager.RecentTaskInfo... tasks) {
+        return new GroupedRecentTaskInfo(tasks, null, TYPE_FREEFORM);
+    }
+
+    private GroupedRecentTaskInfo(@NonNull ActivityManager.RecentTaskInfo[] tasks,
+            @Nullable SplitBounds splitBounds, @GroupType int type) {
+        mTasks = tasks;
         mSplitBounds = splitBounds;
+        mType = type;
     }
 
     GroupedRecentTaskInfo(Parcel parcel) {
-        mTaskInfo1 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
-        mTaskInfo2 = parcel.readTypedObject(ActivityManager.RecentTaskInfo.CREATOR);
+        mTasks = parcel.createTypedArray(ActivityManager.RecentTaskInfo.CREATOR);
         mSplitBounds = parcel.readTypedObject(SplitBounds.CREATOR);
+        mType = parcel.readInt();
+    }
+
+    /**
+     * Get primary {@link ActivityManager.RecentTaskInfo}
+     */
+    @NonNull
+    public ActivityManager.RecentTaskInfo getTaskInfo1() {
+        return mTasks[0];
+    }
+
+    /**
+     * Get secondary {@link ActivityManager.RecentTaskInfo}.
+     *
+     * Used in split screen.
+     */
+    @Nullable
+    public ActivityManager.RecentTaskInfo getTaskInfo2() {
+        if (mTasks.length > 1) {
+            return mTasks[1];
+        }
+        return null;
+    }
+
+    /**
+     * Get all {@link ActivityManager.RecentTaskInfo}s grouped together.
+     */
+    @NonNull
+    public List<ActivityManager.RecentTaskInfo> getTaskInfoList() {
+        return Arrays.asList(mTasks);
+    }
+
+    /**
+     * Return {@link SplitBounds} if this is a split screen entry or {@code null}
+     */
+    @Nullable
+    public SplitBounds getSplitBounds() {
+        return mSplitBounds;
+    }
+
+    /**
+     * Get type of this recents entry. One of {@link GroupType}
+     */
+    @GroupType
+    public int getType() {
+        return mType;
     }
 
     @Override
     public String toString() {
-        String taskString = "Task1: " + getTaskInfo(mTaskInfo1)
-                + ", Task2: " + getTaskInfo(mTaskInfo2);
-        if (mSplitBounds != null) {
-            taskString += ", SplitBounds: " + mSplitBounds.toString();
+        StringBuilder taskString = new StringBuilder();
+        for (int i = 0; i < mTasks.length; i++) {
+            if (i == 0) {
+                taskString.append("Task");
+            } else {
+                taskString.append(", Task");
+            }
+            taskString.append(i + 1).append(": ").append(getTaskInfo(mTasks[i]));
         }
-        return taskString;
+        if (mSplitBounds != null) {
+            taskString.append(", SplitBounds: ").append(mSplitBounds);
+        }
+        taskString.append(", Type=");
+        switch (mType) {
+            case TYPE_SINGLE:
+                taskString.append("TYPE_SINGLE");
+                break;
+            case TYPE_SPLIT:
+                taskString.append("TYPE_SPLIT");
+                break;
+            case TYPE_FREEFORM:
+                taskString.append("TYPE_FREEFORM");
+                break;
+        }
+        return taskString.toString();
     }
 
     private String getTaskInfo(ActivityManager.RecentTaskInfo taskInfo) {
@@ -74,9 +178,9 @@
 
     @Override
     public void writeToParcel(Parcel parcel, int flags) {
-        parcel.writeTypedObject(mTaskInfo1, flags);
-        parcel.writeTypedObject(mTaskInfo2, flags);
+        parcel.writeTypedArray(mTasks, flags);
         parcel.writeTypedObject(mSplitBounds, flags);
+        parcel.writeInt(mType);
     }
 
     @Override
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
index 1b5091f..a8d3bdc 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java
@@ -43,6 +43,7 @@
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.WindowManagerShellWrapper;
 import com.android.wm.shell.common.DisplayController;
+import com.android.wm.shell.common.DisplayInsetsController;
 import com.android.wm.shell.common.DisplayLayout;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
@@ -99,7 +100,8 @@
     @Mock private TaskStackListenerImpl mMockTaskStackListener;
     @Mock private ShellExecutor mMockExecutor;
     @Mock private Optional<OneHandedController> mMockOneHandedController;
-    @Mock private PipParamsChangedForwarder mPipParamsChangedForwarder;
+    @Mock private PipParamsChangedForwarder mMockPipParamsChangedForwarder;
+    @Mock private DisplayInsetsController mMockDisplayInsetsController;
 
     @Mock private DisplayLayout mMockDisplayLayout1;
     @Mock private DisplayLayout mMockDisplayLayout2;
@@ -120,8 +122,8 @@
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mPipParamsChangedForwarder,
-                mMockOneHandedController, mMockExecutor);
+                mMockTaskStackListener, mMockPipParamsChangedForwarder,
+                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor);
         mShellInit.init();
         when(mMockPipBoundsAlgorithm.getSnapAlgorithm()).thenReturn(mMockPipSnapAlgorithm);
         when(mMockPipTouchHandler.getMotionHelper()).thenReturn(mMockPipMotionHelper);
@@ -186,8 +188,8 @@
                 mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController,
                 mMockPhonePipMenuController, mMockPipTaskOrganizer, mMockPipTransitionState,
                 mMockPipTouchHandler, mMockPipTransitionController, mMockWindowManagerShellWrapper,
-                mMockTaskStackListener, mPipParamsChangedForwarder,
-                mMockOneHandedController, mMockExecutor));
+                mMockTaskStackListener, mMockPipParamsChangedForwarder,
+                mMockDisplayInsetsController, mMockOneHandedController, mMockExecutor));
     }
 
     @Test
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
new file mode 100644
index 0000000..baa06f2
--- /dev/null
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/GroupedRecentTaskInfoTest.kt
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2022 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.wm.shell.recents
+
+import android.app.ActivityManager
+import android.graphics.Rect
+import android.os.Parcel
+import android.testing.AndroidTestingRunner
+import android.window.IWindowContainerToken
+import android.window.WindowContainerToken
+import androidx.test.filters.SmallTest
+import com.android.wm.shell.ShellTestCase
+import com.android.wm.shell.util.GroupedRecentTaskInfo
+import com.android.wm.shell.util.GroupedRecentTaskInfo.CREATOR
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_FREEFORM
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SINGLE
+import com.android.wm.shell.util.GroupedRecentTaskInfo.TYPE_SPLIT
+import com.android.wm.shell.util.SplitBounds
+import com.google.common.truth.Correspondence
+import com.google.common.truth.Truth.assertThat
+import org.junit.Test
+import org.junit.runner.RunWith
+import org.mockito.Mockito.mock
+
+/**
+ * Tests for [GroupedRecentTaskInfo]
+ */
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class GroupedRecentTaskInfoTest : ShellTestCase() {
+
+    @Test
+    fun testSingleTask_hasCorrectType() {
+        assertThat(singleTaskGroupInfo().type).isEqualTo(TYPE_SINGLE)
+    }
+
+    @Test
+    fun testSingleTask_task1Set_task2Null() {
+        val group = singleTaskGroupInfo()
+        assertThat(group.taskInfo1.taskId).isEqualTo(1)
+        assertThat(group.taskInfo2).isNull()
+    }
+
+    @Test
+    fun testSingleTask_taskInfoList_hasOneTask() {
+        val list = singleTaskGroupInfo().taskInfoList
+        assertThat(list).hasSize(1)
+        assertThat(list[0].taskId).isEqualTo(1)
+    }
+
+    @Test
+    fun testSplitTasks_hasCorrectType() {
+        assertThat(splitTasksGroupInfo().type).isEqualTo(TYPE_SPLIT)
+    }
+
+    @Test
+    fun testSplitTasks_task1Set_task2Set_boundsSet() {
+        val group = splitTasksGroupInfo()
+        assertThat(group.taskInfo1.taskId).isEqualTo(1)
+        assertThat(group.taskInfo2?.taskId).isEqualTo(2)
+        assertThat(group.splitBounds).isNotNull()
+    }
+
+    @Test
+    fun testSplitTasks_taskInfoList_hasTwoTasks() {
+        val list = splitTasksGroupInfo().taskInfoList
+        assertThat(list).hasSize(2)
+        assertThat(list[0].taskId).isEqualTo(1)
+        assertThat(list[1].taskId).isEqualTo(2)
+    }
+
+    @Test
+    fun testFreeformTasks_hasCorrectType() {
+        assertThat(freeformTasksGroupInfo().type).isEqualTo(TYPE_FREEFORM)
+    }
+
+    @Test
+    fun testSplitTasks_taskInfoList_hasThreeTasks() {
+        val list = freeformTasksGroupInfo().taskInfoList
+        assertThat(list).hasSize(3)
+        assertThat(list[0].taskId).isEqualTo(1)
+        assertThat(list[1].taskId).isEqualTo(2)
+        assertThat(list[2].taskId).isEqualTo(3)
+    }
+
+    @Test
+    fun testParcelling_singleTask() {
+        val recentTaskInfo = singleTaskGroupInfo()
+        val parcel = Parcel.obtain()
+        recentTaskInfo.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+        // Read the object back from the parcel
+        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SINGLE)
+        assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+        assertThat(recentTaskInfoParcel.taskInfo2).isNull()
+    }
+
+    @Test
+    fun testParcelling_splitTasks() {
+        val recentTaskInfo = splitTasksGroupInfo()
+        val parcel = Parcel.obtain()
+        recentTaskInfo.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+        // Read the object back from the parcel
+        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_SPLIT)
+        assertThat(recentTaskInfoParcel.taskInfo1.taskId).isEqualTo(1)
+        assertThat(recentTaskInfoParcel.taskInfo2).isNotNull()
+        assertThat(recentTaskInfoParcel.taskInfo2!!.taskId).isEqualTo(2)
+        assertThat(recentTaskInfoParcel.splitBounds).isNotNull()
+    }
+
+    @Test
+    fun testParcelling_freeformTasks() {
+        val recentTaskInfo = freeformTasksGroupInfo()
+        val parcel = Parcel.obtain()
+        recentTaskInfo.writeToParcel(parcel, 0)
+        parcel.setDataPosition(0)
+        // Read the object back from the parcel
+        val recentTaskInfoParcel = CREATOR.createFromParcel(parcel)
+        assertThat(recentTaskInfoParcel.type).isEqualTo(TYPE_FREEFORM)
+        assertThat(recentTaskInfoParcel.taskInfoList).hasSize(3)
+        // Only compare task ids
+        val taskIdComparator = Correspondence.transforming<ActivityManager.RecentTaskInfo, Int>(
+            { it?.taskId }, "has taskId of"
+        )
+        assertThat(recentTaskInfoParcel.taskInfoList).comparingElementsUsing(taskIdComparator)
+            .containsExactly(1, 2, 3)
+    }
+
+    private fun createTaskInfo(id: Int) = ActivityManager.RecentTaskInfo().apply {
+        taskId = id
+        token = WindowContainerToken(mock(IWindowContainerToken::class.java))
+    }
+
+    private fun singleTaskGroupInfo(): GroupedRecentTaskInfo {
+        val task = createTaskInfo(id = 1)
+        return GroupedRecentTaskInfo.forSingleTask(task)
+    }
+
+    private fun splitTasksGroupInfo(): GroupedRecentTaskInfo {
+        val task1 = createTaskInfo(id = 1)
+        val task2 = createTaskInfo(id = 2)
+        val splitBounds = SplitBounds(Rect(), Rect(), 1, 2)
+        return GroupedRecentTaskInfo.forSplitTasks(task1, task2, splitBounds)
+    }
+
+    private fun freeformTasksGroupInfo(): GroupedRecentTaskInfo {
+        val task1 = createTaskInfo(id = 1)
+        val task2 = createTaskInfo(id = 2)
+        val task3 = createTaskInfo(id = 3)
+        return GroupedRecentTaskInfo.forFreeformTasks(task1, task2, task3)
+    }
+}
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
index 81bb609..e9a1e25 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/recents/RecentTasksControllerTest.java
@@ -20,6 +20,9 @@
 import static android.app.WindowConfiguration.WINDOWING_MODE_FULLSCREEN;
 import static android.app.WindowConfiguration.WINDOWING_MODE_MULTI_WINDOW;
 
+import static com.android.dx.mockito.inline.extended.ExtendedMockito.mockitoSession;
+
+import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertNull;
 import static org.junit.Assert.assertTrue;
@@ -45,11 +48,13 @@
 import androidx.test.filters.SmallTest;
 import androidx.test.runner.AndroidJUnit4;
 
+import com.android.dx.mockito.inline.extended.StaticMockitoSession;
 import com.android.wm.shell.ShellTaskOrganizer;
 import com.android.wm.shell.ShellTestCase;
 import com.android.wm.shell.TestShellExecutor;
 import com.android.wm.shell.common.ShellExecutor;
 import com.android.wm.shell.common.TaskStackListenerImpl;
+import com.android.wm.shell.desktopmode.DesktopMode;
 import com.android.wm.shell.sysui.ShellCommandHandler;
 import com.android.wm.shell.sysui.ShellInit;
 import com.android.wm.shell.util.GroupedRecentTaskInfo;
@@ -179,6 +184,46 @@
     }
 
     @Test
+    public void testGetRecentTasks_groupActiveFreeformTasks() {
+        StaticMockitoSession mockitoSession = mockitoSession().mockStatic(
+                DesktopMode.class).startMocking();
+        when(DesktopMode.isActive(any())).thenReturn(true);
+
+        ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
+        ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
+        ActivityManager.RecentTaskInfo t3 = makeTaskInfo(3);
+        ActivityManager.RecentTaskInfo t4 = makeTaskInfo(4);
+        setRawList(t1, t2, t3, t4);
+
+        mRecentTasksController.addActiveFreeformTask(1);
+        mRecentTasksController.addActiveFreeformTask(3);
+
+        ArrayList<GroupedRecentTaskInfo> recentTasks = mRecentTasksController.getRecentTasks(
+                MAX_VALUE, RECENT_IGNORE_UNAVAILABLE, 0);
+
+        // 2 freeform tasks should be grouped into one, 3 total recents entries
+        assertEquals(3, recentTasks.size());
+        GroupedRecentTaskInfo freeformGroup = recentTasks.get(0);
+        GroupedRecentTaskInfo singleGroup1 = recentTasks.get(1);
+        GroupedRecentTaskInfo singleGroup2 = recentTasks.get(2);
+
+        // Check that groups have expected types
+        assertEquals(GroupedRecentTaskInfo.TYPE_FREEFORM, freeformGroup.getType());
+        assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup1.getType());
+        assertEquals(GroupedRecentTaskInfo.TYPE_SINGLE, singleGroup2.getType());
+
+        // Check freeform group entries
+        assertEquals(t1, freeformGroup.getTaskInfoList().get(0));
+        assertEquals(t3, freeformGroup.getTaskInfoList().get(1));
+
+        // Check single entries
+        assertEquals(t2, singleGroup1.getTaskInfo1());
+        assertEquals(t4, singleGroup2.getTaskInfo1());
+
+        mockitoSession.finishMocking();
+    }
+
+    @Test
     public void testRemovedTaskRemovesSplit() {
         ActivityManager.RecentTaskInfo t1 = makeTaskInfo(1);
         ActivityManager.RecentTaskInfo t2 = makeTaskInfo(2);
@@ -254,6 +299,7 @@
 
     /**
      * Asserts that the recent tasks matches the given task ids.
+     *
      * @param expectedTaskIds list of task ids that map to the flattened task ids of the tasks in
      *                        the grouped task list
      */
@@ -262,22 +308,23 @@
         int[] flattenedTaskIds = new int[recentTasks.size() * 2];
         for (int i = 0; i < recentTasks.size(); i++) {
             GroupedRecentTaskInfo pair = recentTasks.get(i);
-            int taskId1 = pair.mTaskInfo1.taskId;
+            int taskId1 = pair.getTaskInfo1().taskId;
             flattenedTaskIds[2 * i] = taskId1;
-            flattenedTaskIds[2 * i + 1] = pair.mTaskInfo2 != null
-                    ? pair.mTaskInfo2.taskId
+            flattenedTaskIds[2 * i + 1] = pair.getTaskInfo2() != null
+                    ? pair.getTaskInfo2().taskId
                     : -1;
 
-            if (pair.mTaskInfo2 != null) {
-                assertNotNull(pair.mSplitBounds);
-                int leftTopTaskId = pair.mSplitBounds.leftTopTaskId;
-                int bottomRightTaskId = pair.mSplitBounds.rightBottomTaskId;
+            if (pair.getTaskInfo2() != null) {
+                assertNotNull(pair.getSplitBounds());
+                int leftTopTaskId = pair.getSplitBounds().leftTopTaskId;
+                int bottomRightTaskId = pair.getSplitBounds().rightBottomTaskId;
                 // Unclear if pairs are ordered by split position, most likely not.
-                assertTrue(leftTopTaskId == taskId1 || leftTopTaskId == pair.mTaskInfo2.taskId);
+                assertTrue(leftTopTaskId == taskId1
+                        || leftTopTaskId == pair.getTaskInfo2().taskId);
                 assertTrue(bottomRightTaskId == taskId1
-                        || bottomRightTaskId == pair.mTaskInfo2.taskId);
+                        || bottomRightTaskId == pair.getTaskInfo2().taskId);
             } else {
-                assertNull(pair.mSplitBounds);
+                assertNull(pair.getSplitBounds());
             }
         }
         assertTrue("Expected: " + Arrays.toString(expectedTaskIds)
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
index a67853c..ae69b3d 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTestUtils.java
@@ -71,11 +71,11 @@
                 DisplayController displayController, DisplayImeController imeController,
                 DisplayInsetsController insetsController, SplitLayout splitLayout,
                 Transitions transitions, TransactionPool transactionPool,
-                SplitscreenEventLogger logger, ShellExecutor mainExecutor,
+                ShellExecutor mainExecutor,
                 Optional<RecentTasksController> recentTasks) {
             super(context, displayId, syncQueue, taskOrganizer, mainStage,
                     sideStage, displayController, imeController, insetsController, splitLayout,
-                    transitions, transactionPool, logger, mainExecutor, recentTasks);
+                    transitions, transactionPool, mainExecutor, recentTasks);
 
             // Prepare root task for testing.
             mRootTask = new TestRunningTaskInfoBuilder().build();
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
index 1d038f4..ea0033b 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/SplitTransitionTests.java
@@ -95,7 +95,6 @@
     @Mock private TransactionPool mTransactionPool;
     @Mock private Transitions mTransitions;
     @Mock private SurfaceSession mSurfaceSession;
-    @Mock private SplitscreenEventLogger mLogger;
     @Mock private IconProvider mIconProvider;
     @Mock private ShellExecutor mMainExecutor;
     private SplitLayout mSplitLayout;
@@ -127,7 +126,7 @@
         mStageCoordinator = new SplitTestUtils.TestStageCoordinator(mContext, DEFAULT_DISPLAY,
                 mSyncQueue, mTaskOrganizer, mMainStage, mSideStage, mDisplayController,
                 mDisplayImeController, mDisplayInsetsController, mSplitLayout, mTransitions,
-                mTransactionPool, mLogger, mMainExecutor, Optional.empty());
+                mTransactionPool, mMainExecutor, Optional.empty());
         mSplitScreenTransitions = mStageCoordinator.getSplitTransitions();
         doAnswer((Answer<IBinder>) invocation -> mock(IBinder.class))
                 .when(mTransitions).startTransition(anyInt(), any(), any());
diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
index 4b68870..ea9390e 100644
--- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
+++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/splitscreen/StageCoordinatorTests.java
@@ -97,8 +97,6 @@
     @Mock
     private TransactionPool mTransactionPool;
     @Mock
-    private SplitscreenEventLogger mLogger;
-    @Mock
     private ShellExecutor mMainExecutor;
 
     private final Rect mBounds1 = new Rect(10, 20, 30, 40);
@@ -115,7 +113,7 @@
         MockitoAnnotations.initMocks(this);
         mStageCoordinator = spy(new StageCoordinator(mContext, DEFAULT_DISPLAY, mSyncQueue,
                 mTaskOrganizer, mMainStage, mSideStage, mDisplayController, mDisplayImeController,
-                mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool, mLogger,
+                mDisplayInsetsController, mSplitLayout, mTransitions, mTransactionPool,
                 mMainExecutor, Optional.empty()));
         doNothing().when(mStageCoordinator).updateActivityOptions(any(), anyInt());
 
diff --git a/media/java/android/media/AudioSystem.java b/media/java/android/media/AudioSystem.java
index 650f360..7ccbe51 100644
--- a/media/java/android/media/AudioSystem.java
+++ b/media/java/android/media/AudioSystem.java
@@ -2385,6 +2385,14 @@
         return types.size() == 1 && types.contains(type);
     }
 
+    /**
+     * @hide
+     * Return true if the audio device type is a Bluetooth LE Audio device.
+     */
+    public static boolean isLeAudioDeviceType(int type) {
+        return DEVICE_OUT_ALL_BLE_SET.contains(type);
+    }
+
     /** @hide */
     public static final int DEFAULT_MUTE_STREAMS_AFFECTED =
             (1 << STREAM_MUSIC) |
diff --git a/media/java/android/media/ExifInterface.java b/media/java/android/media/ExifInterface.java
index e18642c..0c8cacd 100644
--- a/media/java/android/media/ExifInterface.java
+++ b/media/java/android/media/ExifInterface.java
@@ -79,20 +79,24 @@
 /**
  * This is a class for reading and writing Exif tags in various image file formats.
  * <p>
+ * <b>Note:</b> This class has known issues on some versions of Android. It is recommended to use
+ * the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
+ * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
+ * Library</a> since it offers a superset of the functionality of this class and is more easily
+ * updateable. In addition to the functionality of this class, it supports parsing extra metadata
+ * such as exposure and data compression information as well as setting extra metadata such as GPS
+ * and datetime information.
+ * <p>
  * Supported for reading: JPEG, PNG, WebP, HEIF, DNG, CR2, NEF, NRW, ARW, RW2, ORF, PEF, SRW, RAF,
  * AVIF.
  * <p>
- * Supported for writing: JPEG, PNG, WebP, DNG.
+ * Supported for writing: JPEG, PNG, WebP.
  * <p>
  * Note: JPEG and HEIF files may contain XMP data either inside the Exif data chunk or outside of
  * it. This class will search both locations for XMP data, but if XMP data exist both inside and
  * outside Exif, will favor the XMP data inside Exif over the one outside.
  * <p>
- * Note: It is recommended to use the <a href="{@docRoot}jetpack/androidx.html">AndroidX</a>
- * <a href="{@docRoot}reference/androidx/exifinterface/media/ExifInterface.html">ExifInterface
- * Library</a> since it is a superset of this class. In addition to the functionalities of this
- * class, it supports parsing extra metadata such as exposure and data compression information
- * as well as setting extra metadata such as GPS and datetime information.
+
  */
 public class ExifInterface {
     private static final String TAG = "ExifInterface";
@@ -1294,7 +1298,6 @@
             new ExifTag(TAG_Y_CB_CR_SUB_SAMPLING, 530, IFD_FORMAT_USHORT),
             new ExifTag(TAG_Y_CB_CR_POSITIONING, 531, IFD_FORMAT_USHORT),
             new ExifTag(TAG_REFERENCE_BLACK_WHITE, 532, IFD_FORMAT_URATIONAL),
-            new ExifTag(TAG_XMP, 700, IFD_FORMAT_BYTE),
             new ExifTag(TAG_COPYRIGHT, 33432, IFD_FORMAT_STRING),
             new ExifTag(TAG_EXIF_IFD_POINTER, 34665, IFD_FORMAT_ULONG),
             new ExifTag(TAG_GPS_INFO_IFD_POINTER, 34853, IFD_FORMAT_ULONG),
@@ -2076,7 +2079,7 @@
      * {@link #setAttribute(String,String)} to set all attributes to write and
      * make a single call rather than multiple calls for each attribute.
      * <p>
-     * This method is supported for JPEG, PNG, WebP, and DNG files.
+     * This method is supported for JPEG, PNG, and WebP files.
      * <p class="note">
      * Note: after calling this method, any attempts to obtain range information
      * from {@link #getAttributeRange(String)} or {@link #getThumbnailRange()}
@@ -2088,11 +2091,15 @@
      * <p>
      * For PNG format, the Exif data will be stored as an "eXIf" chunk as per
      * "Extensions to the PNG 1.2 Specification, Version 1.5.0".
+     * <p>
+     * <b>Warning:</b> Calling this method on a DNG-based instance of {@code ExifInterface} may
+     * result in the original image file being overwritten with invalid data on some versions of
+     * Android 13 (API 33).
      */
     public void saveAttributes() throws IOException {
         if (!isSupportedFormatForSavingAttributes()) {
             throw new IOException("ExifInterface only supports saving attributes for JPEG, PNG, "
-                    + "WebP, and DNG formats.");
+                    + "and WebP formats.");
         }
         if (mIsInputStream || (mSeekableFileDescriptor == null && mFilename == null)) {
             throw new IOException(
@@ -2150,10 +2157,6 @@
                     savePngAttributes(bufferedIn, bufferedOut);
                 } else if (mMimeType == IMAGE_TYPE_WEBP) {
                     saveWebpAttributes(bufferedIn, bufferedOut);
-                } else if (mMimeType == IMAGE_TYPE_DNG || mMimeType == IMAGE_TYPE_UNKNOWN) {
-                    ByteOrderedDataOutputStream dataOutputStream =
-                            new ByteOrderedDataOutputStream(bufferedOut, ByteOrder.BIG_ENDIAN);
-                    writeExifSegment(dataOutputStream);
                 }
             }
         } catch (Exception e) {
@@ -5262,8 +5265,7 @@
 
     private boolean isSupportedFormatForSavingAttributes() {
         if (mIsSupportedFile && (mMimeType == IMAGE_TYPE_JPEG || mMimeType == IMAGE_TYPE_PNG
-                || mMimeType == IMAGE_TYPE_WEBP || mMimeType == IMAGE_TYPE_DNG
-                || mMimeType == IMAGE_TYPE_UNKNOWN)) {
+                || mMimeType == IMAGE_TYPE_WEBP)) {
             return true;
         }
         return false;
diff --git a/media/java/android/media/Ringtone.java b/media/java/android/media/Ringtone.java
index 86a94a9..82c3139 100644
--- a/media/java/android/media/Ringtone.java
+++ b/media/java/android/media/Ringtone.java
@@ -29,11 +29,12 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.RemoteException;
+import android.os.Trace;
 import android.provider.MediaStore;
 import android.provider.MediaStore.MediaColumns;
 import android.provider.Settings;
 import android.util.Log;
-
+import com.android.internal.annotations.VisibleForTesting;
 import java.io.IOException;
 import java.util.ArrayList;
 
@@ -136,13 +137,73 @@
      */
     public void setAudioAttributes(AudioAttributes attributes)
             throws IllegalArgumentException {
+        setAudioAttributesField(attributes);
+        // The audio attributes have to be set before the media player is prepared.
+        // Re-initialize it.
+        setUri(mUri, mVolumeShaperConfig);
+        createLocalMediaPlayer();
+    }
+
+    /**
+     * Same as {@link #setAudioAttributes(AudioAttributes)} except this one does not create
+     * the media player.
+     * @hide
+     */
+    public void setAudioAttributesField(@Nullable AudioAttributes attributes) {
         if (attributes == null) {
             throw new IllegalArgumentException("Invalid null AudioAttributes for Ringtone");
         }
         mAudioAttributes = attributes;
-        // The audio attributes have to be set before the media player is prepared.
-        // Re-initialize it.
-        setUri(mUri, mVolumeShaperConfig);
+    }
+
+    /**
+     * Creates a local media player for the ringtone using currently set attributes.
+     * @hide
+     */
+    public void createLocalMediaPlayer() {
+        Trace.beginSection("createLocalMediaPlayer");
+        if (mUri == null) {
+            Log.e(TAG, "Could not create media player as no URI was provided.");
+            return;
+        }
+        destroyLocalPlayer();
+        // try opening uri locally before delegating to remote player
+        mLocalPlayer = new MediaPlayer();
+        try {
+            mLocalPlayer.setDataSource(mContext, mUri);
+            mLocalPlayer.setAudioAttributes(mAudioAttributes);
+            synchronized (mPlaybackSettingsLock) {
+                applyPlaybackProperties_sync();
+            }
+            if (mVolumeShaperConfig != null) {
+                mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig);
+            }
+            mLocalPlayer.prepare();
+
+        } catch (SecurityException | IOException e) {
+            destroyLocalPlayer();
+            if (!mAllowRemote) {
+                Log.w(TAG, "Remote playback not allowed: " + e);
+            }
+        }
+
+        if (LOGD) {
+            if (mLocalPlayer != null) {
+                Log.d(TAG, "Successfully created local player");
+            } else {
+                Log.d(TAG, "Problem opening; delegating to remote player");
+            }
+        }
+        Trace.endSection();
+    }
+
+    /**
+     * Returns whether a local player has been created for this ringtone.
+     * @hide
+     */
+    @VisibleForTesting
+    public boolean hasLocalPlayer() {
+        return mLocalPlayer != null;
     }
 
     /**
@@ -336,8 +397,7 @@
     }
 
     /**
-     * Set {@link Uri} to be used for ringtone playback. Attempts to open
-     * locally, otherwise will delegate playback to remote
+     * Set {@link Uri} to be used for ringtone playback.
      * {@link IRingtonePlayer}.
      *
      * @hide
@@ -348,6 +408,13 @@
     }
 
     /**
+     * @hide
+     */
+    public void setVolumeShaperConfig(@Nullable VolumeShaper.Configuration volumeShaperConfig) {
+        mVolumeShaperConfig = volumeShaperConfig;
+    }
+
+    /**
      * Set {@link Uri} to be used for ringtone playback. Attempts to open
      * locally, otherwise will delegate playback to remote
      * {@link IRingtonePlayer}. Add {@link VolumeShaper} if required.
@@ -356,41 +423,10 @@
      */
     public void setUri(Uri uri, @Nullable VolumeShaper.Configuration volumeShaperConfig) {
         mVolumeShaperConfig = volumeShaperConfig;
-        destroyLocalPlayer();
 
         mUri = uri;
         if (mUri == null) {
-            return;
-        }
-
-        // TODO: detect READ_EXTERNAL and specific content provider case, instead of relying on throwing
-
-        // try opening uri locally before delegating to remote player
-        mLocalPlayer = new MediaPlayer();
-        try {
-            mLocalPlayer.setDataSource(mContext, mUri);
-            mLocalPlayer.setAudioAttributes(mAudioAttributes);
-            synchronized (mPlaybackSettingsLock) {
-                applyPlaybackProperties_sync();
-            }
-            if (mVolumeShaperConfig != null) {
-                mVolumeShaper = mLocalPlayer.createVolumeShaper(mVolumeShaperConfig);
-            }
-            mLocalPlayer.prepare();
-
-        } catch (SecurityException | IOException e) {
             destroyLocalPlayer();
-            if (!mAllowRemote) {
-                Log.w(TAG, "Remote playback not allowed: " + e);
-            }
-        }
-
-        if (LOGD) {
-            if (mLocalPlayer != null) {
-                Log.d(TAG, "Successfully created local player");
-            } else {
-                Log.d(TAG, "Problem opening; delegating to remote player");
-            }
         }
     }
 
diff --git a/media/java/android/media/RingtoneManager.java b/media/java/android/media/RingtoneManager.java
index 2772769..27db41c 100644
--- a/media/java/android/media/RingtoneManager.java
+++ b/media/java/android/media/RingtoneManager.java
@@ -480,8 +480,9 @@
         if (mStopPreviousRingtone && mPreviousRingtone != null) {
             mPreviousRingtone.stop();
         }
-        
-        mPreviousRingtone = getRingtone(mContext, getRingtoneUri(position), inferStreamType());
+
+        mPreviousRingtone =
+                getRingtone(mContext, getRingtoneUri(position), inferStreamType(), true);
         return mPreviousRingtone;
     }
 
@@ -677,7 +678,7 @@
      */
     public static Ringtone getRingtone(final Context context, Uri ringtoneUri) {
         // Don't set the stream type
-        return getRingtone(context, ringtoneUri, -1);
+        return getRingtone(context, ringtoneUri, -1, true);
     }
 
     /**
@@ -698,7 +699,34 @@
             final Context context, Uri ringtoneUri,
             @Nullable VolumeShaper.Configuration volumeShaperConfig) {
         // Don't set the stream type
-        return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig);
+        return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, true);
+    }
+
+    /**
+     * @hide
+     */
+    public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig,
+            boolean createLocalMediaPlayer) {
+        // Don't set the stream type
+        return getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig,
+                createLocalMediaPlayer);
+    }
+
+    /**
+     * @hide
+     */
+    public static Ringtone getRingtone(final Context context, Uri ringtoneUri,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig,
+            AudioAttributes audioAttributes) {
+        // Don't set the stream type
+        Ringtone ringtone =
+                getRingtone(context, ringtoneUri, -1 /* streamType */, volumeShaperConfig, false);
+        if (ringtone != null) {
+            ringtone.setAudioAttributesField(audioAttributes);
+            ringtone.createLocalMediaPlayer();
+        }
+        return ringtone;
     }
 
     //FIXME bypass the notion of stream types within the class
@@ -707,14 +735,19 @@
      * type. Normally, if you change the stream type on the returned
      * {@link Ringtone}, it will re-create the {@link MediaPlayer}. This is just
      * an optimized route to avoid that.
-     * 
+     *
      * @param streamType The stream type for the ringtone, or -1 if it should
      *            not be set (and the default used instead).
+     * @param createLocalMediaPlayer when true, the ringtone returned will be fully
+     *      created otherwise, it will require the caller to create the media player manually
+     *      {@link Ringtone#createLocalMediaPlayer()} in order to play the Ringtone.
      * @see #getRingtone(Context, Uri)
      */
     @UnsupportedAppUsage
-    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType) {
-        return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */);
+    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
+            boolean createLocalMediaPlayer) {
+        return getRingtone(context, ringtoneUri, streamType, null /* volumeShaperConfig */,
+                createLocalMediaPlayer);
     }
 
     //FIXME bypass the notion of stream types within the class
@@ -730,16 +763,21 @@
      * @see #getRingtone(Context, Uri)
      */
     @UnsupportedAppUsage(maxTargetSdk = Build.VERSION_CODES.R, trackingBug = 170729553)
-    private static Ringtone getRingtone(
-            final Context context, Uri ringtoneUri, int streamType,
-            @Nullable VolumeShaper.Configuration volumeShaperConfig) {
+    private static Ringtone getRingtone(final Context context, Uri ringtoneUri, int streamType,
+            @Nullable VolumeShaper.Configuration volumeShaperConfig,
+            boolean createLocalMediaPlayer) {
         try {
             final Ringtone r = new Ringtone(context, true);
             if (streamType >= 0) {
                 //FIXME deprecated call
                 r.setStreamType(streamType);
             }
+
+            r.setVolumeShaperConfig(volumeShaperConfig);
             r.setUri(ringtoneUri, volumeShaperConfig);
+            if (createLocalMediaPlayer) {
+                r.createLocalMediaPlayer();
+            }
             return r;
         } catch (Exception ex) {
             Log.e(TAG, "Failed to open ringtone " + ringtoneUri + ": " + ex);
diff --git a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
index ead5174..0de7be0 100644
--- a/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
+++ b/packages/SettingsLib/IllustrationPreference/res/values/colors.xml
@@ -43,6 +43,8 @@
     <color name="settingslib_color_grey400">#bdc1c6</color>
     <color name="settingslib_color_grey300">#dadce0</color>
     <color name="settingslib_color_grey200">#e8eaed</color>
+    <color name="settingslib_color_grey100">#f1f3f4</color>
+    <color name="settingslib_color_grey50">#f8f9fa</color>
     <color name="settingslib_color_orange600">#e8710a</color>
     <color name="settingslib_color_orange400">#fa903e</color>
     <color name="settingslib_color_orange300">#fcad70</color>
diff --git a/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
new file mode 100644
index 0000000..93b6acc
--- /dev/null
+++ b/packages/SettingsLib/IllustrationPreference/src/com/android/settingslib/widget/LottieColorUtils.java
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2022 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.settingslib.widget;
+
+import android.content.Context;
+import android.content.res.Configuration;
+import android.graphics.PorterDuff;
+import android.graphics.PorterDuffColorFilter;
+
+import com.airbnb.lottie.LottieAnimationView;
+import com.airbnb.lottie.LottieProperty;
+import com.airbnb.lottie.model.KeyPath;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * Util class which dynamically changes the color of tags in a lottie json file between Dark Theme
+ * (DT) and Light Theme (LT). This class assumes the json file is for Dark Theme.
+ */
+public class LottieColorUtils {
+    private static final Map<String, Integer> DARK_TO_LIGHT_THEME_COLOR_MAP;
+
+    static {
+        HashMap<String, Integer> map = new HashMap<>();
+        map.put(
+                ".grey600",
+                R.color.settingslib_color_grey300);
+        map.put(
+                ".grey800",
+                R.color.settingslib_color_grey200);
+        map.put(
+                ".grey900",
+                R.color.settingslib_color_grey50);
+        map.put(
+                ".red400",
+                R.color.settingslib_color_red600);
+        map.put(
+                ".black",
+                android.R.color.white);
+        map.put(
+                ".blue400",
+                R.color.settingslib_color_blue600);
+        map.put(
+                ".green400",
+                R.color.settingslib_color_green600);
+        DARK_TO_LIGHT_THEME_COLOR_MAP = Collections.unmodifiableMap(map);
+    }
+
+    private LottieColorUtils() {
+    }
+
+    private static boolean isDarkMode(Context context) {
+        return (context.getResources().getConfiguration().uiMode & Configuration.UI_MODE_NIGHT_MASK)
+                == Configuration.UI_MODE_NIGHT_YES;
+    }
+
+    /** Applies dynamic colors based on DT vs. LT. The LottieAnimationView should be Dark Theme. */
+    public static void applyDynamicColors(Context context,
+            LottieAnimationView lottieAnimationView) {
+        // Assume the default for the lottie is dark mode
+        if (isDarkMode(context)) {
+            return;
+        }
+        for (String key : DARK_TO_LIGHT_THEME_COLOR_MAP.keySet()) {
+            final int color = context.getColor(DARK_TO_LIGHT_THEME_COLOR_MAP.get(key));
+            lottieAnimationView.addValueCallback(
+                    new KeyPath("**", key, "**"),
+                    LottieProperty.COLOR_FILTER,
+                    frameInfo -> new PorterDuffColorFilter(color, PorterDuff.Mode.SRC_ATOP));
+        }
+    }
+}
diff --git a/packages/SettingsLib/res/values-ta/strings.xml b/packages/SettingsLib/res/values-ta/strings.xml
index 84c5a69..e050ae0 100644
--- a/packages/SettingsLib/res/values-ta/strings.xml
+++ b/packages/SettingsLib/res/values-ta/strings.xml
@@ -597,7 +597,7 @@
     <string name="guest_reset_guest" msgid="6110013010356013758">"கெஸ்ட் அமர்வை மீட்டமை"</string>
     <string name="guest_reset_guest_dialog_title" msgid="8047270010895437534">"கெஸ்ட்டை மீட்டமைக்கவா?"</string>
     <string name="guest_remove_guest_dialog_title" msgid="4548511006624088072">"கெஸ்ட் பயனரை அகற்றவா?"</string>
-    <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"மீட்டமை"</string>
+    <string name="guest_reset_guest_confirm_button" msgid="2989915693215617237">"ரீசெட்"</string>
     <string name="guest_remove_guest_confirm_button" msgid="7858123434954143879">"அகற்று"</string>
     <string name="guest_resetting" msgid="7822120170191509566">"கெஸ்ட்டை மீட்டமைக்கிறது…"</string>
     <string name="guest_reset_and_restart_dialog_title" msgid="3396657008451616041">"கெஸ்ட் அமர்வை ரீசெட் செய்யவா?"</string>
diff --git a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
index 63a9f0c..adfa39e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
+++ b/packages/SettingsLib/src/com/android/settingslib/users/AvatarPhotoController.java
@@ -21,8 +21,6 @@
 import android.content.ContentResolver;
 import android.content.Context;
 import android.content.Intent;
-import android.content.pm.ActivityInfo;
-import android.content.pm.PackageManager;
 import android.graphics.Bitmap;
 import android.graphics.BitmapFactory;
 import android.graphics.Canvas;
@@ -59,9 +57,9 @@
 
         void startActivityForResult(Intent intent, int resultCode);
 
-        boolean startSystemActivityForResult(Intent intent, int resultCode);
-
         int getPhotoSize();
+
+        boolean canCropPhoto();
     }
 
     interface ContextInjector {
@@ -84,7 +82,6 @@
     private static final long DELAY_BEFORE_CROP_MILLIS = 150;
 
     private static final String IMAGES_DIR = "multi_user";
-    private static final String PRE_CROP_PICTURE_FILE_NAME = "PreCropEditUserPhoto.jpg";
     private static final String CROP_PICTURE_FILE_NAME = "CropEditUserPhoto.jpg";
     private static final String TAKE_PICTURE_FILE_NAME = "TakeEditUserPhoto.jpg";
 
@@ -94,7 +91,6 @@
     private final ContextInjector mContextInjector;
 
     private final File mImagesDir;
-    private final Uri mPreCropPictureUri;
     private final Uri mCropPictureUri;
     private final Uri mTakePictureUri;
 
@@ -104,8 +100,6 @@
 
         mImagesDir = new File(mContextInjector.getCacheDir(), IMAGES_DIR);
         mImagesDir.mkdir();
-        mPreCropPictureUri = mContextInjector
-                .createTempImageUri(mImagesDir, PRE_CROP_PICTURE_FILE_NAME, !waiting);
         mCropPictureUri =
                 mContextInjector.createTempImageUri(mImagesDir, CROP_PICTURE_FILE_NAME, !waiting);
         mTakePictureUri =
@@ -137,7 +131,7 @@
                 return true;
             case REQUEST_CODE_TAKE_PHOTO:
                 if (mTakePictureUri.equals(pictureUri)) {
-                    cropPhoto(pictureUri);
+                    cropPhoto();
                 } else {
                     copyAndCropPhoto(pictureUri, false);
                 }
@@ -166,7 +160,7 @@
             ThreadUtils.postOnBackgroundThread(() -> {
                 final ContentResolver cr = mContextInjector.getContentResolver();
                 try (InputStream in = cr.openInputStream(pictureUri);
-                        OutputStream out = cr.openOutputStream(mPreCropPictureUri)) {
+                     OutputStream out = cr.openOutputStream(mTakePictureUri)) {
                     Streams.copy(in, out);
                 } catch (IOException e) {
                     Log.w(TAG, "Failed to copy photo", e);
@@ -174,7 +168,7 @@
                 }
                 Runnable cropRunnable = () -> {
                     if (!mAvatarUi.isFinishing()) {
-                        cropPhoto(mPreCropPictureUri);
+                        cropPhoto();
                     }
                 };
                 if (delayBeforeCrop) {
@@ -189,21 +183,22 @@
         }
     }
 
-    private void cropPhoto(final Uri pictureUri) {
-        // TODO: Use a public intent, when there is one.
-        Intent intent = new Intent("com.android.camera.action.CROP");
-        intent.setDataAndType(pictureUri, "image/*");
-        appendOutputExtra(intent, mCropPictureUri);
-        appendCropExtras(intent);
-        try {
-            StrictMode.disableDeathOnFileUriExposure();
-            if (mAvatarUi.startSystemActivityForResult(intent, REQUEST_CODE_CROP_PHOTO)) {
-                return;
+    private void cropPhoto() {
+        if (mAvatarUi.canCropPhoto()) {
+            // TODO: Use a public intent, when there is one.
+            Intent intent = new Intent("com.android.camera.action.CROP");
+            intent.setDataAndType(mTakePictureUri, "image/*");
+            appendOutputExtra(intent, mCropPictureUri);
+            appendCropExtras(intent);
+            try {
+                StrictMode.disableDeathOnFileUriExposure();
+                mAvatarUi.startActivityForResult(intent, REQUEST_CODE_CROP_PHOTO);
+            } finally {
+                StrictMode.enableDeathOnFileUriExposure();
             }
-        } finally {
-            StrictMode.enableDeathOnFileUriExposure();
+        } else {
+            onPhotoNotCropped(mTakePictureUri);
         }
-        onPhotoNotCropped(pictureUri);
     }
 
     private void appendOutputExtra(Intent intent, Uri pictureUri) {
@@ -325,23 +320,15 @@
         }
 
         @Override
-        public boolean startSystemActivityForResult(Intent intent, int code) {
-            ActivityInfo info = intent.resolveActivityInfo(mActivity.getPackageManager(),
-                    PackageManager.MATCH_SYSTEM_ONLY);
-            if (info == null) {
-                Log.w(TAG, "No system package activity could be found for code " + code);
-                return false;
-            }
-            intent.setPackage(info.packageName);
-            mActivity.startActivityForResult(intent, code);
-            return true;
-        }
-
-        @Override
         public int getPhotoSize() {
             return mActivity.getResources()
                     .getDimensionPixelSize(com.android.internal.R.dimen.user_icon_size);
         }
+
+        @Override
+        public boolean canCropPhoto() {
+            return PhotoCapabilityUtils.canCropPhoto(mActivity);
+        }
     }
 
     static class ContextInjectorImpl implements ContextInjector {
diff --git a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
index d988111..3dc2fab 100644
--- a/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
+++ b/packages/SettingsLib/tests/integ/src/com/android/settingslib/users/AvatarPhotoControllerTest.java
@@ -34,7 +34,6 @@
 import android.content.Context;
 import android.content.Intent;
 import android.graphics.Bitmap;
-import android.graphics.BitmapFactory;
 import android.net.Uri;
 import android.provider.MediaStore;
 
@@ -52,7 +51,6 @@
 import java.io.File;
 import java.io.FileOutputStream;
 import java.io.IOException;
-import java.io.InputStream;
 import java.io.OutputStream;
 
 @RunWith(AndroidJUnit4.class)
@@ -75,7 +73,6 @@
     public void setUp() {
         MockitoAnnotations.initMocks(this);
         when(mMockAvatarUi.getPhotoSize()).thenReturn(PHOTO_SIZE);
-        when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(true);
 
         mImagesDir = new File(
                 InstrumentationRegistry.getTargetContext().getCacheDir(), "multi_user");
@@ -113,7 +110,9 @@
     }
 
     @Test
-    public void takePhotoIsFollowedByCrop() throws IOException {
+    public void takePhotoIsFollowedByCropWhenSupported() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
+
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -122,12 +121,14 @@
         mController.onActivityResult(
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartSystemActivityForResult(
+        verifyStartActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
     public void takePhotoIsNotFollowedByCropWhenResultCodeNotOk() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
+
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -137,11 +138,12 @@
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_CANCELED, intent);
 
         verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
-        verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
     }
 
     @Test
     public void takePhotoIsFollowedByCropWhenTakePhotoUriReturned() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
+
         new File(mImagesDir, "TakeEditUserPhoto.jpg").createNewFile();
 
         Intent intent = new Intent();
@@ -149,12 +151,14 @@
         mController.onActivityResult(
                 REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartSystemActivityForResult(
+        verifyStartActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
     public void choosePhotoIsFollowedByCrop() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
+
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -163,12 +167,14 @@
         mController.onActivityResult(
                 REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartSystemActivityForResult(
+        verifyStartActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
     public void choosePhotoIsNotFollowedByCropWhenResultCodeNotOk() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
+
         new File(mImagesDir, "file.txt").createNewFile();
 
         Intent intent = new Intent();
@@ -178,11 +184,12 @@
                 REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_CANCELED, intent);
 
         verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
-        verify(mMockAvatarUi, never()).startSystemActivityForResult(any(), anyInt());
     }
 
     @Test
     public void choosePhotoIsFollowedByCropWhenTakePhotoUriReturned() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(true);
+
         new File(mImagesDir, "TakeEditUserPhoto.jpg").createNewFile();
 
         Intent intent = new Intent();
@@ -190,11 +197,28 @@
         mController.onActivityResult(
                 REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
 
-        verifyStartSystemActivityForResult(
+        verifyStartActivityForResult(
                 "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
     }
 
     @Test
+    public void choosePhotoIsNotFollowedByCropIntentWhenCropNotSupported() throws IOException {
+        when(mMockAvatarUi.canCropPhoto()).thenReturn(false);
+
+        File file = new File(mImagesDir, "file.txt");
+        saveBitmapToFile(file);
+
+        Intent intent = new Intent();
+        intent.setData(Uri.parse(
+                "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
+        mController.onActivityResult(
+                REQUEST_CODE_CHOOSE_PHOTO, Activity.RESULT_OK, intent);
+
+        verify(mMockAvatarUi, never()).startActivityForResult(any(), anyInt());
+        verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
+    }
+
+    @Test
     public void cropPhotoResultIsReturnedIfResultOkAndContent() {
         Intent intent = new Intent();
         intent.setData(mCropPhotoUri);
@@ -218,58 +242,11 @@
         verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS).times(0)).returnUriResult(mCropPhotoUri);
     }
 
-    @Test
-    public void cropDoesNotUseTakePhotoUri() throws IOException {
-        new File(mImagesDir, "file.txt").createNewFile();
-
-        Intent intent = new Intent();
-        intent.setData(Uri.parse(
-                "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
-        mController.onActivityResult(
-                REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
-
-        Intent startIntent = verifyStartSystemActivityForResult(
-                "com.android.camera.action.CROP", REQUEST_CODE_CROP_PHOTO);
-        assertThat(startIntent.getData()).isNotEqualTo(mTakePhotoUri);
-    }
-
-    @Test
-    public void internalCropUsedIfNoSystemCropperFound() throws IOException {
-        when(mMockAvatarUi.startSystemActivityForResult(any(), anyInt())).thenReturn(false);
-
-        File file = new File(mImagesDir, "file.txt");
-        saveBitmapToFile(file);
-
-        Intent intent = new Intent();
-        intent.setData(Uri.parse(
-                "content://com.android.settingslib.test/my_cache/multi_user/file.txt"));
-        mController.onActivityResult(
-                REQUEST_CODE_TAKE_PHOTO, Activity.RESULT_OK, intent);
-
-        verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS)).returnUriResult(mCropPhotoUri);
-
-        InputStream imageStream = mContext.getContentResolver().openInputStream(mCropPhotoUri);
-        Bitmap bitmap = BitmapFactory.decodeStream(imageStream);
-        assertThat(bitmap.getWidth()).isEqualTo(PHOTO_SIZE);
-        assertThat(bitmap.getHeight()).isEqualTo(PHOTO_SIZE);
-    }
-
-    private Intent verifyStartActivityForResult(String action, int resultCode) {
+    private void verifyStartActivityForResult(String action, int resultCode) {
         ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
         verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS))
                 .startActivityForResult(captor.capture(), eq(resultCode));
-        Intent intent = captor.getValue();
-        assertThat(intent.getAction()).isEqualTo(action);
-        return intent;
-    }
-
-    private Intent verifyStartSystemActivityForResult(String action, int resultCode) {
-        ArgumentCaptor<Intent> captor = ArgumentCaptor.forClass(Intent.class);
-        verify(mMockAvatarUi, timeout(TIMEOUT_MILLIS))
-                .startSystemActivityForResult(captor.capture(), eq(resultCode));
-        Intent intent = captor.getValue();
-        assertThat(intent.getAction()).isEqualTo(action);
-        return intent;
+        assertThat(captor.getValue().getAction()).isEqualTo(action);
     }
 
     private void saveBitmapToFile(File file) throws IOException {
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
new file mode 100644
index 0000000..b006615
--- /dev/null
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SlowUserQueryDetector.kt
@@ -0,0 +1,103 @@
+/*
+ * Copyright (C) 2022 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.internal.systemui.lint
+
+import com.android.tools.lint.detector.api.Category
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Implementation
+import com.android.tools.lint.detector.api.Issue
+import com.android.tools.lint.detector.api.JavaContext
+import com.android.tools.lint.detector.api.Scope
+import com.android.tools.lint.detector.api.Severity
+import com.android.tools.lint.detector.api.SourceCodeScanner
+import com.intellij.psi.PsiMethod
+import org.jetbrains.uast.UCallExpression
+
+/**
+ * Checks for slow calls to ActivityManager.getCurrentUser() or UserManager.getUserInfo() and
+ * suggests using UserTracker instead. For more info, see: http://go/multi-user-in-systemui-slides.
+ */
+@Suppress("UnstableApiUsage")
+class SlowUserQueryDetector : Detector(), SourceCodeScanner {
+
+    override fun getApplicableMethodNames(): List<String> {
+        return listOf("getCurrentUser", "getUserInfo")
+    }
+
+    override fun visitMethodCall(context: JavaContext, node: UCallExpression, method: PsiMethod) {
+        val evaluator = context.evaluator
+        if (
+            evaluator.isStatic(method) &&
+                method.name == "getCurrentUser" &&
+                method.containingClass?.qualifiedName == "android.app.ActivityManager"
+        ) {
+            context.report(
+                ISSUE_SLOW_USER_ID_QUERY,
+                method,
+                context.getNameLocation(node),
+                "ActivityManager.getCurrentUser() is slow. " +
+                    "Use UserTracker.getUserId() instead."
+            )
+        }
+        if (
+            !evaluator.isStatic(method) &&
+                method.name == "getUserInfo" &&
+                method.containingClass?.qualifiedName == "android.os.UserManager"
+        ) {
+            context.report(
+                ISSUE_SLOW_USER_INFO_QUERY,
+                method,
+                context.getNameLocation(node),
+                "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+            )
+        }
+    }
+
+    companion object {
+        @JvmField
+        val ISSUE_SLOW_USER_ID_QUERY: Issue =
+            Issue.create(
+                id = "SlowUserIdQuery",
+                briefDescription = "User ID queried using ActivityManager instead of UserTracker.",
+                explanation =
+                    "ActivityManager.getCurrentUser() makes a binder call and is slow. " +
+                        "Instead, inject a UserTracker and call UserTracker.getUserId(). For " +
+                        "more info, see: http://go/multi-user-in-systemui-slides",
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                    Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+            )
+
+        @JvmField
+        val ISSUE_SLOW_USER_INFO_QUERY: Issue =
+            Issue.create(
+                id = "SlowUserInfoQuery",
+                briefDescription = "User info queried using UserManager instead of UserTracker.",
+                explanation =
+                    "UserManager.getUserInfo() makes a binder call and is slow. " +
+                        "Instead, inject a UserTracker and call UserTracker.getUserInfo(). For " +
+                        "more info, see: http://go/multi-user-in-systemui-slides",
+                category = Category.PERFORMANCE,
+                priority = 8,
+                severity = Severity.WARNING,
+                implementation =
+                    Implementation(SlowUserQueryDetector::class.java, Scope.JAVA_FILE_SCOPE)
+            )
+    }
+}
diff --git a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
index c7c73d3..4879883 100644
--- a/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
+++ b/packages/SystemUI/checks/src/com/android/internal/systemui/lint/SystemUIIssueRegistry.kt
@@ -30,6 +30,8 @@
         get() = listOf(
                 BindServiceViaContextDetector.ISSUE,
                 BroadcastSentViaContextDetector.ISSUE,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY,
                 GetMainLooperViaContextDetector.ISSUE,
                 RegisterReceiverViaContextDetector.ISSUE,
                 SoftwareBitmapDetector.ISSUE,
diff --git a/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
new file mode 100644
index 0000000..2738f04
--- /dev/null
+++ b/packages/SystemUI/checks/tests/com/android/systemui/lint/SlowUserQueryDetectorTest.kt
@@ -0,0 +1,194 @@
+package com.android.internal.systemui.lint
+
+import com.android.tools.lint.checks.infrastructure.LintDetectorTest
+import com.android.tools.lint.checks.infrastructure.TestFile
+import com.android.tools.lint.checks.infrastructure.TestFiles
+import com.android.tools.lint.checks.infrastructure.TestLintTask
+import com.android.tools.lint.detector.api.Detector
+import com.android.tools.lint.detector.api.Issue
+import org.junit.Test
+
+class SlowUserQueryDetectorTest : LintDetectorTest() {
+
+    override fun getDetector(): Detector = SlowUserQueryDetector()
+    override fun lint(): TestLintTask = super.lint().allowMissingSdk(true)
+
+    override fun getIssues(): List<Issue> =
+        listOf(
+            SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+            SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+        )
+
+    @Test
+    fun testGetCurrentUser() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.app.ActivityManager;
+
+                        public class TestClass1 {
+                            public void slewlyGetCurrentUser() {
+                                ActivityManager.getCurrentUser();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectWarningCount(1)
+            .expectContains(
+                "ActivityManager.getCurrentUser() is slow. " +
+                    "Use UserTracker.getUserId() instead."
+            )
+    }
+
+    @Test
+    fun testGetUserInfo() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import android.os.UserManager;
+
+                        public class TestClass2 {
+                            public void slewlyGetUserInfo(UserManager userManager) {
+                                userManager.getUserInfo();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectWarningCount(1)
+            .expectContains(
+                "UserManager.getUserInfo() is slow. " + "Use UserTracker.getUserInfo() instead."
+            )
+    }
+
+    @Test
+    fun testUserTrackerGetUserId() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import com.android.systemui.settings.UserTracker;
+
+                        public class TestClass3 {
+                            public void quicklyGetUserId(UserTracker userTracker) {
+                                userTracker.getUserId();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectClean()
+    }
+
+    @Test
+    fun testUserTrackerGetUserInfo() {
+        lint()
+            .files(
+                TestFiles.java(
+                        """
+                        package test.pkg;
+                        import com.android.systemui.settings.UserTracker;
+
+                        public class TestClass4 {
+                            public void quicklyGetUserId(UserTracker userTracker) {
+                                userTracker.getUserInfo();
+                            }
+                        }
+                        """
+                    )
+                    .indented(),
+                *stubs
+            )
+            .issues(
+                SlowUserQueryDetector.ISSUE_SLOW_USER_ID_QUERY,
+                SlowUserQueryDetector.ISSUE_SLOW_USER_INFO_QUERY
+            )
+            .run()
+            .expectClean()
+    }
+
+    private val activityManagerStub: TestFile =
+        java(
+            """
+            package android.app;
+
+            public class ActivityManager {
+                public static int getCurrentUser() {};
+            }
+            """
+        )
+
+    private val userManagerStub: TestFile =
+        java(
+            """
+            package android.os;
+            import android.content.pm.UserInfo;
+            import android.annotation.UserIdInt;
+
+            public class UserManager {
+                public UserInfo getUserInfo(@UserIdInt int userId) {};
+            }
+            """
+        )
+
+    private val userIdIntStub: TestFile =
+        java(
+            """
+            package android.annotation;
+
+            public @interface UserIdInt {}
+            """
+        )
+
+    private val userInfoStub: TestFile =
+        java(
+            """
+            package android.content.pm;
+
+            public class UserInfo {}
+            """
+        )
+
+    private val userTrackerStub: TestFile =
+        java(
+            """
+            package com.android.systemui.settings;
+            import android.content.pm.UserInfo;
+
+            public interface UserTracker {
+                public int getUserId();
+                public UserInfo getUserInfo();
+            }
+            """
+        )
+
+    private val stubs =
+        arrayOf(activityManagerStub, userManagerStub, userIdIntStub, userInfoStub, userTrackerStub)
+}
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
index 11477f9..6588e22 100644
--- a/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/qs/footer/Fakes.kt
@@ -83,7 +83,11 @@
                 flowOf(
                     securityText?.let { text ->
                         SecurityButtonConfig(
-                            icon = Icon.Resource(R.drawable.ic_info_outline),
+                            icon =
+                                Icon.Resource(
+                                    R.drawable.ic_info_outline,
+                                    contentDescription = null,
+                                ),
                             text = text,
                             isClickable = securityClickable,
                         )
diff --git a/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
new file mode 100644
index 0000000..02d76f4
--- /dev/null
+++ b/packages/SystemUI/compose/gallery/src/com/android/systemui/user/Fakes.kt
@@ -0,0 +1,99 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+package com.android.systemui.user
+
+import android.content.Context
+import androidx.appcompat.content.res.AppCompatResources
+import com.android.systemui.common.shared.model.Text
+import com.android.systemui.compose.gallery.R
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.power.data.repository.FakePowerRepository
+import com.android.systemui.power.domain.interactor.PowerInteractor
+import com.android.systemui.user.data.repository.FakeUserRepository
+import com.android.systemui.user.domain.interactor.UserInteractor
+import com.android.systemui.user.shared.model.UserActionModel
+import com.android.systemui.user.shared.model.UserModel
+import com.android.systemui.user.ui.viewmodel.UserSwitcherViewModel
+import com.android.systemui.util.mockito.mock
+
+object Fakes {
+    private val USER_TINT_COLORS =
+        arrayOf(
+            0x000000,
+            0x0000ff,
+            0x00ff00,
+            0x00ffff,
+            0xff0000,
+            0xff00ff,
+            0xffff00,
+            0xffffff,
+        )
+
+    fun fakeUserSwitcherViewModel(
+        context: Context,
+        userCount: Int,
+    ): UserSwitcherViewModel {
+        return UserSwitcherViewModel.Factory(
+                userInteractor =
+                    UserInteractor(
+                        repository =
+                            FakeUserRepository().apply {
+                                setUsers(
+                                    (0 until userCount).map { index ->
+                                        UserModel(
+                                            id = index,
+                                            name = Text.Loaded("user_$index"),
+                                            image =
+                                                checkNotNull(
+                                                    AppCompatResources.getDrawable(
+                                                        context,
+                                                        R.drawable.ic_avatar_guest_user
+                                                    )
+                                                ),
+                                            isSelected = index == 0,
+                                            isSelectable = true,
+                                        )
+                                    }
+                                )
+                                setActions(
+                                    UserActionModel.values().mapNotNull {
+                                        if (it == UserActionModel.NAVIGATE_TO_USER_MANAGEMENT) {
+                                            null
+                                        } else {
+                                            it
+                                        }
+                                    }
+                                )
+                            },
+                        controller = mock(),
+                        activityStarter = mock(),
+                        keyguardInteractor =
+                            KeyguardInteractor(
+                                repository =
+                                    FakeKeyguardRepository().apply { setKeyguardShowing(false) },
+                            ),
+                    ),
+                powerInteractor =
+                    PowerInteractor(
+                        repository = FakePowerRepository(),
+                    )
+            )
+            .create(UserSwitcherViewModel::class.java)
+    }
+}
diff --git a/packages/SystemUI/ktfmt_includes.txt b/packages/SystemUI/ktfmt_includes.txt
index 51cc195..689938a 100644
--- a/packages/SystemUI/ktfmt_includes.txt
+++ b/packages/SystemUI/ktfmt_includes.txt
@@ -240,8 +240,6 @@
 -packages/SystemUI/src/com/android/systemui/media/nearby/NearbyMediaDevicesManager.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelper.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/MediaTttFlags.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
--packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttLogger.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/ChipStateReceiver.kt
 -packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -529,6 +527,8 @@
 -packages/SystemUI/src/com/android/systemui/statusbar/tv/VpnStatusObserver.kt
 -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowModule.kt
 -packages/SystemUI/src/com/android/systemui/statusbar/window/StatusBarWindowStateController.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
+-packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
 -packages/SystemUI/src/com/android/systemui/toast/ToastDefaultAnimation.kt
 -packages/SystemUI/src/com/android/systemui/toast/ToastLogger.kt
 -packages/SystemUI/src/com/android/systemui/tv/TVSystemUICoreStartableModule.kt
@@ -677,7 +677,6 @@
 -packages/SystemUI/tests/src/com/android/systemui/media/muteawait/MediaMuteAwaitConnectionManagerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/nearby/NearbyMediaDevicesManagerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/MediaTttCommandLineHelperTest.kt
--packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttLoggerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -834,6 +833,7 @@
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/VariableDateViewControllerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/WalletControllerImplTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/statusbar/window/StatusBarWindowStateControllerTest.kt
+-packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/unfold/FoldStateLoggingProviderTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldLatencyTrackerTest.kt
 -packages/SystemUI/tests/src/com/android/systemui/unfold/UnfoldTransitionWallpaperControllerTest.kt
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
new file mode 100644
index 0000000..57b3acd
--- /dev/null
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_bouncer_message_area.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+  ~ Copyright (C) 2022 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
+  -->
+<merge xmlns:android="http://schemas.android.com/apk/res/android">
+    <com.android.keyguard.BouncerKeyguardMessageArea
+        android:id="@+id/bouncer_message_area"
+        style="@style/Keyguard.TextView"
+        android:layout_width="match_parent"
+        android:layout_height="wrap_content"
+        android:layout_marginTop="@dimen/keyguard_lock_padding"
+        android:ellipsize="marquee"
+        android:focusable="true"
+        android:gravity="center"
+        android:singleLine="true" />
+</merge>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
index e77e084..5486adb 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_password_view.xml
@@ -28,6 +28,7 @@
     android:layout_gravity="center_horizontal|bottom"
     android:gravity="bottom"
     >
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
     <Space
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
index 231ead8..2b7bdc2 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pattern_view.xml
@@ -31,6 +31,7 @@
     android:layout_gravity="center_horizontal|bottom"
     android:clipChildren="false"
     android:clipToPadding="false">
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
     <androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/pattern_container"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
index 712f657..64ece47 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_pin_view.xml
@@ -17,23 +17,25 @@
 */
 -->
 
-<com.android.keyguard.KeyguardPINView
-        xmlns:android="http://schemas.android.com/apk/res/android"
-        xmlns:androidprv="http://schemas.android.com/apk/res-auto"
-        xmlns:tools="http://schemas.android.com/tools"
-        android:id="@+id/keyguard_pin_view"
-        android:layout_width="match_parent"
-        android:layout_height="match_parent"
-        androidprv:layout_maxWidth="@dimen/keyguard_security_width"
-        android:layout_gravity="center_horizontal|bottom"
-        android:orientation="vertical"
-        >
+<com.android.keyguard.KeyguardPINView xmlns:android="http://schemas.android.com/apk/res/android"
+    xmlns:androidprv="http://schemas.android.com/apk/res-auto"
+    android:id="@+id/keyguard_pin_view"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:layout_gravity="center_horizontal|bottom"
+    android:clipChildren="false"
+    android:clipToPadding="false"
+    android:orientation="vertical"
+    androidprv:layout_maxWidth="@dimen/keyguard_security_width">
+<include layout="@layout/keyguard_bouncer_message_area"/>
 
-    <androidx.constraintlayout.widget.ConstraintLayout
+<androidx.constraintlayout.widget.ConstraintLayout
         android:id="@+id/pin_container"
         android:layout_width="match_parent"
         android:layout_height="0dp"
         android:layout_marginBottom="8dp"
+        android:clipChildren="false"
+        android:clipToPadding="false"
         android:layout_weight="1"
         android:layoutDirection="ltr"
         android:orientation="vertical">
@@ -79,6 +81,8 @@
             android:layout_width="0dp"
             android:layout_height="0dp"
             android:orientation="horizontal"
+            android:clipChildren="false"
+            android:clipToPadding="false"
 
             androidprv:constraint_referenced_ids="key1,key2,key3,key4,key5,key6,key7,key8,key9,delete_button,key0,key_enter"
 
@@ -186,8 +190,6 @@
 
     </androidx.constraintlayout.widget.ConstraintLayout>
 
-
-
     <include layout="@layout/keyguard_eca"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
index dae2e56..f2fe520 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_pin_view.xml
@@ -26,20 +26,17 @@
         android:layout_height="match_parent"
         androidprv:layout_maxWidth="@dimen/keyguard_security_width"
         android:layout_gravity="center_horizontal|bottom">
-
-  <Space
-      android:layout_width="match_parent"
-      android:layout_height="0dp"
-      android:layout_weight="1"
-      />
-
+    <include layout="@layout/keyguard_bouncer_message_area" />
+    <Space
+          android:layout_width="match_parent"
+          android:layout_height="0dp"
+          android:layout_weight="1" />
     <ImageView
             android:id="@+id/keyguard_sim"
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
             android:tint="@color/background_protected"
             android:src="@drawable/ic_lockscreen_sim"/>
-
     <LinearLayout
             android:layout_width="match_parent"
             android:layout_height="wrap_content"
@@ -52,14 +49,12 @@
              android:layout_width="wrap_content"
              android:layout_height="wrap_content"
              android:layout_marginTop="@dimen/eca_overlap" />
-
         <RelativeLayout
                 android:id="@+id/row0"
                 android:layout_width="match_parent"
                 android:layout_height="wrap_content"
                 android:paddingBottom="4dp"
                 >
-
             <com.android.keyguard.PasswordTextView
                 android:id="@+id/simPinEntry"
                 style="@style/Widget.TextView.Password"
@@ -195,7 +190,6 @@
                     />
         </LinearLayout>
     </LinearLayout>
-
     <include layout="@layout/keyguard_eca"
              android:id="@+id/keyguard_selector_fade_container"
              android:layout_width="match_parent"
@@ -205,5 +199,4 @@
              android:layout_marginTop="@dimen/keyguard_eca_top_margin"
              android:layout_marginBottom="2dp"
              android:gravity="center_horizontal"/>
-
 </com.android.keyguard.KeyguardSimPinView>
diff --git a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
index 74f7820..a21ec29 100644
--- a/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
+++ b/packages/SystemUI/res-keyguard/layout/keyguard_sim_puk_view.xml
@@ -27,12 +27,12 @@
         android:layout_height="match_parent"
         androidprv:layout_maxWidth="@dimen/keyguard_security_width"
         android:layout_gravity="center_horizontal|bottom">
+    <include layout="@layout/keyguard_bouncer_message_area"/>
 
-  <Space
-      android:layout_width="match_parent"
-      android:layout_height="0dp"
-      android:layout_weight="1"
-      />
+    <Space
+        android:layout_width="match_parent"
+        android:layout_height="0dp"
+        android:layout_weight="1" />
 
     <ImageView
             android:id="@+id/keyguard_sim"
diff --git a/packages/SystemUI/res-keyguard/values/styles.xml b/packages/SystemUI/res-keyguard/values/styles.xml
index 625ffd3..a1d1266 100644
--- a/packages/SystemUI/res-keyguard/values/styles.xml
+++ b/packages/SystemUI/res-keyguard/values/styles.xml
@@ -50,7 +50,7 @@
         <item name="android:background">@null</item>
         <item name="android:textSize">32sp</item>
         <item name="android:textColor">?android:attr/textColorPrimary</item>
-        <item name="android:fontFamily">@*android:string/config_headlineFontFamily</item>
+        <item name="android:fontFamily">@*android:string/config_bodyFontFamily</item>
         <item name="android:paddingBottom">-16dp</item>
     </style>
     <style name="Widget.TextView.Password" parent="@android:style/Widget.TextView">
diff --git a/packages/SystemUI/res/drawable/media_seekbar_thumb.xml b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
new file mode 100644
index 0000000..5eb2bfd
--- /dev/null
+++ b/packages/SystemUI/res/drawable/media_seekbar_thumb.xml
@@ -0,0 +1,50 @@
+<!--
+  ~ Copyright (C) 2022 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.
+  -->
+
+<animated-vector xmlns:android="http://schemas.android.com/apk/res/android"
+                 xmlns:aapt="http://schemas.android.com/aapt">
+    <aapt:attr name="android:drawable">
+        <vector android:height="16dp"
+                android:width="4dp"
+                android:viewportHeight="16"
+                android:viewportWidth="4">
+            <group android:name="_R_G">
+                <group android:name="_R_G_L_0_G"
+                       android:translateX="2"
+                       android:translateY="8">
+                    <path android:name="_R_G_L_0_G_D_0_P_0"
+                          android:fillColor="#ffffff"
+                          android:fillAlpha="1"
+                          android:fillType="nonZero"
+                          android:pathData=" M2 -6 C2,-6 2,6 2,6 C2,7.1 1.1,8 0,8 C0,8 0,8 0,8 C-1.1,8 -2,7.1 -2,6 C-2,6 -2,-6 -2,-6 C-2,-7.1 -1.1,-8 0,-8 C0,-8 0,-8 0,-8 C1.1,-8 2,-7.1 2,-6c "/>
+                </group>
+            </group>
+            <group android:name="time_group"/>
+        </vector>
+    </aapt:attr>
+    <target android:name="time_group">
+        <aapt:attr name="android:animation">
+            <set android:ordering="together">
+                <objectAnimator android:propertyName="translateX"
+                                android:duration="1017"
+                                android:startOffset="0"
+                                android:valueFrom="0"
+                                android:valueTo="1"
+                                android:valueType="floatType"/>
+            </set>
+        </aapt:attr>
+    </target>
+</animated-vector>
diff --git a/packages/SystemUI/res/layout/auth_biometric_contents.xml b/packages/SystemUI/res/layout/auth_biometric_contents.xml
index d633803..be76405 100644
--- a/packages/SystemUI/res/layout/auth_biometric_contents.xml
+++ b/packages/SystemUI/res/layout/auth_biometric_contents.xml
@@ -51,7 +51,7 @@
         android:id="@+id/biometric_icon_frame"
         android:layout_width="wrap_content"
         android:layout_height="wrap_content"
-        android:layout_gravity="center_horizontal">
+        android:layout_gravity="center">
 
         <com.airbnb.lottie.LottieAnimationView
             android:id="@+id/biometric_icon"
@@ -61,6 +61,13 @@
             android:contentDescription="@null"
             android:scaleType="fitXY" />
 
+        <com.airbnb.lottie.LottieAnimationView
+            android:id="@+id/biometric_icon_overlay"
+            android:layout_width="wrap_content"
+            android:layout_height="wrap_content"
+            android:layout_gravity="center"
+            android:contentDescription="@null"
+            android:scaleType="fitXY" />
     </FrameLayout>
 
     <!-- For sensors such as UDFPS, this view is used during custom measurement/layout to add extra
diff --git a/packages/SystemUI/res/layout/keyguard_bottom_area.xml b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
index 0ca19d9..8df8c49 100644
--- a/packages/SystemUI/res/layout/keyguard_bottom_area.xml
+++ b/packages/SystemUI/res/layout/keyguard_bottom_area.xml
@@ -83,48 +83,6 @@
         android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
         android:visibility="gone" />
 
-    <ImageView
-        android:id="@+id/wallet_button"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|end"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_wallet_lockscreen"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
-        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-        android:contentDescription="@string/accessibility_wallet_button"
-        android:visibility="gone" />
-
-    <ImageView
-        android:id="@+id/qr_code_scanner_button"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|end"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/ic_qr_code_scanner"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:layout_marginEnd="@dimen/keyguard_affordance_horizontal_offset"
-        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-        android:contentDescription="@string/accessibility_qr_code_scanner_button"
-        android:visibility="gone" />
-
-    <ImageView
-        android:id="@+id/controls_button"
-        android:layout_height="@dimen/keyguard_affordance_fixed_height"
-        android:layout_width="@dimen/keyguard_affordance_fixed_width"
-        android:layout_gravity="bottom|start"
-        android:scaleType="center"
-        android:tint="?android:attr/textColorPrimary"
-        android:src="@drawable/controls_icon"
-        android:background="@drawable/keyguard_bottom_affordance_bg"
-        android:layout_marginStart="@dimen/keyguard_affordance_horizontal_offset"
-        android:layout_marginBottom="@dimen/keyguard_affordance_vertical_offset"
-        android:contentDescription="@string/quick_controls_title"
-        android:visibility="gone" />
-
     <FrameLayout
         android:id="@+id/overlay_container"
         android:layout_width="match_parent"
diff --git a/packages/SystemUI/res/layout/super_notification_shade.xml b/packages/SystemUI/res/layout/super_notification_shade.xml
index 86f8ce2..0c57b934 100644
--- a/packages/SystemUI/res/layout/super_notification_shade.xml
+++ b/packages/SystemUI/res/layout/super_notification_shade.xml
@@ -88,7 +88,7 @@
         android:layout_marginTop="@dimen/status_bar_height"
         android:layout_gravity="top|center_horizontal"
         android:gravity="center_horizontal">
-        <com.android.keyguard.KeyguardMessageArea
+        <com.android.keyguard.AuthKeyguardMessageArea
             android:id="@+id/keyguard_message_area"
             style="@style/Keyguard.TextView"
             android:layout_width="wrap_content"
diff --git a/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json b/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json
new file mode 100644
index 0000000..3d33b2a
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_fingerprint_to_error_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"BiometricPrompt_Symbol_Fingerprint_To_Error_Landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_landscape_base.json b/packages/SystemUI/res/raw/biometricprompt_landscape_base.json
new file mode 100644
index 0000000..3781eee
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_landscape_base.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_landscape_base","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json
new file mode 100644
index 0000000..4950666
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_portrait_base_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"biometricprompt_landscape_base","fr":60,"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":3,"nm":"Null_Circle","parent":1,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle mask 3","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":"Finger","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-60,"s":[55]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":0,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":110,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":140,"s":[10]},{"t":170,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-60,"s":[92.146,-65.896,0],"to":[1.361,6.667,0],"ti":[-1.361,-6.667,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.167,"y":0.167},"t":0,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":0.2},"o":{"x":0.7,"y":0.7},"t":110,"s":[100.313,-25.896,0],"to":[0,0,0],"ti":[0,0,0]},{"t":170,"s":[100.313,-25.896,0]}],"ix":2,"l":2},"a":{"a":0,"k":[160.315,58.684,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-11.013,2.518],[5.251,5.023],[8.982,-2.829],[-0.264,-5.587]],"o":[[12.768,-2.854],[-14.961,2.071],[-6.004,1.89],[8.052,1.403]],"v":[[5.115,7.499],[19.814,-10.087],[-16.489,-3.588],[-24.801,8.684]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[34.67,28.053],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[22.231,-7],[-27.395,-1.197],[-26.792,4.092],[14.179,15.736]],"o":[[-17.931,5.646],[56.062,2.45],[-1.765,-22.396],[-51.819,17.744]],"v":[[-62.102,-8.314],[-39.958,30.079],[80.033,25.905],[54.879,-32.529]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[80.283,32.779],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":"circle mask 7","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":7,"ty":4,"nm":".grey600","cl":"grey600","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":"circle mask","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":".grey800","cl":"grey800","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"circle mask 6","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":"circle mask 2","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":".blue400","cl":"blue400","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":"circle mask 4","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":1,"nm":".grey900","cl":"grey900","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":"circle mask 5","parent":2,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":1,"nm":".black","cl":"black","parent":2,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".grey800","cl":"grey800","parent":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":".grey900","cl":"grey900","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[0,18.167,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[0,10.667,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":4,"nm":"Shape Layer 4","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":".grey900","cl":"grey900","parent":1,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":4,"nm":"device frame mask","parent":24,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,1.167,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".blue400","cl":"blue400","parent":18,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-115.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-199,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-159,"s":[100.25,-105.667,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[100.25,-100.167,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-0.75,-14,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":3,"nm":"device frame mask 5","parent":18,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-165,"op":6.00000000000001,"st":-271,"bm":0},{"ddd":0,"ind":28,"ty":4,"nm":"device frame mask 9","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":29,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-145,"s":[50]},{"t":-75,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-165,"s":[0,0]},{"t":-75,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":73,"s":[50]},{"t":113,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-181,"op":-62,"st":-181,"bm":0},{"ddd":0,"ind":30,"ty":4,"nm":"device frame mask 8","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":31,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-165,"s":[50]},{"t":-95,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-195,"s":[0,0]},{"t":-105,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":43,"s":[50]},{"t":83,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-211,"op":-92,"st":-211,"bm":0},{"ddd":0,"ind":32,"ty":4,"nm":"device frame mask 7","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":33,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-195,"s":[50]},{"t":-125,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-225,"s":[0,0]},{"t":-135,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":13,"s":[50]},{"t":53,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-241,"op":-122,"st":-241,"bm":0},{"ddd":0,"ind":34,"ty":4,"nm":"device frame mask 6","parent":1,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-29.25,-0.917,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0},{"ddd":0,"ind":35,"ty":4,"nm":".blue400","cl":"blue400","parent":23,"tt":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":-225,"s":[50]},{"t":-155,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-255,"s":[0,0]},{"t":-165,"s":[94,94]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":-17,"s":[50]},{"t":23,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.4,0.61568627451,0.964705882353,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-271,"op":-152,"st":-271,"bm":0}]}],"layers":[{"ddd":0,"ind":6,"ty":0,"nm":"biometricprompt_landscape_base","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[170,170,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"w":340,"h":340,"ip":0,"op":900,"st":0,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json b/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json
new file mode 100644
index 0000000..b161609
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_portrait_base_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_portrait_base_topleft","ddd":0,"assets":[],"layers":[{"ddd":0,"ind":6,"ty":3,"nm":"Null 16","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null_Circle","parent":6,"sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[70.333,-88.75,0],"to":[-11.722,17.639,0],"ti":[11.722,-17.639,0]},{"t":-48,"s":[0,17.083,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":8,"ty":4,"nm":".grey905","cl":"grey905","parent":7,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":9,"ty":4,"nm":"circle mask 3","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":10,"ty":4,"nm":"Finger_Flipped","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[-24.98,-35.709,0],"ix":2,"l":2},"a":{"a":0,"k":[31.791,75.23,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[5.03,5.25],[-2.83,8.98],[-5.59,-0.26],[2.52,-11.02]],"o":[[-2.85,12.77],[2.07,-14.96],[1.9,-6],[1.4,8.05],[0,0]],"v":[[7.5,4.99],[-10.09,19.69],[-3.59,-16.61],[8.69,-24.92],[7.5,5]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.760784373564,0.478431402468,0.400000029919,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[27.8,24.94],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[-7.01,22.23],[-1.2,-27.39],[4.09,-26.79],[15.73,14.18]],"o":[[5.64,-17.93],[2.45,56.06],[-22.4,-1.77],[17.73,-51.82]],"v":[[-7.57,-66.9],[30.82,-44.76],[26.65,75.23],[-31.78,50.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.678431372549,0.403921598547,0.305882352941,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[31.79,75.23],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":11,"ty":4,"nm":"circle mask 7","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":12,"ty":4,"nm":".grey600","cl":"grey600","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.25,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.501960784314,0.525490196078,0.545098039216,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":36.9,"ix":2},"o":{"a":0,"k":114.2,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":13,"ty":4,"nm":"circle mask","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":14,"ty":4,"nm":".grey904","cl":"grey904","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[-0.5,0,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[114.218,-17.096],[-112.938,-17.096]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":10,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":0,"k":100,"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":15,"ty":4,"nm":"circle mask 6","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":16,"ty":4,"nm":".grey903","cl":"grey903","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":377,"s":[-180]},{"t":417,"s":[0]}],"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":377,"s":[-1.137,1.771,0],"to":[0.375,0,0],"ti":[-0.375,0,0]},{"t":417,"s":[1.113,1.771,0]}],"ix":2,"l":2},"a":{"a":0,"k":[6.238,5.063,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":77,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":107,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":137,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":167,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.333,"y":0},"t":197,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,-4.637],[-10.23,-3.195],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]},{"i":{"x":0.833,"y":1},"o":{"x":0.7,"y":0},"t":232,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":562,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-8.788,0.393],[-10.23,1.835],[-2.196,9.843],[5.988,1.659],[4.545,0.217],[-2.196,6.948]],"c":false}]},{"t":602,"s":[{"i":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]],"v":[[-4.546,-0.421],[-5.988,1.021],[-2.196,4.813],[5.988,-3.371],[4.545,-4.813],[-2.196,1.918]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[6.238,5.063],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":17,"ty":4,"nm":"circle mask 2","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":18,"ty":4,"nm":".blue400","cl":"blue400","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,8.308,0],"ix":2,"l":2},"a":{"a":0,"k":[41.706,20.979,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[18.645,0],[0,18.645]],"o":[[0,18.645],[-18.644,0],[0,0]],"v":[[33.76,-16.88],[-0.001,16.88],[-33.76,-16.88]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,17.13],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":4,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[22.896,0],[0,22.896]],"o":[[0,22.896],[-22.896,0],[0,0]],"v":[[41.457,-20.729],[-0.001,20.729],[-41.457,-20.729]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[41.706,20.979],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 2","np":4,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":19,"ty":4,"nm":"circle mask 4","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":20,"ty":1,"nm":".grey902","cl":"grey902","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,66,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[52,52,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#202124","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":21,"ty":4,"nm":"circle mask 5","parent":7,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,0.333,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"d":1,"ty":"el","s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-108,"s":[0,0]},{"t":-48,"s":[202,202]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"nm":"Ellipse Path 1","mn":"ADBE Vector Shape - Ellipse","hd":false},{"ty":"st","c":{"a":0,"k":[0.250980392157,0.282352941176,0.294117647059,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"fl","c":{"a":0,"k":[0.078246000701,0.610494037703,0.787910970052,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,-17.333],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Ellipse 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":22,"ty":1,"nm":".black","cl":"black","parent":7,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[0,-17.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[72,72,100],"ix":6,"l":2}},"ao":0,"sw":412,"sh":300,"sc":"#000000","ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":23,"ty":4,"nm":".grey800","cl":"grey800","parent":6,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-108,"s":[-192.25,99.933,0],"to":[5,3.333,0],"ti":[-5,-3.333,0]},{"t":-48,"s":[-162.25,119.933,0]}],"ix":2,"l":2},"a":{"a":0,"k":[-163,100.85,0],"ix":1,"l":2},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2,0.833],"y":[1,1,1]},"o":{"x":[0.7,0.7,0.167],"y":[0,0,0]},"t":-108,"s":[100,100,100]},{"t":-48,"s":[59,59,100]}],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":0,"k":[326,201.699],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":0,"k":8,"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"st","c":{"a":0,"k":[0.235294117647,0.250980392157,0.262745098039,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":2,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":24,"ty":4,"nm":".grey901","cl":"grey901","parent":23,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[100.25,-87.156,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[100.25,-94.656,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.667,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-171,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-141,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.512],[0,0.512],[3,3.512]],"c":false}]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":-111,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]},{"t":-81,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,3.967],[0,0.967],[3,3.967]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-199,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":25,"ty":4,"nm":"Shape Layer 4","parent":6,"td":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-116.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.7,"y":0},"t":-199,"s":[71,-101.083,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.833,"y":0.833},"o":{"x":0.167,"y":0.167},"t":365,"s":[71,-101.083,0],"to":[0,0,0],"ti":[16.833,-14.361,0]},{"t":405,"s":[-30,-14.917,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ty":"rc","d":1,"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-239,"s":[29,29]},{"i":{"x":[0.833,0.833],"y":[1,0.833]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":-199,"s":[29,38]},{"i":{"x":[0.833,0.833],"y":[0.833,0.833]},"o":{"x":[0.167,0.167],"y":[0.167,0.167]},"t":365,"s":[29,36]},{"t":405,"s":[83,83]}],"ix":2},"p":{"a":0,"k":[0,0],"ix":3},"r":{"a":1,"k":[{"i":{"x":[0.833],"y":[0.833]},"o":{"x":[0.167],"y":[0.167]},"t":365,"s":[50]},{"t":405,"s":[50]}],"ix":4},"nm":"Rectangle Path 1","mn":"ADBE Vector Shape - Rect","hd":false},{"ty":"fl","c":{"a":0,"k":[0.400000029919,0.61568627451,0.964705942191,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Rectangle 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":645,"st":-255,"bm":0},{"ddd":0,"ind":26,"ty":4,"nm":".grey900","cl":"grey900","parent":6,"tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[71,-82.917,0],"to":[0,-1.25,0],"ti":[0,1.25,0]},{"t":-199,"s":[71,-90.417,0]}],"ix":2,"l":2},"a":{"a":0,"k":[5.5,4,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":-239,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-0.07,1.5],[0,-1.5],[-0.047,1.5]],"c":false}]},{"t":-199,"s":[{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-3,1.5],[0,-1.5],[3,1.5]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[0.125490196078,0.129411764706,0.141176470588,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":1,"ix":5},"lc":1,"lj":1,"ml":10,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[5.5,4],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 1","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false}],"ip":-255,"op":-199,"st":-255,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json
new file mode 100644
index 0000000..034ac87
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json
new file mode 100644
index 0000000..e5cc565e
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json
new file mode 100644
index 0000000..b082265
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_fingerprint_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_fingerprint_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 12","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short_For_ErrorToFingerprint","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json
new file mode 100644
index 0000000..befe3bb
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json
new file mode 100644
index 0000000..d75b335
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 13","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json
new file mode 100644
index 0000000..e6b2db1
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_error_to_success_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_error_to_success_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":112,"s":[0]},{"t":122,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":112,"op":1012,"st":112,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":118,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":257,"s":[100]},{"t":277,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":108,"op":1280,"st":108,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 13","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_ErrorToSuccess","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":792,"st":-108,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json
new file mode 100644
index 0000000..0da143c
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_error_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json
new file mode 100644
index 0000000..15457c7
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_error_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_error_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 14","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":830,"st":-70,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json
new file mode 100644
index 0000000..f39894b
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_landscape.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_landscape","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[170,77.667,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json
new file mode 100644
index 0000000..6d4f4e2
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_bottomright.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_portrait_bottomright","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 15","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json
new file mode 100644
index 0000000..b7bb0d5
--- /dev/null
+++ b/packages/SystemUI/res/raw/biometricprompt_symbol_fingerprint_to_success_portrait_topleft.json
@@ -0,0 +1 @@
+{"v":"5.9.0","fr":60,"ip":0,"op":21,"w":340,"h":340,"nm":"biometricprompt_symbol_fingerprint_to_success_portrait_topleft","ddd":0,"assets":[{"id":"comp_0","nm":"Fingerprint_Animation_ForConfirm_Short","fr":60,"layers":[{"ddd":0,"ind":1,"ty":4,"nm":"circle fill 5","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":2,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0],[0,0]],"o":[[0,0],[0,0],[0,0]],"v":[[-52.056,-2.445],[-17.306,32.25],[52.194,-37.194]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"tm","s":{"a":0,"k":0,"ix":1},"e":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"t":249,"s":[100]}],"ix":2},"o":{"a":0,"k":0,"ix":3},"m":1,"ix":2,"nm":"Trim Paths 1","mn":"ADBE Vector Filter - Trim","hd":false}],"ip":239,"op":1139,"st":239,"bm":0},{"ddd":0,"ind":3,"ty":4,"nm":".green400","cl":"green400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":239,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":249,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":388,"s":[100]},{"t":408,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.450980392157,0.709803921569,0.470588235294,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":239,"op":1411,"st":239,"bm":0},{"ddd":0,"ind":4,"ty":4,"nm":"circle fill 3","td":1,"sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":5,"ty":4,"nm":".white","cl":"white","tt":1,"sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":1,"k":[{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":80,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.7,"y":0},"t":90,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"i":{"x":0.2,"y":1},"o":{"x":0.8,"y":0},"t":108,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,-49.945],[-0.056,14.056]],"c":false}]},{"t":118,"s":[{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.111,14.055],[-0.056,14.056]],"c":false}]}],"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0,0],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 1","np":3,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,0],[0,0]],"o":[[0,0],[0,0]],"v":[[-0.056,35.389],[-0.111,50.111]],"c":false},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"st","c":{"a":0,"k":[1,1,1,1],"ix":3},"o":{"a":0,"k":100,"ix":4},"w":{"a":0,"k":14,"ix":5},"lc":1,"lj":1,"ml":4,"bm":0,"nm":"Stroke 1","mn":"ADBE Vector Graphic - Stroke","hd":false},{"ty":"tr","p":{"a":0,"k":[0.049,42.698],"ix":2},"a":{"a":0,"k":[0.049,42.698],"ix":1},"s":{"a":1,"k":[{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":80,"s":[0,0]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.7,0.7],"y":[0,0]},"t":90,"s":[100,100]},{"i":{"x":[0.2,0.2],"y":[1,1]},"o":{"x":[0.8,0.8],"y":[0,0]},"t":108,"s":[100,100]},{"t":118,"s":[0,0]}],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Shape 2","np":3,"cix":2,"bm":0,"ix":2,"mn":"ADBE Vector Group","hd":false}],"ip":80,"op":980,"st":80,"bm":0},{"ddd":0,"ind":6,"ty":4,"nm":".red400","cl":"red400","sr":1,"ks":{"o":{"a":1,"k":[{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":80,"s":[0]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.167],"y":[0]},"t":90,"s":[100]},{"i":{"x":[0.2],"y":[1]},"o":{"x":[0.7],"y":[0]},"t":108,"s":[100]},{"t":118,"s":[0]}],"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":0,"k":[206,150,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"shapes":[{"ty":"gr","it":[{"ind":0,"ty":"sh","ix":1,"ks":{"a":0,"k":{"i":[[0,62.45],[-62.45,0],[0,-62.45],[62.45,0]],"o":[[0,-62.45],[62.45,0],[0,62.45],[-62.45,0]],"v":[[-113.08,0],[0,-113.08],[113.08,0],[0,113.08]],"c":true},"ix":2},"nm":"Path 1","mn":"ADBE Vector Shape - Group","hd":false},{"ty":"tr","p":{"a":0,"k":[206,150],"ix":2},"a":{"a":0,"k":[0,0],"ix":1},"s":{"a":0,"k":[100,100],"ix":3},"r":{"a":0,"k":0,"ix":6},"o":{"a":0,"k":100,"ix":7},"sk":{"a":0,"k":0,"ix":4},"sa":{"a":0,"k":0,"ix":5},"nm":"Transform"}],"nm":"Group 4","np":2,"cix":2,"bm":0,"ix":1,"mn":"ADBE Vector Group","hd":false},{"ty":"fl","c":{"a":0,"k":[0.933333393172,0.403921598547,0.360784313725,1],"ix":4},"o":{"a":0,"k":100,"ix":5},"r":1,"bm":0,"nm":"Fill 1","mn":"ADBE Vector Graphic - Fill","hd":false}],"ip":80,"op":1252,"st":80,"bm":0},{"ddd":0,"ind":7,"ty":3,"nm":"Null 1","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":0,"ix":10},"p":{"a":1,"k":[{"i":{"x":0.833,"y":0.833},"o":{"x":0.333,"y":0.333},"t":85,"s":[209.333,136.333,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":440,"s":[209.333,136.333,0],"to":[1.944,2.278,0],"ti":[3.056,-2.278,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":450,"s":[221,150,0],"to":[-3.056,2.278,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":460,"s":[191,150,0],"to":[0,0,0],"ti":[0,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":470,"s":[221,150,0],"to":[0,0,0],"ti":[2.5,0,0]},{"i":{"x":0.667,"y":1},"o":{"x":0.333,"y":0},"t":480,"s":[191,150,0],"to":[-2.5,0,0],"ti":[-2.5,0,0]},{"t":490,"s":[206,150,0]}],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[132,132,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0}]}],"layers":[{"ddd":0,"ind":1,"ty":3,"nm":"Null 15","sr":1,"ks":{"o":{"a":0,"k":0,"ix":11},"r":{"a":0,"k":-90,"ix":10},"p":{"a":0,"k":[170,170,0],"ix":2,"l":2},"a":{"a":0,"k":[0,0,0],"ix":1,"l":2},"s":{"a":0,"k":[100,100,100],"ix":6,"l":2}},"ao":0,"ip":0,"op":900,"st":0,"bm":0},{"ddd":0,"ind":2,"ty":0,"nm":"Fingerprint_Animation_ForConfirm_Short","parent":1,"refId":"comp_0","sr":1,"ks":{"o":{"a":0,"k":100,"ix":11},"r":{"a":0,"k":90,"ix":10},"p":{"a":0,"k":[0,-92.333,0],"ix":2,"l":2},"a":{"a":0,"k":[206,150,0],"ix":1,"l":2},"s":{"a":0,"k":[30,30,100],"ix":6,"l":2}},"ao":0,"w":412,"h":300,"ip":0,"op":661,"st":-239,"bm":0}],"markers":[{"tm":255,"cm":"","dr":0},{"tm":364,"cm":"","dr":0},{"tm":482,"cm":"","dr":0},{"tm":600,"cm":"","dr":0}]}
\ No newline at end of file
diff --git a/packages/SystemUI/res/values-sw600dp/config.xml b/packages/SystemUI/res/values-sw600dp/config.xml
index c0071cb..80628f9 100644
--- a/packages/SystemUI/res/values-sw600dp/config.xml
+++ b/packages/SystemUI/res/values-sw600dp/config.xml
@@ -35,9 +35,6 @@
     <!-- How many lines to show in the security footer -->
     <integer name="qs_security_footer_maxLines">1</integer>
 
-    <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
-    <bool name="allow_force_nav_bar_handle_opaque">false</bool>
-
     <bool name="config_use_large_screen_shade_header">true</bool>
 
     <!-- Whether to show the side fps hint while on bouncer -->
diff --git a/packages/SystemUI/res/values-sw720dp-port/dimens.xml b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
index a0bf072..3d8da8a 100644
--- a/packages/SystemUI/res/values-sw720dp-port/dimens.xml
+++ b/packages/SystemUI/res/values-sw720dp-port/dimens.xml
@@ -23,7 +23,7 @@
     <dimen name="status_view_margin_horizontal">124dp</dimen>
     <dimen name="keyguard_clock_top_margin">80dp</dimen>
     <dimen name="keyguard_status_view_bottom_margin">80dp</dimen>
-    <dimen name="bouncer_user_switcher_y_trans">90dp</dimen>
+    <dimen name="bouncer_user_switcher_y_trans">200dp</dimen>
 
     <dimen name="large_screen_shade_header_left_padding">24dp</dimen>
     <dimen name="qqs_layout_padding_bottom">40dp</dimen>
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index ec22c60..a802723 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -587,9 +587,6 @@
          when the double-press power gesture is used. Ignored if empty. -->
     <string translatable="false" name="config_cameraGesturePackage"></string>
 
-    <!-- Determines whether to allow the nav bar handle to be forced to be opaque. -->
-    <bool name="allow_force_nav_bar_handle_opaque">true</bool>
-
     <!-- Whether a transition of ACTIVITY_TYPE_DREAM to the home app should play a home sound
          effect -->
     <bool name="config_playHomeSoundAfterDream">false</bool>
@@ -617,8 +614,9 @@
     <!-- Which face help messages to surface when fingerprint is also enrolled.
          Message ids correspond with the acquired ids in BiometricFaceConstants -->
     <integer-array name="config_face_help_msgs_when_fingerprint_enrolled">
-        <item>25</item>
-        <item>26</item>
+        <item>3</item> <!-- TOO_DARK -->
+        <item>25</item> <!-- DARK_GLASSES -->
+        <item>26</item> <!-- MOUTH_COVERING_DETECTED -->
     </integer-array>
 
     <!-- Whether the communal service should be enabled -->
@@ -629,11 +627,15 @@
 
     <!-- This value is used when calculating whether the device is in ambient light mode. It is
         light mode when the light sensor sample value exceeds above this value. -->
-    <integer name="config_ambientLightModeThreshold">10</integer>
+    <item name="config_ambientLightModeThreshold" translatable="false" format="float" type="dimen">
+        0.8
+    </item>
 
     <!-- This value is used when calculating whether the device is in ambient dark mode. It is
         dark mode when the light sensor sample value drops below this value. -->
-    <integer name="config_ambientDarkModeThreshold">5</integer>
+    <item name="config_ambientDarkModeThreshold" translatable="false" format="float" type="dimen">
+        0.4
+    </item>
 
     <!-- This value is used when calculating whether the device is in ambient light mode. Each
         sample contains light sensor events from this span of time duration. -->
diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml
index a36a518..ac3eb7e 100644
--- a/packages/SystemUI/res/values/styles.xml
+++ b/packages/SystemUI/res/values/styles.xml
@@ -573,6 +573,7 @@
     </style>
 
     <style name="MediaPlayer.ProgressBar" parent="@android:style/Widget.ProgressBar.Horizontal">
+        <item name="android:thumb">@drawable/media_seekbar_thumb</item>
         <item name="android:thumbTint">?android:attr/textColorPrimary</item>
         <item name="android:progressDrawable">@drawable/media_squiggly_progress</item>
         <item name="android:progressTint">?android:attr/textColorPrimary</item>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
index a030bf6..e77c650 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/recents/ISystemUiProxy.aidl
@@ -42,13 +42,6 @@
     void onOverviewShown(boolean fromHome) = 6;
 
     /**
-     * Control the {@param alpha} of the option nav bar button (back-button in 2 button mode
-     * and home handle & background in gestural mode).  The {@param animate} is currently only
-     * supported for 2 button mode.
-     */
-    void setNavBarButtonAlpha(float alpha, boolean animate) = 19;
-
-    /**
      * Proxies motion events from the homescreen UI to the status bar. Only called when
      * swipe down is detected on WORKSPACE. The sender guarantees the following order of events on
      * the tracking pointer.
diff --git a/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt
new file mode 100644
index 0000000..82ce1ca
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/AuthKeyguardMessageArea.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright (C) 2022 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.keyguard
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.graphics.Color
+import android.util.AttributeSet
+
+/**
+ * Displays security messages for auth outside of the security method (pin, password, pattern), like
+ * biometric auth.
+ */
+class AuthKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
+    KeyguardMessageArea(context, attrs) {
+    override fun updateTextColor() {
+        setTextColor(ColorStateList.valueOf(Color.WHITE))
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
new file mode 100644
index 0000000..0075ddd
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/BouncerKeyguardMessageArea.kt
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2022 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.keyguard
+
+import android.content.Context
+import android.content.res.ColorStateList
+import android.content.res.TypedArray
+import android.graphics.Color
+import android.util.AttributeSet
+import com.android.settingslib.Utils
+
+/** Displays security messages for the keyguard bouncer. */
+class BouncerKeyguardMessageArea(context: Context?, attrs: AttributeSet?) :
+    KeyguardMessageArea(context, attrs) {
+    private val DEFAULT_COLOR = -1
+    private var mDefaultColorState: ColorStateList? = null
+    private var mNextMessageColorState: ColorStateList? = ColorStateList.valueOf(DEFAULT_COLOR)
+
+    override fun updateTextColor() {
+        var colorState = mDefaultColorState
+        mNextMessageColorState?.defaultColor?.let { color ->
+            if (color != DEFAULT_COLOR) {
+                colorState = mNextMessageColorState
+                mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR)
+            }
+        }
+        setTextColor(colorState)
+    }
+
+    override fun setNextMessageColor(colorState: ColorStateList?) {
+        mNextMessageColorState = colorState
+    }
+
+    override fun onThemeChanged() {
+        val array: TypedArray =
+            mContext.obtainStyledAttributes(intArrayOf(android.R.attr.textColorPrimary))
+        val newTextColors: ColorStateList = ColorStateList.valueOf(array.getColor(0, Color.RED))
+        array.recycle()
+        mDefaultColorState = newTextColors
+        super.onThemeChanged()
+    }
+
+    override fun reloadColor() {
+        mDefaultColorState = Utils.getColorAttr(context, android.R.attr.textColorPrimary)
+        super.reloadColor()
+    }
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
index b8fcb10..92ba619 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardAbsKeyInputViewController.java
@@ -50,7 +50,6 @@
     private final FalsingCollector mFalsingCollector;
     private final EmergencyButtonController mEmergencyButtonController;
     private CountDownTimer mCountdownTimer;
-    protected KeyguardMessageAreaController mMessageAreaController;
     private boolean mDismissing;
     protected AsyncTask<?, ?, ?> mPendingLockCheck;
     protected boolean mResumed;
@@ -80,14 +79,13 @@
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             LatencyTracker latencyTracker, FalsingCollector falsingCollector,
             EmergencyButtonController emergencyButtonController) {
-        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
+        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
+                messageAreaControllerFactory);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
         mFalsingCollector = falsingCollector;
         mEmergencyButtonController = emergencyButtonController;
-        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
-        mMessageAreaController = messageAreaControllerFactory.create(kma);
     }
 
     abstract void resetState();
@@ -95,7 +93,6 @@
     @Override
     public void onInit() {
         super.onInit();
-        mMessageAreaController.init();
     }
 
     @Override
@@ -134,6 +131,10 @@
 
     @Override
     public void showMessage(CharSequence message, ColorStateList colorState) {
+        if (mMessageAreaController == null) {
+            return;
+        }
+
         if (colorState != null) {
             mMessageAreaController.setNextMessageColor(colorState);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
index 87300c3..f26b905 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardInputViewController.java
@@ -17,9 +17,11 @@
 package com.android.keyguard;
 
 import android.annotation.CallSuper;
+import android.annotation.Nullable;
 import android.content.res.ColorStateList;
 import android.content.res.Resources;
 import android.telephony.TelephonyManager;
+import android.util.Log;
 import android.view.inputmethod.InputMethodManager;
 
 import com.android.internal.util.LatencyTracker;
@@ -44,7 +46,7 @@
     private final EmergencyButton mEmergencyButton;
     private final EmergencyButtonController mEmergencyButtonController;
     private boolean mPaused;
-
+    protected KeyguardMessageAreaController<BouncerKeyguardMessageArea> mMessageAreaController;
 
     // The following is used to ignore callbacks from SecurityViews that are no longer current
     // (e.g. face unlock). This avoids unwanted asynchronous events from messing with the
@@ -72,12 +74,24 @@
 
     protected KeyguardInputViewController(T view, SecurityMode securityMode,
             KeyguardSecurityCallback keyguardSecurityCallback,
-            EmergencyButtonController emergencyButtonController) {
+            EmergencyButtonController emergencyButtonController,
+            @Nullable KeyguardMessageAreaController.Factory messageAreaControllerFactory) {
         super(view);
         mSecurityMode = securityMode;
         mKeyguardSecurityCallback = keyguardSecurityCallback;
         mEmergencyButton = view == null ? null : view.findViewById(R.id.emergency_call_button);
         mEmergencyButtonController = emergencyButtonController;
+        if (messageAreaControllerFactory != null) {
+            try {
+                BouncerKeyguardMessageArea kma = view.requireViewById(R.id.bouncer_message_area);
+                mMessageAreaController = messageAreaControllerFactory.create(kma);
+                mMessageAreaController.init();
+                mMessageAreaController.setIsVisible(true);
+            } catch (IllegalArgumentException exception) {
+                Log.e("KeyguardInputViewController",
+                        "Ensure that a BouncerKeyguardMessageArea is included in the layout");
+            }
+        }
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
index 5ab2fd0..c79fc2c 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageArea.java
@@ -17,9 +17,7 @@
 package com.android.keyguard;
 
 import android.content.Context;
-import android.content.res.ColorStateList;
 import android.content.res.TypedArray;
-import android.graphics.Color;
 import android.os.Handler;
 import android.os.Looper;
 import android.os.SystemClock;
@@ -33,7 +31,6 @@
 import androidx.annotation.Nullable;
 
 import com.android.internal.policy.SystemBarUtils;
-import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
 import java.lang.ref.WeakReference;
@@ -41,7 +38,7 @@
 /***
  * Manages a number of views inside of the given layout. See below for a list of widgets.
  */
-public class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
+public abstract class KeyguardMessageArea extends TextView implements SecurityMessageDisplay {
     /** Handler token posted with accessibility announcement runnables. */
     private static final Object ANNOUNCE_TOKEN = new Object();
 
@@ -50,15 +47,11 @@
      * lift-to-type from interrupting itself.
      */
     private static final long ANNOUNCEMENT_DELAY = 250;
-    private static final int DEFAULT_COLOR = -1;
 
     private final Handler mHandler;
 
-    private ColorStateList mDefaultColorState;
     private CharSequence mMessage;
-    private ColorStateList mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
-    private boolean mBouncerShowing;
-    private boolean mAltBouncerShowing;
+    private boolean mIsVisible;
     /**
      * Container that wraps the KeyguardMessageArea - may be null if current view hierarchy doesn't
      * contain {@link R.id.keyguard_message_area_container}.
@@ -96,23 +89,11 @@
         mContainer.setLayoutParams(lp);
     }
 
-    @Override
-    public void setNextMessageColor(ColorStateList colorState) {
-        mNextMessageColorState = colorState;
-    }
-
-    void onThemeChanged() {
-        TypedArray array = mContext.obtainStyledAttributes(new int[] {
-                android.R.attr.textColorPrimary
-        });
-        ColorStateList newTextColors = ColorStateList.valueOf(array.getColor(0, Color.RED));
-        array.recycle();
-        mDefaultColorState = newTextColors;
+    protected void onThemeChanged() {
         update();
     }
 
-    void reloadColor() {
-        mDefaultColorState = Utils.getColorAttr(getContext(), android.R.attr.textColorPrimary);
+    protected void reloadColor() {
         update();
     }
 
@@ -151,17 +132,6 @@
         setMessage(message);
     }
 
-    public static KeyguardMessageArea findSecurityMessageDisplay(View v) {
-        KeyguardMessageArea messageArea = v.findViewById(R.id.keyguard_message_area);
-        if (messageArea == null) {
-            messageArea = v.getRootView().findViewById(R.id.keyguard_message_area);
-        }
-        if (messageArea == null) {
-            throw new RuntimeException("Can't find keyguard_message_area in " + v.getClass());
-        }
-        return messageArea;
-    }
-
     private void securityMessageChanged(CharSequence message) {
         mMessage = message;
         update();
@@ -177,40 +147,23 @@
 
     void update() {
         CharSequence status = mMessage;
-        setVisibility(TextUtils.isEmpty(status) || (!mBouncerShowing && !mAltBouncerShowing)
-                ? INVISIBLE : VISIBLE);
+        setVisibility(TextUtils.isEmpty(status) || (!mIsVisible) ? INVISIBLE : VISIBLE);
         setText(status);
-        ColorStateList colorState = mDefaultColorState;
-        if (mNextMessageColorState.getDefaultColor() != DEFAULT_COLOR) {
-            colorState = mNextMessageColorState;
-            mNextMessageColorState = ColorStateList.valueOf(DEFAULT_COLOR);
-        }
-        if (mAltBouncerShowing) {
-            // alt bouncer has a black scrim, so always show the text in white
-            colorState = ColorStateList.valueOf(Color.WHITE);
-        }
-        setTextColor(colorState);
+        updateTextColor();
     }
 
     /**
      * Set whether the bouncer is fully showing
      */
-    public void setBouncerShowing(boolean bouncerShowing) {
-        if (mBouncerShowing != bouncerShowing) {
-            mBouncerShowing = bouncerShowing;
+    public void setIsVisible(boolean isVisible) {
+        if (mIsVisible != isVisible) {
+            mIsVisible = isVisible;
             update();
         }
     }
 
-    /**
-     * Set whether the alt bouncer is showing
-     */
-    void setAltBouncerShowing(boolean showing) {
-        if (mAltBouncerShowing != showing) {
-            mAltBouncerShowing = showing;
-            update();
-        }
-    }
+    /** Set the text color */
+    protected abstract void updateTextColor();
 
     /**
      * Runnable used to delay accessibility announcements.
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
index 3ec8ce9..c2802f7 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardMessageAreaController.java
@@ -26,11 +26,14 @@
 
 import javax.inject.Inject;
 
-/** Controller for a {@link KeyguardMessageAreaController}. */
-public class KeyguardMessageAreaController extends ViewController<KeyguardMessageArea> {
+/**
+ * Controller for a {@link KeyguardMessageAreaController}.
+ * @param <T> A subclass of KeyguardMessageArea.
+ */
+public class KeyguardMessageAreaController<T extends KeyguardMessageArea>
+        extends ViewController<T> {
     private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     private final ConfigurationController mConfigurationController;
-    private boolean mAltBouncerShowing;
 
     private KeyguardUpdateMonitorCallback mInfoCallback = new KeyguardUpdateMonitorCallback() {
         public void onFinishedGoingToSleep(int why) {
@@ -59,7 +62,7 @@
         }
     };
 
-    private KeyguardMessageAreaController(KeyguardMessageArea view,
+    protected KeyguardMessageAreaController(T view,
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             ConfigurationController configurationController) {
         super(view);
@@ -83,17 +86,10 @@
     }
 
     /**
-     * Set whether alt bouncer is showing
+     * Indicate that view is visible and can display messages.
      */
-    public void setAltBouncerShowing(boolean showing) {
-        mView.setAltBouncerShowing(showing);
-    }
-
-    /**
-     * Set bouncer is fully showing
-     */
-    public void setBouncerShowing(boolean showing) {
-        mView.setBouncerShowing(showing);
+    public void setIsVisible(boolean isVisible) {
+        mView.setIsVisible(isVisible);
     }
 
     public void setMessage(CharSequence s) {
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
index 6844b65..20fa8f8 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPINView.java
@@ -16,23 +16,25 @@
 
 package com.android.keyguard;
 
-import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_APPEAR;
 import static com.android.internal.jank.InteractionJankMonitor.CUJ_LOCKSCREEN_PIN_DISAPPEAR;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_HALF_OPENED;
 import static com.android.systemui.statusbar.policy.DevicePostureController.DEVICE_POSTURE_UNKNOWN;
 
+import android.animation.ValueAnimator;
 import android.content.Context;
 import android.content.res.Configuration;
 import android.util.AttributeSet;
+import android.util.MathUtils;
 import android.view.View;
 import android.view.animation.AnimationUtils;
+import android.view.animation.Interpolator;
 
 import androidx.constraintlayout.widget.ConstraintLayout;
 import androidx.constraintlayout.widget.ConstraintSet;
 
-import com.android.settingslib.animation.AppearAnimationUtils;
 import com.android.settingslib.animation.DisappearAnimationUtils;
 import com.android.systemui.R;
+import com.android.systemui.animation.Interpolators;
 import com.android.systemui.statusbar.policy.DevicePostureController.DevicePostureInt;
 
 /**
@@ -40,7 +42,7 @@
  */
 public class KeyguardPINView extends KeyguardPinBasedInputView {
 
-    private final AppearAnimationUtils mAppearAnimationUtils;
+    ValueAnimator mAppearAnimator = ValueAnimator.ofFloat(0f, 1f);
     private final DisappearAnimationUtils mDisappearAnimationUtils;
     private final DisappearAnimationUtils mDisappearAnimationUtilsLocked;
     private ConstraintLayout mContainer;
@@ -54,7 +56,6 @@
 
     public KeyguardPINView(Context context, AttributeSet attrs) {
         super(context, attrs);
-        mAppearAnimationUtils = new AppearAnimationUtils(context);
         mDisappearAnimationUtils = new DisappearAnimationUtils(context,
                 125, 0.6f /* translationScale */,
                 0.45f /* delayScale */, AnimationUtils.loadInterpolator(
@@ -169,25 +170,20 @@
 
     @Override
     public void startAppearAnimation() {
-        enableClipping(false);
-        setAlpha(1f);
-        setTranslationY(mAppearAnimationUtils.getStartTranslation());
-        AppearAnimationUtils.startTranslationYAnimation(this, 0 /* delay */, 500 /* duration */,
-                0, mAppearAnimationUtils.getInterpolator(),
-                getAnimationListener(CUJ_LOCKSCREEN_PIN_APPEAR));
-        mAppearAnimationUtils.startAnimation2d(mViews,
-                new Runnable() {
-                    @Override
-                    public void run() {
-                        enableClipping(true);
-                    }
-                });
+        if (mAppearAnimator.isRunning()) {
+            mAppearAnimator.cancel();
+        }
+        mAppearAnimator.setDuration(650);
+        mAppearAnimator.addUpdateListener(animation -> animate(animation.getAnimatedFraction()));
+        mAppearAnimator.start();
     }
 
     public boolean startDisappearAnimation(boolean needsSlowUnlockTransition,
             final Runnable finishRunnable) {
+        if (mAppearAnimator.isRunning()) {
+            mAppearAnimator.cancel();
+        }
 
-        enableClipping(false);
         setTranslationY(0);
         DisappearAnimationUtils disappearAnimationUtils = needsSlowUnlockTransition
                         ? mDisappearAnimationUtilsLocked
@@ -195,7 +191,6 @@
         disappearAnimationUtils.createAnimation(
                 this, 0, 200, mDisappearYTranslation, false,
                 mDisappearAnimationUtils.getInterpolator(), () -> {
-                    enableClipping(true);
                     if (finishRunnable != null) {
                         finishRunnable.run();
                     }
@@ -204,14 +199,32 @@
         return true;
     }
 
-    private void enableClipping(boolean enable) {
-        mContainer.setClipToPadding(enable);
-        mContainer.setClipChildren(enable);
-        setClipChildren(enable);
-    }
-
     @Override
     public boolean hasOverlappingRendering() {
         return false;
     }
+
+    /** Animate subviews according to expansion or time. */
+    private void animate(float progress) {
+        for (int i = 0; i < mViews.length; i++) {
+            View[] row = mViews[i];
+            for (View view : row) {
+                if (view == null) {
+                    continue;
+                }
+
+                float scaledProgress = MathUtils.constrain(
+                        (progress - 0.075f * i) / (1f - 0.075f * mViews.length),
+                        0f,
+                        1f
+                );
+                view.setAlpha(scaledProgress);
+                Interpolator interpolator = Interpolators.STANDARD_ACCELERATE;
+                view.setTranslationY(40 - (40 * interpolator.getInterpolation(scaledProgress)));
+                if (view instanceof NumPadAnimationListener) {
+                    ((NumPadAnimationListener) view).setProgress(scaledProgress);
+                }
+            }
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
index 1862fc7..afc2590 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternView.java
@@ -71,7 +71,7 @@
      */
     private long mLastPokeTime = -UNLOCK_PATTERN_WAKE_INTERVAL_MS;
 
-    KeyguardMessageArea mSecurityMessageDisplay;
+    BouncerKeyguardMessageArea mSecurityMessageDisplay;
     private View mEcaView;
     private ConstraintLayout mContainer;
 
@@ -120,7 +120,7 @@
     @Override
     protected void onAttachedToWindow() {
         super.onAttachedToWindow();
-        mSecurityMessageDisplay = KeyguardMessageArea.findSecurityMessageDisplay(this);
+        mSecurityMessageDisplay = findViewById(R.id.bouncer_message_area);
     }
 
     @Override
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
index 9aa6f03..9871645 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardPatternViewController.java
@@ -59,12 +59,9 @@
     private final LatencyTracker mLatencyTracker;
     private final FalsingCollector mFalsingCollector;
     private final EmergencyButtonController mEmergencyButtonController;
-    private final KeyguardMessageAreaController.Factory mMessageAreaControllerFactory;
     private final DevicePostureController mPostureController;
     private final DevicePostureController.Callback mPostureCallback =
             posture -> mView.onDevicePostureChanged(posture);
-
-    private KeyguardMessageAreaController mMessageAreaController;
     private LockPatternView mLockPatternView;
     private CountDownTimer mCountdownTimer;
     private AsyncTask<?, ?, ?> mPendingLockCheck;
@@ -201,15 +198,13 @@
             EmergencyButtonController emergencyButtonController,
             KeyguardMessageAreaController.Factory messageAreaControllerFactory,
             DevicePostureController postureController) {
-        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController);
+        super(view, securityMode, keyguardSecurityCallback, emergencyButtonController,
+                messageAreaControllerFactory);
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mLatencyTracker = latencyTracker;
         mFalsingCollector = falsingCollector;
         mEmergencyButtonController = emergencyButtonController;
-        mMessageAreaControllerFactory = messageAreaControllerFactory;
-        KeyguardMessageArea kma = KeyguardMessageArea.findSecurityMessageDisplay(mView);
-        mMessageAreaController = mMessageAreaControllerFactory.create(kma);
         mLockPatternView = mView.findViewById(R.id.lockPatternView);
         mPostureController = postureController;
     }
@@ -217,7 +212,6 @@
     @Override
     public void onInit() {
         super.onInit();
-        mMessageAreaController.init();
     }
 
     @Override
@@ -346,6 +340,9 @@
 
     @Override
     public void showMessage(CharSequence message, ColorStateList colorState) {
+        if (mMessageAreaController == null) {
+            return;
+        }
         if (colorState != null) {
             mMessageAreaController.setNextMessageColor(colorState);
         }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
index d0baf3d..f73c98e 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityContainer.java
@@ -665,7 +665,8 @@
                 // When using EXACTLY spec, measure will use the layout width if > 0. Set before
                 // measuring the child
                 lp.width = MeasureSpec.getSize(updatedWidthMeasureSpec);
-                measureChildWithMargins(view, updatedWidthMeasureSpec, 0, heightMeasureSpec, 0);
+                measureChildWithMargins(view, updatedWidthMeasureSpec, 0,
+                        heightMeasureSpec, 0);
 
                 maxWidth = Math.max(maxWidth,
                         view.getMeasuredWidth() + lp.leftMargin + lp.rightMargin);
@@ -1306,7 +1307,6 @@
             int yTrans = mResources.getDimensionPixelSize(R.dimen.bouncer_user_switcher_y_trans);
             if (mResources.getConfiguration().orientation == Configuration.ORIENTATION_PORTRAIT) {
                 mUserSwitcherViewGroup.setTranslationY(yTrans);
-                mViewFlipper.setTranslationY(-yTrans);
             } else {
                 // Attempt to reposition a bit higher to make up for this frame being a bit lower
                 // on the device
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
index 3aa5ada..bddf4b0 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardSecurityViewFlipperController.java
@@ -146,7 +146,8 @@
         protected NullKeyguardInputViewController(SecurityMode securityMode,
                 KeyguardSecurityCallback keyguardSecurityCallback,
                 EmergencyButtonController emergencyButtonController) {
-            super(null, securityMode, keyguardSecurityCallback, emergencyButtonController);
+            super(null, securityMode, keyguardSecurityCallback, emergencyButtonController,
+                    null);
         }
 
         @Override
@@ -156,7 +157,6 @@
 
         @Override
         public void onStartingToHide() {
-
         }
     }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
index acbea1b..7d6f377 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUnfoldTransition.kt
@@ -50,12 +50,10 @@
             viewsIdToTranslate =
                 setOf(
                     ViewIdToTranslate(R.id.keyguard_status_area, LEFT, filterNever),
-                    ViewIdToTranslate(R.id.controls_button, LEFT, filterNever),
                     ViewIdToTranslate(R.id.lockscreen_clock_view_large, LEFT, filterSplitShadeOnly),
                     ViewIdToTranslate(R.id.lockscreen_clock_view, LEFT, filterNever),
                     ViewIdToTranslate(
                         R.id.notification_stack_scroller, RIGHT, filterSplitShadeOnly),
-                    ViewIdToTranslate(R.id.wallet_button, RIGHT, filterNever),
                     ViewIdToTranslate(R.id.start_button, LEFT, filterNever),
                     ViewIdToTranslate(R.id.end_button, RIGHT, filterNever)),
             progressProvider = unfoldProgressProvider)
diff --git a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
index 4984300..4283832 100644
--- a/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
+++ b/packages/SystemUI/src/com/android/keyguard/KeyguardUpdateMonitor.java
@@ -466,6 +466,7 @@
                     FACE_AUTH_TRIGGERED_TRUST_DISABLED);
         }
 
+        mLogger.logTrustChanged(wasTrusted, enabled, userId);
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -481,12 +482,16 @@
             final boolean userHasTrust = getUserHasTrust(userId);
             if (userHasTrust && trustGrantedMessages != null) {
                 for (String msg : trustGrantedMessages) {
-                    if (!TextUtils.isEmpty(msg)) {
-                        message = msg;
+                    message = msg;
+                    if (!TextUtils.isEmpty(message)) {
                         break;
                     }
                 }
             }
+
+            if (message != null) {
+                mLogger.logShowTrustGrantedMessage(message.toString());
+            }
             for (int i = 0; i < mCallbacks.size(); i++) {
                 KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
                 if (cb != null) {
@@ -743,6 +748,7 @@
         mFingerprintCancelSignal = null;
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_FP_AUTHENTICATED);
+        mLogger.d("onFingerprintAuthenticated");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -986,6 +992,7 @@
         mFaceCancelSignal = null;
         updateBiometricListeningState(BIOMETRIC_ACTION_UPDATE,
                 FACE_AUTH_UPDATED_ON_FACE_AUTHENTICATED);
+        mLogger.d("onFaceAuthenticated");
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
             if (cb != null) {
@@ -3445,6 +3452,7 @@
         mUserFaceAuthenticated.clear();
         mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FINGERPRINT, unlockedUser);
         mTrustManager.clearAllBiometricRecognized(BiometricSourceType.FACE, unlockedUser);
+        mLogger.d("clearBiometricRecognized");
 
         for (int i = 0; i < mCallbacks.size(); i++) {
             KeyguardUpdateMonitorCallback cb = mCallbacks.get(i).get();
@@ -3694,6 +3702,9 @@
     @Override
     public void dump(PrintWriter pw, String[] args) {
         pw.println("KeyguardUpdateMonitor state:");
+        pw.println("  getUserHasTrust()=" + getUserHasTrust(getCurrentUser()));
+        pw.println("  getUserUnlockedWithBiometric()="
+                + getUserUnlockedWithBiometric(getCurrentUser()));
         pw.println("  SIM States:");
         for (SimData data : mSimDatas.values()) {
             pw.println("    " + data.toString());
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
new file mode 100644
index 0000000..f449edf
--- /dev/null
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimationListener.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2022 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.keyguard
+
+/** Interface for classes to track animation progress. */
+interface NumPadAnimationListener {
+    /** Track the progress of the animation. */
+    fun setProgress(progress: Float)
+}
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
index c91c899..e0cafae 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadAnimator.java
@@ -48,6 +48,10 @@
     private int mTextColorPrimary;
     private int mTextColorPressed;
     private int mStyle;
+    private float mStartRadius;
+    private float mEndRadius;
+    private int mHeight;
+
     private static final int EXPAND_ANIMATION_MS = 100;
     private static final int EXPAND_COLOR_ANIMATION_MS = 50;
     private static final int CONTRACT_ANIMATION_DELAY_MS = 33;
@@ -80,12 +84,20 @@
         mContractAnimatorSet.start();
     }
 
+    public void setProgress(float progress) {
+        mBackground.setCornerRadius(mEndRadius + (mStartRadius - mEndRadius) * progress);
+        int height = (int) (mHeight * 0.8f + mHeight * 0.2 * progress);
+        int difference = mHeight - height;
+        mBackground.setBounds(0, difference / 2, mHeight, mHeight - difference / 2);
+    }
+
     void onLayout(int height) {
-        float startRadius = height / 2f;
-        float endRadius = height / 4f;
-        mBackground.setCornerRadius(startRadius);
-        mExpandAnimator.setFloatValues(startRadius, endRadius);
-        mContractAnimator.setFloatValues(endRadius, startRadius);
+        mHeight = height;
+        mStartRadius = height / 2f;
+        mEndRadius = height / 4f;
+        mBackground.setCornerRadius(mStartRadius);
+        mExpandAnimator.setFloatValues(mStartRadius, mEndRadius);
+        mContractAnimator.setFloatValues(mEndRadius, mStartRadius);
     }
 
     /**
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
index 8099f75..37060987c 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadButton.java
@@ -30,7 +30,7 @@
 /**
  * Similar to the {@link NumPadKey}, but displays an image.
  */
-public class NumPadButton extends AlphaOptimizedImageButton {
+public class NumPadButton extends AlphaOptimizedImageButton implements NumPadAnimationListener {
 
     @Nullable
     private NumPadAnimator mAnimator;
@@ -104,4 +104,11 @@
         a.recycle();
         ((VectorDrawable) getDrawable()).setTintList(ColorStateList.valueOf(imageColor));
     }
+
+    @Override
+    public void setProgress(float progress) {
+        if (mAnimator != null) {
+            mAnimator.setProgress(progress);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
index 4aed251..0a4880e 100644
--- a/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
+++ b/packages/SystemUI/src/com/android/keyguard/NumPadKey.java
@@ -37,7 +37,10 @@
 import com.android.settingslib.Utils;
 import com.android.systemui.R;
 
-public class NumPadKey extends ViewGroup {
+/**
+ * Viewgroup for the bouncer numpad button, specifically for digits.
+ */
+public class NumPadKey extends ViewGroup implements NumPadAnimationListener {
     // list of "ABC", etc per digit, starting with '0'
     static String sKlondike[];
 
@@ -221,4 +224,11 @@
         performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
                 HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
     }
+
+    @Override
+    public void setProgress(float progress) {
+        if (mAnimator != null) {
+            mAnimator.setProgress(progress);
+        }
+    }
 }
diff --git a/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java b/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
index 7c86a1d..777bd19 100644
--- a/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
+++ b/packages/SystemUI/src/com/android/keyguard/SecurityMessageDisplay.java
@@ -20,7 +20,8 @@
 
 public interface SecurityMessageDisplay {
 
-    void setNextMessageColor(ColorStateList colorState);
+    /** Set text color for the next security message. */
+    default void setNextMessageColor(ColorStateList colorState) {}
 
     void setMessage(CharSequence msg);
 
diff --git a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
index 2bc98f1..7a00cd9 100644
--- a/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
+++ b/packages/SystemUI/src/com/android/keyguard/logging/KeyguardUpdateMonitorLogger.kt
@@ -340,4 +340,40 @@
                     bool1 = dismissKeyguard
                 }, { "reportUserRequestedUnlock origin=$str1 reason=$str2 dismissKeyguard=$bool1" })
     }
+
+    fun logShowTrustGrantedMessage(
+            message: String
+    ) {
+        logBuffer.log(TAG, DEBUG, {
+            str1 = message
+        }, { "showTrustGrantedMessage message$str1" })
+    }
+
+    fun logTrustChanged(
+            wasTrusted: Boolean,
+            isNowTrusted: Boolean,
+            userId: Int
+    ) {
+        logBuffer.log(TAG, DEBUG, {
+            bool1 = wasTrusted
+            bool2 = isNowTrusted
+            int1 = userId
+        }, { "onTrustChanged[user=$int1] wasTrusted=$bool1 isNowTrusted=$bool2" })
+    }
+
+    fun logKeyguardStateUpdate(
+            secure: Boolean,
+            canDismissLockScreen: Boolean,
+            trusted: Boolean,
+            trustManaged: Boolean
+
+    ) {
+        logBuffer.log("KeyguardState", DEBUG, {
+            bool1 = secure
+            bool2 = canDismissLockScreen
+            bool3 = trusted
+            bool4 = trustManaged
+        }, { "#update secure=$bool1 canDismissKeyguard=$bool2" +
+                " trusted=$bool3 trustManaged=$bool4" })
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
index 40d1eff..e4c197f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceIconController.kt
@@ -29,8 +29,9 @@
 /** Face/Fingerprint combined icon animator for BiometricPrompt. */
 class AuthBiometricFingerprintAndFaceIconController(
         context: Context,
-        iconView: LottieAnimationView
-) : AuthBiometricFingerprintIconController(context, iconView) {
+        iconView: LottieAnimationView,
+        iconViewOverlay: LottieAnimationView
+) : AuthBiometricFingerprintIconController(context, iconView, iconViewOverlay) {
 
     override val actsAsConfirmButton: Boolean = true
 
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
index 7371442..7f5a67f 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintAndFaceView.kt
@@ -39,5 +39,5 @@
     override fun onPointerDown(failedModalities: Set<Int>) = failedModalities.contains(TYPE_FACE)
 
     override fun createIconController(): AuthIconController =
-        AuthBiometricFingerprintAndFaceIconController(mContext, mIconView)
+        AuthBiometricFingerprintAndFaceIconController(mContext, mIconView, mIconViewOverlay)
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
index 9b5f54a..b40b356 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintIconController.kt
@@ -18,7 +18,12 @@
 
 import android.annotation.RawRes
 import android.content.Context
+import android.hardware.fingerprint.FingerprintManager
+import android.view.DisplayInfo
+import android.view.Surface
+import android.view.View
 import com.airbnb.lottie.LottieAnimationView
+import com.android.settingslib.widget.LottieColorUtils
 import com.android.systemui.R
 import com.android.systemui.biometrics.AuthBiometricView.BiometricState
 import com.android.systemui.biometrics.AuthBiometricView.STATE_AUTHENTICATED
@@ -32,14 +37,18 @@
 /** Fingerprint only icon animator for BiometricPrompt.  */
 open class AuthBiometricFingerprintIconController(
         context: Context,
-        iconView: LottieAnimationView
+        iconView: LottieAnimationView,
+        protected val iconViewOverlay: LottieAnimationView
 ) : AuthIconController(context, iconView) {
 
+    private val isSideFps: Boolean
     var iconLayoutParamSize: Pair<Int, Int> = Pair(1, 1)
         set(value) {
             if (field == value) {
                 return
             }
+            iconViewOverlay.layoutParams.width = value.first
+            iconViewOverlay.layoutParams.height = value.second
             iconView.layoutParams.width = value.first
             iconView.layoutParams.height = value.second
             field = value
@@ -50,9 +59,53 @@
                 R.dimen.biometric_dialog_fingerprint_icon_width),
                 context.resources.getDimensionPixelSize(
                         R.dimen.biometric_dialog_fingerprint_icon_height))
+        var sideFps = false
+        (context.getSystemService(Context.FINGERPRINT_SERVICE)
+                as FingerprintManager?)?.let { fpm ->
+            for (prop in fpm.sensorPropertiesInternal) {
+                if (prop.isAnySidefpsType) {
+                    sideFps = true
+                }
+            }
+        }
+        isSideFps = sideFps
+        val displayInfo = DisplayInfo()
+        context.display?.getDisplayInfo(displayInfo)
+        if (isSideFps && displayInfo.rotation == Surface.ROTATION_180) {
+            iconView.rotation = 180f
+        }
     }
 
-    override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+    private fun updateIconSideFps(@BiometricState lastState: Int, @BiometricState newState: Int) {
+        val displayInfo = DisplayInfo()
+        context.display?.getDisplayInfo(displayInfo)
+        val rotation = displayInfo.rotation
+        val iconAnimation = getSideFpsAnimationForTransition(rotation)
+        val iconViewOverlayAnimation =
+                getSideFpsOverlayAnimationForTransition(lastState, newState, rotation) ?: return
+
+        if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
+            iconView.setAnimation(iconAnimation)
+            iconViewOverlay.setAnimation(iconViewOverlayAnimation)
+        }
+
+        val iconContentDescription = getIconContentDescription(newState)
+        if (iconContentDescription != null) {
+            iconView.contentDescription = iconContentDescription
+            iconViewOverlay.contentDescription = iconContentDescription
+        }
+
+        iconView.frame = 0
+        iconViewOverlay.frame = 0
+        if (shouldAnimateForTransition(lastState, newState)) {
+            iconView.playAnimation()
+            iconViewOverlay.playAnimation()
+        }
+        LottieColorUtils.applyDynamicColors(context, iconView)
+        LottieColorUtils.applyDynamicColors(context, iconViewOverlay)
+    }
+
+    private fun updateIconNormal(@BiometricState lastState: Int, @BiometricState newState: Int) {
         val icon = getAnimationForTransition(lastState, newState) ?: return
 
         if (!(lastState == STATE_AUTHENTICATING_ANIMATING_IN && newState == STATE_AUTHENTICATING)) {
@@ -68,6 +121,16 @@
         if (shouldAnimateForTransition(lastState, newState)) {
             iconView.playAnimation()
         }
+        LottieColorUtils.applyDynamicColors(context, iconView)
+    }
+
+    override fun updateIcon(@BiometricState lastState: Int, @BiometricState newState: Int) {
+        if (isSideFps) {
+            updateIconSideFps(lastState, newState)
+        } else {
+            iconViewOverlay.visibility = View.GONE
+            updateIconNormal(lastState, newState)
+        }
     }
 
     private fun getIconContentDescription(@BiometricState newState: Int): CharSequence? {
@@ -125,4 +188,89 @@
         }
         return if (id != null) return id else null
     }
+
+    @RawRes
+    private fun getSideFpsAnimationForTransition(rotation: Int): Int = when (rotation) {
+        Surface.ROTATION_0 -> R.raw.biometricprompt_landscape_base
+        Surface.ROTATION_90 -> R.raw.biometricprompt_portrait_base_topleft
+        Surface.ROTATION_180 -> R.raw.biometricprompt_landscape_base
+        Surface.ROTATION_270 -> R.raw.biometricprompt_portrait_base_bottomright
+        else -> R.raw.biometricprompt_landscape_base
+    }
+
+    @RawRes
+    private fun getSideFpsOverlayAnimationForTransition(
+            @BiometricState oldState: Int,
+            @BiometricState newState: Int,
+            rotation: Int
+    ): Int? = when (newState) {
+        STATE_HELP,
+        STATE_ERROR -> {
+            when (rotation) {
+                Surface.ROTATION_0 -> R.raw.biometricprompt_fingerprint_to_error_landscape
+                Surface.ROTATION_90 ->
+                    R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft
+                Surface.ROTATION_180 ->
+                    R.raw.biometricprompt_fingerprint_to_error_landscape
+                Surface.ROTATION_270 ->
+                    R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright
+                else -> R.raw.biometricprompt_fingerprint_to_error_landscape
+            }
+        }
+        STATE_AUTHENTICATING_ANIMATING_IN,
+        STATE_AUTHENTICATING -> {
+            if (oldState == STATE_ERROR || oldState == STATE_HELP) {
+                when (rotation) {
+                    Surface.ROTATION_0 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_error_to_fingerprint_portrait_bottomright
+                    else -> R.raw.biometricprompt_symbol_error_to_fingerprint_landscape
+                }
+            } else {
+                when (rotation) {
+                    Surface.ROTATION_0 -> R.raw.biometricprompt_fingerprint_to_error_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_fingerprint_to_error_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_error_portrait_bottomright
+                    else -> R.raw.biometricprompt_fingerprint_to_error_landscape
+                }
+            }
+        }
+        STATE_AUTHENTICATED -> {
+            if (oldState == STATE_ERROR || oldState == STATE_HELP) {
+                when (rotation) {
+                    Surface.ROTATION_0 ->
+                        R.raw.biometricprompt_symbol_error_to_success_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_error_to_success_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_symbol_error_to_success_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_error_to_success_portrait_bottomright
+                    else -> R.raw.biometricprompt_symbol_error_to_success_landscape
+                }
+            } else {
+                when (rotation) {
+                    Surface.ROTATION_0 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+                    Surface.ROTATION_90 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_topleft
+                    Surface.ROTATION_180 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+                    Surface.ROTATION_270 ->
+                        R.raw.biometricprompt_symbol_fingerprint_to_success_portrait_bottomright
+                    else -> R.raw.biometricprompt_symbol_fingerprint_to_success_landscape
+                }
+            }
+        }
+        else -> null
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
index 9cce066..2066634 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricFingerprintView.kt
@@ -86,7 +86,7 @@
     override fun supportsSmallDialog() = false
 
     override fun createIconController(): AuthIconController =
-        AuthBiometricFingerprintIconController(mContext, mIconView)
+        AuthBiometricFingerprintIconController(mContext, mIconView, mIconViewOverlay)
 
     fun updateOverrideIconLayoutParamsSize() {
         udfpsAdapter?.let {
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
index fc5cf9f..e94b1f8 100644
--- a/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/AuthBiometricView.java
@@ -133,6 +133,7 @@
     private TextView mSubtitleView;
     private TextView mDescriptionView;
     private View mIconHolderView;
+    protected LottieAnimationView mIconViewOverlay;
     protected LottieAnimationView mIconView;
     protected TextView mIndicatorView;
 
@@ -651,6 +652,7 @@
         mTitleView = findViewById(R.id.title);
         mSubtitleView = findViewById(R.id.subtitle);
         mDescriptionView = findViewById(R.id.description);
+        mIconViewOverlay = findViewById(R.id.biometric_icon_overlay);
         mIconView = findViewById(R.id.biometric_icon);
         mIconHolderView = findViewById(R.id.biometric_icon_frame);
         mIndicatorView = findViewById(R.id.indicator);
@@ -689,6 +691,11 @@
 
         mIconController = createIconController();
         if (mIconController.getActsAsConfirmButton()) {
+            mIconViewOverlay.setOnClickListener((view)->{
+                if (mState == STATE_PENDING_CONFIRMATION) {
+                    updateState(STATE_AUTHENTICATED);
+                }
+            });
             mIconView.setOnClickListener((view) -> {
                 if (mState == STATE_PENDING_CONFIRMATION) {
                     updateState(STATE_AUTHENTICATED);
diff --git a/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
new file mode 100644
index 0000000..f2d8aaa
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/biometrics/BiometricMessageDeferral.kt
@@ -0,0 +1,89 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+/**
+ * Provides whether an acquired error message should be shown immediately when its received (see
+ * [shouldDefer]) or should be shown when the biometric error is received [getDeferredMessage].
+ * @property excludedMessages messages that are excluded from counts
+ * @property messagesToDefer messages that shouldn't show immediately when received, but may be
+ * shown later if the message is the most frequent message processed and meets [THRESHOLD]
+ * percentage of all messages (excluding [excludedMessages])
+ */
+class BiometricMessageDeferral(
+    private val excludedMessages: Set<Int>,
+    private val messagesToDefer: Set<Int>
+) {
+    private val msgCounts: MutableMap<Int, Int> = HashMap() // msgId => frequency of msg
+    private val msgIdToCharSequence: MutableMap<Int, CharSequence> = HashMap() // msgId => message
+    private var totalRelevantMessages = 0
+    private var mostFrequentMsgIdToDefer: Int? = null
+
+    /** Reset all saved counts. */
+    fun reset() {
+        totalRelevantMessages = 0
+        msgCounts.clear()
+        msgIdToCharSequence.clear()
+    }
+
+    /** Whether the given message should be deferred instead of being shown immediately. */
+    fun shouldDefer(acquiredMsgId: Int): Boolean {
+        return messagesToDefer.contains(acquiredMsgId)
+    }
+
+    /**
+     * Adds the acquiredMsgId to the counts if it's not in [excludedMessages]. We still count
+     * messages that shouldn't be deferred in these counts.
+     */
+    fun processMessage(acquiredMsgId: Int, helpString: CharSequence) {
+        if (excludedMessages.contains(acquiredMsgId)) {
+            return
+        }
+
+        totalRelevantMessages++
+        msgIdToCharSequence[acquiredMsgId] = helpString
+
+        val newAcquiredMsgCount = msgCounts.getOrDefault(acquiredMsgId, 0) + 1
+        msgCounts[acquiredMsgId] = newAcquiredMsgCount
+        if (
+            messagesToDefer.contains(acquiredMsgId) &&
+                (mostFrequentMsgIdToDefer == null ||
+                    newAcquiredMsgCount > msgCounts.getOrDefault(mostFrequentMsgIdToDefer!!, 0))
+        ) {
+            mostFrequentMsgIdToDefer = acquiredMsgId
+        }
+    }
+
+    /**
+     * Get the most frequent deferred message that meets the [THRESHOLD] percentage of processed
+     * messages excluding [excludedMessages].
+     * @return null if no messages have been deferred OR deferred messages didn't meet the
+     * [THRESHOLD] percentage of messages to show.
+     */
+    fun getDeferredMessage(): CharSequence? {
+        mostFrequentMsgIdToDefer?.let {
+            if (msgCounts.getOrDefault(it, 0) > (THRESHOLD * totalRelevantMessages)) {
+                return msgIdToCharSequence[mostFrequentMsgIdToDefer]
+            }
+        }
+
+        return null
+    }
+    companion object {
+        const val THRESHOLD = .5f
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
index 0b65966..6c45af2 100644
--- a/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/shared/model/Icon.kt
@@ -24,11 +24,15 @@
  * [Icon.Resource] to a resource.
  */
 sealed class Icon {
+    abstract val contentDescription: ContentDescription?
+
     data class Loaded(
         val drawable: Drawable,
+        override val contentDescription: ContentDescription?,
     ) : Icon()
 
     data class Resource(
         @DrawableRes val res: Int,
+        override val contentDescription: ContentDescription?,
     ) : Icon()
 }
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
index d6433aa..93ae637 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/ContentDescriptionViewBinder.kt
@@ -21,14 +21,16 @@
 
 object ContentDescriptionViewBinder {
     fun bind(
-        contentDescription: ContentDescription,
+        contentDescription: ContentDescription?,
         view: View,
     ) {
-        when (contentDescription) {
-            is ContentDescription.Loaded -> view.contentDescription = contentDescription.description
-            is ContentDescription.Resource -> {
-                view.contentDescription = view.context.resources.getString(contentDescription.res)
+        view.contentDescription =
+            when (contentDescription) {
+                null -> null
+                is ContentDescription.Loaded -> contentDescription.description
+                is ContentDescription.Resource -> {
+                    view.context.resources.getString(contentDescription.res)
+                }
             }
-        }
     }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
index aecee2a..108e22b 100644
--- a/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/common/ui/binder/IconViewBinder.kt
@@ -24,6 +24,7 @@
         icon: Icon,
         view: ImageView,
     ) {
+        ContentDescriptionViewBinder.bind(icon.contentDescription, view)
         when (icon) {
             is Icon.Loaded -> view.setImageDrawable(icon.drawable)
             is Icon.Resource -> view.setImageResource(icon.res)
diff --git a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
index d89c0be..b598554 100644
--- a/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
+++ b/packages/SystemUI/src/com/android/systemui/doze/DozeHost.java
@@ -101,6 +101,11 @@
          * Called when the always on suppression state changes. See {@link #isAlwaysOnSuppressed()}.
          */
         default void onAlwaysOnSuppressedChanged(boolean suppressed) {}
+
+        /**
+         * Called when the dozing state may have been updated.
+         */
+        default void onDozingChanged(boolean isDozing) {}
     }
 
     interface PulseCallback {
diff --git a/packages/SystemUI/src/com/android/systemui/flags/Flags.java b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
index 1482303..586585c 100644
--- a/packages/SystemUI/src/com/android/systemui/flags/Flags.java
+++ b/packages/SystemUI/src/com/android/systemui/flags/Flags.java
@@ -66,6 +66,10 @@
     public static final UnreleasedFlag FSI_REQUIRES_KEYGUARD =
             new UnreleasedFlag(110, true);
 
+    public static final UnreleasedFlag INSTANT_VOICE_REPLY = new UnreleasedFlag(111, true);
+
+    // next id: 112
+
     /***************************************/
     // 200 - keyguard/lockscreen
 
@@ -88,13 +92,6 @@
     public static final ResourceBooleanFlag FACE_SCANNING_ANIM =
             new ResourceBooleanFlag(205, R.bool.config_enableFaceScanningAnimation);
 
-    /**
-     * Whether the KeyguardBottomArea(View|Controller) should use the modern architecture or the old
-     * one.
-     */
-    public static final ReleasedFlag MODERN_BOTTOM_AREA = new ReleasedFlag(206, true);
-
-
     public static final UnreleasedFlag LOCKSCREEN_CUSTOM_CLOCKS = new UnreleasedFlag(207);
 
     /**
@@ -187,6 +184,9 @@
     // 801 - region sampling
     public static final UnreleasedFlag REGION_SAMPLING = new UnreleasedFlag(801);
 
+    // 802 - wallpaper rendering
+    public static final UnreleasedFlag USE_CANVAS_RENDERER = new UnreleasedFlag(802);
+
     /***************************************/
     // 900 - media
     public static final ReleasedFlag MEDIA_TAP_TO_TRANSFER = new ReleasedFlag(900);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
index 6dfbd42..2da9232 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardService.java
@@ -29,6 +29,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OPEN;
@@ -189,6 +190,9 @@
             return apps.length == 0 ? TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER
                     : TRANSIT_OLD_KEYGUARD_GOING_AWAY;
         } else if (type == TRANSIT_KEYGUARD_OCCLUDE) {
+            boolean isOccludeByDream = apps.length > 0 && apps[0].taskInfo.topActivityType
+                    == WindowConfiguration.ACTIVITY_TYPE_DREAM;
+            if (isOccludeByDream) return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
             return TRANSIT_OLD_KEYGUARD_OCCLUDE;
         } else if (type == TRANSIT_KEYGUARD_UNOCCLUDE) {
             return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
@@ -303,6 +307,12 @@
                 definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE,
                         occludeAnimationAdapter);
 
+                final RemoteAnimationAdapter occludeByDreamAnimationAdapter =
+                        new RemoteAnimationAdapter(
+                                mKeyguardViewMediator.getOccludeByDreamAnimationRunner(), 0, 0);
+                definition.addRemoteAnimation(TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM,
+                        occludeByDreamAnimationAdapter);
+
                 final RemoteAnimationAdapter unoccludeAnimationAdapter =
                         new RemoteAnimationAdapter(
                                 mKeyguardViewMediator.getUnoccludeAnimationRunner(), 0, 0);
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
index d4ef467..d4e0f061 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/KeyguardViewMediator.java
@@ -887,6 +887,86 @@
     private IRemoteAnimationRunner mOccludeAnimationRunner =
             new OccludeActivityLaunchRemoteAnimationRunner(mOccludeAnimationController);
 
+    private final IRemoteAnimationRunner mOccludeByDreamAnimationRunner =
+            new IRemoteAnimationRunner.Stub() {
+                @Nullable private ValueAnimator mOccludeByDreamAnimator;
+
+                @Override
+                public void onAnimationCancelled(boolean isKeyguardOccluded) {
+                    if (mOccludeByDreamAnimator != null) {
+                        mOccludeByDreamAnimator.cancel();
+                    }
+                    setOccluded(isKeyguardOccluded /* isOccluded */, false /* animate */);
+                    if (DEBUG) {
+                        Log.d(TAG, "Occlude by Dream animation cancelled. Occluded state is now: "
+                                + mOccluded);
+                    }
+                }
+
+                @Override
+                public void onAnimationStart(int transit, RemoteAnimationTarget[] apps,
+                        RemoteAnimationTarget[] wallpapers, RemoteAnimationTarget[] nonApps,
+                        IRemoteAnimationFinishedCallback finishedCallback) throws RemoteException {
+                    setOccluded(true /* isOccluded */, true /* animate */);
+
+                    if (apps == null || apps.length == 0 || apps[0] == null) {
+                        if (DEBUG) {
+                            Log.d(TAG, "No apps provided to the OccludeByDream runner; "
+                                    + "skipping occluding animation.");
+                        }
+                        finishedCallback.onAnimationFinished();
+                        return;
+                    }
+
+                    final RemoteAnimationTarget primary = apps[0];
+                    final boolean isDream = (apps[0].taskInfo.topActivityType
+                            == WindowConfiguration.ACTIVITY_TYPE_DREAM);
+                    if (!isDream) {
+                        Log.w(TAG, "The occluding app isn't Dream; "
+                                + "finishing up. Please check that the config is correct.");
+                        finishedCallback.onAnimationFinished();
+                        return;
+                    }
+
+                    final SyncRtSurfaceTransactionApplier applier =
+                            new SyncRtSurfaceTransactionApplier(
+                                    mKeyguardViewControllerLazy.get().getViewRootImpl().getView());
+
+                    mContext.getMainExecutor().execute(() -> {
+                        if (mOccludeByDreamAnimator != null) {
+                            mOccludeByDreamAnimator.cancel();
+                        }
+
+                        mOccludeByDreamAnimator = ValueAnimator.ofFloat(0f, 1f);
+                        // Use the same duration as for the UNOCCLUDE.
+                        mOccludeByDreamAnimator.setDuration(UNOCCLUDE_ANIMATION_DURATION);
+                        mOccludeByDreamAnimator.setInterpolator(Interpolators.LINEAR);
+                        mOccludeByDreamAnimator.addUpdateListener(
+                                animation -> {
+                                    SyncRtSurfaceTransactionApplier.SurfaceParams.Builder
+                                            paramsBuilder =
+                                            new SyncRtSurfaceTransactionApplier.SurfaceParams
+                                                    .Builder(primary.leash)
+                                                    .withAlpha(animation.getAnimatedFraction());
+                                    applier.scheduleApply(paramsBuilder.build());
+                                });
+                        mOccludeByDreamAnimator.addListener(new AnimatorListenerAdapter() {
+                            @Override
+                            public void onAnimationEnd(Animator animation) {
+                                try {
+                                    finishedCallback.onAnimationFinished();
+                                    mOccludeByDreamAnimator = null;
+                                } catch (RemoteException e) {
+                                    e.printStackTrace();
+                                }
+                            }
+                        });
+
+                        mOccludeByDreamAnimator.start();
+                    });
+                }
+            };
+
     /**
      * Animation controller for activities that unocclude the keyguard. This does not use the
      * ActivityLaunchAnimator since we're just translating down, rather than emerging from a view
@@ -1682,6 +1762,10 @@
         return mOccludeAnimationRunner;
     }
 
+    public IRemoteAnimationRunner getOccludeByDreamAnimationRunner() {
+        return mOccludeByDreamAnimationRunner;
+    }
+
     public IRemoteAnimationRunner getUnoccludeAnimationRunner() {
         return mUnoccludeAnimationRunner;
     }
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
index e52d9ee..840a4b2 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/data/repository/KeyguardRepository.kt
@@ -20,6 +20,7 @@
 import com.android.systemui.common.coroutine.ConflatedCallbackFlow.conflatedCallbackFlow
 import com.android.systemui.common.shared.model.Position
 import com.android.systemui.dagger.SysUISingleton
+import com.android.systemui.doze.DozeHost
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import javax.inject.Inject
@@ -28,6 +29,7 @@
 import kotlinx.coroutines.flow.MutableStateFlow
 import kotlinx.coroutines.flow.StateFlow
 import kotlinx.coroutines.flow.asStateFlow
+import kotlinx.coroutines.flow.distinctUntilChanged
 
 /** Defines interface for classes that encapsulate application state for the keyguard. */
 interface KeyguardRepository {
@@ -102,6 +104,7 @@
 constructor(
     statusBarStateController: StatusBarStateController,
     keyguardStateController: KeyguardStateController,
+    dozeHost: DozeHost,
 ) : KeyguardRepository {
     private val _animateBottomAreaDozingTransitions = MutableStateFlow(false)
     override val animateBottomAreaDozingTransitions =
@@ -136,19 +139,21 @@
         awaitClose { keyguardStateController.removeCallback(callback) }
     }
 
-    override val isDozing: Flow<Boolean> = conflatedCallbackFlow {
-        val callback =
-            object : StatusBarStateController.StateListener {
-                override fun onDozingChanged(isDozing: Boolean) {
-                    trySendWithFailureLogging(isDozing, TAG, "updated isDozing")
-                }
+    override val isDozing: Flow<Boolean> =
+        conflatedCallbackFlow {
+                val callback =
+                    object : DozeHost.Callback {
+                        override fun onDozingChanged(isDozing: Boolean) {
+                            trySendWithFailureLogging(isDozing, TAG, "updated isDozing")
+                        }
+                    }
+                dozeHost.addCallback(callback)
+                trySendWithFailureLogging(false, TAG, "initial isDozing: false")
+
+                awaitClose { dozeHost.removeCallback(callback) }
             }
+            .distinctUntilChanged()
 
-        statusBarStateController.addCallback(callback)
-        trySendWithFailureLogging(statusBarStateController.isDozing, TAG, "initial isDozing")
-
-        awaitClose { statusBarStateController.removeCallback(callback) }
-    }
     override val dozeAmount: Flow<Float> = conflatedCallbackFlow {
         val callback =
             object : StatusBarStateController.StateListener {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
index 9a69e26..95acc0b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/interactor/KeyguardQuickAffordanceInteractor.kt
@@ -32,6 +32,7 @@
 import kotlin.reflect.KClass
 import kotlinx.coroutines.flow.Flow
 import kotlinx.coroutines.flow.combine
+import kotlinx.coroutines.flow.onStart
 
 @SysUISingleton
 class KeyguardQuickAffordanceInteractor
@@ -88,7 +89,15 @@
         position: KeyguardQuickAffordancePosition
     ): Flow<KeyguardQuickAffordanceModel> {
         val configs = registry.getAll(position)
-        return combine(configs.map { config -> config.state }) { states ->
+        return combine(
+            configs.map { config ->
+                // We emit an initial "Hidden" value to make sure that there's always an initial
+                // value and avoid subtle bugs where the downstream isn't receiving any values
+                // because one config implementation is not emitting an initial value. For example,
+                // see b/244296596.
+                config.state.onStart { emit(KeyguardQuickAffordanceConfig.State.Hidden) }
+            }
+        ) { states ->
             val index = states.indexOfFirst { it is KeyguardQuickAffordanceConfig.State.Visible }
             if (index != -1) {
                 val visibleState = states[index] as KeyguardQuickAffordanceConfig.State.Visible
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
index 8f32ff9..ac2c9b1 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfig.kt
@@ -94,6 +94,7 @@
                                 hasFavorites = favorites?.isNotEmpty() == true,
                                 hasServiceInfos = serviceInfos.isNotEmpty(),
                                 iconResourceId = component.getTileImageId(),
+                                visibility = component.getVisibility(),
                             ),
                             TAG,
                         )
@@ -110,9 +111,16 @@
         isFeatureEnabled: Boolean,
         hasFavorites: Boolean,
         hasServiceInfos: Boolean,
+        visibility: ControlsComponent.Visibility,
         @DrawableRes iconResourceId: Int?,
     ): KeyguardQuickAffordanceConfig.State {
-        return if (isFeatureEnabled && hasFavorites && hasServiceInfos && iconResourceId != null) {
+        return if (
+            isFeatureEnabled &&
+                hasFavorites &&
+                hasServiceInfos &&
+                iconResourceId != null &&
+                visibility == ControlsComponent.Visibility.AVAILABLE
+        ) {
             KeyguardQuickAffordanceConfig.State.Visible(
                 icon = ContainedDrawable.WithResource(iconResourceId),
                 contentDescriptionResourceId = component.getTileTitleId(),
diff --git a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
index ae4c7c7..6baf6e1 100644
--- a/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/MediaHierarchyManager.kt
@@ -41,6 +41,7 @@
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.dreams.DreamOverlayStateController
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.dream.MediaDreamComplication
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.NotifPanelEvents
 import com.android.systemui.statusbar.CrossFadeHelper
@@ -401,7 +402,7 @@
         }
 
     /**
-     * Is the doze animation currently Running
+     * Is the dream overlay currently active
      */
     private var dreamOverlayActive: Boolean = false
         private set(value) {
@@ -412,6 +413,17 @@
         }
 
     /**
+     * Is the dream media complication currently active
+     */
+    private var dreamMediaComplicationActive: Boolean = false
+        private set(value) {
+            if (field != value) {
+                field = value
+                updateDesiredLocation(forceNoAnimation = true)
+            }
+        }
+
+    /**
      * The current cross fade progress. 0.5f means it's just switching
      * between the start and the end location and the content is fully faded, while 0.75f means
      * that we're halfway faded in again in the target state.
@@ -500,6 +512,12 @@
         })
 
         dreamOverlayStateController.addCallback(object : DreamOverlayStateController.Callback {
+            override fun onComplicationsChanged() {
+                dreamMediaComplicationActive = dreamOverlayStateController.complications.any {
+                    it is MediaDreamComplication
+                }
+            }
+
             override fun onStateChanged() {
                 dreamOverlayStateController.isOverlayActive.also { dreamOverlayActive = it }
             }
@@ -1068,7 +1086,7 @@
         val onLockscreen = (!bypassController.bypassEnabled &&
             (statusbarState == StatusBarState.KEYGUARD))
         val location = when {
-            dreamOverlayActive -> LOCATION_DREAM_OVERLAY
+            dreamOverlayActive && dreamMediaComplicationActive -> LOCATION_DREAM_OVERLAY
             (qsExpansion > 0.0f || inSplitShade) && !onLockscreen -> LOCATION_QS
             qsExpansion > 0.4f && onLockscreen -> LOCATION_QS
             !hasActiveMedia -> LOCATION_QS
diff --git a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
index 75fa2f1..0b9b32b 100644
--- a/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
+++ b/packages/SystemUI/src/com/android/systemui/media/RingtonePlayer.java
@@ -96,8 +96,9 @@
             mToken = token;
 
             mRingtone = new Ringtone(getContextForUser(user), false);
-            mRingtone.setAudioAttributes(aa);
+            mRingtone.setAudioAttributesField(aa);
             mRingtone.setUri(uri, volumeShaperConfig);
+            mRingtone.createLocalMediaPlayer();
         }
 
         @Override
diff --git a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
index acd04f2..dc1488e 100644
--- a/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
+++ b/packages/SystemUI/src/com/android/systemui/media/dream/MediaDreamSentinel.java
@@ -19,6 +19,7 @@
 import static com.android.systemui.flags.Flags.MEDIA_DREAM_COMPLICATION;
 
 import android.content.Context;
+import android.util.Log;
 
 import androidx.annotation.NonNull;
 import androidx.annotation.Nullable;
@@ -38,6 +39,9 @@
  * the media complication as appropriate
  */
 public class MediaDreamSentinel extends CoreStartable {
+    private static final String TAG = "MediaDreamSentinel";
+    private static final boolean DEBUG = Log.isLoggable(TAG, Log.DEBUG);
+
     private final MediaDataManager.Listener mListener = new MediaDataManager.Listener() {
         private boolean mAdded;
         @Override
@@ -46,11 +50,17 @@
 
         @Override
         public void onMediaDataRemoved(@NonNull String key) {
+            final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia();
+            if (DEBUG) {
+                Log.d(TAG, "onMediaDataRemoved(" + key + "), mAdded=" + mAdded + ", hasActiveMedia="
+                        + hasActiveMedia);
+            }
+
             if (!mAdded) {
                 return;
             }
 
-            if (mMediaDataManager.hasActiveMedia()) {
+            if (hasActiveMedia) {
                 return;
             }
 
@@ -71,11 +81,24 @@
                 return;
             }
 
+            final boolean hasActiveMedia = mMediaDataManager.hasActiveMedia();
+            if (DEBUG) {
+                Log.d(TAG, "onMediaDataLoaded(" + key + "), mAdded=" + mAdded + ", hasActiveMedia="
+                        + hasActiveMedia);
+            }
+
+            // Media data can become inactive without triggering onMediaDataRemoved.
+            if (mAdded && !hasActiveMedia) {
+                mAdded = false;
+                mDreamOverlayStateController.removeComplication(mMediaEntryComplication);
+                return;
+            }
+
             if (mAdded) {
                 return;
             }
 
-            if (!mMediaDataManager.hasActiveMedia()) {
+            if (!hasActiveMedia) {
                 return;
             }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
index 35a6c74..5d6d683 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiver.kt
@@ -34,15 +34,14 @@
 import com.android.systemui.R
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
 import com.android.systemui.media.taptotransfer.common.MediaTttLogger
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
 import com.android.systemui.util.animation.AnimationUtil.Companion.frames
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
 import javax.inject.Inject
 
 /**
@@ -56,18 +55,16 @@
         context: Context,
         @MediaTttReceiverLogger logger: MediaTttLogger,
         windowManager: WindowManager,
-        viewUtil: ViewUtil,
         mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
         @Main private val mainHandler: Handler,
         private val uiEventLogger: MediaTttReceiverUiEventLogger,
-) : MediaTttChipControllerCommon<ChipReceiverInfo>(
+) : TemporaryViewDisplayController<ChipReceiverInfo>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
@@ -119,18 +116,18 @@
         uiEventLogger.logReceiverStateChange(chipState)
 
         if (chipState == ChipStateReceiver.FAR_FROM_SENDER) {
-            removeChip(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
+            removeView(removalReason = ChipStateReceiver.FAR_FROM_SENDER::class.simpleName!!)
             return
         }
         if (appIcon == null) {
-            displayChip(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
+            displayView(ChipReceiverInfo(routeInfo, appIconDrawableOverride = null, appName))
             return
         }
 
         appIcon.loadDrawableAsync(
                 context,
                 Icon.OnDrawableLoadedListener { drawable ->
-                    displayChip(ChipReceiverInfo(routeInfo, drawable, appName))
+                    displayView(ChipReceiverInfo(routeInfo, drawable, appName))
                 },
                 // Notify the listener on the main handler since the listener will update
                 // the UI.
@@ -138,19 +135,19 @@
         )
     }
 
-    override fun updateChipView(newChipInfo: ChipReceiverInfo, currentChipView: ViewGroup) {
-        super.updateChipView(newChipInfo, currentChipView)
+    override fun updateView(newInfo: ChipReceiverInfo, currentView: ViewGroup) {
+        super.updateView(newInfo, currentView)
         val iconName = setIcon(
-                currentChipView,
-                newChipInfo.routeInfo.clientPackageName,
-                newChipInfo.appIconDrawableOverride,
-                newChipInfo.appNameOverride
+                currentView,
+                newInfo.routeInfo.clientPackageName,
+                newInfo.appIconDrawableOverride,
+                newInfo.appNameOverride
         )
-        currentChipView.contentDescription = iconName
+        currentView.contentDescription = iconName
     }
 
-    override fun animateChipIn(chipView: ViewGroup) {
-        val appIconView = chipView.requireViewById<View>(R.id.app_icon)
+    override fun animateViewIn(view: ViewGroup) {
+        val appIconView = view.requireViewById<View>(R.id.app_icon)
         appIconView.animate()
                 .translationYBy(-1 * getTranslationAmount().toFloat())
                 .setDuration(30.frames)
@@ -160,8 +157,8 @@
                 .setDuration(5.frames)
                 .start()
         // Using withEndAction{} doesn't apply a11y focus when screen is unlocked.
-        appIconView.postOnAnimation { chipView.requestAccessibilityFocus() }
-        startRipple(chipView.requireViewById(R.id.ripple))
+        appIconView.postOnAnimation { view.requestAccessibilityFocus() }
+        startRipple(view.requireViewById(R.id.ripple))
     }
 
     override fun getIconSize(isAppIcon: Boolean): Int? =
@@ -216,7 +213,7 @@
     val routeInfo: MediaRoute2Info,
     val appIconDrawableOverride: Drawable?,
     val appNameOverride: CharSequence?
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
     override fun getTimeoutMs() = DEFAULT_TIMEOUT_MILLIS
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
index a153cb6..bde588c 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/ChipStateSender.kt
@@ -25,7 +25,7 @@
 import com.android.internal.logging.UiEventLogger
 import com.android.internal.statusbar.IUndoMediaTransferCallback
 import com.android.systemui.R
-import com.android.systemui.media.taptotransfer.common.DEFAULT_TIMEOUT_MILLIS
+import com.android.systemui.temporarydisplay.DEFAULT_TIMEOUT_MILLIS
 
 /**
  * A class enumerating all the possible states of the media tap-to-transfer chip on the sender
@@ -120,7 +120,7 @@
                 // state, but that may take too long to go through the binder and the user may be
                 // confused ast o why the UI hasn't changed yet. So, we immediately change the UI
                 // here.
-                controllerSender.displayChip(
+                controllerSender.displayView(
                     ChipSenderInfo(
                         TRANSFER_TO_THIS_DEVICE_TRIGGERED, routeInfo, undoCallback
                     )
@@ -155,7 +155,7 @@
                 // state, but that may take too long to go through the binder and the user may be
                 // confused as to why the UI hasn't changed yet. So, we immediately change the UI
                 // here.
-                controllerSender.displayChip(
+                controllerSender.displayView(
                     ChipSenderInfo(
                         TRANSFER_TO_RECEIVER_TRIGGERED, routeInfo, undoCallback
                     )
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
index 9335489..0c1ebd7 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
+++ b/packages/SystemUI/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSender.kt
@@ -33,14 +33,13 @@
 import com.android.systemui.animation.ViewHierarchyAnimator
 import com.android.systemui.dagger.SysUISingleton
 import com.android.systemui.dagger.qualifiers.Main
-import com.android.systemui.media.taptotransfer.common.ChipInfoCommon
-import com.android.systemui.media.taptotransfer.common.MediaTttChipControllerCommon
 import com.android.systemui.media.taptotransfer.common.MediaTttLogger
-import com.android.systemui.media.taptotransfer.common.MediaTttRemovalReason
 import com.android.systemui.statusbar.CommandQueue
 import com.android.systemui.statusbar.policy.ConfigurationController
+import com.android.systemui.temporarydisplay.TemporaryDisplayRemovalReason
+import com.android.systemui.temporarydisplay.TemporaryViewDisplayController
+import com.android.systemui.temporarydisplay.TemporaryViewInfo
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
 import javax.inject.Inject
 
 /**
@@ -53,17 +52,15 @@
         context: Context,
         @MediaTttSenderLogger logger: MediaTttLogger,
         windowManager: WindowManager,
-        viewUtil: ViewUtil,
         @Main mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
         private val uiEventLogger: MediaTttSenderUiEventLogger
-) : MediaTttChipControllerCommon<ChipSenderInfo>(
+) : TemporaryViewDisplayController<ChipSenderInfo>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
@@ -106,53 +103,52 @@
         uiEventLogger.logSenderStateChange(chipState)
 
         if (chipState == ChipStateSender.FAR_FROM_RECEIVER) {
-            removeChip(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
+            removeView(removalReason = ChipStateSender.FAR_FROM_RECEIVER::class.simpleName!!)
         } else {
-            displayChip(ChipSenderInfo(chipState, routeInfo, undoCallback))
+            displayView(ChipSenderInfo(chipState, routeInfo, undoCallback))
         }
     }
 
-    /** Displays the chip view for the given state. */
-    override fun updateChipView(
-            newChipInfo: ChipSenderInfo,
-            currentChipView: ViewGroup
+    override fun updateView(
+        newInfo: ChipSenderInfo,
+        currentView: ViewGroup
     ) {
-        super.updateChipView(newChipInfo, currentChipView)
+        super.updateView(newInfo, currentView)
 
-        val chipState = newChipInfo.state
+        val chipState = newInfo.state
 
         // App icon
-        val iconName = setIcon(currentChipView, newChipInfo.routeInfo.clientPackageName)
+        val iconName = setIcon(currentView, newInfo.routeInfo.clientPackageName)
 
         // Text
-        val otherDeviceName = newChipInfo.routeInfo.name.toString()
+        val otherDeviceName = newInfo.routeInfo.name.toString()
         val chipText = chipState.getChipTextString(context, otherDeviceName)
-        currentChipView.requireViewById<TextView>(R.id.text).text = chipText
+        currentView.requireViewById<TextView>(R.id.text).text = chipText
 
         // Loading
-        currentChipView.requireViewById<View>(R.id.loading).visibility =
+        currentView.requireViewById<View>(R.id.loading).visibility =
             chipState.isMidTransfer.visibleIfTrue()
 
         // Undo
-        val undoView = currentChipView.requireViewById<View>(R.id.undo)
+        val undoView = currentView.requireViewById<View>(R.id.undo)
         val undoClickListener = chipState.undoClickListener(
-                this, newChipInfo.routeInfo, newChipInfo.undoCallback, uiEventLogger
+                this, newInfo.routeInfo, newInfo.undoCallback, uiEventLogger
         )
         undoView.setOnClickListener(undoClickListener)
         undoView.visibility = (undoClickListener != null).visibleIfTrue()
 
         // Failure
-        currentChipView.requireViewById<View>(R.id.failure_icon).visibility =
+        currentView.requireViewById<View>(R.id.failure_icon).visibility =
             chipState.isTransferFailure.visibleIfTrue()
 
         // For accessibility
-        currentChipView.requireViewById<ViewGroup>(
+        currentView.requireViewById<ViewGroup>(
                 R.id.media_ttt_sender_chip_inner
         ).contentDescription = "$iconName $chipText"
     }
 
-    override fun animateChipIn(chipView: ViewGroup) {
-        val chipInnerView = chipView.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
+    override fun animateViewIn(view: ViewGroup) {
+        val chipInnerView = view.requireViewById<ViewGroup>(R.id.media_ttt_sender_chip_inner)
         ViewHierarchyAnimator.animateAddition(
             chipInnerView,
             ViewHierarchyAnimator.Hotspot.TOP,
@@ -165,14 +161,14 @@
         )
     }
 
-    override fun removeChip(removalReason: String) {
+    override fun removeView(removalReason: String) {
         // Don't remove the chip if we're mid-transfer since the user should still be able to
         // see the status of the transfer. (But do remove it if it's finally timed out.)
-        if (chipInfo?.state?.isMidTransfer == true &&
-                removalReason != MediaTttRemovalReason.REASON_TIMEOUT) {
+        if (info?.state?.isMidTransfer == true &&
+                removalReason != TemporaryDisplayRemovalReason.REASON_TIMEOUT) {
             return
         }
-        super.removeChip(removalReason)
+        super.removeView(removalReason)
     }
 
     private fun Boolean.visibleIfTrue(): Int {
@@ -188,7 +184,7 @@
     val state: ChipStateSender,
     val routeInfo: MediaRoute2Info,
     val undoCallback: IUndoMediaTransferCallback? = null
-) : ChipInfoCommon {
+) : TemporaryViewInfo {
     override fun getTimeoutMs() = state.timeout
 }
 
diff --git a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
index 75e48d2..30947e8 100644
--- a/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
+++ b/packages/SystemUI/src/com/android/systemui/navigationbar/NavigationBar.java
@@ -35,7 +35,6 @@
 
 import static com.android.internal.accessibility.common.ShortcutConstants.CHOOSER_PACKAGE_NAME;
 import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.HOME_BUTTON_LONG_PRESS_DURATION_MS;
-import static com.android.internal.config.sysui.SystemUiDeviceConfigFlags.NAV_BAR_HANDLE_FORCE_OPAQUE;
 import static com.android.systemui.navigationbar.NavBarHelper.transitionMode;
 import static com.android.systemui.recents.OverviewProxyService.OverviewProxyListener;
 import static com.android.systemui.shared.recents.utilities.Utilities.isTablet;
@@ -229,10 +228,7 @@
     private Locale mLocale;
     private int mLayoutDirection;
 
-    private boolean mAllowForceNavBarHandleOpaque;
-    private boolean mForceNavBarHandleOpaque;
     private Optional<Long> mHomeButtonLongPressDurationMs;
-    private boolean mIsCurrentUserSetup;
 
     /** @see android.view.WindowInsetsController#setSystemBarsAppearance(int, int) */
     private @Appearance int mAppearance;
@@ -379,37 +375,6 @@
         }
 
         @Override
-        public void onNavBarButtonAlphaChanged(float alpha, boolean animate) {
-            if (!mIsCurrentUserSetup) {
-                // If the current user is not yet setup, then don't update any button alphas
-                return;
-            }
-            if (QuickStepContract.isLegacyMode(mNavBarMode)) {
-                // Don't allow the bar buttons to be affected by the alpha
-                return;
-            }
-
-            ButtonDispatcher buttonDispatcher = null;
-            boolean forceVisible = false;
-            if (QuickStepContract.isGesturalMode(mNavBarMode)) {
-                // Disallow home handle animations when in gestural
-                animate = false;
-                forceVisible = mAllowForceNavBarHandleOpaque && mForceNavBarHandleOpaque;
-                buttonDispatcher = mView.getHomeHandle();
-                if (getBarTransitions() != null) {
-                    getBarTransitions().setBackgroundOverrideAlpha(alpha);
-                }
-            } else if (QuickStepContract.isSwipeUpMode(mNavBarMode)) {
-                buttonDispatcher = mView.getBackButton();
-            }
-            if (buttonDispatcher != null) {
-                buttonDispatcher.setVisibility(
-                        (forceVisible || alpha > 0) ? View.VISIBLE : View.INVISIBLE);
-                buttonDispatcher.setAlpha(forceVisible ? 1f : alpha, animate);
-            }
-        }
-
-        @Override
         public void onHomeRotationEnabled(boolean enabled) {
             mView.getRotationButtonController().setHomeRotationEnabled(enabled);
         }
@@ -456,15 +421,10 @@
             new DeviceConfig.OnPropertiesChangedListener() {
                 @Override
                 public void onPropertiesChanged(DeviceConfig.Properties properties) {
-                    if (properties.getKeyset().contains(NAV_BAR_HANDLE_FORCE_OPAQUE)) {
-                        mForceNavBarHandleOpaque = properties.getBoolean(
-                                NAV_BAR_HANDLE_FORCE_OPAQUE, /* defaultValue = */ true);
-                    }
-
                     if (properties.getKeyset().contains(HOME_BUTTON_LONG_PRESS_DURATION_MS)) {
                         mHomeButtonLongPressDurationMs = Optional.of(
-                            properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0)
-                        ).filter(duration -> duration != 0);
+                            properties.getLong(HOME_BUTTON_LONG_PRESS_DURATION_MS, 0))
+                                .filter(duration -> duration != 0);
                         if (mView != null) {
                             reconfigureHomeLongClick();
                         }
@@ -472,14 +432,6 @@
                 }
             };
 
-    private final DeviceProvisionedController.DeviceProvisionedListener mUserSetupListener =
-            new DeviceProvisionedController.DeviceProvisionedListener() {
-                @Override
-                public void onUserSetupChanged() {
-                    mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
-                }
-            };
-
     private final NotificationShadeDepthController.DepthListener mDepthListener =
             new NotificationShadeDepthController.DepthListener() {
                 boolean mHasBlurs;
@@ -660,12 +612,6 @@
         mCommandQueue.addCallback(this);
         mLongPressHomeEnabled = mNavBarHelper.getLongPressHomeEnabled();
         mNavBarHelper.init();
-        mAllowForceNavBarHandleOpaque = mContext.getResources().getBoolean(
-                R.bool.allow_force_nav_bar_handle_opaque);
-        mForceNavBarHandleOpaque = mDeviceConfigProxy.getBoolean(
-                DeviceConfig.NAMESPACE_SYSTEMUI,
-                NAV_BAR_HANDLE_FORCE_OPAQUE,
-                /* defaultValue = */ true);
         mHomeButtonLongPressDurationMs = Optional.of(mDeviceConfigProxy.getLong(
                 DeviceConfig.NAMESPACE_SYSTEMUI,
                 HOME_BUTTON_LONG_PRESS_DURATION_MS,
@@ -685,8 +631,6 @@
         // Respect the latest disabled-flags.
         mCommandQueue.recomputeDisableFlags(mDisplayId, false);
 
-        mIsCurrentUserSetup = mDeviceProvisionedController.isCurrentUserSetup();
-        mDeviceProvisionedController.addCallback(mUserSetupListener);
         mNotificationShadeDepthController.addListener(mDepthListener);
     }
 
@@ -698,7 +642,6 @@
 
         mNavBarHelper.removeNavTaskStateUpdater(mNavbarTaskbarStateUpdater);
         mNavBarHelper.destroy();
-        mDeviceProvisionedController.removeCallback(mUserSetupListener);
         mNotificationShadeDepthController.removeListener(mDepthListener);
 
         mDeviceConfigProxy.removeOnPropertiesChangedListener(mOnPropertiesChangedListener);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
index 56298fa..920f463 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSAnimator.java
@@ -16,6 +16,7 @@
 
 import android.animation.TimeInterpolator;
 import android.animation.ValueAnimator;
+import android.annotation.NonNull;
 import android.util.Log;
 import android.util.Pair;
 import android.util.SparseArray;
@@ -30,15 +31,11 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.qs.QSTile;
 import com.android.systemui.plugins.qs.QSTileView;
-import com.android.systemui.qs.PagedTileLayout.PageListener;
-import com.android.systemui.qs.QSHost.Callback;
 import com.android.systemui.qs.QSPanel.QSTileLayout;
 import com.android.systemui.qs.TouchAnimator.Builder;
-import com.android.systemui.qs.TouchAnimator.Listener;
 import com.android.systemui.qs.dagger.QSScope;
 import com.android.systemui.qs.tileimpl.HeightOverrideable;
 import com.android.systemui.tuner.TunerService;
-import com.android.systemui.tuner.TunerService.Tunable;
 
 import java.util.ArrayList;
 import java.util.Collection;
@@ -47,16 +44,26 @@
 
 import javax.inject.Inject;
 
-/** */
+/**
+ * Performs the animated transition between the QQS and QS views.
+ *
+ * <p>The transition is driven externally via {@link #setPosition(float)}, where 0 is a fully
+ * collapsed QQS and one a fully expanded QS.
+ *
+ * <p>This implementation maintains a set of {@code TouchAnimator} to transition the properties of
+ * views both in QQS and QS. These {@code TouchAnimator} are re-created lazily if contents of either
+ * view change, see {@link #requestAnimatorUpdate()}.
+ *
+ * <p>During the transition, both QS and QQS are visible. For overlapping tiles (Whenever the QS
+ * shows the first page), the corresponding QS tiles are hidden until QS is fully expanded.
+ */
 @QSScope
-public class QSAnimator implements Callback, PageListener, Listener, OnLayoutChangeListener,
-        OnAttachStateChangeListener, Tunable {
+public class QSAnimator implements QSHost.Callback, PagedTileLayout.PageListener,
+        TouchAnimator.Listener, OnLayoutChangeListener,
+        OnAttachStateChangeListener {
 
     private static final String TAG = "QSAnimator";
 
-    private static final String ALLOW_FANCY_ANIMATION = "sysui_qs_fancy_anim";
-    private static final String MOVE_FULL_ROWS = "sysui_qs_move_whole_rows";
-
     private static final float EXPANDED_TILE_DELAY = .86f;
     //Non first page delays
     private static final float QS_TILE_LABEL_FADE_OUT_START = 0.15f;
@@ -65,7 +72,6 @@
 
     public static final float SHORT_PARALLAX_AMOUNT = 0.1f;
 
-
     /**
      * List of all views that will be reset when clearing animation state
      * see {@link #clearAnimationState()} }
@@ -125,14 +131,11 @@
     private boolean mNeedsAnimatorUpdate = false;
     private boolean mOnKeyguard;
 
-    private boolean mAllowFancy;
-    private boolean mFullRows;
     private int mNumQuickTiles;
     private int mLastQQSTileHeight;
     private float mLastPosition;
     private final QSTileHost mHost;
     private final Executor mExecutor;
-    private final TunerService mTunerService;
     private boolean mShowCollapsedOnKeyguard;
     private boolean mTranslateWhileExpanding;
     private int mQQSTop;
@@ -153,7 +156,6 @@
         mQuickStatusBarHeader = quickStatusBarHeader;
         mHost = qsTileHost;
         mExecutor = executor;
-        mTunerService = tunerService;
         mQSExpansionPathInterpolator = qsExpansionPathInterpolator;
         mHost.addCallback(this);
         mQsPanelController.addOnAttachStateChangeListener(this);
@@ -199,7 +201,6 @@
         setCurrentPosition();
     }
 
-
     private void setCurrentPosition() {
         setPosition(mLastPosition);
     }
@@ -210,30 +211,15 @@
     }
 
     @Override
-    public void onViewAttachedToWindow(@Nullable View v) {
-        mTunerService.addTunable(this, ALLOW_FANCY_ANIMATION,
-                MOVE_FULL_ROWS);
-    }
-
-    @Override
-    public void onViewDetachedFromWindow(View v) {
-        mHost.removeCallback(this);
-        mTunerService.removeTunable(this);
-    }
-
-    @Override
-    public void onTuningChanged(String key, String newValue) {
-        if (ALLOW_FANCY_ANIMATION.equals(key)) {
-            mAllowFancy = TunerService.parseIntegerSwitch(newValue, true);
-            if (!mAllowFancy) {
-                clearAnimationState();
-            }
-        } else if (MOVE_FULL_ROWS.equals(key)) {
-            mFullRows = TunerService.parseIntegerSwitch(newValue, true);
-        }
+    public void onViewAttachedToWindow(@NonNull View view) {
         updateAnimators();
     }
 
+    @Override
+    public void onViewDetachedFromWindow(@NonNull View v) {
+        mHost.removeCallback(this);
+    }
+
     private void addNonFirstPageAnimators(int page) {
         Pair<HeightExpansionAnimator, TouchAnimator> pair = createSecondaryPageAnimators(page);
         if (pair != null) {
@@ -339,8 +325,7 @@
                 View view = mQs.getView();
 
                 // This case: less tiles to animate in small displays.
-                if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()
-                        && mAllowFancy) {
+                if (count < mQuickQSPanelController.getTileLayout().getNumVisibleTiles()) {
                     // Quick tiles.
                     QSTileView quickTileView = mQuickQSPanelController.getTileView(tile);
                     if (quickTileView == null) continue;
@@ -422,7 +407,7 @@
                     mAnimatedQsViews.add(tileView);
                     mAllViews.add(quickTileView);
                     mAllViews.add(quickTileView.getSecondaryLabel());
-                } else if (mFullRows && isIconInAnimatedRow(count)) {
+                } else if (isIconInAnimatedRow(count)) {
 
                     firstPageBuilder.addFloat(tileView, "translationY", -heightDiff, 0);
 
@@ -457,44 +442,42 @@
             }
         }
 
-        if (mAllowFancy) {
-            animateBrightnessSlider(firstPageBuilder);
+        animateBrightnessSlider(firstPageBuilder);
 
-            mFirstPageAnimator = firstPageBuilder
-                    // Fade in the tiles/labels as we reach the final position.
-                    .addFloat(tileLayout, "alpha", 0, 1)
-                    .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
-                    .setListener(this)
-                    .build();
+        mFirstPageAnimator = firstPageBuilder
+                // Fade in the tiles/labels as we reach the final position.
+                .addFloat(tileLayout, "alpha", 0, 1)
+                .addFloat(quadraticInterpolatorBuilder.build(), "position", 0, 1)
+                .setListener(this)
+                .build();
 
-            // Fade in the media player as we reach the final position
-            Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
-            if (mQsPanelController.shouldUseHorizontalLayout()
-                    && mQsPanelController.mMediaHost.hostView != null) {
-                builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
-            } else {
-                // In portrait, media view should always be visible
-                mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
-            }
-            mAllPagesDelayedAnimator = builder.build();
-            translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
-            qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
-            translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
-            if (mOnFirstPage) {
-                // Only recreate this animator if we're in the first page. That way we know that
-                // the first page is attached and has the proper positions/measures.
-                mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
-            }
-            mTranslationYAnimator = translationYBuilder.build();
-            mTranslationXAnimator = translationXBuilder.build();
-            if (mQQSTileHeightAnimator != null) {
-                mQQSTileHeightAnimator.setInterpolator(
-                        mQSExpansionPathInterpolator.getYInterpolator());
-            }
-            if (mOtherFirstPageTilesHeightAnimator != null) {
-                mOtherFirstPageTilesHeightAnimator.setInterpolator(
-                        mQSExpansionPathInterpolator.getYInterpolator());
-            }
+        // Fade in the media player as we reach the final position
+        Builder builder = new Builder().setStartDelay(EXPANDED_TILE_DELAY);
+        if (mQsPanelController.shouldUseHorizontalLayout()
+                && mQsPanelController.mMediaHost.hostView != null) {
+            builder.addFloat(mQsPanelController.mMediaHost.hostView, "alpha", 0, 1);
+        } else {
+            // In portrait, media view should always be visible
+            mQsPanelController.mMediaHost.hostView.setAlpha(1.0f);
+        }
+        mAllPagesDelayedAnimator = builder.build();
+        translationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+        qqsTranslationYBuilder.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
+        translationXBuilder.setInterpolator(mQSExpansionPathInterpolator.getXInterpolator());
+        if (mOnFirstPage) {
+            // Only recreate this animator if we're in the first page. That way we know that
+            // the first page is attached and has the proper positions/measures.
+            mQQSTranslationYAnimator = qqsTranslationYBuilder.build();
+        }
+        mTranslationYAnimator = translationYBuilder.build();
+        mTranslationXAnimator = translationXBuilder.build();
+        if (mQQSTileHeightAnimator != null) {
+            mQQSTileHeightAnimator.setInterpolator(
+                    mQSExpansionPathInterpolator.getYInterpolator());
+        }
+        if (mOtherFirstPageTilesHeightAnimator != null) {
+            mOtherFirstPageTilesHeightAnimator.setInterpolator(
+                    mQSExpansionPathInterpolator.getYInterpolator());
         }
         mNonfirstPageAlphaAnimator = nonFirstPageAlphaBuilder
                 .addFloat(mQuickQsPanel, "alpha", 1, 0)
@@ -568,7 +551,7 @@
 
             if (animator == null) {
                 animator = new HeightExpansionAnimator(
-                                this, mLastQQSTileHeight, tileView.getMeasuredHeight());
+                        this, mLastQQSTileHeight, tileView.getMeasuredHeight());
                 animator.setInterpolator(mQSExpansionPathInterpolator.getYInterpolator());
             }
             animator.addView(tileView);
@@ -639,7 +622,7 @@
     }
 
     private void getRelativePositionInt(int[] loc1, View view, View parent) {
-        if(view == parent || view == null) return;
+        if (view == parent || view == null) return;
         // Ignore tile pages as they can have some offset we don't want to take into account in
         // RTL.
         if (!isAPage(view)) {
@@ -672,7 +655,6 @@
             }
         }
         mLastPosition = position;
-        if (!mAllowFancy) return;
         if (mOnFirstPage) {
             mQuickQsPanel.setAlpha(1);
             mFirstPageAnimator.setPosition(position);
@@ -806,30 +788,31 @@
 
         private final ValueAnimator.AnimatorUpdateListener mUpdateListener =
                 new ValueAnimator.AnimatorUpdateListener() {
-            float mLastT = -1;
-            @Override
-            public void onAnimationUpdate(ValueAnimator valueAnimator) {
-                float t = valueAnimator.getAnimatedFraction();
-                final int viewCount = mViews.size();
-                int height = (Integer) valueAnimator.getAnimatedValue();
-                for (int i = 0; i < viewCount; i++) {
-                    View v = mViews.get(i);
-                    if (v instanceof HeightOverrideable) {
-                        ((HeightOverrideable) v).setHeightOverride(height);
-                    } else {
-                        v.setBottom(v.getTop() + height);
+                    float mLastT = -1;
+
+                    @Override
+                    public void onAnimationUpdate(ValueAnimator valueAnimator) {
+                        float t = valueAnimator.getAnimatedFraction();
+                        final int viewCount = mViews.size();
+                        int height = (Integer) valueAnimator.getAnimatedValue();
+                        for (int i = 0; i < viewCount; i++) {
+                            View v = mViews.get(i);
+                            if (v instanceof HeightOverrideable) {
+                                ((HeightOverrideable) v).setHeightOverride(height);
+                            } else {
+                                v.setBottom(v.getTop() + height);
+                            }
+                        }
+                        if (t == 0f) {
+                            mListener.onAnimationAtStart();
+                        } else if (t == 1f) {
+                            mListener.onAnimationAtEnd();
+                        } else if (mLastT <= 0 || mLastT == 1) {
+                            mListener.onAnimationStarted();
+                        }
+                        mLastT = t;
                     }
-                }
-                if (t == 0f) {
-                    mListener.onAnimationAtStart();
-                } else if (t == 1f) {
-                    mListener.onAnimationAtEnd();
-                } else if (mLastT <= 0 || mLastT == 1) {
-                    mListener.onAnimationStarted();
-                }
-                mLastT = t;
-            }
-        };
+                };
 
         HeightExpansionAnimator(TouchAnimator.Listener listener, int startHeight, int endHeight) {
             mListener = listener;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
index b20d7ba..67bf300 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooter.java
@@ -97,7 +97,8 @@
         super(rootView);
         mFooterText = mView.findViewById(R.id.footer_text);
         mPrimaryFooterIcon = mView.findViewById(R.id.primary_footer_icon);
-        mFooterIcon = new Icon.Resource(R.drawable.ic_info_outline);
+        mFooterIcon = new Icon.Resource(
+                R.drawable.ic_info_outline, /* contentDescription= */ null);
         mContext = rootView.getContext();
         mSecurityController = securityController;
         mMainHandler = mainHandler;
diff --git a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
index f632274..bd75c75 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
+++ b/packages/SystemUI/src/com/android/systemui/qs/QSSecurityFooterUtils.java
@@ -75,6 +75,7 @@
 import com.android.systemui.R;
 import com.android.systemui.animation.DialogCuj;
 import com.android.systemui.animation.DialogLaunchAnimator;
+import com.android.systemui.common.shared.model.ContentDescription;
 import com.android.systemui.common.shared.model.Icon;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Application;
@@ -243,16 +244,17 @@
                 isWorkProfileOn).toString();
 
         Icon icon;
+        ContentDescription contentDescription = null;
         if (isParentalControlsEnabled) {
-            icon = new Icon.Loaded(securityModel.getDeviceAdminIcon());
+            icon = new Icon.Loaded(securityModel.getDeviceAdminIcon(), contentDescription);
         } else if (vpnName != null || vpnNameWorkProfile != null) {
             if (securityModel.isVpnBranded()) {
-                icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn);
+                icon = new Icon.Resource(R.drawable.stat_sys_branded_vpn, contentDescription);
             } else {
-                icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic);
+                icon = new Icon.Resource(R.drawable.stat_sys_vpn_ic, contentDescription);
             }
         } else {
-            icon = new Icon.Resource(R.drawable.ic_info_outline);
+            icon = new Icon.Resource(R.drawable.ic_info_outline, contentDescription);
         }
 
         return new SecurityButtonConfig(icon, text, isClickable);
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
index 8dd506e..28ddead 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/binder/FooterActionsViewBinder.kt
@@ -31,7 +31,6 @@
 import androidx.lifecycle.lifecycleScope
 import androidx.lifecycle.repeatOnLifecycle
 import com.android.systemui.R
-import com.android.systemui.common.ui.binder.ContentDescriptionViewBinder
 import com.android.systemui.common.ui.binder.IconViewBinder
 import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.people.ui.view.PeopleViewBinder.bind
@@ -233,10 +232,8 @@
 
         val icon = model.icon
         val iconView = button.icon
-        val contentDescription = model.contentDescription
 
         IconViewBinder.bind(icon, iconView)
-        ContentDescriptionViewBinder.bind(contentDescription, iconView)
         if (model.iconTint != null) {
             iconView.setColorFilter(model.iconTint, PorterDuff.Mode.SRC_IN)
         } else {
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
index 4c0879e..2ad0513 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsButtonViewModel.kt
@@ -18,7 +18,6 @@
 
 import android.annotation.DrawableRes
 import android.view.View
-import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 
 /**
@@ -29,7 +28,6 @@
     val icon: Icon,
     val iconTint: Int?,
     @DrawableRes val background: Int,
-    val contentDescription: ContentDescription,
     // TODO(b/230830644): Replace View by an Expandable interface that can expand in either dialog
     // or activity.
     val onClick: (View) -> Unit,
diff --git a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
index b556a3e..a935338 100644
--- a/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModel.kt
@@ -138,10 +138,12 @@
     /** The model for the settings button. */
     val settings: FooterActionsButtonViewModel =
         FooterActionsButtonViewModel(
-            Icon.Resource(R.drawable.ic_settings),
+            Icon.Resource(
+                R.drawable.ic_settings,
+                ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+            ),
             iconTint = null,
             R.drawable.qs_footer_action_circle,
-            ContentDescription.Resource(R.string.accessibility_quick_settings_settings),
             this::onSettingsButtonClicked,
         )
 
@@ -149,14 +151,16 @@
     val power: FooterActionsButtonViewModel? =
         if (showPowerButton) {
             FooterActionsButtonViewModel(
-                Icon.Resource(android.R.drawable.ic_lock_power_off),
+                Icon.Resource(
+                    android.R.drawable.ic_lock_power_off,
+                    ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+                ),
                 iconTint =
                     Utils.getColorAttrDefaultColor(
                         context,
                         com.android.internal.R.attr.textColorOnAccent,
                     ),
                 R.drawable.qs_footer_action_circle_color,
-                ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu),
                 this::onPowerButtonClicked,
             )
         } else {
@@ -252,10 +256,12 @@
             }
 
         return FooterActionsButtonViewModel(
-            Icon.Loaded(icon),
+            Icon.Loaded(
+                icon,
+                ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
+            ),
             iconTint,
             R.drawable.qs_footer_action_circle,
-            ContentDescription.Loaded(userSwitcherContentDescription(status.currentUserName)),
             this::onUserSwitcherClicked,
         )
     }
diff --git a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
index 30862b7..3788ad9 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/OverviewProxyService.java
@@ -61,6 +61,7 @@
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.PatternMatcher;
+import android.os.Process;
 import android.os.RemoteException;
 import android.os.SystemClock;
 import android.os.UserHandle;
@@ -174,7 +175,6 @@
     private boolean mBound;
     private boolean mIsEnabled;
     private int mCurrentBoundedUserId = -1;
-    private float mNavBarButtonAlpha;
     private boolean mInputFocusTransferStarted;
     private float mInputFocusTransferStartY;
     private long mInputFocusTransferStartMillis;
@@ -296,12 +296,6 @@
         }
 
         @Override
-        public void setNavBarButtonAlpha(float alpha, boolean animate) {
-            verifyCallerAndClearCallingIdentityPostMain("setNavBarButtonAlpha", () ->
-                    notifyNavBarButtonAlphaChanged(alpha, animate));
-        }
-
-        @Override
         public void onAssistantProgress(@FloatRange(from = 0.0, to = 1.0) float progress) {
             verifyCallerAndClearCallingIdentityPostMain("onAssistantProgress", () ->
                     notifyAssistantProgress(progress));
@@ -581,6 +575,12 @@
             AssistUtils assistUtils,
             DumpManager dumpManager) {
         super(broadcastDispatcher);
+
+        // b/241601880: This component shouldn't be running for a non-primary user
+        if (!Process.myUserHandle().equals(UserHandle.SYSTEM)) {
+            Log.e(TAG_OPS, "Unexpected initialization for non-primary user", new Throwable());
+        }
+
         mContext = context;
         mPipOptional = pipOptional;
         mCentralSurfacesOptionalLazy = centralSurfacesOptionalLazy;
@@ -603,9 +603,6 @@
         mBackAnimation = backAnimation;
         mUiEventLogger = uiEventLogger;
 
-        // Assumes device always starts with back button until launcher tells it that it does not
-        mNavBarButtonAlpha = 1.0f;
-
         dumpManager.registerDumpable(getClass().getSimpleName(), this);
 
         // Listen for nav bar mode changes
@@ -807,7 +804,6 @@
             mConnectionCallbacks.add(listener);
         }
         listener.onConnectionChanged(mOverviewProxy != null);
-        listener.onNavBarButtonAlphaChanged(mNavBarButtonAlpha, false);
     }
 
     @Override
@@ -837,17 +833,10 @@
         if (mOverviewProxy != null) {
             mOverviewProxy.asBinder().unlinkToDeath(mOverviewServiceDeathRcpt, 0);
             mOverviewProxy = null;
-            notifyNavBarButtonAlphaChanged(1f, false /* animate */);
             notifyConnectionChanged();
         }
     }
 
-    private void notifyNavBarButtonAlphaChanged(float alpha, boolean animate) {
-        for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
-            mConnectionCallbacks.get(i).onNavBarButtonAlphaChanged(alpha, animate);
-        }
-    }
-
     private void notifyHomeRotationEnabled(boolean enabled) {
         for (int i = mConnectionCallbacks.size() - 1; i >= 0; --i) {
             mConnectionCallbacks.get(i).onHomeRotationEnabled(enabled);
@@ -1076,7 +1065,6 @@
         pw.print("  mInputFocusTransferStartMillis="); pw.println(mInputFocusTransferStartMillis);
         pw.print("  mWindowCornerRadius="); pw.println(mWindowCornerRadius);
         pw.print("  mSupportsRoundedCornersOnWindows="); pw.println(mSupportsRoundedCornersOnWindows);
-        pw.print("  mNavBarButtonAlpha="); pw.println(mNavBarButtonAlpha);
         pw.print("  mActiveNavBarRegion="); pw.println(mActiveNavBarRegion);
         pw.print("  mNavBarMode="); pw.println(mNavBarMode);
         mSysUiState.dump(pw, args);
@@ -1091,8 +1079,6 @@
         default void onQuickScrubStarted() {}
         /** Notify the recents app (overview) is started by 3-button navigation. */
         default void onToggleRecentApps() {}
-        /** Notify changes in the nav bar button alpha */
-        default void onNavBarButtonAlphaChanged(float alpha, boolean animate) {}
         default void onHomeRotationEnabled(boolean enabled) {}
         default void onTaskbarStatusUpdated(boolean visible, boolean stashed) {}
         default void onTaskbarAutohideSuspend(boolean suspend) {}
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
index 91c6a9c..c3b265f 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationPanelViewController.java
@@ -117,7 +117,6 @@
 import com.android.systemui.camera.CameraGestureHelper;
 import com.android.systemui.classifier.Classifier;
 import com.android.systemui.classifier.FalsingCollector;
-import com.android.systemui.controls.dagger.ControlsComponent;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.DisplayId;
 import com.android.systemui.dagger.qualifiers.Main;
@@ -140,7 +139,6 @@
 import com.android.systemui.plugins.qs.QS;
 import com.android.systemui.plugins.statusbar.StatusBarStateController;
 import com.android.systemui.plugins.statusbar.StatusBarStateController.StateListener;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
 import com.android.systemui.screenrecord.RecordingController;
 import com.android.systemui.shade.transition.ShadeTransitionController;
 import com.android.systemui.shared.system.QuickStepContract;
@@ -217,7 +215,6 @@
 import com.android.systemui.util.ListenerSet;
 import com.android.systemui.util.Utils;
 import com.android.systemui.util.time.SystemClock;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
 import com.android.wm.shell.animation.FlingAnimationUtils;
 
 import java.io.PrintWriter;
@@ -325,9 +322,6 @@
     private final FragmentService mFragmentService;
     private final ScrimController mScrimController;
     private final PrivacyDotViewController mPrivacyDotViewController;
-    private final QuickAccessWalletController mQuickAccessWalletController;
-    private final QRCodeScannerController mQRCodeScannerController;
-    private final ControlsComponent mControlsComponent;
     private final NotificationRemoteInputManager mRemoteInputManager;
 
     private final LockscreenShadeTransitionController mLockscreenShadeTransitionController;
@@ -696,8 +690,8 @@
     };
 
     private final CameraGestureHelper mCameraGestureHelper;
-    private final Provider<KeyguardBottomAreaViewModel> mKeyguardBottomAreaViewModelProvider;
-    private final Provider<KeyguardBottomAreaInteractor> mKeyguardBottomAreaInteractorProvider;
+    private final KeyguardBottomAreaViewModel mKeyguardBottomAreaViewModel;
+    private final KeyguardBottomAreaInteractor mKeyguardBottomAreaInteractor;
 
     @Inject
     public NotificationPanelViewController(NotificationPanelView view,
@@ -746,8 +740,6 @@
             NavigationModeController navigationModeController,
             FragmentService fragmentService,
             ContentResolver contentResolver,
-            QuickAccessWalletController quickAccessWalletController,
-            QRCodeScannerController qrCodeScannerController,
             RecordingController recordingController,
             LargeScreenShadeHeaderController largeScreenShadeHeaderController,
             ScreenOffAnimationController screenOffAnimationController,
@@ -755,7 +747,6 @@
             PanelExpansionStateManager panelExpansionStateManager,
             NotificationRemoteInputManager remoteInputManager,
             Optional<SysUIUnfoldComponent> unfoldComponent,
-            ControlsComponent controlsComponent,
             InteractionJankMonitor interactionJankMonitor,
             QsFrameTranslateController qsFrameTranslateController,
             SysUiState sysUiState,
@@ -768,8 +759,8 @@
             ShadeTransitionController shadeTransitionController,
             SystemClock systemClock,
             CameraGestureHelper cameraGestureHelper,
-            Provider<KeyguardBottomAreaViewModel> keyguardBottomAreaViewModelProvider,
-            Provider<KeyguardBottomAreaInteractor> keyguardBottomAreaInteractorProvider) {
+            KeyguardBottomAreaViewModel keyguardBottomAreaViewModel,
+            KeyguardBottomAreaInteractor keyguardBottomAreaInteractor) {
         super(view,
                 falsingManager,
                 dozeLog,
@@ -791,9 +782,6 @@
         mVibratorHelper = vibratorHelper;
         mKeyguardMediaController = keyguardMediaController;
         mPrivacyDotViewController = privacyDotViewController;
-        mQuickAccessWalletController = quickAccessWalletController;
-        mQRCodeScannerController = qrCodeScannerController;
-        mControlsComponent = controlsComponent;
         mMetricsLogger = metricsLogger;
         mConfigurationController = configurationController;
         mFlingAnimationUtilsBuilder = flingAnimationUtilsBuilder;
@@ -897,7 +885,7 @@
 
         mQsFrameTranslateController = qsFrameTranslateController;
         updateUserSwitcherFlags();
-        mKeyguardBottomAreaViewModelProvider = keyguardBottomAreaViewModelProvider;
+        mKeyguardBottomAreaViewModel = keyguardBottomAreaViewModel;
         onFinishInflate();
         keyguardUnlockAnimationController.addKeyguardUnlockAnimationListener(
                 new KeyguardUnlockAnimationController.KeyguardUnlockAnimationListener() {
@@ -951,7 +939,7 @@
                     }
                 });
         mCameraGestureHelper = cameraGestureHelper;
-        mKeyguardBottomAreaInteractorProvider = keyguardBottomAreaInteractorProvider;
+        mKeyguardBottomAreaInteractor = keyguardBottomAreaInteractor;
     }
 
     @VisibleForTesting
@@ -1276,17 +1264,7 @@
     }
 
     private void initBottomArea() {
-        if (mFeatureFlags.isEnabled(Flags.MODERN_BOTTOM_AREA)) {
-            mKeyguardBottomArea.init(mKeyguardBottomAreaViewModelProvider.get(), mFalsingManager);
-        } else {
-            // TODO(b/235403546): remove this method call when the new implementation is complete
-            //  and these are not needed.
-            mKeyguardBottomArea.init(
-                    mFalsingManager,
-                    mQuickAccessWalletController,
-                    mControlsComponent,
-                    mQRCodeScannerController);
-        }
+        mKeyguardBottomArea.init(mKeyguardBottomAreaViewModel, mFalsingManager);
     }
 
     @VisibleForTesting
@@ -1403,7 +1381,6 @@
         }
 
         mNotificationStackScrollLayoutController.setIntrinsicPadding(stackScrollerPadding);
-        mKeyguardBottomArea.setAntiBurnInOffsetX(mClockPositionResult.clockX);
 
         mStackScrollerMeasuringPass++;
         requestScrollerTopPaddingUpdate(animate);
@@ -1453,7 +1430,7 @@
                 mKeyguardStatusViewController.getClockBottom(mStatusBarHeaderHeightKeyguard),
                 mKeyguardStatusViewController.isClockTopAligned());
         mClockPositionAlgorithm.run(mClockPositionResult);
-        mKeyguardBottomAreaInteractorProvider.get().setClockPosition(
+        mKeyguardBottomAreaInteractor.setClockPosition(
                 mClockPositionResult.clockX, mClockPositionResult.clockY);
         boolean animate = mNotificationStackScrollLayoutController.isAddOrRemoveAnimationPending();
         boolean animateClock = (animate || mAnimateNextPositionUpdate) && shouldAnimateClockChange;
@@ -3296,8 +3273,7 @@
                 getExpandedFraction());
         float alpha = Math.min(expansionAlpha, 1 - computeQsExpansionFraction());
         alpha *= mBottomAreaShadeAlpha;
-        mKeyguardBottomArea.setComponentAlphas(alpha);
-        mKeyguardBottomAreaInteractorProvider.get().setAlpha(alpha);
+        mKeyguardBottomAreaInteractor.setAlpha(alpha);
         mLockIconViewController.setAlpha(alpha);
     }
 
@@ -3496,8 +3472,7 @@
     }
 
     private void updateDozingVisibilities(boolean animate) {
-        mKeyguardBottomArea.setDozing(mDozing, animate);
-        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+        mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
         if (!mDozing && animate) {
             mKeyguardStatusBarViewController.animateKeyguardStatusBarIn();
         }
@@ -3799,8 +3774,7 @@
         mView.setDozing(dozing);
         mDozing = dozing;
         mNotificationStackScrollLayoutController.setDozing(mDozing, animate);
-        mKeyguardBottomArea.setDozing(mDozing, animate);
-        mKeyguardBottomAreaInteractorProvider.get().setAnimateDozingTransitions(animate);
+        mKeyguardBottomAreaInteractor.setAnimateDozingTransitions(animate);
         mKeyguardStatusBarViewController.setDozing(mDozing);
 
         if (dozing) {
@@ -3849,7 +3823,6 @@
 
     public void dozeTimeTick() {
         mLockIconViewController.dozeTimeTick();
-        mKeyguardBottomArea.dozeTimeTick();
         mKeyguardStatusViewController.dozeTimeTick();
         if (mInterpolatedDarkAmount > 0) {
             positionClockAndNotifications();
@@ -4672,7 +4645,6 @@
         public void onDozeAmountChanged(float linearAmount, float amount) {
             mInterpolatedDarkAmount = amount;
             mLinearDarkAmount = linearAmount;
-            mKeyguardBottomArea.setDarkAmount(mInterpolatedDarkAmount);
             positionClockAndNotifications();
         }
     }
diff --git a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
index e93f605..abafecc 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
+++ b/packages/SystemUI/src/com/android/systemui/shade/NotificationShadeWindowViewController.java
@@ -29,6 +29,7 @@
 import android.view.ViewGroup;
 
 import com.android.internal.annotations.VisibleForTesting;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.LockIconViewController;
 import com.android.systemui.R;
 import com.android.systemui.classifier.FalsingCollector;
@@ -138,6 +139,13 @@
         return mView.findViewById(R.id.keyguard_bouncer_container);
     }
 
+    /**
+     * @return Location where to place the KeyguardMessageArea
+     */
+    public AuthKeyguardMessageArea getKeyguardMessageArea() {
+        return mView.findViewById(R.id.keyguard_message_area);
+    }
+
     /** Inflates the {@link R.layout#status_bar_expanded} layout and sets it up. */
     public void setupExpandedStatusBar() {
         mStackScrollLayout = mView.findViewById(R.id.notification_stack_scroller);
diff --git a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
index 621a609..9b3fe92 100644
--- a/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
+++ b/packages/SystemUI/src/com/android/systemui/shade/PulsingGestureListener.kt
@@ -26,6 +26,7 @@
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.dagger.CentralSurfacesComponent
 import com.android.systemui.tuner.TunerService
@@ -49,6 +50,7 @@
         private val dockManager: DockManager,
         private val centralSurfaces: CentralSurfaces,
         private val ambientDisplayConfiguration: AmbientDisplayConfiguration,
+        private val statusBarStateController: StatusBarStateController,
         tunerService: TunerService,
         dumpManager: DumpManager
 ) : GestureDetector.SimpleOnGestureListener(), Dumpable {
@@ -74,7 +76,8 @@
     }
 
     override fun onSingleTapConfirmed(e: MotionEvent): Boolean {
-        if (singleTapEnabled &&
+        if (statusBarStateController.isPulsing &&
+                singleTapEnabled &&
                 !dockManager.isDocked &&
                 !falsingManager.isProximityNear &&
                 !falsingManager.isFalseTap(FalsingManager.MODERATE_PENALTY)
@@ -89,7 +92,8 @@
     }
 
     override fun onDoubleTap(e: MotionEvent): Boolean {
-        if ((doubleTapEnabled || singleTapEnabled) &&
+        if (statusBarStateController.isPulsing &&
+                (doubleTapEnabled || singleTapEnabled) &&
                 !falsingManager.isProximityNear &&
                 !falsingManager.isFalseDoubleTap
         ) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
index 47dc5c2..408c61f 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/KeyguardIndicationController.java
@@ -19,6 +19,10 @@
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_MANAGEMENT_DISCLOSURE;
 import static android.app.admin.DevicePolicyResources.Strings.SystemUi.KEYGUARD_NAMED_MANAGEMENT_DISCLOSURE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_FIRST_FRAME_RECEIVED;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_GOOD;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_START;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK;
 import static android.hardware.biometrics.BiometricSourceType.FACE;
 import static android.view.View.GONE;
 import static android.view.View.VISIBLE;
@@ -78,6 +82,7 @@
 import com.android.settingslib.Utils;
 import com.android.settingslib.fuelgauge.BatteryStatus;
 import com.android.systemui.R;
+import com.android.systemui.biometrics.BiometricMessageDeferral;
 import com.android.systemui.broadcast.BroadcastDispatcher;
 import com.android.systemui.dagger.SysUISingleton;
 import com.android.systemui.dagger.qualifiers.Background;
@@ -178,7 +183,7 @@
     private boolean mBatteryPresent = true;
     private long mChargingTimeRemaining;
     private String mBiometricErrorMessageToShowOnScreenOn;
-    private final Set<Integer> mCoExFaceHelpMsgIdsToShow;
+    private final Set<Integer> mCoExFaceAcquisitionMsgIdsToShow;
     private boolean mInited;
 
     private KeyguardUpdateMonitorCallback mUpdateMonitorCallback;
@@ -249,11 +254,11 @@
         mScreenLifecycle = screenLifecycle;
         mScreenLifecycle.addObserver(mScreenObserver);
 
-        mCoExFaceHelpMsgIdsToShow = new HashSet<>();
+        mCoExFaceAcquisitionMsgIdsToShow = new HashSet<>();
         int[] msgIds = context.getResources().getIntArray(
                 com.android.systemui.R.array.config_face_help_msgs_when_fingerprint_enrolled);
         for (int msgId : msgIds) {
-            mCoExFaceHelpMsgIdsToShow.add(msgId);
+            mCoExFaceAcquisitionMsgIdsToShow.add(msgId);
         }
 
         mHandler = new Handler(mainLooper) {
@@ -687,11 +692,11 @@
     /**
      * Returns the indication text indicating that trust has been granted.
      *
-     * @return {@code null} or an empty string if a trust indication text should not be shown.
+     * @return an empty string if a trust indication text should not be shown.
      */
     @VisibleForTesting
     String getTrustGrantedIndication() {
-        return TextUtils.isEmpty(mTrustGrantedIndication)
+        return mTrustGrantedIndication == null
                 ? mContext.getString(R.string.keyguard_indication_trust_unlocked)
                 : mTrustGrantedIndication.toString();
     }
@@ -927,7 +932,7 @@
                 return; // udfps affordance is highlighted, no need to show action to unlock
             } else if (mKeyguardUpdateMonitor.isFaceEnrolled()) {
                 String message = mContext.getString(R.string.keyguard_retry);
-                mStatusBarKeyguardViewManager.showBouncerMessage(message, mInitialTextColorState);
+                mStatusBarKeyguardViewManager.setKeyguardMessage(message, mInitialTextColorState);
             }
         } else {
             final boolean canSkipBouncer = mKeyguardUpdateMonitor.getUserCanSkipBouncer(
@@ -990,7 +995,7 @@
                 mTopIndicationView == null ? null : mTopIndicationView.getText()));
         pw.println("  computePowerIndication(): " + computePowerIndication());
         pw.println("  trustGrantedIndication: " + getTrustGrantedIndication());
-        pw.println("    mCoExFaceHelpMsgIdsToShow=" + mCoExFaceHelpMsgIdsToShow);
+        pw.println("    mCoExFaceHelpMsgIdsToShow=" + mCoExFaceAcquisitionMsgIdsToShow);
         mRotateTextViewController.dump(pw, args);
     }
 
@@ -1048,6 +1053,17 @@
                 return;
             }
 
+            if (biometricSourceType == FACE) {
+                if (msgId == KeyguardUpdateMonitor.BIOMETRIC_HELP_FACE_NOT_RECOGNIZED) {
+                    mFaceAcquiredMessageDeferral.reset();
+                } else {
+                    mFaceAcquiredMessageDeferral.processMessage(msgId, helpString);
+                    if (mFaceAcquiredMessageDeferral.shouldDefer(msgId)) {
+                        return;
+                    }
+                }
+            }
+
             final boolean faceAuthSoftError = biometricSourceType == FACE
                     && msgId != BIOMETRIC_HELP_FACE_NOT_RECOGNIZED;
             final boolean faceAuthFailed = biometricSourceType == FACE
@@ -1055,19 +1071,24 @@
             final boolean isUnlockWithFingerprintPossible =
                     mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
                             getCurrentUser());
-            if (faceAuthSoftError
-                    && isUnlockWithFingerprintPossible
-                    && !mCoExFaceHelpMsgIdsToShow.contains(msgId)) {
+            final boolean isCoExFaceAcquisitionMessage =
+                    faceAuthSoftError && isUnlockWithFingerprintPossible;
+            if (isCoExFaceAcquisitionMessage && !mCoExFaceAcquisitionMsgIdsToShow.contains(msgId)) {
                 if (DEBUG) {
                     Log.d(TAG, "skip showing msgId=" + msgId + " helpString=" + helpString
                             + ", due to co-ex logic");
                 }
                 return;
             } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                mStatusBarKeyguardViewManager.showBouncerMessage(helpString,
+                mStatusBarKeyguardViewManager.setKeyguardMessage(helpString,
                         mInitialTextColorState);
             } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
-                if (faceAuthFailed && isUnlockWithFingerprintPossible) {
+                if (isCoExFaceAcquisitionMessage && msgId == FACE_ACQUIRED_TOO_DARK) {
+                    showBiometricMessage(
+                            helpString,
+                            mContext.getString(R.string.keyguard_suggest_fingerprint)
+                    );
+                } else if (faceAuthFailed && isUnlockWithFingerprintPossible) {
                     showBiometricMessage(
                             mContext.getString(R.string.keyguard_face_failed),
                             mContext.getString(R.string.keyguard_suggest_fingerprint)
@@ -1090,41 +1111,51 @@
         @Override
         public void onBiometricError(int msgId, String errString,
                 BiometricSourceType biometricSourceType) {
-            if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
-                return;
+            CharSequence deferredFaceMessage = null;
+            if (biometricSourceType == FACE) {
+                deferredFaceMessage = mFaceAcquiredMessageDeferral.getDeferredMessage();
+                mFaceAcquiredMessageDeferral.reset();
             }
 
-            if (biometricSourceType == FACE
-                    && msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS) {
-                // suppress all face UNABLE_TO_PROCESS errors
+            if (shouldSuppressBiometricError(msgId, biometricSourceType, mKeyguardUpdateMonitor)) {
                 if (DEBUG) {
-                    Log.d(TAG, "skip showing FACE_ERROR_UNABLE_TO_PROCESS errString="
-                            + errString);
+                    Log.d(TAG, "suppressingBiometricError msgId=" + msgId
+                            + " source=" + biometricSourceType);
                 }
-            } else if (biometricSourceType == FACE
-                    && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+            } else if (biometricSourceType == FACE && msgId == FaceManager.FACE_ERROR_TIMEOUT) {
+                // Co-ex: show deferred message OR nothing
                 if (mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
-                        getCurrentUser())) {
-                    // no message if fingerprint is also enrolled
+                        KeyguardUpdateMonitor.getCurrentUser())) {
+                    // if we're on the lock screen (bouncer isn't showing), show the deferred msg
+                    if (deferredFaceMessage != null
+                            && !mStatusBarKeyguardViewManager.isBouncerShowing()) {
+                        showBiometricMessage(
+                                deferredFaceMessage,
+                                mContext.getString(R.string.keyguard_suggest_fingerprint)
+                        );
+                        return;
+                    }
+
+                    // otherwise, don't show any message
                     if (DEBUG) {
                         Log.d(TAG, "skip showing FACE_ERROR_TIMEOUT due to co-ex logic");
                     }
                     return;
                 }
 
-                // The face timeout message is not very actionable, let's ask the user to
+                // Face-only: The face timeout message is not very actionable, let's ask the user to
                 // manually retry.
-                if (mStatusBarKeyguardViewManager.isShowingAlternateAuth()) {
-                    mStatusBarKeyguardViewManager.showBouncerMessage(
-                            mContext.getResources().getString(R.string.keyguard_try_fingerprint),
-                            mInitialTextColorState
+                if (deferredFaceMessage != null) {
+                    showBiometricMessage(
+                            deferredFaceMessage,
+                            mContext.getString(R.string.keyguard_unlock)
                     );
                 } else {
                     // suggest swiping up to unlock (try face auth again or swipe up to bouncer)
                     showActionToUnlock();
                 }
             } else if (mStatusBarKeyguardViewManager.isBouncerShowing()) {
-                mStatusBarKeyguardViewManager.showBouncerMessage(errString, mInitialTextColorState);
+                mStatusBarKeyguardViewManager.setKeyguardMessage(errString, mInitialTextColorState);
             } else if (mScreenLifecycle.getScreenState() == SCREEN_ON) {
                 showBiometricMessage(errString);
             } else {
@@ -1134,8 +1165,9 @@
 
         private boolean shouldSuppressBiometricError(int msgId,
                 BiometricSourceType biometricSourceType, KeyguardUpdateMonitor updateMonitor) {
-            if (biometricSourceType == BiometricSourceType.FINGERPRINT)
+            if (biometricSourceType == BiometricSourceType.FINGERPRINT) {
                 return shouldSuppressFingerprintError(msgId, updateMonitor);
+            }
             if (biometricSourceType == FACE) {
                 return shouldSuppressFaceError(msgId, updateMonitor);
             }
@@ -1161,7 +1193,8 @@
             // check of whether non-strong biometric is allowed
             return ((!updateMonitor.isUnlockingWithBiometricAllowed(true /* isStrongBiometric */)
                     && msgId != FaceManager.FACE_ERROR_LOCKOUT_PERMANENT)
-                    || msgId == FaceManager.FACE_ERROR_CANCELED);
+                    || msgId == FaceManager.FACE_ERROR_CANCELED
+                    || msgId == FaceManager.FACE_ERROR_UNABLE_TO_PROCESS);
         }
 
 
@@ -1200,10 +1233,11 @@
                 boolean isStrongBiometric) {
             super.onBiometricAuthenticated(userId, biometricSourceType, isStrongBiometric);
             hideBiometricMessage();
-
-            if (biometricSourceType == FACE
-                    && !mKeyguardBypassController.canBypass()) {
-                showActionToUnlock();
+            if (biometricSourceType == FACE) {
+                mFaceAcquiredMessageDeferral.reset();
+                if (!mKeyguardBypassController.canBypass()) {
+                    showActionToUnlock();
+                }
             }
         }
 
@@ -1274,4 +1308,14 @@
             }
         }
     };
+
+    private final BiometricMessageDeferral mFaceAcquiredMessageDeferral =
+            new BiometricMessageDeferral(
+                    Set.of(
+                            FACE_ACQUIRED_GOOD,
+                            FACE_ACQUIRED_START,
+                            FACE_ACQUIRED_FIRST_FRAME_RECEIVED
+                    ),
+                    Set.of(FACE_ACQUIRED_TOO_DARK)
+            );
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
index f6c4a31..cb13fcf 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShadeDepthController.kt
@@ -81,7 +81,6 @@
     }
 
     lateinit var root: View
-    private var blurRoot: View? = null
     private var keyguardAnimator: Animator? = null
     private var notificationAnimator: Animator? = null
     private var updateScheduled: Boolean = false
@@ -235,7 +234,7 @@
 
         val opaque = scrimsVisible && !blursDisabledForAppLaunch
         Trace.traceCounter(Trace.TRACE_TAG_APP, "shade_blur_radius", blur)
-        blurUtils.applyBlur(blurRoot?.viewRootImpl ?: root.viewRootImpl, blur, opaque)
+        blurUtils.applyBlur(root.viewRootImpl, blur, opaque)
         lastAppliedBlur = blur
         wallpaperController.setNotificationShadeZoom(zoomOut)
         listeners.forEach {
@@ -271,7 +270,6 @@
                     override fun onAnimationEnd(animation: Animator?) {
                         keyguardAnimator = null
                         wakeAndUnlockBlurRadius = 0f
-                        scheduleUpdate()
                     }
                 })
                 start()
@@ -302,7 +300,6 @@
 
         override fun onDozeAmountChanged(linear: Float, eased: Float) {
             wakeAndUnlockBlurRadius = blurUtils.blurRadiusOfRatio(eased)
-            scheduleUpdate()
         }
     }
 
@@ -439,12 +436,11 @@
         shadeAnimation.animateTo(blurUtils.blurRadiusOfRatio(targetBlurNormalized).toInt())
     }
 
-    private fun scheduleUpdate(viewToBlur: View? = null) {
+    private fun scheduleUpdate() {
         if (updateScheduled) {
             return
         }
         updateScheduled = true
-        blurRoot = viewToBlur
         choreographer.postFrameCallback(updateBlurCallback)
     }
 
@@ -495,16 +491,11 @@
          */
         private var pendingRadius = -1
 
-        /**
-         * View on {@link Surface} that wants depth.
-         */
-        private var view: View? = null
-
         private var springAnimation = SpringAnimation(this, object :
                 FloatPropertyCompat<DepthAnimation>("blurRadius") {
             override fun setValue(rect: DepthAnimation?, value: Float) {
                 radius = value
-                scheduleUpdate(view)
+                scheduleUpdate()
             }
 
             override fun getValue(rect: DepthAnimation?): Float {
@@ -519,11 +510,10 @@
             springAnimation.addEndListener { _, _, _, _ -> pendingRadius = -1 }
         }
 
-        fun animateTo(newRadius: Int, viewToBlur: View? = null) {
-            if (pendingRadius == newRadius && view == viewToBlur) {
+        fun animateTo(newRadius: Int) {
+            if (pendingRadius == newRadius) {
                 return
             }
-            view = viewToBlur
             pendingRadius = newRadius
             springAnimation.animateToFinalPosition(newRadius.toFloat())
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
index cea3deb..41c0367 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/NotificationShelf.java
@@ -16,6 +16,8 @@
 
 package com.android.systemui.statusbar;
 
+import static com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress;
+
 import android.content.Context;
 import android.content.res.Configuration;
 import android.content.res.Resources;
@@ -90,6 +92,12 @@
         super(context, attrs);
     }
 
+    @VisibleForTesting
+    public NotificationShelf(Context context, AttributeSet attrs, boolean showNotificationShelf) {
+        super(context, attrs);
+        mShowNotificationShelf = showNotificationShelf;
+    }
+
     @Override
     @VisibleForTesting
     public void onFinishInflate() {
@@ -175,7 +183,11 @@
 
             if (ambientState.isExpansionChanging() && !ambientState.isOnKeyguard()) {
                 float expansion = ambientState.getExpansionFraction();
-                viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+                if (ambientState.isBouncerInTransit()) {
+                    viewState.alpha = aboutToShowBouncerProgress(expansion);
+                } else {
+                    viewState.alpha = ShadeInterpolation.getContentAlpha(expansion);
+                }
             } else {
                 viewState.alpha = 1f - ambientState.getHideAmount();
             }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
index 3627b40..52f4c1c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/collection/coordinator/BubbleCoordinator.java
@@ -144,11 +144,6 @@
         public void invalidateNotifications(String reason) {
             mNotifFilter.invalidateList(reason);
         }
-
-        @Override
-        public void maybeCancelSummary(NotificationEntry entry) {
-            // no-op
-        }
     };
 
     private boolean isInterceptingDismissal(NotificationEntry entry) {
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
index ea28452..ce465bc 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/AmbientState.java
@@ -23,6 +23,8 @@
 import android.content.Context;
 import android.util.MathUtils;
 
+import androidx.annotation.VisibleForTesting;
+
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
@@ -137,7 +139,17 @@
      * True right after we swipe up on lockscreen and have not finished the fling down that follows.
      * False when we stop flinging or leave lockscreen.
      */
-    private boolean mNeedFlingAfterLockscreenSwipeUp = false;
+    private boolean mIsFlingRequiredAfterLockScreenSwipeUp = false;
+
+    @VisibleForTesting
+    public boolean isFlingRequiredAfterLockScreenSwipeUp() {
+        return mIsFlingRequiredAfterLockScreenSwipeUp;
+    }
+
+    @VisibleForTesting
+    public void setFlingRequiredAfterLockScreenSwipeUp(boolean value) {
+        mIsFlingRequiredAfterLockScreenSwipeUp = value;
+    }
 
     /**
      * @return Height of the notifications panel without top padding when expansion completes.
@@ -181,7 +193,7 @@
     public void setSwipingUp(boolean isSwipingUp) {
         if (!isSwipingUp && mIsSwipingUp) {
             // Just stopped swiping up.
-            mNeedFlingAfterLockscreenSwipeUp = true;
+            mIsFlingRequiredAfterLockScreenSwipeUp = true;
         }
         mIsSwipingUp = isSwipingUp;
     }
@@ -196,10 +208,10 @@
     /**
      * @param isFlinging Whether we are flinging the shade open or closed.
      */
-    public void setIsFlinging(boolean isFlinging) {
+    public void setFlinging(boolean isFlinging) {
         if (isOnKeyguard() && !isFlinging && mIsFlinging) {
             // Just stopped flinging.
-            mNeedFlingAfterLockscreenSwipeUp = false;
+            mIsFlingRequiredAfterLockScreenSwipeUp = false;
         }
         mIsFlinging = isFlinging;
     }
@@ -508,7 +520,7 @@
 
     public void setStatusBarState(int statusBarState) {
         if (mStatusBarState != StatusBarState.KEYGUARD) {
-            mNeedFlingAfterLockscreenSwipeUp = false;
+            mIsFlingRequiredAfterLockScreenSwipeUp = false;
         }
         mStatusBarState = statusBarState;
     }
@@ -576,7 +588,7 @@
      * @return Whether we need to do a fling down after swiping up on lockscreen.
      */
     public boolean isFlingingAfterSwipeUpOnLockscreen() {
-        return mIsFlinging && mNeedFlingAfterLockscreenSwipeUp;
+        return mIsFlinging && mIsFlingRequiredAfterLockScreenSwipeUp;
     }
 
     /**
@@ -744,7 +756,8 @@
         pw.println("mIsSwipingUp=" + mIsSwipingUp);
         pw.println("mPanelTracking=" + mPanelTracking);
         pw.println("mIsFlinging=" + mIsFlinging);
-        pw.println("mNeedFlingAfterLockscreenSwipeUp=" + mNeedFlingAfterLockscreenSwipeUp);
+        pw.println("mIsFlingRequiredAfterLockScreenSwipeUp="
+                + mIsFlingRequiredAfterLockScreenSwipeUp);
         pw.println("mZDistanceBetweenElements=" + mZDistanceBetweenElements);
         pw.println("mBaseZHeight=" + mBaseZHeight);
     }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
index 1fb265f..5fbaa51 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayout.java
@@ -2794,10 +2794,9 @@
         if (mDebugRemoveAnimation) {
             Log.d(TAG, "generateRemove " + key
                     + "\nmIsExpanded " + mIsExpanded
-                    + "\nmAnimationsEnabled " + mAnimationsEnabled
-                    + "\n!invisible group " + !isChildInInvisibleGroup(child));
+                    + "\nmAnimationsEnabled " + mAnimationsEnabled);
         }
-        if (mIsExpanded && mAnimationsEnabled && !isChildInInvisibleGroup(child)) {
+        if (mIsExpanded && mAnimationsEnabled) {
             if (!mChildrenToAddAnimated.contains(child)) {
                 if (mDebugRemoveAnimation) {
                     Log.d(TAG, "needsAnimation = true " + key);
@@ -2845,26 +2844,6 @@
         return hasAddEvent && mAddedHeadsUpChildren.contains(child);
     }
 
-    // TODO (b/162832756): remove since this won't happen in new pipeline (we prune groups in
-    //  ShadeListBuilder)
-    /**
-     * @param child the child to query
-     * @return whether a view is not a top level child but a child notification and that group is
-     * not expanded
-     */
-    @ShadeViewRefactor(RefactorComponent.ADAPTER)
-    private boolean isChildInInvisibleGroup(View child) {
-        if (child instanceof ExpandableNotificationRow) {
-            ExpandableNotificationRow row = (ExpandableNotificationRow) child;
-            NotificationEntry groupSummary =
-                    mGroupMembershipManager.getGroupSummary(row.getEntry());
-            if (groupSummary != null && groupSummary.getRow() != row) {
-                return row.getVisibility() == View.INVISIBLE;
-            }
-        }
-        return false;
-    }
-
     /**
      * Updates the scroll position when a child was removed
      *
@@ -5042,7 +5021,7 @@
 
     @ShadeViewRefactor(RefactorComponent.SHADE_VIEW)
     public void setPanelFlinging(boolean flinging) {
-        mAmbientState.setIsFlinging(flinging);
+        mAmbientState.setFlinging(flinging);
         if (!flinging) {
             // re-calculate the stack height which was frozen while flinging
             updateStackPosition();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
index 20b6d0b..f37243a 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfaces.java
@@ -40,6 +40,7 @@
 
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.systemui.Dumpable;
 import com.android.systemui.animation.ActivityLaunchAnimator;
@@ -220,6 +221,9 @@
 
     ViewGroup getBouncerContainer();
 
+    /** Get the Keyguard Message Area that displays auth messages. */
+    AuthKeyguardMessageArea getKeyguardMessageArea();
+
     int getStatusBarHeight();
 
     void updateQsExpansionEnabled();
@@ -390,8 +394,6 @@
     void fadeKeyguardAfterLaunchTransition(Runnable beforeFading,
             Runnable endRunnable, Runnable cancelRunnable);
 
-    void fadeKeyguardWhilePulsing();
-
     void animateKeyguardUnoccluding();
 
     void startLaunchTransitionTimeout();
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
index 6426aef..cebb4b7 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/CentralSurfacesImpl.java
@@ -120,6 +120,7 @@
 import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
 import com.android.internal.statusbar.IStatusBarService;
 import com.android.internal.statusbar.RegisterStatusBarResult;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.FaceAuthApiRequestReason;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -1582,6 +1583,11 @@
     }
 
     @Override
+    public AuthKeyguardMessageArea getKeyguardMessageArea() {
+        return mNotificationShadeWindowViewController.getKeyguardMessageArea();
+    }
+
+    @Override
     public int getStatusBarHeight() {
         return mStatusBarWindowController.getStatusBarHeight();
     }
@@ -3019,19 +3025,6 @@
     }
 
     /**
-     * Fades the content of the Keyguard while we are dozing and makes it invisible when finished
-     * fading.
-     */
-    @Override
-    public void fadeKeyguardWhilePulsing() {
-        mNotificationPanelViewController.fadeOut(0, FADE_KEYGUARD_DURATION_PULSING,
-                ()-> {
-                hideKeyguard();
-                mStatusBarKeyguardViewManager.onKeyguardFadedAway();
-            }).start();
-    }
-
-    /**
      * Plays the animation when an activity that was occluding Keyguard goes away.
      */
     @Override
@@ -3320,14 +3313,12 @@
         // show the bouncer/lockscreen.
         if (!mKeyguardViewMediator.isHiding()
                 && !mKeyguardUnlockAnimationController.isPlayingCannedUnlockAnimation()) {
-            if (mState == StatusBarState.SHADE_LOCKED
-                    && mKeyguardUpdateMonitor.isUdfpsEnrolled()) {
+            if (mState == StatusBarState.SHADE_LOCKED) {
                 // shade is showing while locked on the keyguard, so go back to showing the
                 // lock screen where users can use the UDFPS affordance to enter the device
                 mStatusBarKeyguardViewManager.reset(true);
-            } else if ((mState == StatusBarState.KEYGUARD
-                    && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing())
-                    || mState == StatusBarState.SHADE_LOCKED) {
+            } else if (mState == StatusBarState.KEYGUARD
+                    && !mStatusBarKeyguardViewManager.bouncerIsOrWillBeShowing()) {
                 mStatusBarKeyguardViewManager.showGenericBouncer(true /* scrimmed */);
             }
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
index ddff7d8..24ce5e9 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/DozeServiceHost.java
@@ -28,8 +28,6 @@
 import android.view.MotionEvent;
 import android.view.View;
 
-import androidx.annotation.Nullable;
-
 import com.android.internal.annotations.VisibleForTesting;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.systemui.assist.AssistManager;
@@ -50,11 +48,9 @@
 import com.android.systemui.statusbar.notification.collection.NotificationEntry;
 import com.android.systemui.statusbar.policy.BatteryController;
 import com.android.systemui.statusbar.policy.DeviceProvisionedController;
-import com.android.systemui.unfold.FoldAodAnimationController;
-import com.android.systemui.unfold.SysUIUnfoldComponent;
+import com.android.systemui.util.Assert;
 
 import java.util.ArrayList;
-import java.util.Optional;
 
 import javax.inject.Inject;
 
@@ -80,8 +76,6 @@
     private final WakefulnessLifecycle mWakefulnessLifecycle;
     private final SysuiStatusBarStateController mStatusBarStateController;
     private final DeviceProvisionedController mDeviceProvisionedController;
-    @Nullable
-    private final FoldAodAnimationController mFoldAodAnimationController;
     private final HeadsUpManagerPhone mHeadsUpManagerPhone;
     private final BatteryController mBatteryController;
     private final ScrimController mScrimController;
@@ -114,7 +108,6 @@
             Lazy<AssistManager> assistManagerLazy,
             DozeScrimController dozeScrimController, KeyguardUpdateMonitor keyguardUpdateMonitor,
             PulseExpansionHandler pulseExpansionHandler,
-            Optional<SysUIUnfoldComponent> sysUIUnfoldComponent,
             NotificationShadeWindowController notificationShadeWindowController,
             NotificationWakeUpCoordinator notificationWakeUpCoordinator,
             AuthController authController,
@@ -138,8 +131,6 @@
         mNotificationWakeUpCoordinator = notificationWakeUpCoordinator;
         mAuthController = authController;
         mNotificationIconAreaController = notificationIconAreaController;
-        mFoldAodAnimationController = sysUIUnfoldComponent
-                .map(SysUIUnfoldComponent::getFoldAodAnimationController).orElse(null);
     }
 
     // TODO: we should try to not pass status bar in here if we can avoid it.
@@ -167,6 +158,7 @@
     }
 
     void firePowerSaveChanged(boolean active) {
+        Assert.isMainThread();
         for (Callback callback : mCallbacks) {
             callback.onPowerSaveChanged(active);
         }
@@ -177,6 +169,7 @@
             entry.setPulseSuppressed(true);
             mNotificationIconAreaController.updateAodNotificationIcons();
         };
+        Assert.isMainThread();
         for (Callback callback : mCallbacks) {
             callback.onNotificationAlerted(pulseSuppressedListener);
         }
@@ -193,11 +186,13 @@
 
     @Override
     public void addCallback(@NonNull Callback callback) {
+        Assert.isMainThread();
         mCallbacks.add(callback);
     }
 
     @Override
     public void removeCallback(@NonNull Callback callback) {
+        Assert.isMainThread();
         mCallbacks.remove(callback);
     }
 
@@ -212,12 +207,10 @@
     }
 
     void updateDozing() {
-        // When in wake-and-unlock while pulsing, keep dozing state until fully unlocked.
-        boolean
-                dozing =
-                mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD
-                        || mBiometricUnlockControllerLazy.get().getMode()
-                        == BiometricUnlockController.MODE_WAKE_AND_UNLOCK_PULSING;
+        Assert.isMainThread();
+
+        boolean dozing =
+                mDozingRequested && mStatusBarStateController.getState() == StatusBarState.KEYGUARD;
         // When in wake-and-unlock we may not have received a change to StatusBarState
         // but we still should not be dozing, manually set to false.
         if (mBiometricUnlockControllerLazy.get().getMode()
@@ -225,10 +218,10 @@
             dozing = false;
         }
 
-        mStatusBarStateController.setIsDozing(dozing);
-        if (mFoldAodAnimationController != null) {
-            mFoldAodAnimationController.setIsDozing(dozing);
+        for (Callback callback : mCallbacks) {
+            callback.onDozingChanged(dozing);
         }
+        mStatusBarStateController.setIsDozing(dozing);
     }
 
     @Override
@@ -452,6 +445,7 @@
             return;
         }
         mAlwaysOnSuppressed = suppressed;
+        Assert.isMainThread();
         for (Callback callback : mCallbacks) {
             callback.onAlwaysOnSuppressedChanged(suppressed);
         }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
deleted file mode 100644
index dc77d10..0000000
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.java
+++ /dev/null
@@ -1,682 +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
- */
-
-package com.android.systemui.statusbar.phone;
-
-import static com.android.internal.util.Preconditions.checkNotNull;
-import static com.android.systemui.controls.dagger.ControlsComponent.Visibility.AVAILABLE;
-import static com.android.systemui.doze.util.BurnInHelperKt.getBurnInOffset;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.DEFAULT_PAYMENT_APP_CHANGE;
-import static com.android.systemui.wallet.controller.QuickAccessWalletController.WalletChangeEvent.WALLET_PREFERENCE_CHANGE;
-
-import android.app.ActivityTaskManager;
-import android.app.admin.DevicePolicyManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.res.ColorStateList;
-import android.content.res.Configuration;
-import android.graphics.drawable.Drawable;
-import android.os.RemoteException;
-import android.os.UserHandle;
-import android.service.quickaccesswallet.GetWalletCardsError;
-import android.service.quickaccesswallet.GetWalletCardsResponse;
-import android.service.quickaccesswallet.QuickAccessWalletClient;
-import android.util.AttributeSet;
-import android.util.Log;
-import android.util.TypedValue;
-import android.view.View;
-import android.view.ViewGroup;
-import android.view.ViewPropertyAnimator;
-import android.view.WindowInsets;
-import android.widget.FrameLayout;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.annotation.Nullable;
-
-import com.android.settingslib.Utils;
-import com.android.systemui.Dependency;
-import com.android.systemui.R;
-import com.android.systemui.animation.ActivityLaunchAnimator;
-import com.android.systemui.animation.Interpolators;
-import com.android.systemui.controls.dagger.ControlsComponent;
-import com.android.systemui.controls.management.ControlsListingController;
-import com.android.systemui.controls.ui.ControlsActivity;
-import com.android.systemui.controls.ui.ControlsUiController;
-import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder;
-import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel;
-import com.android.systemui.plugins.ActivityStarter;
-import com.android.systemui.plugins.FalsingManager;
-import com.android.systemui.qrcodescanner.controller.QRCodeScannerController;
-import com.android.systemui.statusbar.policy.KeyguardStateController;
-import com.android.systemui.wallet.controller.QuickAccessWalletController;
-
-import java.util.ArrayList;
-import java.util.List;
-
-/**
- * Implementation for the bottom area of the Keyguard, including camera/phone affordance and status
- * text.
- */
-public class KeyguardBottomAreaView extends FrameLayout {
-
-    private static final String TAG = "CentralSurfaces/KeyguardBottomAreaView";
-    private static final int DOZE_ANIMATION_ELEMENT_DURATION = 250;
-
-    private ImageView mWalletButton;
-    private ImageView mQRCodeScannerButton;
-    private ImageView mControlsButton;
-    private boolean mHasCard = false;
-    private final WalletCardRetriever mCardRetriever = new WalletCardRetriever();
-    private QuickAccessWalletController mQuickAccessWalletController;
-    private QRCodeScannerController mQRCodeScannerController;
-    private ControlsComponent mControlsComponent;
-    private boolean mControlServicesAvailable = false;
-
-    @Nullable private View mAmbientIndicationArea;
-    private ViewGroup mIndicationArea;
-    private TextView mIndicationText;
-    private TextView mIndicationTextBottom;
-    private ViewGroup mOverlayContainer;
-
-    private ActivityStarter mActivityStarter;
-    private KeyguardStateController mKeyguardStateController;
-    private FalsingManager mFalsingManager;
-
-    private boolean mDozing;
-    private int mIndicationBottomMargin;
-    private int mIndicationPadding;
-    private float mDarkAmount;
-    private int mBurnInXOffset;
-    private int mBurnInYOffset;
-
-    private final ControlsListingController.ControlsListingCallback mListingCallback =
-            serviceInfos -> post(() -> {
-                boolean available = !serviceInfos.isEmpty();
-
-                if (available != mControlServicesAvailable) {
-                    mControlServicesAvailable = available;
-                    updateControlsVisibility();
-                    updateAffordanceColors();
-                }
-            });
-
-    private final KeyguardStateController.Callback mKeyguardStateCallback =
-            new KeyguardStateController.Callback() {
-        @Override
-        public void onKeyguardShowingChanged() {
-            if (mKeyguardStateController.isShowing()) {
-                if (mQuickAccessWalletController != null) {
-                    mQuickAccessWalletController.queryWalletCards(mCardRetriever);
-                }
-            }
-        }
-    };
-
-    @Nullable private KeyguardBottomAreaViewBinder.Binding mBinding;
-    private boolean mUsesBinder;
-
-    public KeyguardBottomAreaView(Context context) {
-        this(context, null);
-    }
-
-    public KeyguardBottomAreaView(Context context, AttributeSet attrs) {
-        this(context, attrs, 0);
-    }
-
-    public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr) {
-        this(context, attrs, defStyleAttr, 0);
-    }
-
-    public KeyguardBottomAreaView(Context context, AttributeSet attrs, int defStyleAttr,
-            int defStyleRes) {
-        super(context, attrs, defStyleAttr, defStyleRes);
-    }
-
-    /**
-     * Initializes the view.
-     */
-    public void init(
-            final KeyguardBottomAreaViewModel viewModel,
-            final FalsingManager falsingManager) {
-        Log.i(TAG, System.identityHashCode(this) + " initialized with a binder");
-        mUsesBinder = true;
-        mBinding = KeyguardBottomAreaViewBinder.bind(this, viewModel, falsingManager);
-    }
-
-    /**
-     * Initializes the {@link KeyguardBottomAreaView} with the given dependencies
-     *
-     * @deprecated Use
-     * {@link #init(KeyguardBottomAreaViewModel, FalsingManager)} instead
-     */
-    @Deprecated
-    public void init(
-            FalsingManager falsingManager,
-            QuickAccessWalletController controller,
-            ControlsComponent controlsComponent,
-            QRCodeScannerController qrCodeScannerController) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        Log.i(TAG, "initialized without a binder");
-        mFalsingManager = falsingManager;
-
-        mQuickAccessWalletController = controller;
-        mQuickAccessWalletController.setupWalletChangeObservers(
-                mCardRetriever, WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
-        mQuickAccessWalletController.updateWalletPreference();
-        mQuickAccessWalletController.queryWalletCards(mCardRetriever);
-        updateWalletVisibility();
-
-        mControlsComponent = controlsComponent;
-        mControlsComponent.getControlsListingController().ifPresent(
-                c -> c.addCallback(mListingCallback));
-
-        mQRCodeScannerController = qrCodeScannerController;
-        mQRCodeScannerController.registerQRCodeScannerChangeObservers(
-                QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
-                QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
-        updateQRCodeButtonVisibility();
-
-        updateAffordanceColors();
-    }
-
-    /**
-     * Initializes this instance of {@link KeyguardBottomAreaView} based on the given instance of
-     * another {@link KeyguardBottomAreaView}
-     */
-    public void initFrom(KeyguardBottomAreaView oldBottomArea) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        // if it exists, continue to use the original ambient indication container
-        // instead of the newly inflated one
-        if (mAmbientIndicationArea != null) {
-            // remove old ambient indication from its parent
-            View originalAmbientIndicationView =
-                    oldBottomArea.findViewById(R.id.ambient_indication_container);
-            ((ViewGroup) originalAmbientIndicationView.getParent())
-                    .removeView(originalAmbientIndicationView);
-
-            // remove current ambient indication from its parent (discard)
-            ViewGroup ambientIndicationParent = (ViewGroup) mAmbientIndicationArea.getParent();
-            int ambientIndicationIndex =
-                    ambientIndicationParent.indexOfChild(mAmbientIndicationArea);
-            ambientIndicationParent.removeView(mAmbientIndicationArea);
-
-            // add the old ambient indication to this view
-            ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex);
-            mAmbientIndicationArea = originalAmbientIndicationView;
-
-            // update burn-in offsets
-            dozeTimeTick();
-        }
-    }
-
-    @Override
-    protected void onFinishInflate() {
-        super.onFinishInflate();
-        if (mUsesBinder) {
-            return;
-        }
-
-        mOverlayContainer = findViewById(R.id.overlay_container);
-        mWalletButton = findViewById(R.id.wallet_button);
-        mQRCodeScannerButton = findViewById(R.id.qr_code_scanner_button);
-        mControlsButton = findViewById(R.id.controls_button);
-        mIndicationArea = findViewById(R.id.keyguard_indication_area);
-        mAmbientIndicationArea = findViewById(R.id.ambient_indication_container);
-        mIndicationText = findViewById(R.id.keyguard_indication_text);
-        mIndicationTextBottom = findViewById(R.id.keyguard_indication_text_bottom);
-        mIndicationBottomMargin = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_margin_bottom);
-        mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
-        mKeyguardStateController = Dependency.get(KeyguardStateController.class);
-        mKeyguardStateController.addCallback(mKeyguardStateCallback);
-        setClipChildren(false);
-        setClipToPadding(false);
-        mActivityStarter = Dependency.get(ActivityStarter.class);
-
-        mIndicationPadding = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_area_padding);
-        updateWalletVisibility();
-        updateQRCodeButtonVisibility();
-        updateControlsVisibility();
-    }
-
-    @Override
-    protected void onAttachedToWindow() {
-        super.onAttachedToWindow();
-        if (mUsesBinder) {
-            return;
-        }
-
-        final IntentFilter filter = new IntentFilter();
-        filter.addAction(DevicePolicyManager.ACTION_DEVICE_POLICY_MANAGER_STATE_CHANGED);
-        mKeyguardStateController.addCallback(mKeyguardStateCallback);
-    }
-
-    @Override
-    protected void onDetachedFromWindow() {
-        super.onDetachedFromWindow();
-        if (mUsesBinder) {
-            return;
-        }
-
-        mKeyguardStateController.removeCallback(mKeyguardStateCallback);
-
-        if (mQuickAccessWalletController != null) {
-            mQuickAccessWalletController.unregisterWalletChangeObservers(
-                    WALLET_PREFERENCE_CHANGE, DEFAULT_PAYMENT_APP_CHANGE);
-        }
-
-        if (mQRCodeScannerController != null) {
-            mQRCodeScannerController.unregisterQRCodeScannerChangeObservers(
-                    QRCodeScannerController.DEFAULT_QR_CODE_SCANNER_CHANGE,
-                    QRCodeScannerController.QR_CODE_SCANNER_PREFERENCE_CHANGE);
-        }
-
-        if (mControlsComponent != null) {
-            mControlsComponent.getControlsListingController().ifPresent(
-                    c -> c.removeCallback(mListingCallback));
-        }
-    }
-
-    @Override
-    protected void onConfigurationChanged(Configuration newConfig) {
-        super.onConfigurationChanged(newConfig);
-        if (mUsesBinder) {
-            if (mBinding != null) {
-                mBinding.onConfigurationChanged();
-            }
-            return;
-        }
-
-        mIndicationBottomMargin = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_margin_bottom);
-        mBurnInYOffset = getResources().getDimensionPixelSize(
-                R.dimen.default_burn_in_prevention_offset);
-        MarginLayoutParams mlp = (MarginLayoutParams) mIndicationArea.getLayoutParams();
-        if (mlp.bottomMargin != mIndicationBottomMargin) {
-            mlp.bottomMargin = mIndicationBottomMargin;
-            mIndicationArea.setLayoutParams(mlp);
-        }
-
-        // Respect font size setting.
-        mIndicationTextBottom.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.text_size_small_material));
-        mIndicationText.setTextSize(TypedValue.COMPLEX_UNIT_PX,
-                getResources().getDimensionPixelSize(
-                        com.android.internal.R.dimen.text_size_small_material));
-
-        ViewGroup.LayoutParams lp = mWalletButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
-        mWalletButton.setLayoutParams(lp);
-
-        lp = mQRCodeScannerButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
-        mQRCodeScannerButton.setLayoutParams(lp);
-
-        lp = mControlsButton.getLayoutParams();
-        lp.width = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_width);
-        lp.height = getResources().getDimensionPixelSize(R.dimen.keyguard_affordance_fixed_height);
-        mControlsButton.setLayoutParams(lp);
-
-        mIndicationPadding = getResources().getDimensionPixelSize(
-                R.dimen.keyguard_indication_area_padding);
-
-        updateWalletVisibility();
-        updateQRCodeButtonVisibility();
-        updateAffordanceColors();
-    }
-
-    private void updateWalletVisibility() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mDozing
-                || mQuickAccessWalletController == null
-                || !mQuickAccessWalletController.isWalletEnabled()
-                || !mHasCard) {
-            mWalletButton.setVisibility(GONE);
-
-            if (mControlsButton.getVisibility() == GONE) {
-                mIndicationArea.setPadding(0, 0, 0, 0);
-            }
-        } else {
-            mWalletButton.setVisibility(VISIBLE);
-            mWalletButton.setOnClickListener(this::onWalletClick);
-            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
-        }
-    }
-
-    private void updateControlsVisibility() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mControlsComponent == null) return;
-
-        mControlsButton.setImageResource(mControlsComponent.getTileImageId());
-        mControlsButton.setContentDescription(getContext()
-                .getString(mControlsComponent.getTileTitleId()));
-        updateAffordanceColors();
-
-        boolean hasFavorites = mControlsComponent.getControlsController()
-                .map(c -> c.getFavorites().size() > 0)
-                .orElse(false);
-        if (mDozing
-                || !hasFavorites
-                || !mControlServicesAvailable
-                || mControlsComponent.getVisibility() != AVAILABLE) {
-            mControlsButton.setVisibility(GONE);
-            if (mWalletButton.getVisibility() == GONE) {
-                mIndicationArea.setPadding(0, 0, 0, 0);
-            }
-        } else {
-            mControlsButton.setVisibility(VISIBLE);
-            mControlsButton.setOnClickListener(this::onControlsClick);
-            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
-        }
-    }
-
-    public void setDarkAmount(float darkAmount) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (darkAmount == mDarkAmount) {
-            return;
-        }
-        mDarkAmount = darkAmount;
-        dozeTimeTick();
-    }
-
-    /**
-     * Returns a list of animators to use to animate the indication areas.
-     */
-    public List<ViewPropertyAnimator> getIndicationAreaAnimators() {
-        if (mUsesBinder) {
-            return checkNotNull(mBinding).getIndicationAreaAnimators();
-        }
-
-        List<ViewPropertyAnimator> animators =
-                new ArrayList<>(mAmbientIndicationArea != null ? 2 : 1);
-        animators.add(mIndicationArea.animate());
-        if (mAmbientIndicationArea != null) {
-            animators.add(mAmbientIndicationArea.animate());
-        }
-        return animators;
-    }
-
-    @Override
-    public boolean hasOverlappingRendering() {
-        return false;
-    }
-
-    private void startFinishDozeAnimation() {
-        long delay = 0;
-        if (mWalletButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mWalletButton, delay);
-        }
-        if (mQRCodeScannerButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mQRCodeScannerButton, delay);
-        }
-        if (mControlsButton.getVisibility() == View.VISIBLE) {
-            startFinishDozeAnimationElement(mControlsButton, delay);
-        }
-    }
-
-    private void startFinishDozeAnimationElement(View element, long delay) {
-        element.setAlpha(0f);
-        element.setTranslationY(element.getHeight() / 2);
-        element.animate()
-                .alpha(1f)
-                .translationY(0f)
-                .setInterpolator(Interpolators.LINEAR_OUT_SLOW_IN)
-                .setStartDelay(delay)
-                .setDuration(DOZE_ANIMATION_ELEMENT_DURATION);
-    }
-
-    public void setDozing(boolean dozing, boolean animate) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        mDozing = dozing;
-
-        updateWalletVisibility();
-        updateControlsVisibility();
-        updateQRCodeButtonVisibility();
-
-        if (dozing) {
-            mOverlayContainer.setVisibility(INVISIBLE);
-        } else {
-            mOverlayContainer.setVisibility(VISIBLE);
-            if (animate) {
-                startFinishDozeAnimation();
-            }
-        }
-    }
-
-    public void dozeTimeTick() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        int burnInYOffset = getBurnInOffset(mBurnInYOffset * 2, false /* xAxis */)
-                - mBurnInYOffset;
-        mIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
-        if (mAmbientIndicationArea != null) {
-            mAmbientIndicationArea.setTranslationY(burnInYOffset * mDarkAmount);
-        }
-    }
-
-    public void setAntiBurnInOffsetX(int burnInXOffset) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mBurnInXOffset == burnInXOffset) {
-            return;
-        }
-        mBurnInXOffset = burnInXOffset;
-        mIndicationArea.setTranslationX(burnInXOffset);
-        if (mAmbientIndicationArea != null) {
-            mAmbientIndicationArea.setTranslationX(burnInXOffset);
-        }
-    }
-
-    /**
-     * Sets the alpha of various sub-components, for example the indication areas and bottom quick
-     * action buttons. Does not set the alpha of the lock icon.
-     */
-    public void setComponentAlphas(float alpha) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        setImportantForAccessibility(
-                alpha == 0f
-                        ? View.IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
-                        : View.IMPORTANT_FOR_ACCESSIBILITY_AUTO);
-        if (mAmbientIndicationArea != null) {
-            mAmbientIndicationArea.setAlpha(alpha);
-        }
-        mIndicationArea.setAlpha(alpha);
-        mWalletButton.setAlpha(alpha);
-        mQRCodeScannerButton.setAlpha(alpha);
-        mControlsButton.setAlpha(alpha);
-    }
-
-    @Override
-    public WindowInsets onApplyWindowInsets(WindowInsets insets) {
-        int bottom = insets.getDisplayCutout() != null
-                ? insets.getDisplayCutout().getSafeInsetBottom() : 0;
-        if (isPaddingRelative()) {
-            setPaddingRelative(getPaddingStart(), getPaddingTop(), getPaddingEnd(), bottom);
-        } else {
-            setPadding(getPaddingLeft(), getPaddingTop(), getPaddingRight(), bottom);
-        }
-        return insets;
-    }
-
-    private void updateQRCodeButtonVisibility() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mQuickAccessWalletController != null
-                && mQuickAccessWalletController.isWalletEnabled()) {
-            // Don't enable if quick access wallet is enabled
-            return;
-        }
-
-        if (mQRCodeScannerController != null
-                && mQRCodeScannerController.isEnabledForLockScreenButton()) {
-            mQRCodeScannerButton.setVisibility(VISIBLE);
-            mQRCodeScannerButton.setOnClickListener(this::onQRCodeScannerClicked);
-            mIndicationArea.setPadding(mIndicationPadding, 0, mIndicationPadding, 0);
-        } else {
-            mQRCodeScannerButton.setVisibility(GONE);
-            if (mControlsButton.getVisibility() == GONE) {
-                mIndicationArea.setPadding(0, 0, 0, 0);
-            }
-        }
-    }
-
-    private void onQRCodeScannerClicked(View view) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        Intent intent = mQRCodeScannerController.getIntent();
-        if (intent != null) {
-            try {
-                ActivityTaskManager.getService().startActivityAsUser(
-                                null, getContext().getBasePackageName(),
-                                getContext().getAttributionTag(), intent,
-                                intent.resolveTypeIfNeeded(getContext().getContentResolver()),
-                                null, null, 0, Intent.FLAG_ACTIVITY_NEW_TASK, null, null,
-                                UserHandle.CURRENT.getIdentifier());
-            } catch (RemoteException e) {
-                // This is unexpected. Nonetheless, just log the error and prevent the UI from
-                // crashing
-                Log.e(TAG, "Unexpected intent: " + intent
-                        + " when the QR code scanner button was clicked");
-            }
-        }
-    }
-
-    private void updateAffordanceColors() {
-        if (mUsesBinder) {
-            return;
-        }
-
-        int iconColor = Utils.getColorAttrDefaultColor(
-                mContext,
-                com.android.internal.R.attr.textColorPrimary);
-        mWalletButton.getDrawable().setTint(iconColor);
-        mControlsButton.getDrawable().setTint(iconColor);
-        mQRCodeScannerButton.getDrawable().setTint(iconColor);
-
-        ColorStateList bgColor = Utils.getColorAttr(
-                mContext,
-                com.android.internal.R.attr.colorSurface);
-        mWalletButton.setBackgroundTintList(bgColor);
-        mControlsButton.setBackgroundTintList(bgColor);
-        mQRCodeScannerButton.setBackgroundTintList(bgColor);
-    }
-
-    private void onWalletClick(View v) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        // More coming here; need to inform the user about how to proceed
-        if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return;
-        }
-
-        ActivityLaunchAnimator.Controller animationController = createLaunchAnimationController(v);
-        mQuickAccessWalletController.startQuickAccessUiIntent(
-                mActivityStarter, animationController, mHasCard);
-    }
-
-    protected ActivityLaunchAnimator.Controller createLaunchAnimationController(View view) {
-        return ActivityLaunchAnimator.Controller.fromView(view, null);
-    }
-
-    private void onControlsClick(View v) {
-        if (mUsesBinder) {
-            return;
-        }
-
-        if (mFalsingManager.isFalseTap(FalsingManager.LOW_PENALTY)) {
-            return;
-        }
-
-        Intent intent = new Intent(mContext, ControlsActivity.class)
-                .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP | Intent.FLAG_ACTIVITY_NEW_TASK)
-                .putExtra(ControlsUiController.EXTRA_ANIMATE, true);
-
-        ActivityLaunchAnimator.Controller controller =
-                v != null ? ActivityLaunchAnimator.Controller.fromView(v, null /* cujType */)
-                        : null;
-        if (mControlsComponent.getVisibility() == AVAILABLE) {
-            mActivityStarter.startActivity(intent, true /* dismissShade */, controller,
-                    true /* showOverLockscreenWhenLocked */);
-        } else {
-            mActivityStarter.postStartActivityDismissingKeyguard(intent, 0 /* delay */, controller);
-        }
-    }
-
-    private class WalletCardRetriever implements
-            QuickAccessWalletClient.OnWalletCardsRetrievedCallback {
-
-        @Override
-        public void onWalletCardsRetrieved(@NonNull GetWalletCardsResponse response) {
-            mHasCard = !response.getWalletCards().isEmpty();
-            Drawable tileIcon = mQuickAccessWalletController.getWalletClient().getTileIcon();
-            if (tileIcon != null) {
-                mWalletButton.setImageDrawable(tileIcon);
-            }
-            post(() -> {
-                updateWalletVisibility();
-                updateAffordanceColors();
-            });
-        }
-
-        @Override
-        public void onWalletCardRetrievalError(@NonNull GetWalletCardsError error) {
-            mHasCard = false;
-            post(() -> {
-                updateWalletVisibility();
-                updateAffordanceColors();
-            });
-        }
-    }
-}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
new file mode 100644
index 0000000..4897c52
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaView.kt
@@ -0,0 +1,117 @@
+/*
+ * 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
+ */
+package com.android.systemui.statusbar.phone
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.AttributeSet
+import android.view.View
+import android.view.ViewGroup
+import android.view.ViewPropertyAnimator
+import android.view.WindowInsets
+import android.widget.FrameLayout
+import com.android.systemui.R
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder
+import com.android.systemui.keyguard.ui.binder.KeyguardBottomAreaViewBinder.bind
+import com.android.systemui.keyguard.ui.viewmodel.KeyguardBottomAreaViewModel
+import com.android.systemui.plugins.FalsingManager
+
+/**
+ * Renders the bottom area of the lock-screen. Concerned primarily with the quick affordance UI
+ * elements. A secondary concern is the interaction of the quick affordance elements with the
+ * indication area between them, though the indication area is primarily controlled elsewhere.
+ */
+class KeyguardBottomAreaView
+@JvmOverloads
+constructor(
+    context: Context,
+    attrs: AttributeSet? = null,
+    defStyleAttr: Int = 0,
+    defStyleRes: Int = 0,
+) :
+    FrameLayout(
+        context,
+        attrs,
+        defStyleAttr,
+        defStyleRes,
+    ) {
+
+    private var ambientIndicationArea: View? = null
+    private lateinit var binding: KeyguardBottomAreaViewBinder.Binding
+
+    /** Initializes the view. */
+    fun init(
+        viewModel: KeyguardBottomAreaViewModel,
+        falsingManager: FalsingManager,
+    ) {
+        binding = bind(this, viewModel, falsingManager)
+    }
+
+    /**
+     * Initializes this instance of [KeyguardBottomAreaView] based on the given instance of another
+     * [KeyguardBottomAreaView]
+     */
+    fun initFrom(oldBottomArea: KeyguardBottomAreaView) {
+        // if it exists, continue to use the original ambient indication container
+        // instead of the newly inflated one
+        ambientIndicationArea?.let { nonNullAmbientIndicationArea ->
+            // remove old ambient indication from its parent
+            val originalAmbientIndicationView =
+                oldBottomArea.findViewById<View>(R.id.ambient_indication_container)
+            (originalAmbientIndicationView.parent as ViewGroup).removeView(
+                originalAmbientIndicationView
+            )
+
+            // remove current ambient indication from its parent (discard)
+            val ambientIndicationParent = nonNullAmbientIndicationArea.parent as ViewGroup
+            val ambientIndicationIndex =
+                ambientIndicationParent.indexOfChild(nonNullAmbientIndicationArea)
+            ambientIndicationParent.removeView(nonNullAmbientIndicationArea)
+
+            // add the old ambient indication to this view
+            ambientIndicationParent.addView(originalAmbientIndicationView, ambientIndicationIndex)
+            ambientIndicationArea = originalAmbientIndicationView
+        }
+    }
+
+    override fun onFinishInflate() {
+        super.onFinishInflate()
+        ambientIndicationArea = findViewById(R.id.ambient_indication_container)
+    }
+
+    override fun onConfigurationChanged(newConfig: Configuration) {
+        super.onConfigurationChanged(newConfig)
+        binding.onConfigurationChanged()
+    }
+
+    /** Returns a list of animators to use to animate the indication areas. */
+    val indicationAreaAnimators: List<ViewPropertyAnimator>
+        get() = binding.getIndicationAreaAnimators()
+
+    override fun hasOverlappingRendering(): Boolean {
+        return false
+    }
+
+    override fun onApplyWindowInsets(insets: WindowInsets): WindowInsets {
+        val bottom = insets.displayCutout?.safeInsetBottom ?: 0
+        if (isPaddingRelative) {
+            setPaddingRelative(paddingStart, paddingTop, paddingEnd, bottom)
+        } else {
+            setPadding(paddingLeft, paddingTop, paddingRight, bottom)
+        }
+        return insets
+    }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
index f106e54..4c5c23c 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManager.java
@@ -44,7 +44,7 @@
 
 import com.android.internal.util.LatencyTracker;
 import com.android.internal.widget.LockPatternUtils;
-import com.android.keyguard.KeyguardMessageArea;
+import com.android.keyguard.AuthKeyguardMessageArea;
 import com.android.keyguard.KeyguardMessageAreaController;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
@@ -122,7 +122,7 @@
     private final DreamOverlayStateController mDreamOverlayStateController;
     @Nullable
     private final FoldAodAnimationController mFoldAodAnimationController;
-    private KeyguardMessageAreaController mKeyguardMessageAreaController;
+    private KeyguardMessageAreaController<AuthKeyguardMessageArea> mKeyguardMessageAreaController;
     private final Lazy<com.android.systemui.shade.ShadeController> mShadeController;
 
     private final BouncerExpansionCallback mExpansionCallback = new BouncerExpansionCallback() {
@@ -311,7 +311,7 @@
         mBypassController = bypassController;
         mNotificationContainer = notificationContainer;
         mKeyguardMessageAreaController = mKeyguardMessageAreaFactory.create(
-            KeyguardMessageArea.findSecurityMessageDisplay(container));
+                centralSurfaces.getKeyguardMessageArea());
 
         registerListeners();
     }
@@ -378,11 +378,9 @@
             return;
         } else if (mNotificationPanelViewController.isUnlockHintRunning()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_HIDDEN);
-        } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED
-                && mKeyguardUpdateManager.isUdfpsEnrolled()) {
+        } else if (mStatusBarStateController.getState() == StatusBarState.SHADE_LOCKED) {
             // Don't expand to the bouncer. Instead transition back to the lock screen (see
-            // CentralSurfaces#showBouncerOrLockScreenIfKeyguard) where the user can use the UDFPS
-            // affordance to enter the device (or swipe up to the input bouncer)
+            // CentralSurfaces#showBouncerOrLockScreenIfKeyguard)
             return;
         } else if (bouncerNeedsScrimming()) {
             mBouncer.setExpansion(KeyguardBouncer.EXPANSION_VISIBLE);
@@ -616,7 +614,8 @@
     private void updateAlternateAuthShowing(boolean updateScrim) {
         final boolean isShowingAltAuth = isShowingAlternateAuth();
         if (mKeyguardMessageAreaController != null) {
-            mKeyguardMessageAreaController.setAltBouncerShowing(isShowingAltAuth);
+            mKeyguardMessageAreaController.setIsVisible(isShowingAltAuth);
+            mKeyguardMessageAreaController.setMessage("");
         }
         mBypassController.setAltBouncerShowing(isShowingAltAuth);
         mKeyguardUpdateManager.setUdfpsBouncerShowing(isShowingAltAuth);
@@ -837,30 +836,24 @@
             });
         } else {
             executeAfterKeyguardGoneAction();
-            boolean wakeUnlockPulsing =
-                    mBiometricUnlockController.getMode() == MODE_WAKE_AND_UNLOCK_PULSING;
             mCentralSurfaces.setKeyguardFadingAway(startTime, delay, fadeoutDuration);
             mBiometricUnlockController.startKeyguardFadingAway();
             hideBouncer(true /* destroyView */);
-            if (wakeUnlockPulsing) {
-                mCentralSurfaces.fadeKeyguardWhilePulsing();
+
+            boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
+            if (!staying) {
+                mNotificationShadeWindowController.setKeyguardFadingAway(true);
+                mCentralSurfaces.hideKeyguard();
+                // hide() will happen asynchronously and might arrive after the scrims
+                // were already hidden, this means that the transition callback won't
+                // be triggered anymore and StatusBarWindowController will be forever in
+                // the fadingAway state.
+                mCentralSurfaces.updateScrimController();
                 wakeAndUnlockDejank();
             } else {
-                boolean staying = mStatusBarStateController.leaveOpenOnKeyguardHide();
-                if (!staying) {
-                    mNotificationShadeWindowController.setKeyguardFadingAway(true);
-                    mCentralSurfaces.hideKeyguard();
-                    // hide() will happen asynchronously and might arrive after the scrims
-                    // were already hidden, this means that the transition callback won't
-                    // be triggered anymore and StatusBarWindowController will be forever in
-                    // the fadingAway state.
-                    mCentralSurfaces.updateScrimController();
-                    wakeAndUnlockDejank();
-                } else {
-                    mCentralSurfaces.hideKeyguard();
-                    mCentralSurfaces.finishKeyguardFadingAway();
-                    mBiometricUnlockController.finishKeyguardFadingAway();
-                }
+                mCentralSurfaces.hideKeyguard();
+                mCentralSurfaces.finishKeyguardFadingAway();
+                mBiometricUnlockController.finishKeyguardFadingAway();
             }
 
             updateStates();
@@ -1043,7 +1036,6 @@
         if (bouncerShowing != mLastBouncerShowing || mFirstUpdate) {
             mNotificationShadeWindowController.setBouncerShowing(bouncerShowing);
             mCentralSurfaces.setBouncerShowing(bouncerShowing);
-            mKeyguardMessageAreaController.setBouncerShowing(bouncerShowing);
         }
 
         if (occluded != mLastOccluded || mFirstUpdate) {
@@ -1192,7 +1184,8 @@
         }
     }
 
-    public void showBouncerMessage(String message, ColorStateList colorState) {
+    /** Display security message to relevant KeyguardMessageArea. */
+    public void setKeyguardMessage(String message, ColorStateList colorState) {
         if (isShowingAlternateAuth()) {
             if (mKeyguardMessageAreaController != null) {
                 mKeyguardMessageAreaController.setMessage(message);
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
index 1987528..3c243ac 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModel.kt
@@ -16,8 +16,15 @@
 
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
+import android.content.Context
 import android.graphics.Color
 import androidx.annotation.DrawableRes
+import androidx.annotation.StringRes
+import androidx.annotation.VisibleForTesting
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
+import com.android.systemui.R
+import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
@@ -41,6 +48,7 @@
 class WifiViewModel @Inject constructor(
     statusBarPipelineFlags: StatusBarPipelineFlags,
     private val constants: WifiConstants,
+    private val context: Context,
     private val logger: ConnectivityPipelineLogger,
     private val interactor: WifiInteractor,
 ) {
@@ -61,18 +69,43 @@
         }
     }
 
+    /** The content description for the wifi icon. */
+    private val contentDescription: Flow<ContentDescription?> = interactor.wifiNetwork.map {
+        when (it) {
+            is WifiNetworkModel.CarrierMerged -> null
+            is WifiNetworkModel.Inactive ->
+                ContentDescription.Loaded(
+                    "${context.getString(WIFI_NO_CONNECTION)},${context.getString(NO_INTERNET)}"
+                )
+            is WifiNetworkModel.Active ->
+                when (it.level) {
+                    null -> null
+                    else -> {
+                        val levelDesc = context.getString(WIFI_CONNECTION_STRENGTH[it.level])
+                        when {
+                            it.isValidated -> ContentDescription.Loaded(levelDesc)
+                            else -> ContentDescription.Loaded(
+                                "$levelDesc,${context.getString(NO_INTERNET)}"
+                            )
+                        }
+                    }
+                }
+        }
+    }
+
     /**
      * The wifi icon that should be displayed. Null if we shouldn't display any icon.
      */
     val wifiIcon: Flow<Icon?> = combine(
             interactor.isForceHidden,
-            iconResId
-        ) { isForceHidden, iconResId ->
+            iconResId,
+            contentDescription,
+        ) { isForceHidden, iconResId, contentDescription ->
             when {
                 isForceHidden ||
                     iconResId == null ||
                     iconResId <= 0 -> null
-                else -> Icon.Resource(iconResId)
+                else -> Icon.Resource(iconResId, contentDescription)
             }
         }
 
@@ -94,4 +127,10 @@
     } else {
         flowOf(Color.CYAN)
     }
+
+    companion object {
+        @StringRes
+        @VisibleForTesting
+        internal val NO_INTERNET = R.string.data_connection_no_internet
+    }
 }
diff --git a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
index bdac888..f4d08e0 100644
--- a/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
+++ b/packages/SystemUI/src/com/android/systemui/statusbar/policy/KeyguardStateControllerImpl.java
@@ -31,6 +31,7 @@
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
 import com.android.keyguard.KeyguardUpdateMonitorCallback;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
 import com.android.systemui.Dumpable;
 import com.android.systemui.R;
 import com.android.systemui.dagger.SysUISingleton;
@@ -60,6 +61,7 @@
     private final KeyguardUpdateMonitorCallback mKeyguardUpdateMonitorCallback =
             new UpdateMonitorCallback();
     private final Lazy<KeyguardUnlockAnimationController> mUnlockAnimationControllerLazy;
+    private final KeyguardUpdateMonitorLogger mLogger;
 
     private boolean mCanDismissLockScreen;
     private boolean mShowing;
@@ -107,8 +109,10 @@
             KeyguardUpdateMonitor keyguardUpdateMonitor,
             LockPatternUtils lockPatternUtils,
             Lazy<KeyguardUnlockAnimationController> keyguardUnlockAnimationController,
+            KeyguardUpdateMonitorLogger logger,
             DumpManager dumpManager) {
         mContext = context;
+        mLogger = logger;
         mKeyguardUpdateMonitor = keyguardUpdateMonitor;
         mLockPatternUtils = lockPatternUtils;
         mKeyguardUpdateMonitor.registerCallback(mKeyguardUpdateMonitorCallback);
@@ -245,6 +249,8 @@
             mTrusted = trusted;
             mTrustManaged = trustManaged;
             mFaceAuthEnabled = faceAuthEnabled;
+            mLogger.logKeyguardStateUpdate(
+                    mSecure, mCanDismissLockScreen, mTrusted, mTrustManaged);
             notifyUnlockedChanged();
         }
         Trace.endSection();
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
similarity index 64%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
index 3a0ac1b..734eeec 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayController.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
 
 import android.annotation.LayoutRes
 import android.annotation.SuppressLint
@@ -37,30 +37,30 @@
 import com.android.settingslib.Utils
 import com.android.systemui.R
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.util.concurrency.DelayableExecutor
-import com.android.systemui.util.view.ViewUtil
 
 /**
- * A superclass controller that provides common functionality for showing chips on the sender device
- * and the receiver device.
+ * A generic controller that can temporarily display a new view in a new window.
  *
- * Subclasses need to override and implement [updateChipView], which is where they can control what
+ * Subclasses need to override and implement [updateView], which is where they can control what
  * gets displayed to the user.
  *
  * The generic type T is expected to contain all the information necessary for the subclasses to
- * display the chip in a certain state, since they receive <T> in [updateChipView].
+ * display the view in a certain state, since they receive <T> in [updateView].
+ *
+ * TODO(b/245610654): Remove all the media-specific logic from this class.
  */
-abstract class MediaTttChipControllerCommon<T : ChipInfoCommon>(
-        internal val context: Context,
-        internal val logger: MediaTttLogger,
-        internal val windowManager: WindowManager,
-        private val viewUtil: ViewUtil,
-        @Main private val mainExecutor: DelayableExecutor,
-        private val accessibilityManager: AccessibilityManager,
-        private val configurationController: ConfigurationController,
-        private val powerManager: PowerManager,
-        @LayoutRes private val chipLayoutRes: Int,
+abstract class TemporaryViewDisplayController<T : TemporaryViewInfo>(
+    internal val context: Context,
+    internal val logger: MediaTttLogger,
+    internal val windowManager: WindowManager,
+    @Main private val mainExecutor: DelayableExecutor,
+    private val accessibilityManager: AccessibilityManager,
+    private val configurationController: ConfigurationController,
+    private val powerManager: PowerManager,
+    @LayoutRes private val viewLayoutRes: Int,
 ) {
     /**
      * Window layout params that will be used as a starting point for the [windowLayoutParams] of
@@ -85,31 +85,31 @@
      */
     internal abstract val windowLayoutParams: WindowManager.LayoutParams
 
-    /** The chip view currently being displayed. Null if the chip is not being displayed. */
-    private var chipView: ViewGroup? = null
+    /** The view currently being displayed. Null if the view is not being displayed. */
+    private var view: ViewGroup? = null
 
-    /** The chip info currently being displayed. Null if the chip is not being displayed. */
-    internal var chipInfo: T? = null
+    /** The info currently being displayed. Null if the view is not being displayed. */
+    internal var info: T? = null
 
-    /** A [Runnable] that, when run, will cancel the pending timeout of the chip. */
-    private var cancelChipViewTimeout: Runnable? = null
+    /** A [Runnable] that, when run, will cancel the pending timeout of the view. */
+    private var cancelViewTimeout: Runnable? = null
 
     /**
-     * Displays the chip with the provided [newChipInfo].
+     * Displays the view with the provided [newInfo].
      *
-     * This method handles inflating and attaching the view, then delegates to [updateChipView] to
-     * display the correct information in the chip.
+     * This method handles inflating and attaching the view, then delegates to [updateView] to
+     * display the correct information in the view.
      */
-    fun displayChip(newChipInfo: T) {
-        val currentChipView = chipView
+    fun displayView(newInfo: T) {
+        val currentView = view
 
-        if (currentChipView != null) {
-            updateChipView(newChipInfo, currentChipView)
+        if (currentView != null) {
+            updateView(newInfo, currentView)
         } else {
-            // The chip is new, so set up all our callbacks and inflate the view
+            // The view is new, so set up all our callbacks and inflate the view
             configurationController.addCallback(displayScaleListener)
-            // Wake the screen if necessary so the user will see the chip. (Per b/239426653, we want
-            // the chip to show over the dream state, so we should only wake up if the screen is
+            // Wake the screen if necessary so the user will see the view. (Per b/239426653, we want
+            // the view to show over the dream state, so we should only wake up if the screen is
             // completely off.)
             if (!powerManager.isScreenOn) {
                 powerManager.wakeUp(
@@ -119,79 +119,79 @@
                 )
             }
 
-            inflateAndUpdateChip(newChipInfo)
+            inflateAndUpdateView(newInfo)
         }
 
-        // Cancel and re-set the chip timeout each time we get a new state.
+        // Cancel and re-set the view timeout each time we get a new state.
         val timeout = accessibilityManager.getRecommendedTimeoutMillis(
-            newChipInfo.getTimeoutMs().toInt(),
-            // Not all chips have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
+            newInfo.getTimeoutMs().toInt(),
+            // Not all views have controls so FLAG_CONTENT_CONTROLS might be superfluous, but
             // include it just to be safe.
             FLAG_CONTENT_ICONS or FLAG_CONTENT_TEXT or FLAG_CONTENT_CONTROLS
        )
-        cancelChipViewTimeout?.run()
-        cancelChipViewTimeout = mainExecutor.executeDelayed(
-            { removeChip(MediaTttRemovalReason.REASON_TIMEOUT) },
+        cancelViewTimeout?.run()
+        cancelViewTimeout = mainExecutor.executeDelayed(
+            { removeView(TemporaryDisplayRemovalReason.REASON_TIMEOUT) },
             timeout.toLong()
         )
     }
 
-    /** Inflates a new chip view, updates it with [newChipInfo], and adds the view to the window. */
-    private fun inflateAndUpdateChip(newChipInfo: T) {
-        val newChipView = LayoutInflater
+    /** Inflates a new view, updates it with [newInfo], and adds the view to the window. */
+    private fun inflateAndUpdateView(newInfo: T) {
+        val newView = LayoutInflater
                 .from(context)
-                .inflate(chipLayoutRes, null) as ViewGroup
-        chipView = newChipView
-        updateChipView(newChipInfo, newChipView)
-        windowManager.addView(newChipView, windowLayoutParams)
-        animateChipIn(newChipView)
+                .inflate(viewLayoutRes, null) as ViewGroup
+        view = newView
+        updateView(newInfo, newView)
+        windowManager.addView(newView, windowLayoutParams)
+        animateViewIn(newView)
     }
 
-    /** Removes then re-inflates the chip. */
-    private fun reinflateChip() {
-        val currentChipInfo = chipInfo
-        if (chipView == null || currentChipInfo == null) { return }
+    /** Removes then re-inflates the view. */
+    private fun reinflateView() {
+        val currentInfo = info
+        if (view == null || currentInfo == null) { return }
 
-        windowManager.removeView(chipView)
-        inflateAndUpdateChip(currentChipInfo)
+        windowManager.removeView(view)
+        inflateAndUpdateView(currentInfo)
     }
 
     private val displayScaleListener = object : ConfigurationController.ConfigurationListener {
         override fun onDensityOrFontScaleChanged() {
-            reinflateChip()
+            reinflateView()
         }
     }
 
     /**
-     * Hides the chip.
+     * Hides the view.
      *
-     * @param removalReason a short string describing why the chip was removed (timeout, state
+     * @param removalReason a short string describing why the view was removed (timeout, state
      *     change, etc.)
      */
-    open fun removeChip(removalReason: String) {
-        if (chipView == null) { return }
+    open fun removeView(removalReason: String) {
+        if (view == null) { return }
         logger.logChipRemoval(removalReason)
         configurationController.removeCallback(displayScaleListener)
-        windowManager.removeView(chipView)
-        chipView = null
-        chipInfo = null
-        // No need to time the chip out since it's already gone
-        cancelChipViewTimeout?.run()
+        windowManager.removeView(view)
+        view = null
+        info = null
+        // No need to time the view out since it's already gone
+        cancelViewTimeout?.run()
     }
 
     /**
-     * A method implemented by subclasses to update [currentChipView] based on [newChipInfo].
+     * A method implemented by subclasses to update [currentView] based on [newInfo].
      */
     @CallSuper
-    open fun updateChipView(newChipInfo: T, currentChipView: ViewGroup) {
-        chipInfo = newChipInfo
+    open fun updateView(newInfo: T, currentView: ViewGroup) {
+        info = newInfo
     }
 
     /**
-     * A method that can be implemented by subclcasses to do custom animations for when the chip
+     * A method that can be implemented by subclasses to do custom animations for when the view
      * appears.
      */
-    open fun animateChipIn(chipView: ViewGroup) {}
+    open fun animateViewIn(view: ViewGroup) {}
 
     /**
      * Returns the size that the icon should be, or null if no size override is needed.
@@ -209,12 +209,12 @@
      * @return the content description of the icon.
      */
     internal fun setIcon(
-        currentChipView: ViewGroup,
+        currentView: ViewGroup,
         appPackageName: String?,
         appIconDrawableOverride: Drawable? = null,
         appNameOverride: CharSequence? = null,
     ): CharSequence {
-        val appIconView = currentChipView.requireViewById<CachingIconView>(R.id.app_icon)
+        val appIconView = currentView.requireViewById<CachingIconView>(R.id.app_icon)
         val iconInfo = getIconInfo(appPackageName)
 
         getIconSize(iconInfo.isAppIcon)?.let { size ->
@@ -264,9 +264,9 @@
 // Used in CTS tests UpdateMediaTapToTransferSenderDisplayTest and
 // UpdateMediaTapToTransferReceiverDisplayTest
 private const val WINDOW_TITLE = "Media Transfer Chip View"
-private val TAG = MediaTttChipControllerCommon::class.simpleName!!
+private val TAG = TemporaryViewDisplayController::class.simpleName!!
 
-object MediaTttRemovalReason {
+object TemporaryDisplayRemovalReason {
     const val REASON_TIMEOUT = "TIMEOUT"
     const val REASON_SCREEN_TAP = "SCREEN_TAP"
 }
diff --git a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
similarity index 73%
rename from packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
rename to packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
index a29c588..4fe753a 100644
--- a/packages/SystemUI/src/com/android/systemui/media/taptotransfer/common/ChipInfoCommon.kt
+++ b/packages/SystemUI/src/com/android/systemui/temporarydisplay/TemporaryViewInfo.kt
@@ -14,17 +14,17 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
 
 /**
- * A superclass chip state that will be subclassed by the sender chip and receiver chip.
+ * A superclass view state used with [TemporaryViewDisplayController].
  */
-interface ChipInfoCommon {
+interface TemporaryViewInfo {
     /**
-     * Returns the amount of time the given chip state should display on the screen before it times
+     * Returns the amount of time the given view state should display on the screen before it times
      * out and disappears.
      */
-    fun getTimeoutMs(): Long
+    fun getTimeoutMs(): Long = DEFAULT_TIMEOUT_MILLIS
 }
 
 const val DEFAULT_TIMEOUT_MILLIS = 10000L
diff --git a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
index 8f127fd..0f06144 100644
--- a/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
+++ b/packages/SystemUI/src/com/android/systemui/unfold/FoldAodAnimationController.kt
@@ -18,22 +18,31 @@
 
 import android.content.Context
 import android.hardware.devicestate.DeviceStateManager
-import android.os.Handler
 import android.os.PowerManager
 import android.provider.Settings
+import androidx.annotation.VisibleForTesting
 import androidx.core.view.OneShotPreDrawListener
+import androidx.lifecycle.Lifecycle
+import androidx.lifecycle.repeatOnLifecycle
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.dagger.qualifiers.Main
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
+import com.android.systemui.lifecycle.repeatWhenAttached
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.statusbar.phone.ScreenOffAnimation
 import com.android.systemui.statusbar.policy.CallbackController
 import com.android.systemui.unfold.FoldAodAnimationController.FoldAodAnimationStatus
+import com.android.systemui.util.concurrency.DelayableExecutor
 import com.android.systemui.util.settings.GlobalSettings
-import java.util.concurrent.Executor
+import dagger.Lazy
 import java.util.function.Consumer
 import javax.inject.Inject
+import kotlinx.coroutines.CoroutineScope
+import kotlinx.coroutines.Job
+import kotlinx.coroutines.flow.collect
+import kotlinx.coroutines.launch
 
 /**
  * Controls folding to AOD animation: when AOD is enabled and foldable device is folded we play a
@@ -43,16 +52,16 @@
 class FoldAodAnimationController
 @Inject
 constructor(
-    @Main private val handler: Handler,
-    @Main private val executor: Executor,
+    @Main private val executor: DelayableExecutor,
     private val context: Context,
     private val deviceStateManager: DeviceStateManager,
     private val wakefulnessLifecycle: WakefulnessLifecycle,
     private val globalSettings: GlobalSettings,
     private val latencyTracker: LatencyTracker,
+    private val keyguardInteractor: Lazy<KeyguardInteractor>,
 ) : CallbackController<FoldAodAnimationStatus>, ScreenOffAnimation, WakefulnessLifecycle.Observer {
 
-    private lateinit var mCentralSurfaces: CentralSurfaces
+    private lateinit var centralSurfaces: CentralSurfaces
 
     private var isFolded = false
     private var isFoldHandled = true
@@ -64,12 +73,13 @@
 
     private var shouldPlayAnimation = false
     private var isAnimationPlaying = false
+    private var cancelAnimation: Runnable? = null
 
     private val statusListeners = arrayListOf<FoldAodAnimationStatus>()
     private val foldToAodLatencyTracker = FoldToAodLatencyTracker()
 
     private val startAnimationRunnable = Runnable {
-        mCentralSurfaces.notificationPanelViewController.startFoldToAodAnimation(
+        centralSurfaces.notificationPanelViewController.startFoldToAodAnimation(
             /* startAction= */ { foldToAodLatencyTracker.onAnimationStarted() },
             /* endAction= */ { setAnimationState(playing = false) },
             /* cancelAction= */ { setAnimationState(playing = false) },
@@ -77,10 +87,14 @@
     }
 
     override fun initialize(centralSurfaces: CentralSurfaces, lightRevealScrim: LightRevealScrim) {
-        this.mCentralSurfaces = centralSurfaces
+        this.centralSurfaces = centralSurfaces
 
         deviceStateManager.registerCallback(executor, FoldListener())
         wakefulnessLifecycle.addObserver(this)
+
+        centralSurfaces.notificationPanelViewController.view.repeatWhenAttached {
+            repeatOnLifecycle(Lifecycle.State.STARTED) { listenForDozing(this) }
+        }
     }
 
     /** Returns true if we should run fold to AOD animation */
@@ -94,7 +108,7 @@
     override fun startAnimation(): Boolean =
         if (shouldStartAnimation()) {
             setAnimationState(playing = true)
-            mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
+            centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
             true
         } else {
             setAnimationState(playing = false)
@@ -104,8 +118,8 @@
     override fun onStartedWakingUp() {
         if (isAnimationPlaying) {
             foldToAodLatencyTracker.cancel()
-            handler.removeCallbacks(startAnimationRunnable)
-            mCentralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
+            cancelAnimation?.run()
+            centralSurfaces.notificationPanelViewController.cancelFoldToAodAnimation()
         }
 
         setAnimationState(playing = false)
@@ -138,13 +152,13 @@
             // We should play the folding to AOD animation
 
             setAnimationState(playing = true)
-            mCentralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
+            centralSurfaces.notificationPanelViewController.prepareFoldToAodAnimation()
 
             // We don't need to wait for the scrim as it is already displayed
             // but we should wait for the initial animation preparations to be drawn
             // (setting initial alpha/translation)
             OneShotPreDrawListener.add(
-                mCentralSurfaces.notificationPanelViewController.view,
+                centralSurfaces.notificationPanelViewController.view,
                 onReady
             )
         } else {
@@ -165,18 +179,14 @@
 
     fun onScreenTurnedOn() {
         if (shouldPlayAnimation) {
-            handler.removeCallbacks(startAnimationRunnable)
+            cancelAnimation?.run()
 
             // Post starting the animation to the next frame to avoid junk due to inset changes
-            handler.post(startAnimationRunnable)
+            cancelAnimation = executor.executeDelayed(startAnimationRunnable, /* delayMillis= */ 0)
             shouldPlayAnimation = false
         }
     }
 
-    fun setIsDozing(dozing: Boolean) {
-        isDozing = dozing
-    }
-
     override fun isAnimationPlaying(): Boolean = isAnimationPlaying
 
     override fun isKeyguardHideDelayed(): Boolean = isAnimationPlaying()
@@ -204,6 +214,11 @@
         statusListeners.remove(listener)
     }
 
+    @VisibleForTesting
+    internal suspend fun listenForDozing(scope: CoroutineScope): Job {
+        return scope.launch { keyguardInteractor.get().isDozing.collect { isDozing = it } }
+    }
+
     interface FoldAodAnimationStatus {
         fun onFoldToAodAnimationChanged()
     }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
index 7baebf4..f71d596 100644
--- a/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Flow.kt
@@ -16,11 +16,15 @@
 
 package com.android.systemui.util.kotlin
 
+import java.util.concurrent.atomic.AtomicReference
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.coroutineScope
 import kotlinx.coroutines.flow.Flow
+import kotlinx.coroutines.flow.collect
 import kotlinx.coroutines.flow.distinctUntilChanged
-import kotlinx.coroutines.flow.drop
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.onStart
-import kotlinx.coroutines.flow.zip
+import kotlinx.coroutines.launch
 
 /**
  * Returns a new [Flow] that combines the two most recent emissions from [this] using [transform].
@@ -29,15 +33,16 @@
  *
  * Useful for code that needs to compare the current value to the previous value.
  */
-fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> {
-    // same as current flow, but with the very first event skipped
-    val nextEvents = drop(1)
-    // zip current flow and nextEvents; transform will receive a pair of old and new value. This
-    // works because zip will suppress emissions until both flows have emitted something; since in
-    // this case both flows are emitting at the same rate, but the current flow just has one extra
-    // thing emitted at the start, the effect is that zip will cache the most recent value while
-    // waiting for the next emission from nextEvents.
-    return zip(nextEvents, transform)
+fun <T, R> Flow<T>.pairwiseBy(transform: suspend (old: T, new: T) -> R): Flow<R> = flow {
+    val noVal = Any()
+    var previousValue: Any? = noVal
+    collect { newVal ->
+        if (previousValue != noVal) {
+            @Suppress("UNCHECKED_CAST")
+            emit(transform(previousValue as T, newVal))
+        }
+        previousValue = newVal
+    }
 }
 
 /**
@@ -74,10 +79,19 @@
 /**
  * Returns a new [Flow] that combines the [Set] changes between each emission from [this] using
  * [transform].
+ *
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
+ * a change event to be emitted that contains no removals, and all elements from that first [Set]
+ * as additions.
+ *
+ * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
+ * until a second [Set] has been emitted from the upstream [Flow].
  */
 fun <T, R> Flow<Set<T>>.setChangesBy(
     transform: suspend (removed: Set<T>, added: Set<T>) -> R,
-): Flow<R> = onStart { emit(emptySet()) }.distinctUntilChanged()
+    emitFirstEvent: Boolean = true,
+): Flow<R> = (if (emitFirstEvent) onStart { emit(emptySet()) } else this)
+    .distinctUntilChanged()
     .pairwiseBy { old: Set<T>, new: Set<T> ->
         // If an element was present in the old set, but not the new one, then it was removed
         val removed = old - new
@@ -86,8 +100,18 @@
         transform(removed, added)
     }
 
-/** Returns a new [Flow] that produces the [Set] changes between each emission from [this]. */
-fun <T> Flow<Set<T>>.setChanges(): Flow<SetChanges<T>> = setChangesBy(::SetChanges)
+/**
+ * Returns a new [Flow] that produces the [Set] changes between each emission from [this].
+ *
+ * If [emitFirstEvent] is `true`, then the first [Set] emitted from the upstream [Flow] will cause
+ * a change event to be emitted that contains no removals, and all elements from that first [Set]
+ * as additions.
+ *
+ * If [emitFirstEvent] is `false`, then the first emission is ignored and no changes are emitted
+ * until a second [Set] has been emitted from the upstream [Flow].
+ */
+fun <T> Flow<Set<T>>.setChanges(emitFirstEvent: Boolean = true): Flow<SetChanges<T>> =
+    setChangesBy(::SetChanges, emitFirstEvent)
 
 /** Contains the difference in elements between two [Set]s. */
 data class SetChanges<T>(
@@ -96,3 +120,35 @@
     /** Elements that are present in the second [Set] but not in the first. */
     val added: Set<T>,
 )
+
+/**
+ * Returns a new [Flow] that emits at the same rate as [this], but combines the emitted value with
+ * the most recent emission from [other] using [transform].
+ *
+ * Note that the returned Flow will not emit anything until [other] has emitted at least one value.
+ */
+fun <A, B, C> Flow<A>.sample(other: Flow<B>, transform: suspend (A, B) -> C): Flow<C> = flow {
+    coroutineScope {
+        val noVal = Any()
+        val sampledRef = AtomicReference(noVal)
+        val job = launch(Dispatchers.Unconfined) {
+            other.collect { sampledRef.set(it) }
+        }
+        collect {
+            val sampled = sampledRef.get()
+            if (sampled != noVal) {
+                @Suppress("UNCHECKED_CAST")
+                emit(transform(it, sampled as B))
+            }
+        }
+        job.cancel()
+    }
+}
+
+/**
+ * Returns a new [Flow] that emits at the same rate as [this], but emits the most recently emitted
+ * value from [other] instead.
+ *
+ * Note that the returned Flow will not emit anything until [other] has emitted at least one value.
+ */
+fun <A> Flow<*>.sample(other: Flow<A>): Flow<A> = sample(other) { _, a -> a }
diff --git a/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt b/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt
new file mode 100644
index 0000000..2e551f1
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/util/kotlin/Suspend.kt
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.coroutineScope
+import kotlinx.coroutines.launch
+
+/**
+ * Runs the given [blocks] in parallel, returning the result of the first one to complete, and
+ * cancelling all others.
+ */
+suspend fun <R> race(vararg blocks: suspend () -> R): R = coroutineScope {
+    val completion = CompletableDeferred<R>()
+    val raceJob = launch {
+        for (block in blocks) {
+            launch { completion.complete(block()) }
+        }
+    }
+    completion.await().also { raceJob.cancel() }
+}
diff --git a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
index 8c41374..4e77514 100644
--- a/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
+++ b/packages/SystemUI/src/com/android/systemui/wmshell/BubblesManager.java
@@ -311,18 +311,6 @@
             }
 
             @Override
-            public void notifyMaybeCancelSummary(String key) {
-                sysuiMainExecutor.execute(() -> {
-                    final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
-                    if (entry != null) {
-                        for (NotifCallback cb : mCallbacks) {
-                            cb.maybeCancelSummary(entry);
-                        }
-                    }
-                });
-            }
-
-            @Override
             public void updateNotificationBubbleButton(String key) {
                 sysuiMainExecutor.execute(() -> {
                     final NotificationEntry entry = mCommonNotifCollection.getEntry(key);
@@ -646,15 +634,5 @@
          * filtered from the shade.
          */
         void invalidateNotifications(@NonNull String reason);
-
-        /**
-         * Called on a bubbled entry that has been removed when there are no longer
-         * bubbled entries in its group.
-         *
-         * Checks whether its group has any other (non-bubbled) children. If it doesn't,
-         * removes all remnants of the group's summary from the notification pipeline.
-         * TODO: (b/145659174) Only old pipeline needs this - delete post-migration.
-         */
-        void maybeCancelSummary(@NonNull NotificationEntry entry);
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
similarity index 90%
rename from packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
rename to packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
index 013c298..0a9c745 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/AuthKeyguardMessageAreaTest.java
@@ -33,14 +33,14 @@
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
 @RunWithLooper
-public class KeyguardMessageAreaTest extends SysuiTestCase {
+public class AuthKeyguardMessageAreaTest extends SysuiTestCase {
     private KeyguardMessageArea mKeyguardMessageArea;
 
     @Before
     public void setUp() throws Exception {
         MockitoAnnotations.initMocks(this);
-        mKeyguardMessageArea = new KeyguardMessageArea(mContext, null);
-        mKeyguardMessageArea.setBouncerShowing(true);
+        mKeyguardMessageArea = new AuthKeyguardMessageArea(mContext, null);
+        mKeyguardMessageArea.setIsVisible(true);
     }
 
     @Test
@@ -53,7 +53,7 @@
 
     @Test
     public void testHiddenWhenBouncerHidden() {
-        mKeyguardMessageArea.setBouncerShowing(false);
+        mKeyguardMessageArea.setIsVisible(false);
         mKeyguardMessageArea.setVisibility(View.INVISIBLE);
         mKeyguardMessageArea.setMessage("oobleck");
         assertThat(mKeyguardMessageArea.getVisibility()).isEqualTo(View.INVISIBLE);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
index 90f7fda..8bbaf3d 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardAbsKeyInputViewControllerTest.java
@@ -56,7 +56,7 @@
     @Mock
     private PasswordTextView mPasswordEntry;
     @Mock
-    private KeyguardMessageArea mKeyguardMessageArea;
+    private BouncerKeyguardMessageArea mKeyguardMessageArea;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
@@ -85,7 +85,7 @@
         when(mAbsKeyInputView.getPasswordTextViewId()).thenReturn(1);
         when(mAbsKeyInputView.findViewById(1)).thenReturn(mPasswordEntry);
         when(mAbsKeyInputView.isAttachedToWindow()).thenReturn(true);
-        when(mAbsKeyInputView.findViewById(R.id.keyguard_message_area))
+        when(mAbsKeyInputView.requireViewById(R.id.bouncer_message_area))
                 .thenReturn(mKeyguardMessageArea);
         mKeyguardAbsKeyInputViewController = new KeyguardAbsKeyInputViewController(mAbsKeyInputView,
                 mKeyguardUpdateMonitor, mSecurityMode, mLockPatternUtils, mKeyguardSecurityCallback,
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
index 8293cc2..69524e5 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardMessageAreaControllerTest.java
@@ -89,8 +89,8 @@
 
     @Test
     public void testSetBouncerVisible() {
-        mMessageAreaController.setBouncerShowing(true);
-        verify(mKeyguardMessageArea).setBouncerShowing(true);
+        mMessageAreaController.setIsVisible(true);
+        verify(mKeyguardMessageArea).setIsVisible(true);
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
index ec85603..b89dbd9 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPasswordViewControllerTest.kt
@@ -64,9 +64,10 @@
     @Mock
     lateinit var keyguardViewController: KeyguardViewController
     @Mock
-    private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+    private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
     @Mock
-    private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+    private lateinit var mKeyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
 
     private lateinit var keyguardPasswordViewController: KeyguardPasswordViewController
 
@@ -74,7 +75,8 @@
     fun setup() {
         MockitoAnnotations.initMocks(this)
         Mockito.`when`(
-            keyguardPasswordView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area)
+            keyguardPasswordView
+                .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area)
         ).thenReturn(mKeyguardMessageArea)
         Mockito.`when`(messageAreaControllerFactory.create(mKeyguardMessageArea))
             .thenReturn(mKeyguardMessageAreaController)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
index 616a105..3262a77 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPatternViewControllerTest.kt
@@ -66,10 +66,11 @@
     var mKeyguardMessageAreaControllerFactory: KeyguardMessageAreaController.Factory
 
     @Mock
-    private lateinit var mKeyguardMessageArea: KeyguardMessageArea
+    private lateinit var mKeyguardMessageArea: BouncerKeyguardMessageArea
 
     @Mock
-    private lateinit var mKeyguardMessageAreaController: KeyguardMessageAreaController
+    private lateinit var mKeyguardMessageAreaController:
+        KeyguardMessageAreaController<BouncerKeyguardMessageArea>
 
     @Mock
     private lateinit var mLockPatternView: LockPatternView
@@ -83,7 +84,8 @@
     fun setup() {
         MockitoAnnotations.initMocks(this)
         `when`(mKeyguardPatternView.isAttachedToWindow).thenReturn(true)
-        `when`(mKeyguardPatternView.findViewById<KeyguardMessageArea>(R.id.keyguard_message_area))
+        `when`(mKeyguardPatternView
+            .requireViewById<BouncerKeyguardMessageArea>(R.id.bouncer_message_area))
             .thenReturn(mKeyguardMessageArea)
         `when`(mKeyguardPatternView.findViewById<LockPatternView>(R.id.lockPatternView))
             .thenReturn(mLockPatternView)
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
index 7bc8e8a..97d556b 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardPinBasedInputViewControllerTest.java
@@ -51,7 +51,7 @@
     @Mock
     private PasswordTextView mPasswordEntry;
     @Mock
-    private KeyguardMessageArea mKeyguardMessageArea;
+    private BouncerKeyguardMessageArea mKeyguardMessageArea;
     @Mock
     private KeyguardUpdateMonitor mKeyguardUpdateMonitor;
     @Mock
@@ -90,7 +90,7 @@
         when(mPinBasedInputView.findViewById(1)).thenReturn(mPasswordEntry);
         when(mPinBasedInputView.isAttachedToWindow()).thenReturn(true);
         when(mPinBasedInputView.getButtons()).thenReturn(mButtons);
-        when(mPinBasedInputView.findViewById(R.id.keyguard_message_area))
+        when(mPinBasedInputView.requireViewById(R.id.bouncer_message_area))
                 .thenReturn(mKeyguardMessageArea);
         when(mPinBasedInputView.findViewById(R.id.delete_button))
                 .thenReturn(mDeleteButton);
diff --git a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
index d68e8bd..c6ebaa8 100644
--- a/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/keyguard/KeyguardSecurityContainerControllerTest.java
@@ -41,6 +41,7 @@
 import android.hardware.biometrics.BiometricSourceType;
 import android.testing.AndroidTestingRunner;
 import android.testing.TestableLooper;
+import android.view.LayoutInflater;
 import android.view.MotionEvent;
 import android.view.View;
 import android.view.WindowInsetsController;
@@ -117,7 +118,7 @@
     @Mock
     private KeyguardMessageAreaController mKeyguardMessageAreaController;
     @Mock
-    private KeyguardMessageArea mKeyguardMessageArea;
+    private BouncerKeyguardMessageArea mKeyguardMessageArea;
     @Mock
     private ConfigurationController mConfigurationController;
     @Mock
@@ -163,9 +164,10 @@
         when(mAdminSecondaryLockScreenControllerFactory.create(any(KeyguardSecurityCallback.class)))
                 .thenReturn(mAdminSecondaryLockScreenController);
         when(mSecurityViewFlipper.getWindowInsetsController()).thenReturn(mWindowInsetsController);
-        mKeyguardPasswordView = spy(new KeyguardPasswordView(getContext()));
+        mKeyguardPasswordView = spy((KeyguardPasswordView) LayoutInflater.from(mContext).inflate(
+                R.layout.keyguard_password_view, null));
         when(mKeyguardPasswordView.getRootView()).thenReturn(mSecurityViewFlipper);
-        when(mKeyguardPasswordView.findViewById(R.id.keyguard_message_area))
+        when(mKeyguardPasswordView.requireViewById(R.id.bouncer_message_area))
                 .thenReturn(mKeyguardMessageArea);
         when(mKeyguardMessageAreaControllerFactory.create(any(KeyguardMessageArea.class)))
                 .thenReturn(mKeyguardMessageAreaController);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
new file mode 100644
index 0000000..419fedf
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/biometrics/BiometricMessageDeferralTest.kt
@@ -0,0 +1,147 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.biometrics
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import org.junit.Assert.assertEquals
+import org.junit.Assert.assertFalse
+import org.junit.Assert.assertNull
+import org.junit.Assert.assertTrue
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class BiometricMessageDeferralTest : SysuiTestCase() {
+
+    @Test
+    fun testProcessNoMessages_noDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf())
+
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testProcessNonDeferredMessages_noDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+        // WHEN there are no deferred messages processed
+        for (i in 0..3) {
+            biometricMessageDeferral.processMessage(4, "test")
+        }
+
+        // THEN getDeferredMessage is null
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testAllProcessedMessagesWereDeferred() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+        // WHEN all the processed messages are a deferred message
+        for (i in 0..3) {
+            biometricMessageDeferral.processMessage(1, "test")
+        }
+
+        // THEN deferredMessage will return the string associated with the deferred msgId
+        assertEquals("test", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testReturnsMostFrequentDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+        // WHEN there's two msgId=1 processed and one msgId=2 processed
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(2, "msgId-2")
+
+        // THEN the most frequent deferred message is that meets the threshold is returned
+        assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testDeferredMessage_mustMeetThreshold() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1))
+
+        // WHEN more nonDeferredMessages are shown than the deferred message
+        val totalMessages = 10
+        val nonDeferredMessagesCount =
+            (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+        for (i in 0 until nonDeferredMessagesCount) {
+            biometricMessageDeferral.processMessage(4, "non-deferred-msg")
+        }
+        for (i in nonDeferredMessagesCount until totalMessages) {
+            biometricMessageDeferral.processMessage(1, "msgId-1")
+        }
+
+        // THEN there's no deferred message because it didn't meet the threshold
+        assertNull(biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testDeferredMessage_manyExcludedMessages_getDeferredMessage() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1))
+
+        // WHEN more excludedMessages are shown than the deferred message
+        val totalMessages = 10
+        val excludedMessagesCount = (totalMessages * BiometricMessageDeferral.THRESHOLD).toInt() + 1
+        for (i in 0 until excludedMessagesCount) {
+            biometricMessageDeferral.processMessage(3, "excluded-msg")
+        }
+        for (i in excludedMessagesCount until totalMessages) {
+            biometricMessageDeferral.processMessage(1, "msgId-1")
+        }
+
+        // THEN there IS a deferred message because the deferred msg meets the threshold amongst the
+        // non-excluded messages
+        assertEquals("msgId-1", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testResetClearsOutCounts() {
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(), setOf(1, 2))
+
+        // GIVEN two msgId=1 events processed
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+        biometricMessageDeferral.processMessage(1, "msgId-1")
+
+        // WHEN counts are reset and then a single deferred message is processed (msgId=2)
+        biometricMessageDeferral.reset()
+        biometricMessageDeferral.processMessage(2, "msgId-2")
+
+        // THEN msgId-2 is the deferred message since the two msgId=1 events were reset
+        assertEquals("msgId-2", biometricMessageDeferral.getDeferredMessage())
+    }
+
+    @Test
+    fun testShouldDefer() {
+        // GIVEN should defer msgIds 1 and 2
+        val biometricMessageDeferral = BiometricMessageDeferral(setOf(3), setOf(1, 2))
+
+        // THEN shouldDefer returns true for ids 1 & 2
+        assertTrue(biometricMessageDeferral.shouldDefer(1))
+        assertTrue(biometricMessageDeferral.shouldDefer(2))
+
+        // THEN should defer returns false for ids 3 & 4
+        assertFalse(biometricMessageDeferral.shouldDefer(3))
+        assertFalse(biometricMessageDeferral.shouldDefer(4))
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
index 3aa2266..ba1e168 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/KeyguardRepositoryImplTest.kt
@@ -19,6 +19,7 @@
 import androidx.test.filters.SmallTest
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.common.shared.model.Position
+import com.android.systemui.doze.DozeHost
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.mockito.argumentCaptor
@@ -40,6 +41,7 @@
 class KeyguardRepositoryImplTest : SysuiTestCase() {
 
     @Mock private lateinit var statusBarStateController: StatusBarStateController
+    @Mock private lateinit var dozeHost: DozeHost
     @Mock private lateinit var keyguardStateController: KeyguardStateController
 
     private lateinit var underTest: KeyguardRepositoryImpl
@@ -48,7 +50,12 @@
     fun setUp() {
         MockitoAnnotations.initMocks(this)
 
-        underTest = KeyguardRepositoryImpl(statusBarStateController, keyguardStateController)
+        underTest =
+            KeyguardRepositoryImpl(
+                statusBarStateController,
+                keyguardStateController,
+                dozeHost,
+            )
     }
 
     @Test
@@ -129,8 +136,8 @@
         var latest: Boolean? = null
         val job = underTest.isDozing.onEach { latest = it }.launchIn(this)
 
-        val captor = argumentCaptor<StatusBarStateController.StateListener>()
-        verify(statusBarStateController).addCallback(captor.capture())
+        val captor = argumentCaptor<DozeHost.Callback>()
+        verify(dozeHost).addCallback(captor.capture())
 
         captor.value.onDozingChanged(true)
         assertThat(latest).isTrue()
@@ -139,7 +146,7 @@
         assertThat(latest).isFalse()
 
         job.cancel()
-        verify(statusBarStateController).removeCallback(captor.value)
+        verify(dozeHost).removeCallback(captor.value)
     }
 
     @Test
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
index 9acd21c..9a91ea91 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigParameterizedStateTest.kt
@@ -51,18 +51,19 @@
         @Parameters(
             name =
                 "feature enabled = {0}, has favorites = {1}, has service infos = {2}, can show" +
-                    " while locked = {3} - expected visible = {4}"
+                    " while locked = {3}, visibility is AVAILABLE {4} - expected visible = {5}"
         )
         @JvmStatic
         fun data() =
-            (0 until 16)
+            (0 until 32)
                 .map { combination ->
                     arrayOf(
-                        /* isFeatureEnabled= */ combination and 0b1000 != 0,
-                        /* hasFavorites= */ combination and 0b0100 != 0,
-                        /* hasServiceInfos= */ combination and 0b0010 != 0,
-                        /* canShowWhileLocked= */ combination and 0b0001 != 0,
-                        /* isVisible= */ combination == 0b1111,
+                        /* isFeatureEnabled= */ combination and 0b10000 != 0,
+                        /* hasFavorites= */ combination and 0b01000 != 0,
+                        /* hasServiceInfos= */ combination and 0b00100 != 0,
+                        /* canShowWhileLocked= */ combination and 0b00010 != 0,
+                        /* visibilityAvailable= */ combination and 0b00001 != 0,
+                        /* isVisible= */ combination == 0b11111,
                     )
                 }
                 .toList()
@@ -81,7 +82,8 @@
     @JvmField @Parameter(1) var hasFavorites: Boolean = false
     @JvmField @Parameter(2) var hasServiceInfos: Boolean = false
     @JvmField @Parameter(3) var canShowWhileLocked: Boolean = false
-    @JvmField @Parameter(4) var isVisible: Boolean = false
+    @JvmField @Parameter(4) var isVisibilityAvailable: Boolean = false
+    @JvmField @Parameter(5) var isVisibleExpected: Boolean = false
 
     @Before
     fun setUp() {
@@ -93,6 +95,14 @@
             .thenReturn(Optional.of(controlsListingController))
         whenever(component.canShowWhileLockedSetting)
             .thenReturn(MutableStateFlow(canShowWhileLocked))
+        whenever(component.getVisibility())
+            .thenReturn(
+                if (isVisibilityAvailable) {
+                    ControlsComponent.Visibility.AVAILABLE
+                } else {
+                    ControlsComponent.Visibility.UNAVAILABLE
+                }
+            )
 
         underTest =
             HomeControlsKeyguardQuickAffordanceConfig(
@@ -128,7 +138,7 @@
 
         assertThat(values.last())
             .isInstanceOf(
-                if (isVisible) {
+                if (isVisibleExpected) {
                     KeyguardQuickAffordanceConfig.State.Visible::class.java
                 } else {
                     KeyguardQuickAffordanceConfig.State.Hidden::class.java
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
index 059487d..dede4ec 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/quickaffordance/HomeControlsKeyguardQuickAffordanceConfigTest.kt
@@ -69,6 +69,7 @@
         val controlsController = mock<ControlsController>()
         whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
         whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+        whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
         whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
 
         val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
@@ -87,6 +88,7 @@
         val controlsController = mock<ControlsController>()
         whenever(component.getControlsController()).thenReturn(Optional.of(controlsController))
         whenever(component.getControlsListingController()).thenReturn(Optional.empty())
+        whenever(component.getVisibility()).thenReturn(ControlsComponent.Visibility.AVAILABLE)
         whenever(controlsController.getFavorites()).thenReturn(listOf(mock()))
 
         val values = mutableListOf<KeyguardQuickAffordanceConfig.State>()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
index d3fc29f..19d8412 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/domain/usecase/KeyguardQuickAffordanceInteractorTest.kt
@@ -36,6 +36,7 @@
 import kotlinx.coroutines.flow.launchIn
 import kotlinx.coroutines.flow.onEach
 import kotlinx.coroutines.test.runBlockingTest
+import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -110,6 +111,10 @@
                 .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_START)
                 .onEach { latest = it }
                 .launchIn(this)
+        // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+        // produce an initial value. We yield to give the coroutine time to emit the first real
+        // value from our config.
+        yield()
 
         assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
         val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
@@ -136,6 +141,10 @@
                 .quickAffordance(KeyguardQuickAffordancePosition.BOTTOM_END)
                 .onEach { latest = it }
                 .launchIn(this)
+        // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+        // produce an initial value. We yield to give the coroutine time to emit the first real
+        // value from our config.
+        yield()
 
         assertThat(latest).isInstanceOf(KeyguardQuickAffordanceModel.Visible::class.java)
         val visibleModel = latest as KeyguardQuickAffordanceModel.Visible
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
index 14b85b8..c612091 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/viewmodel/KeyguardBottomAreaViewModelTest.kt
@@ -224,7 +224,10 @@
         repository.setAnimateDozingTransitions(false)
         yield()
 
-        assertThat(values).isEqualTo(listOf(false, true, false))
+        // Note the extra false value in the beginning. This is to cover for the initial value
+        // inserted by the quick affordance interactor which it does to cover for config
+        // implementations that don't emit an initial value.
+        assertThat(values).isEqualTo(listOf(false, false, true, false))
         job.cancel()
     }
 
@@ -372,6 +375,10 @@
 
         var latest: KeyguardQuickAffordanceViewModel? = null
         val job = underTest.startButton.onEach { latest = it }.launchIn(this)
+        // The interactor has an onStart { emit(Hidden) } to cover for upstream configs that don't
+        // produce an initial value. We yield to give the coroutine time to emit the first real
+        // value from our config.
+        yield()
 
         assertQuickAffordanceViewModel(
             viewModel = latest,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
index 18bfd04..954b438 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/MediaHierarchyManagerTest.kt
@@ -29,6 +29,7 @@
 import com.android.systemui.controls.controller.ControlsControllerImplTest.Companion.eq
 import com.android.systemui.dreams.DreamOverlayStateController
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.media.dream.MediaDreamComplication
 import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.shade.testing.FakeNotifPanelEvents
 import com.android.systemui.statusbar.StatusBarState
@@ -38,6 +39,8 @@
 import com.android.systemui.statusbar.policy.KeyguardStateController
 import com.android.systemui.util.animation.UniqueObjectHostView
 import com.android.systemui.util.mockito.any
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.nullable
 import com.android.systemui.util.settings.FakeSettings
 import com.android.systemui.utils.os.FakeHandler
 import com.google.common.truth.Truth.assertThat
@@ -79,6 +82,9 @@
     private lateinit var wakefullnessObserver: ArgumentCaptor<(WakefulnessLifecycle.Observer)>
     @Captor
     private lateinit var statusBarCallback: ArgumentCaptor<(StatusBarStateController.StateListener)>
+    @Captor
+    private lateinit var dreamOverlayCallback:
+            ArgumentCaptor<(DreamOverlayStateController.Callback)>
     @JvmField
     @Rule
     val mockito = MockitoJUnit.rule()
@@ -113,6 +119,7 @@
                 fakeHandler,)
         verify(wakefulnessLifecycle).addObserver(wakefullnessObserver.capture())
         verify(statusBarStateController).addCallback(statusBarCallback.capture())
+        verify(dreamOverlayStateController).addCallback(dreamOverlayCallback.capture())
         setupHost(lockHost, MediaHierarchyManager.LOCATION_LOCKSCREEN, LOCKSCREEN_TOP)
         setupHost(qsHost, MediaHierarchyManager.LOCATION_QS, QS_TOP)
         setupHost(qqsHost, MediaHierarchyManager.LOCATION_QQS, QQS_TOP)
@@ -332,6 +339,27 @@
         assertThat(mediaHierarchyManager.isCurrentlyInGuidedTransformation()).isFalse()
     }
 
+    @Test
+    fun testDream() {
+        goToDream()
+        setMediaDreamComplicationEnabled(true)
+        verify(mediaCarouselController).onDesiredLocationChanged(
+                eq(MediaHierarchyManager.LOCATION_DREAM_OVERLAY),
+                nullable(),
+                eq(false),
+                anyLong(),
+                anyLong())
+        clearInvocations(mediaCarouselController)
+
+        setMediaDreamComplicationEnabled(false)
+        verify(mediaCarouselController).onDesiredLocationChanged(
+                eq(MediaHierarchyManager.LOCATION_QQS),
+                any(MediaHostState::class.java),
+                eq(false),
+                anyLong(),
+                anyLong())
+    }
+
     private fun enableSplitShade() {
         context.getOrCreateTestableResources().addOverride(
             R.bool.config_use_split_notification_shade, true
@@ -343,6 +371,8 @@
         whenever(statusBarStateController.state).thenReturn(StatusBarState.KEYGUARD)
         settings.putInt(Settings.Secure.MEDIA_CONTROLS_LOCK_SCREEN, 1)
         statusBarCallback.value.onStatePreChange(StatusBarState.SHADE, StatusBarState.KEYGUARD)
+        whenever(dreamOverlayStateController.isOverlayActive).thenReturn(false)
+        dreamOverlayCallback.value.onStateChanged()
         clearInvocations(mediaCarouselController)
     }
 
@@ -354,6 +384,17 @@
         )
     }
 
+    private fun goToDream() {
+        whenever(dreamOverlayStateController.isOverlayActive).thenReturn(true)
+        dreamOverlayCallback.value.onStateChanged()
+    }
+
+    private fun setMediaDreamComplicationEnabled(enabled: Boolean) {
+        val complications = if (enabled) listOf(mock<MediaDreamComplication>()) else emptyList()
+        whenever(dreamOverlayStateController.complications).thenReturn(complications)
+        dreamOverlayCallback.value.onComplicationsChanged()
+    }
+
     private fun expandQS() {
         mediaHierarchyManager.qsExpansion = 1.0f
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
index 2e864dc..0bfc034 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/dream/MediaDreamSentinelTest.java
@@ -72,13 +72,13 @@
     }
 
     @Test
-    public void testComplicationAddition() {
+    public void testOnMediaDataLoaded_complicationAddition() {
         final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
                 mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
-
         sentinel.start();
 
         final MediaDataManager.Listener listener = captureMediaDataListener();
+
         when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
         listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */ true,
                 /* receivedSmartspaceCardLatency= */ 0, /* isSsReactived= */ false);
@@ -90,6 +90,19 @@
         verify(mDreamOverlayStateController).addComplication(eq(mMediaEntryComplication));
         verify(mDreamOverlayStateController, never()).addComplication(
                 not(eq(mMediaEntryComplication)));
+    }
+
+    @Test
+    public void testOnMediaDataRemoved_complicationRemoval() {
+        final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+                mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
+        sentinel.start();
+
+        final MediaDataManager.Listener listener = captureMediaDataListener();
+
+        when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
 
         listener.onMediaDataRemoved(mKey);
         verify(mDreamOverlayStateController, never()).removeComplication(any());
@@ -100,7 +113,30 @@
     }
 
     @Test
-    public void testMediaDreamSentinel_mediaComplicationDisabled_doNotAddComplication() {
+    public void testOnMediaDataLoaded_complicationRemoval() {
+        final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
+                mDreamOverlayStateController, mMediaEntryComplication, mFeatureFlags);
+        sentinel.start();
+
+        final MediaDataManager.Listener listener = captureMediaDataListener();
+
+        when(mMediaDataManager.hasActiveMedia()).thenReturn(true);
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+        verify(mDreamOverlayStateController, never()).removeComplication(any());
+
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+        verify(mDreamOverlayStateController, never()).removeComplication(any());
+
+        when(mMediaDataManager.hasActiveMedia()).thenReturn(false);
+        listener.onMediaDataLoaded(mKey, mOldKey, mData, /* immediately= */true,
+                /* receivedSmartspaceCardLatency= */0, /* isSsReactived= */ false);
+        verify(mDreamOverlayStateController).removeComplication(eq(mMediaEntryComplication));
+    }
+
+    @Test
+    public void testOnMediaDataLoaded_mediaComplicationDisabled_doesNotAddComplication() {
         when(mFeatureFlags.isEnabled(MEDIA_DREAM_COMPLICATION)).thenReturn(false);
 
         final MediaDreamSentinel sentinel = new MediaDreamSentinel(mContext, mMediaDataManager,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
index 171d893..e7b4593 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/receiver/MediaTttChipControllerReceiverTest.kt
@@ -41,7 +41,6 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -74,8 +73,6 @@
     @Mock
     private lateinit var windowManager: WindowManager
     @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
     private lateinit var commandQueue: CommandQueue
     private lateinit var commandQueueCallback: CommandQueue.Callbacks
     private lateinit var fakeAppIconDrawable: Drawable
@@ -102,7 +99,6 @@
             context,
             logger,
             windowManager,
-            viewUtil,
             FakeExecutor(FakeSystemClock()),
             accessibilityManager,
             configurationController,
@@ -182,7 +178,7 @@
 
     @Test
     fun setIcon_isAppIcon_usesAppIconSize() {
-        controllerReceiver.displayChip(getChipReceiverInfo())
+        controllerReceiver.displayView(getChipReceiverInfo())
         val chipView = getChipView()
 
         controllerReceiver.setIcon(chipView, PACKAGE_NAME)
@@ -198,7 +194,7 @@
 
     @Test
     fun setIcon_notAppIcon_usesGenericIconSize() {
-        controllerReceiver.displayChip(getChipReceiverInfo())
+        controllerReceiver.displayView(getChipReceiverInfo())
         val chipView = getChipView()
 
         controllerReceiver.setIcon(chipView, appPackageName = null)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
index 1061e3c..52b6eed 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/sender/MediaTttChipControllerSenderTest.kt
@@ -42,7 +42,6 @@
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.mockito.eq
 import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -51,8 +50,8 @@
 import org.mockito.Mock
 import org.mockito.Mockito.never
 import org.mockito.Mockito.verify
-import org.mockito.MockitoAnnotations
 import org.mockito.Mockito.`when` as whenever
+import org.mockito.MockitoAnnotations
 
 @SmallTest
 @RunWith(AndroidTestingRunner::class)
@@ -75,8 +74,6 @@
     @Mock
     private lateinit var windowManager: WindowManager
     @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
     private lateinit var commandQueue: CommandQueue
     private lateinit var commandQueueCallback: CommandQueue.Callbacks
     private lateinit var fakeAppIconDrawable: Drawable
@@ -110,7 +107,6 @@
             context,
             logger,
             windowManager,
-            viewUtil,
             fakeExecutor,
             accessibilityManager,
             configurationController,
@@ -309,7 +305,7 @@
     @Test
     fun almostCloseToStartCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
         val state = almostCloseToStartCast()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -325,7 +321,7 @@
     @Test
     fun almostCloseToEndCast_appIcon_deviceName_noLoadingIcon_noUndo_noFailureIcon() {
         val state = almostCloseToEndCast()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -341,7 +337,7 @@
     @Test
     fun transferToReceiverTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
         val state = transferToReceiverTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -357,7 +353,7 @@
     @Test
     fun transferToThisDeviceTriggered_appIcon_loadingIcon_noUndo_noFailureIcon() {
         val state = transferToThisDeviceTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -373,7 +369,7 @@
     @Test
     fun transferToReceiverSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
         val state = transferToReceiverSucceeded()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -387,7 +383,7 @@
 
     @Test
     fun transferToReceiverSucceeded_nullUndoRunnable_noUndo() {
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback = null))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback = null))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -398,7 +394,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -414,7 +410,7 @@
             }
         }
 
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
         getChipView().getUndoButton().performClick()
 
         assertThat(undoCallbackCalled).isTrue()
@@ -425,7 +421,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToReceiverSucceeded(undoCallback))
+        controllerSender.displayView(transferToReceiverSucceeded(undoCallback))
 
         getChipView().getUndoButton().performClick()
 
@@ -440,7 +436,7 @@
     @Test
     fun transferToThisDeviceSucceeded_appIcon_deviceName_noLoadingIcon_noFailureIcon() {
         val state = transferToThisDeviceSucceeded()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -454,7 +450,7 @@
 
     @Test
     fun transferToThisDeviceSucceeded_nullUndoRunnable_noUndo() {
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback = null))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback = null))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.GONE)
@@ -465,7 +461,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
 
         val chipView = getChipView()
         assertThat(chipView.getUndoButton().visibility).isEqualTo(View.VISIBLE)
@@ -481,7 +477,7 @@
             }
         }
 
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
         getChipView().getUndoButton().performClick()
 
         assertThat(undoCallbackCalled).isTrue()
@@ -492,7 +488,7 @@
         val undoCallback = object : IUndoMediaTransferCallback.Stub() {
             override fun onUndoTriggered() {}
         }
-        controllerSender.displayChip(transferToThisDeviceSucceeded(undoCallback))
+        controllerSender.displayView(transferToThisDeviceSucceeded(undoCallback))
 
         getChipView().getUndoButton().performClick()
 
@@ -507,7 +503,7 @@
     @Test
     fun transferToReceiverFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
         val state = transferToReceiverFailed()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -523,7 +519,7 @@
     @Test
     fun transferToThisDeviceFailed_appIcon_noDeviceName_noLoadingIcon_noUndo_failureIcon() {
         val state = transferToThisDeviceFailed()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
 
         val chipView = getChipView()
         assertThat(chipView.getAppIconView().drawable).isEqualTo(fakeAppIconDrawable)
@@ -538,24 +534,24 @@
 
     @Test
     fun changeFromAlmostCloseToStartToTransferTriggered_loadingIconAppears() {
-        controllerSender.displayChip(almostCloseToStartCast())
-        controllerSender.displayChip(transferToReceiverTriggered())
+        controllerSender.displayView(almostCloseToStartCast())
+        controllerSender.displayView(transferToReceiverTriggered())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.VISIBLE)
     }
 
     @Test
     fun changeFromTransferTriggeredToTransferSucceeded_loadingIconDisappears() {
-        controllerSender.displayChip(transferToReceiverTriggered())
-        controllerSender.displayChip(transferToReceiverSucceeded())
+        controllerSender.displayView(transferToReceiverTriggered())
+        controllerSender.displayView(transferToReceiverSucceeded())
 
         assertThat(getChipView().getLoadingIconVisibility()).isEqualTo(View.GONE)
     }
 
     @Test
     fun changeFromTransferTriggeredToTransferSucceeded_undoButtonAppears() {
-        controllerSender.displayChip(transferToReceiverTriggered())
-        controllerSender.displayChip(
+        controllerSender.displayView(transferToReceiverTriggered())
+        controllerSender.displayView(
             transferToReceiverSucceeded(
                 object : IUndoMediaTransferCallback.Stub() {
                     override fun onUndoTriggered() {}
@@ -568,26 +564,26 @@
 
     @Test
     fun changeFromTransferSucceededToAlmostCloseToStart_undoButtonDisappears() {
-        controllerSender.displayChip(transferToReceiverSucceeded())
-        controllerSender.displayChip(almostCloseToStartCast())
+        controllerSender.displayView(transferToReceiverSucceeded())
+        controllerSender.displayView(almostCloseToStartCast())
 
         assertThat(getChipView().getUndoButton().visibility).isEqualTo(View.GONE)
     }
 
     @Test
     fun changeFromTransferTriggeredToTransferFailed_failureIconAppears() {
-        controllerSender.displayChip(transferToReceiverTriggered())
-        controllerSender.displayChip(transferToReceiverFailed())
+        controllerSender.displayView(transferToReceiverTriggered())
+        controllerSender.displayView(transferToReceiverFailed())
 
         assertThat(getChipView().getFailureIcon().visibility).isEqualTo(View.VISIBLE)
     }
 
     @Test
-    fun transferToReceiverTriggeredThenRemoveChip_chipStillDisplayed() {
-        controllerSender.displayChip(transferToReceiverTriggered())
+    fun transferToReceiverTriggeredThenRemoveView_viewStillDisplayed() {
+        controllerSender.displayView(transferToReceiverTriggered())
         fakeClock.advanceTime(1000L)
 
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
         fakeExecutor.runAllReady()
 
         verify(windowManager, never()).removeView(any())
@@ -596,9 +592,9 @@
     @Test
     fun transferToReceiverTriggeredThenFarFromReceiver_eventuallyTimesOut() {
         val state = transferToReceiverTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
         fakeClock.advanceTime(1000L)
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
 
         fakeClock.advanceTime(TIMEOUT + 1L)
 
@@ -606,11 +602,11 @@
     }
 
     @Test
-    fun transferToThisDeviceTriggeredThenRemoveChip_chipStillDisplayed() {
-        controllerSender.displayChip(transferToThisDeviceTriggered())
+    fun transferToThisDeviceTriggeredThenRemoveView_viewStillDisplayed() {
+        controllerSender.displayView(transferToThisDeviceTriggered())
         fakeClock.advanceTime(1000L)
 
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
         fakeExecutor.runAllReady()
 
         verify(windowManager, never()).removeView(any())
@@ -619,9 +615,9 @@
     @Test
     fun transferToThisDeviceTriggeredThenFarFromReceiver_eventuallyTimesOut() {
         val state = transferToThisDeviceTriggered()
-        controllerSender.displayChip(state)
+        controllerSender.displayView(state)
         fakeClock.advanceTime(1000L)
-        controllerSender.removeChip("fakeRemovalReason")
+        controllerSender.removeView("fakeRemovalReason")
 
         fakeClock.advanceTime(TIMEOUT + 1L)
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
index e4751d1..2a4996f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/qs/footer/ui/viewmodel/FooterActionsViewModelTest.kt
@@ -70,9 +70,13 @@
         val underTest = utils.footerActionsViewModel(showPowerButton = false)
         val settings = underTest.settings
 
-        assertThat(settings.contentDescription)
-            .isEqualTo(ContentDescription.Resource(R.string.accessibility_quick_settings_settings))
-        assertThat(settings.icon).isEqualTo(Icon.Resource(R.drawable.ic_settings))
+        assertThat(settings.icon)
+            .isEqualTo(
+                Icon.Resource(
+                    R.drawable.ic_settings,
+                    ContentDescription.Resource(R.string.accessibility_quick_settings_settings)
+                )
+            )
         assertThat(settings.background).isEqualTo(R.drawable.qs_footer_action_circle)
         assertThat(settings.iconTint).isNull()
     }
@@ -87,11 +91,13 @@
         val underTestWithPower = utils.footerActionsViewModel(showPowerButton = true)
         val power = underTestWithPower.power
         assertThat(power).isNotNull()
-        assertThat(power!!.contentDescription)
+        assertThat(power!!.icon)
             .isEqualTo(
-                ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+                Icon.Resource(
+                    android.R.drawable.ic_lock_power_off,
+                    ContentDescription.Resource(R.string.accessibility_quick_settings_power_menu)
+                )
             )
-        assertThat(power.icon).isEqualTo(Icon.Resource(android.R.drawable.ic_lock_power_off))
         assertThat(power.background).isEqualTo(R.drawable.qs_footer_action_circle_color)
         assertThat(power.iconTint)
             .isEqualTo(
@@ -164,14 +170,13 @@
         utils.setUserSwitcherEnabled(settings, true, userId)
         val userSwitcher = currentUserSwitcher()
         assertThat(userSwitcher).isNotNull()
-        assertThat(userSwitcher!!.contentDescription)
-            .isEqualTo(ContentDescription.Loaded("Signed in as foo"))
-        assertThat(userSwitcher.icon).isEqualTo(Icon.Loaded(picture))
+        assertThat(userSwitcher!!.icon)
+            .isEqualTo(Icon.Loaded(picture, ContentDescription.Loaded("Signed in as foo")))
         assertThat(userSwitcher.background).isEqualTo(R.drawable.qs_footer_action_circle)
 
         // Change the current user name.
         userSwitcherControllerWrapper.currentUserName = "bar"
-        assertThat(currentUserSwitcher()?.contentDescription)
+        assertThat(currentUserSwitcher()?.icon?.contentDescription)
             .isEqualTo(ContentDescription.Loaded("Signed in as bar"))
 
         fun iconTint(): Int? = currentUserSwitcher()!!.iconTint
@@ -243,7 +248,7 @@
         // Map any SecurityModel into a non-null SecurityButtonConfig.
         val buttonConfig =
             SecurityButtonConfig(
-                icon = Icon.Resource(0),
+                icon = Icon.Resource(res = 0, contentDescription = null),
                 text = "foo",
                 isClickable = true,
             )
@@ -340,7 +345,7 @@
         assertThat(foregroundServices.displayText).isTrue()
         securityToConfig = {
             SecurityButtonConfig(
-                icon = Icon.Resource(0),
+                icon = Icon.Resource(res = 0, contentDescription = null),
                 text = "foo",
                 isClickable = true,
             )
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
index f267013..3224a6f 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationPanelViewControllerTest.java
@@ -547,8 +547,6 @@
                 mNavigationModeController,
                 mFragmentService,
                 mContentResolver,
-                mQuickAccessWalletController,
-                mQrCodeScannerController,
                 mRecordingController,
                 mLargeScreenShadeHeaderController,
                 mScreenOffAnimationController,
@@ -556,7 +554,6 @@
                 mPanelExpansionStateManager,
                 mNotificationRemoteInputManager,
                 mSysUIUnfoldComponent,
-                mControlsComponent,
                 mInteractionJankMonitor,
                 mQsFrameTranslateController,
                 mSysUiState,
@@ -569,8 +566,8 @@
                 mShadeTransitionController,
                 mSystemClock,
                 mock(CameraGestureHelper.class),
-                () -> mKeyguardBottomAreaViewModel,
-                () -> mKeyguardBottomAreaInteractor);
+                mKeyguardBottomAreaViewModel,
+                mKeyguardBottomAreaInteractor);
         mNotificationPanelViewController.initDependencies(
                 mCentralSurfaces,
                 () -> {},
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
index 43fc8983..2adc389 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/NotificationShadeWindowViewControllerTest.kt
@@ -19,8 +19,10 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import android.view.MotionEvent
+import android.view.ViewGroup
 import androidx.test.filters.SmallTest
 import com.android.keyguard.LockIconViewController
+import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.classifier.FalsingCollectorFake
 import com.android.systemui.dock.DockManager
@@ -246,6 +248,18 @@
         verify(phoneStatusBarViewController).sendTouchToView(nextEvent)
         assertThat(returnVal).isTrue()
     }
+
+    @Test
+    fun testGetBouncerContainer() {
+        underTest.bouncerContainer
+        verify(view).findViewById<ViewGroup>(R.id.keyguard_bouncer_container)
+    }
+
+    @Test
+    fun testGetKeyguardMessageArea() {
+        underTest.keyguardMessageArea
+        verify(view).findViewById<ViewGroup>(R.id.keyguard_message_area)
+    }
 }
 
 private val downEv = MotionEvent.obtain(0L, 0L, MotionEvent.ACTION_DOWN, 0f, 0f, 0)
diff --git a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
index d2970a6..97c0bb2 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/shade/PulsingGestureListenerTest.kt
@@ -27,6 +27,7 @@
 import com.android.systemui.dock.DockManager
 import com.android.systemui.dump.DumpManager
 import com.android.systemui.plugins.FalsingManager
+import com.android.systemui.plugins.statusbar.StatusBarStateController
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.tuner.TunerService
 import com.android.systemui.tuner.TunerService.Tunable
@@ -63,6 +64,8 @@
     private lateinit var tunerService: TunerService
     @Mock
     private lateinit var dumpManager: DumpManager
+    @Mock
+    private lateinit var statusBarStateController: StatusBarStateController
 
     private lateinit var tunableCaptor: ArgumentCaptor<Tunable>
     private lateinit var underTest: PulsingGestureListener
@@ -77,6 +80,7 @@
                 dockManager,
                 centralSurfaces,
                 ambientDisplayConfiguration,
+                statusBarStateController,
                 tunerService,
                 dumpManager
         )
@@ -85,6 +89,8 @@
 
     @Test
     fun testGestureDetector_singleTapEnabled() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -102,6 +108,8 @@
 
     @Test
     fun testGestureDetector_doubleTapEnabled() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN double tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -119,6 +127,8 @@
 
     @Test
     fun testGestureDetector_singleTapEnabled_falsing() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -135,7 +145,23 @@
     }
 
     @Test
+    fun testGestureDetector_notPulsing_noFalsingCheck() {
+        whenever(statusBarStateController.isPulsing).thenReturn(false)
+
+        // GIVEN tap is enabled, prox not covered
+        whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
+        // WHEN there's a tap
+        underTest.onSingleTapConfirmed(downEv)
+
+        // THEN the falsing manager never gets a call (because the device wasn't pulsing
+        // during the tap)
+        verify(falsingManager, never()).isFalseTap(anyInt())
+    }
+
+    @Test
     fun testGestureDetector_doubleTapEnabled_falsing() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN double tap is enabled, prox not covered
         whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -153,6 +179,8 @@
 
     @Test
     fun testGestureDetector_singleTapEnabled_proxCovered() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN tap is enabled, not a false tap based on classifiers
         whenever(ambientDisplayConfiguration.tapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
@@ -170,6 +198,8 @@
 
     @Test
     fun testGestureDetector_doubleTapEnabled_proxCovered() {
+        whenever(statusBarStateController.isPulsing).thenReturn(true)
+
         // GIVEN double tap is enabled, not a false tap based on classifiers
         whenever(ambientDisplayConfiguration.doubleTapGestureEnabled(anyInt())).thenReturn(true)
         updateSettings()
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
index 798f47d..ac8874b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/KeyguardIndicationControllerTest.java
@@ -19,6 +19,7 @@
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_DEFAULT;
 import static android.app.admin.DevicePolicyManager.DEVICE_OWNER_TYPE_FINANCED;
 import static android.content.pm.UserInfo.FLAG_MANAGED_PROFILE;
+import static android.hardware.biometrics.BiometricFaceConstants.FACE_ERROR_TIMEOUT;
 
 import static com.android.keyguard.KeyguardUpdateMonitor.BIOMETRIC_HELP_FINGERPRINT_NOT_RECOGNIZED;
 import static com.android.systemui.keyguard.KeyguardIndicationRotateTextViewController.INDICATION_TYPE_ALIGNMENT;
@@ -65,7 +66,6 @@
 import android.graphics.Color;
 import android.hardware.biometrics.BiometricFaceConstants;
 import android.hardware.biometrics.BiometricSourceType;
-import android.hardware.face.FaceManager;
 import android.hardware.fingerprint.FingerprintManager;
 import android.os.BatteryManager;
 import android.os.Looper;
@@ -602,7 +602,7 @@
         String message = mContext.getString(R.string.keyguard_unlock);
 
         mController.setVisible(true);
-        mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+        mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
                 "A message", BiometricSourceType.FACE);
 
         verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, message);
@@ -636,10 +636,10 @@
         when(mKeyguardUpdateMonitor.isFaceEnrolled()).thenReturn(true);
 
         mController.setVisible(true);
-        mController.getKeyguardCallback().onBiometricError(FaceManager.FACE_ERROR_TIMEOUT,
+        mController.getKeyguardCallback().onBiometricError(FACE_ERROR_TIMEOUT,
                 "A message", BiometricSourceType.FACE);
 
-        verify(mStatusBarKeyguardViewManager).showBouncerMessage(eq(message), any());
+        verify(mStatusBarKeyguardViewManager).setKeyguardMessage(eq(message), any());
     }
 
     @Test
@@ -651,7 +651,7 @@
 
         mController.setVisible(true);
         mController.getKeyguardCallback().onBiometricError(
-                FaceManager.FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
+                FACE_ERROR_TIMEOUT, message, BiometricSourceType.FACE);
         verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
     }
 
@@ -698,8 +698,7 @@
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
         };
         for (int msgId : msgIds) {
             mKeyguardUpdateMonitorCallback.onBiometricHelp(
@@ -728,8 +727,7 @@
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LEFT,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_HIGH,
                 BiometricFaceConstants.FACE_ACQUIRED_TOO_LOW,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT,
-                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_BRIGHT
         };
         for (int msgId : msgIds) {
             final String numberedHelpString = helpString + msgId;
@@ -743,6 +741,64 @@
     }
 
     @Test
+    public void sendTooDarkFaceHelpMessages_onTimeout_noFpEnrolled() {
+        createController();
+
+        // GIVEN fingerprint NOT enrolled
+        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+                0)).thenReturn(false);
+
+        // WHEN help message received
+        final String helpString = "helpMsg";
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+                helpString,
+                BiometricSourceType.FACE
+        );
+
+        // THEN help message not shown yet
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+        // WHEN face timeout error received
+        mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+                BiometricSourceType.FACE);
+
+        // THEN the low light message shows with suggestion to swipe up to unlock
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+                mContext.getString(R.string.keyguard_unlock));
+    }
+
+    @Test
+    public void sendTooDarkFaceHelpMessages_onTimeout_fingerprintEnrolled() {
+        createController();
+
+        // GIVEN fingerprint enrolled
+        when(mKeyguardUpdateMonitor.getCachedIsUnlockWithFingerprintPossible(
+                0)).thenReturn(true);
+
+        // WHEN help message received
+        final String helpString = "helpMsg";
+        mKeyguardUpdateMonitorCallback.onBiometricHelp(
+                BiometricFaceConstants.FACE_ACQUIRED_TOO_DARK,
+                helpString,
+                BiometricSourceType.FACE
+        );
+
+        // THEN help message not shown yet
+        verifyNoMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE);
+
+        // WHEN face timeout error received
+        mKeyguardUpdateMonitorCallback.onBiometricError(FACE_ERROR_TIMEOUT, "face timeout",
+                BiometricSourceType.FACE);
+
+        // THEN the low light message shows and suggests trying fingerprint
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE, helpString);
+        verifyIndicationMessage(INDICATION_TYPE_BIOMETRIC_MESSAGE_FOLLOW_UP,
+                mContext.getString(R.string.keyguard_suggest_fingerprint));
+    }
+
+    @Test
     public void updateMonitor_listenerUpdatesIndication() {
         createController();
         String restingIndication = "Resting indication";
@@ -994,14 +1050,14 @@
     }
 
     @Test
-    public void onTrustGrantedMessageDoesShowsOnTrustGranted() {
+    public void onTrustGrantedMessageShowsOnTrustGranted() {
         createController();
         mController.setVisible(true);
 
         // GIVEN trust is granted
         when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
 
-        // WHEN the showTrustGranted message is called
+        // WHEN the showTrustGranted method is called
         final String trustGrantedMsg = "testing trust granted message";
         mController.getKeyguardCallback().showTrustGrantedMessage(trustGrantedMsg);
 
@@ -1012,6 +1068,38 @@
     }
 
     @Test
+    public void onTrustGrantedMessage_nullMessage_showsDefaultMessage() {
+        createController();
+        mController.setVisible(true);
+
+        // GIVEN trust is granted
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+        // WHEN the showTrustGranted method is called with a null message
+        mController.getKeyguardCallback().showTrustGrantedMessage(null);
+
+        // THEN verify the default trust granted message shows
+        verifyIndicationMessage(
+                INDICATION_TYPE_TRUST,
+                getContext().getString(R.string.keyguard_indication_trust_unlocked));
+    }
+
+    @Test
+    public void onTrustGrantedMessage_emptyString_showsNoMessage() {
+        createController();
+        mController.setVisible(true);
+
+        // GIVEN trust is granted
+        when(mKeyguardUpdateMonitor.getUserHasTrust(anyInt())).thenReturn(true);
+
+        // WHEN the showTrustGranted method is called with an EMPTY string
+        mController.getKeyguardCallback().showTrustGrantedMessage("");
+
+        // THEN verify NO trust message is shown
+        verifyNoMessage(INDICATION_TYPE_TRUST);
+    }
+
+    @Test
     public void coEx_faceSuccess_showsPressToOpen() {
         // GIVEN bouncer isn't showing, can skip bouncer, udfps is supported, no a11y enabled
         when(mStatusBarKeyguardViewManager.isBouncerShowing()).thenReturn(false);
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
index b166b73..6446fb5 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/NotificationShadeDepthControllerTest.kt
@@ -48,7 +48,6 @@
 import org.mockito.Captor
 import org.mockito.Mock
 import org.mockito.Mockito
-import org.mockito.Mockito.`when`
 import org.mockito.Mockito.any
 import org.mockito.Mockito.anyFloat
 import org.mockito.Mockito.anyString
@@ -56,6 +55,7 @@
 import org.mockito.Mockito.never
 import org.mockito.Mockito.reset
 import org.mockito.Mockito.verify
+import org.mockito.Mockito.`when`
 import org.mockito.junit.MockitoJUnit
 
 @RunWith(AndroidTestingRunner::class)
@@ -139,7 +139,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 1f, expanded = true, tracking = false, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(maxBlur), any())
+        verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
     @Test
@@ -147,7 +147,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 0.01f, expanded = false, tracking = false, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(maxBlur), any())
+        verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
     @Test
@@ -157,7 +157,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 0f, expanded = false, tracking = false, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(0), any())
+        verify(shadeAnimation).animateTo(eq(0))
     }
 
     @Test
@@ -168,15 +168,15 @@
         onPanelExpansionChanged_apliesBlur_ifShade()
         clearInvocations(shadeAnimation)
         notificationShadeDepthController.onPanelExpansionChanged(event)
-        verify(shadeAnimation, never()).animateTo(anyInt(), any())
+        verify(shadeAnimation, never()).animateTo(anyInt())
 
         notificationShadeDepthController.onPanelExpansionChanged(
             event.copy(fraction = 0.9f, tracking = true))
-        verify(shadeAnimation, never()).animateTo(anyInt(), any())
+        verify(shadeAnimation, never()).animateTo(anyInt())
 
         notificationShadeDepthController.onPanelExpansionChanged(
             event.copy(fraction = 0.8f, tracking = false))
-        verify(shadeAnimation).animateTo(eq(0), any())
+        verify(shadeAnimation).animateTo(eq(0))
     }
 
     @Test
@@ -186,7 +186,7 @@
         notificationShadeDepthController.onPanelExpansionChanged(
             PanelExpansionChangeEvent(
                 fraction = 0.6f, expanded = true, tracking = true, dragDownPxAmount = 0f))
-        verify(shadeAnimation).animateTo(eq(maxBlur), any())
+        verify(shadeAnimation).animateTo(eq(maxBlur))
     }
 
     @Test
@@ -212,7 +212,7 @@
 
         statusBarState = StatusBarState.KEYGUARD
         statusBarStateListener.onStateChanged(statusBarState)
-        verify(shadeAnimation).animateTo(eq(0), any())
+        verify(shadeAnimation).animateTo(eq(0))
     }
 
     @Test
@@ -395,13 +395,13 @@
     @Test
     fun brightnessMirrorVisible_whenVisible() {
         notificationShadeDepthController.brightnessMirrorVisible = true
-        verify(brightnessSpring).animateTo(eq(maxBlur), any())
+        verify(brightnessSpring).animateTo(eq(maxBlur))
     }
 
     @Test
     fun brightnessMirrorVisible_whenHidden() {
         notificationShadeDepthController.brightnessMirrorVisible = false
-        verify(brightnessSpring).animateTo(eq(0), any())
+        verify(brightnessSpring).animateTo(eq(0))
     }
 
     @Test
@@ -424,7 +424,7 @@
     fun ignoreShadeBlurUntilHidden_whennNull_ignoresIfShadeHasNoBlur() {
         `when`(shadeAnimation.radius).thenReturn(0f)
         notificationShadeDepthController.blursDisabledForAppLaunch = true
-        verify(shadeAnimation, never()).animateTo(anyInt(), any())
+        verify(shadeAnimation, never()).animateTo(anyInt())
     }
 
     private fun enableSplitShade() {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
new file mode 100644
index 0000000..11798a7
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/AmbientStateTest.kt
@@ -0,0 +1,390 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License
+ */
+
+package com.android.systemui.statusbar.notification.stack
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.android.systemui.dump.DumpManager
+import com.android.systemui.statusbar.StatusBarState
+import com.android.systemui.statusbar.phone.StatusBarKeyguardViewManager
+import com.android.systemui.util.mockito.mock
+import com.android.systemui.util.mockito.whenever
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+private const val MAX_PULSE_HEIGHT = 100000f
+
+@RunWith(AndroidTestingRunner::class)
+@SmallTest
+class AmbientStateTest : SysuiTestCase() {
+
+    private val dumpManager = mock<DumpManager>()
+    private val sectionProvider = StackScrollAlgorithm.SectionProvider { _, _ -> false }
+    private val bypassController = StackScrollAlgorithm.BypassController { false }
+    private val statusBarKeyguardViewManager = mock<StatusBarKeyguardViewManager>()
+
+    private lateinit var sut: AmbientState
+
+    @Before
+    fun setUp() {
+        sut =
+            AmbientState(
+                context,
+                dumpManager,
+                sectionProvider,
+                bypassController,
+                statusBarKeyguardViewManager,
+            )
+    }
+
+    // region isDimmed
+    @Test
+    fun isDimmed_whenTrue_shouldReturnTrue() {
+        sut.arrangeDimmed(true)
+
+        assertThat(sut.isDimmed).isTrue()
+    }
+
+    @Test
+    fun isDimmed_whenFalse_shouldReturnFalse() {
+        sut.arrangeDimmed(false)
+
+        assertThat(sut.isDimmed).isFalse()
+    }
+
+    @Test
+    fun isDimmed_whenDozeAmountIsEmpty_shouldReturnTrue() {
+        sut.arrangeDimmed(true)
+        sut.dozeAmount = 0f
+
+        assertThat(sut.isDimmed).isTrue()
+    }
+
+    @Test
+    fun isDimmed_whenPulseExpandingIsFalse_shouldReturnTrue() {
+        sut.arrangeDimmed(true)
+        sut.arrangePulseExpanding(false)
+        sut.dozeAmount = 1f // arrangePulseExpanding changes dozeAmount
+
+        assertThat(sut.isDimmed).isTrue()
+    }
+    // endregion
+
+    // region pulseHeight
+    @Test
+    fun pulseHeight_whenValueChanged_shouldCallListener() {
+        var listenerCalledCount = 0
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+        sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
+
+        sut.pulseHeight = 0f
+
+        assertThat(listenerCalledCount).isEqualTo(1)
+    }
+
+    @Test
+    fun pulseHeight_whenSetSameValue_shouldDoNothing() {
+        var listenerCalledCount = 0
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+        sut.setOnPulseHeightChangedListener { listenerCalledCount++ }
+
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+
+        assertThat(listenerCalledCount).isEqualTo(0)
+    }
+
+    @Test
+    fun pulseHeight_whenValueIsFull_shouldReturn0() {
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun pulseHeight_whenValueIsNotFull_shouldReturnValue() {
+        val expected = MAX_PULSE_HEIGHT - 0.1f
+        sut.pulseHeight = expected
+
+        assertThat(sut.pulseHeight).isEqualTo(expected)
+    }
+    // endregion
+
+    // region statusBarState
+    @Test
+    fun statusBarState_whenPreviousStateIsNotKeyguardAndChange_shouldSetIsFlingRequiredToFalse() {
+        sut.setStatusBarState(StatusBarState.SHADE)
+        sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+        sut.setStatusBarState(StatusBarState.KEYGUARD)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+    }
+
+    @Test
+    fun statusBarState_whenPreviousStateIsKeyguardAndChange_shouldDoNothing() {
+        sut.setStatusBarState(StatusBarState.KEYGUARD)
+        sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+        sut.setStatusBarState(StatusBarState.SHADE)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+    // endregion
+
+    // region hideAmount
+    @Test
+    fun hideAmount_whenSetToFullValue_shouldReturnZeroFromPulseHeight() {
+        sut.hideAmount = 0f
+        sut.pulseHeight = 1f
+
+        sut.hideAmount = 1f
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun hideAmount_whenSetToAnyNotFullValue_shouldDoNothing() {
+        sut.hideAmount = 1f
+        sut.pulseHeight = 1f
+
+        sut.hideAmount = 0f
+
+        assertThat(sut.pulseHeight).isEqualTo(1f)
+    }
+    // endregion
+
+    // region dozeAmount
+    @Test
+    fun dozeAmount_whenDozeAmountIsSetToFullDozing_shouldReturnZeroFromPulseHeight() {
+        sut.dozeAmount = 0f
+        sut.pulseHeight = 1f
+
+        sut.dozeAmount = 1f
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun dozeAmount_whenDozeAmountIsSetToFullAwake_shouldReturnZeroFromPulseHeight() {
+        sut.dozeAmount = 1f
+        sut.pulseHeight = 1f
+
+        sut.dozeAmount = 0f
+
+        assertThat(sut.pulseHeight).isEqualTo(0f)
+    }
+
+    @Test
+    fun dozeAmount_whenDozeAmountIsSetAnyValueNotFullAwakeOrDozing_shouldDoNothing() {
+        sut.dozeAmount = 1f
+        sut.pulseHeight = 1f
+
+        sut.dozeAmount = 0.5f
+
+        assertThat(sut.pulseHeight).isEqualTo(1f)
+    }
+    // endregion
+
+    // region trackedHeadsUpRow
+    @Test
+    fun trackedHeadsUpRow_whenIsAboveTheShelf_shouldReturnInstance() {
+        sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(true) }
+
+        assertThat(sut.trackedHeadsUpRow).isNotNull()
+    }
+
+    @Test
+    fun trackedHeadsUpRow_whenIsNotAboveTheShelf_shouldReturnNull() {
+        sut.trackedHeadsUpRow = mock { whenever(isAboveShelf).thenReturn(false) }
+
+        assertThat(sut.trackedHeadsUpRow).isNull()
+    }
+    // endregion
+
+    // region isSwipingUp
+    @Test
+    fun isSwipingUp_whenValueChangedToTrue_shouldRequireFling() {
+        sut.isSwipingUp = false
+        sut.isFlingRequiredAfterLockScreenSwipeUp = false
+
+        sut.isSwipingUp = true
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+    }
+
+    @Test
+    fun isSwipingUp_whenValueChangedToFalse_shouldRequireFling() {
+        sut.isSwipingUp = true
+        sut.isFlingRequiredAfterLockScreenSwipeUp = false
+
+        sut.isSwipingUp = false
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+    // endregion
+
+    // region isFlinging
+    @Test
+    fun isFlinging_shouldNotNeedFling() {
+        sut.arrangeFlinging(true)
+
+        sut.setFlinging(false)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isFalse()
+    }
+
+    @Test
+    fun isFlinging_whenNotOnLockScreen_shouldDoNothing() {
+        sut.arrangeFlinging(true)
+        sut.setStatusBarState(StatusBarState.SHADE)
+        sut.isFlingRequiredAfterLockScreenSwipeUp = true
+
+        sut.setFlinging(false)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+
+    @Test
+    fun isFlinging_whenValueChangedToTrue_shouldDoNothing() {
+        sut.arrangeFlinging(false)
+
+        sut.setFlinging(true)
+
+        assertThat(sut.isFlingRequiredAfterLockScreenSwipeUp).isTrue()
+    }
+    // endregion
+
+    // region scrollY
+    @Test
+    fun scrollY_shouldSetValueGreaterThanZero() {
+        sut.scrollY = 0
+
+        sut.scrollY = 1
+
+        assertThat(sut.scrollY).isEqualTo(1)
+    }
+
+    @Test
+    fun scrollY_shouldNotSetValueLessThanZero() {
+        sut.scrollY = 0
+
+        sut.scrollY = -1
+
+        assertThat(sut.scrollY).isEqualTo(0)
+    }
+    // endregion
+
+    // region setOverScrollAmount
+    fun setOverScrollAmount_shouldSetValueOnTop() {
+        sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ true)
+
+        val resultOnTop = sut.getOverScrollAmount(/* top = */ true)
+        val resultOnBottom = sut.getOverScrollAmount(/* top = */ false)
+
+        assertThat(resultOnTop).isEqualTo(10f)
+        assertThat(resultOnBottom).isEqualTo(0f)
+    }
+
+    fun setOverScrollAmount_shouldSetValueOnBottom() {
+        sut.setOverScrollAmount(/* amount = */ 10f, /* onTop = */ false)
+
+        val resultOnTop = sut.getOverScrollAmount(/* top */ true)
+        val resultOnBottom = sut.getOverScrollAmount(/* top */ false)
+
+        assertThat(resultOnTop).isEqualTo(0f)
+        assertThat(resultOnBottom).isEqualTo(10f)
+    }
+    // endregion
+
+    // region IsPulseExpanding
+    @Test
+    fun isPulseExpanding_shouldReturnTrue() {
+        sut.arrangePulseExpanding(true)
+
+        assertThat(sut.isPulseExpanding).isTrue()
+    }
+
+    @Test
+    fun isPulseExpanding_whenPulseHeightIsMax_shouldReturnFalse() {
+        sut.arrangePulseExpanding(true)
+        sut.pulseHeight = MAX_PULSE_HEIGHT
+
+        assertThat(sut.isPulseExpanding).isFalse()
+    }
+
+    @Test
+    fun isPulseExpanding_whenDozeAmountIsZero_shouldReturnFalse() {
+        sut.arrangePulseExpanding(true)
+        sut.dozeAmount = 0f
+
+        assertThat(sut.isPulseExpanding).isFalse()
+    }
+
+    @Test
+    fun isPulseExpanding_whenHideAmountIsFull_shouldReturnFalse() {
+        sut.arrangePulseExpanding(true)
+        sut.hideAmount = 1f
+
+        assertThat(sut.isPulseExpanding).isFalse()
+    }
+    // endregion
+
+    // region isOnKeyguard
+    @Test
+    fun isOnKeyguard_whenStatusBarStateIsKeyguard_shouldReturnTrue() {
+        sut.setStatusBarState(StatusBarState.KEYGUARD)
+
+        assertThat(sut.isOnKeyguard).isTrue()
+    }
+
+    @Test
+    fun isOnKeyguard_whenStatusBarStateIsNotKeyguard_shouldReturnFalse() {
+        sut.setStatusBarState(StatusBarState.SHADE)
+
+        assertThat(sut.isOnKeyguard).isFalse()
+    }
+    // endregion
+}
+
+// region Arrange helper methods.
+private fun AmbientState.arrangeDimmed(value: Boolean) {
+    isDimmed = value
+    dozeAmount = if (value) 0f else 1f
+    arrangePulseExpanding(!value)
+}
+
+private fun AmbientState.arrangePulseExpanding(value: Boolean) {
+    if (value) {
+        dozeAmount = 1f
+        hideAmount = 0f
+        pulseHeight = 0f
+    } else {
+        dozeAmount = 0f
+        hideAmount = 1f
+        pulseHeight = MAX_PULSE_HEIGHT
+    }
+}
+
+private fun AmbientState.arrangeFlinging(value: Boolean) {
+    setStatusBarState(StatusBarState.KEYGUARD)
+    setFlinging(value)
+    isFlingRequiredAfterLockScreenSwipeUp = true
+}
+// endregion
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
index 3f19036..7741813 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationShelfTest.kt
@@ -3,15 +3,22 @@
 import android.testing.AndroidTestingRunner
 import android.testing.TestableLooper.RunWithLooper
 import androidx.test.filters.SmallTest
+import com.android.keyguard.BouncerPanelExpansionCalculator.aboutToShowBouncerProgress
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.animation.ShadeInterpolation
 import com.android.systemui.statusbar.NotificationShelf
 import com.android.systemui.statusbar.StatusBarIconView
+import com.android.systemui.statusbar.notification.row.ExpandableNotificationRow
 import com.android.systemui.statusbar.notification.row.ExpandableView
-import junit.framework.Assert.*
+import com.android.systemui.statusbar.notification.stack.StackScrollAlgorithm.StackScrollAlgorithmState
+import com.android.systemui.util.mockito.mock
+import junit.framework.Assert.assertEquals
+import junit.framework.Assert.assertFalse
+import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
-import org.mockito.Mockito.*
+import org.mockito.Mockito.mock
 import org.mockito.Mockito.`when` as whenever
 
 /**
@@ -22,13 +29,18 @@
 @RunWithLooper
 class NotificationShelfTest : SysuiTestCase() {
 
-    private val shelf = NotificationShelf(context, /* attrs */ null)
+    private val shelf = NotificationShelf(
+            context,
+            /* attrs */ null,
+            /* showNotificationShelf */true
+    )
     private val shelfState = shelf.viewState as NotificationShelf.ShelfState
     private val ambientState = mock(AmbientState::class.java)
+    private val hostLayoutController: NotificationStackScrollLayoutController = mock()
 
     @Before
     fun setUp() {
-        shelf.bind(ambientState, /* hostLayoutController */ null)
+        shelf.bind(ambientState, /* hostLayoutController */ hostLayoutController)
         shelf.layout(/* left */ 0, /* top */ 0, /* right */ 30, /* bottom */5)
     }
 
@@ -37,7 +49,7 @@
         setFractionToShade(0f)
         setOnLockscreen(true)
 
-        shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f);
+        shelf.updateActualWidth(/* fractionToShade */ 0f, /* shortestWidth */ 10f)
         assertTrue(shelf.actualWidth == 10)
 
         shelf.updateActualWidth(/* fractionToShade */ 0.5f, /* shortestWidth */ 10f)
@@ -155,7 +167,7 @@
         whenever(expandableView.actualHeight).thenReturn(20)
 
         whenever(expandableView.minHeight).thenReturn(20)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(true)
 
         whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -182,7 +194,7 @@
         whenever(expandableView.actualHeight).thenReturn(20)
 
         whenever(expandableView.minHeight).thenReturn(20)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(true)
 
         whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -209,7 +221,7 @@
         whenever(expandableView.actualHeight).thenReturn(25)
 
         whenever(expandableView.minHeight).thenReturn(25)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(true)
 
         whenever(ambientState.isOnKeyguard).thenReturn(true)
@@ -236,7 +248,7 @@
         whenever(expandableView.actualHeight).thenReturn(10)
 
         whenever(expandableView.minHeight).thenReturn(10)
-        whenever(expandableView.shelfTransformationTarget).thenReturn(null)  // use translationY
+        whenever(expandableView.shelfTransformationTarget).thenReturn(null) // use translationY
         whenever(expandableView.isInShelf).thenReturn(false)
 
         whenever(ambientState.isExpansionChanging).thenReturn(false)
@@ -251,6 +263,42 @@
         assertEquals(0f, amountInShelf)
     }
 
+    @Test
+    fun updateState_expansionChanging_shelfTransparent() {
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.25f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    fun updateState_expansionChangingWhileBouncerInTransit_shelfTransparent() {
+        whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.85f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    fun updateState_expansionChanging_shelfAlphaUpdated() {
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.6f,
+                expectedAlpha = ShadeInterpolation.getContentAlpha(0.6f)
+        )
+    }
+
+    @Test
+    fun updateState_expansionChangingWhileBouncerInTransit_shelfAlphaUpdated() {
+        whenever(ambientState.isBouncerInTransit).thenReturn(true)
+
+        updateState_expansionChanging_shelfAlphaUpdated(
+                expansionFraction = 0.95f,
+                expectedAlpha = aboutToShowBouncerProgress(0.95f)
+        )
+    }
+
     private fun setFractionToShade(fraction: Float) {
         whenever(ambientState.fractionToShade).thenReturn(fraction)
     }
@@ -258,4 +306,19 @@
     private fun setOnLockscreen(isOnLockscreen: Boolean) {
         whenever(ambientState.isOnKeyguard).thenReturn(isOnLockscreen)
     }
-}
\ No newline at end of file
+
+    private fun updateState_expansionChanging_shelfAlphaUpdated(
+            expansionFraction: Float,
+            expectedAlpha: Float
+    ) {
+        whenever(ambientState.lastVisibleBackgroundChild)
+                .thenReturn(ExpandableNotificationRow(mContext, null))
+        whenever(ambientState.isExpansionChanging).thenReturn(true)
+        whenever(ambientState.expansionFraction).thenReturn(expansionFraction)
+        whenever(hostLayoutController.speedBumpIndex).thenReturn(0)
+
+        shelf.updateState(StackScrollAlgorithmState(), ambientState)
+
+        assertEquals(expectedAlpha, shelf.viewState.alpha)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
index 3c22edc..6ae021b 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/NotificationStackScrollLayoutTest.java
@@ -250,7 +250,7 @@
         // Validate that when the animation ends the stackEndHeight is recalculated immediately
         clearInvocations(mAmbientState);
         mStackScroller.setPanelFlinging(false);
-        verify(mAmbientState).setIsFlinging(eq(false));
+        verify(mAmbientState).setFlinging(eq(false));
         verify(mAmbientState).setStackEndHeight(anyFloat());
         verify(mAmbientState).setStackHeight(anyFloat());
     }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
index 24eff5f..40aec82 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/notification/stack/StackScrollAlgorithmTest.kt
@@ -20,7 +20,10 @@
 import junit.framework.Assert.assertTrue
 import org.junit.Before
 import org.junit.Test
+import org.mockito.Mockito.any
+import org.mockito.Mockito.eq
 import org.mockito.Mockito.mock
+import org.mockito.Mockito.verify
 import org.mockito.Mockito.`when` as whenever
 
 @SmallTest
@@ -35,7 +38,6 @@
     private val emptyShadeView = EmptyShadeView(context, /* attrs= */ null).apply {
         layout(/* l= */ 0, /* t= */ 0, /* r= */ 100, /* b= */ 100)
     }
-
     private val ambientState = AmbientState(
             context,
             dumpManager,
@@ -115,29 +117,54 @@
     }
 
     @Test
-    fun resetViewStates_isExpansionChanging_viewBecomesTransparent() {
+    fun resetViewStates_expansionChanging_notificationBecomesTransparent() {
         whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
-        ambientState.isExpansionChanging = true
-        ambientState.expansionFraction = 0.25f
-        stackScrollAlgorithm.initView(context)
-
-        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
-
-        val expected = getContentAlpha(0.25f)
-        assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.25f,
+                expectedAlpha = 0.0f
+        )
     }
 
     @Test
-    fun resetViewStates_isExpansionChangingWhileBouncerInTransit_viewBecomesTransparent() {
+    fun resetViewStates_expansionChangingWhileBouncerInTransit_viewBecomesTransparent() {
         whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.85f,
+                expectedAlpha = 0.0f
+        )
+    }
+
+    @Test
+    fun resetViewStates_expansionChanging_notificationAlphaUpdated() {
+        whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(false)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.6f,
+                expectedAlpha = getContentAlpha(0.6f)
+        )
+    }
+
+    @Test
+    fun resetViewStates_expansionChangingWhileBouncerInTransit_notificationAlphaUpdated() {
+        whenever(mStatusBarKeyguardViewManager.isBouncerInTransit).thenReturn(true)
+        resetViewStates_expansionChanging_notificationAlphaUpdated(
+                expansionFraction = 0.95f,
+                expectedAlpha = aboutToShowBouncerProgress(0.95f)
+        )
+    }
+
+    @Test
+    fun resetViewStates_expansionChanging_shelfUpdated() {
+        ambientState.shelf = notificationShelf
         ambientState.isExpansionChanging = true
-        ambientState.expansionFraction = 0.25f
+        ambientState.expansionFraction = 0.6f
         stackScrollAlgorithm.initView(context)
 
         stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
 
-        val expected = aboutToShowBouncerProgress(0.25f)
-        assertThat(notificationRow.viewState.alpha).isEqualTo(expected)
+        verify(notificationShelf).updateState(
+                /* algorithmState= */any(),
+                /* ambientState= */eq(ambientState)
+        )
     }
 
     @Test
@@ -479,6 +506,19 @@
                 /* originalCornerRoundness= */ 1f)
         assertEquals(1f, currentRoundness)
     }
+
+    private fun resetViewStates_expansionChanging_notificationAlphaUpdated(
+            expansionFraction: Float,
+            expectedAlpha: Float
+    ) {
+        ambientState.isExpansionChanging = true
+        ambientState.expansionFraction = expansionFraction
+        stackScrollAlgorithm.initView(context)
+
+        stackScrollAlgorithm.resetViewStates(ambientState, /* speedBumpIndex= */ 0)
+
+        assertThat(notificationRow.viewState.alpha).isEqualTo(expectedAlpha)
+    }
 }
 
 private fun mockExpandableNotificationRow(): ExpandableNotificationRow {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
index 5c9871a..9de9db1 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/DozeServiceHostTest.java
@@ -29,6 +29,7 @@
 
 import android.os.PowerManager;
 import android.testing.AndroidTestingRunner;
+import android.testing.TestableLooper.RunWithLooper;
 import android.view.View;
 
 import androidx.test.filters.SmallTest;
@@ -61,10 +62,10 @@
 import java.util.Arrays;
 import java.util.Collections;
 import java.util.HashSet;
-import java.util.Optional;
 
 @SmallTest
 @RunWith(AndroidTestingRunner.class)
+@RunWithLooper(setAsMainLooper = true)
 public class DozeServiceHostTest extends SysuiTestCase {
 
     private DozeServiceHost mDozeServiceHost;
@@ -92,6 +93,7 @@
     @Mock private View mAmbientIndicationContainer;
     @Mock private BiometricUnlockController mBiometricUnlockController;
     @Mock private AuthController mAuthController;
+    @Mock private DozeHost.Callback mCallback;
 
     @Before
     public void setup() {
@@ -100,7 +102,7 @@
                 mStatusBarStateController, mDeviceProvisionedController, mHeadsUpManager,
                 mBatteryController, mScrimController, () -> mBiometricUnlockController,
                 mKeyguardViewMediator, () -> mAssistManager, mDozeScrimController,
-                mKeyguardUpdateMonitor, mPulseExpansionHandler, Optional.empty(),
+                mKeyguardUpdateMonitor, mPulseExpansionHandler,
                 mNotificationShadeWindowController, mNotificationWakeUpCoordinator,
                 mAuthController, mNotificationIconAreaController);
 
@@ -114,16 +116,19 @@
 
     @Test
     public void testStartStopDozing() {
+        mDozeServiceHost.addCallback(mCallback);
         when(mStatusBarStateController.getState()).thenReturn(StatusBarState.KEYGUARD);
         when(mStatusBarStateController.isKeyguardRequested()).thenReturn(true);
 
         assertFalse(mDozeServiceHost.getDozingRequested());
 
         mDozeServiceHost.startDozing();
+        verify(mCallback).onDozingChanged(eq(true));
         verify(mStatusBarStateController).setIsDozing(eq(true));
         verify(mCentralSurfaces).updateIsKeyguard();
 
         mDozeServiceHost.stopDozing();
+        verify(mCallback).onDozingChanged(eq(false));
         verify(mStatusBarStateController).setIsDozing(eq(false));
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
deleted file mode 100644
index 3440fa5..0000000
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/KeyguardBottomAreaTest.kt
+++ /dev/null
@@ -1,54 +0,0 @@
-package com.android.systemui.statusbar.phone
-
-import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.view.LayoutInflater
-import androidx.test.filters.SmallTest
-import com.android.systemui.R
-import com.android.systemui.SysuiTestCase
-import com.android.systemui.assist.AssistManager
-import com.android.systemui.plugins.ActivityStarter
-import com.android.systemui.statusbar.policy.AccessibilityController
-import com.android.systemui.statusbar.policy.FlashlightController
-import com.android.systemui.statusbar.policy.KeyguardStateController
-import com.android.systemui.tuner.TunerService
-import java.util.concurrent.Executor
-import org.junit.Before
-import org.junit.Test
-import org.junit.runner.RunWith
-import org.mockito.Mock
-import org.mockito.MockitoAnnotations
-
-@SmallTest
-@RunWith(AndroidTestingRunner::class)
-@TestableLooper.RunWithLooper(setAsMainLooper = true)
-class KeyguardBottomAreaTest : SysuiTestCase() {
-
-    @Mock
-    private lateinit var mCentralSurfaces: CentralSurfaces
-    private lateinit var mKeyguardBottomArea: KeyguardBottomAreaView
-
-    @Before
-    fun setup() {
-        MockitoAnnotations.initMocks(this)
-        // Mocked dependencies
-        mDependency.injectMockDependency(AccessibilityController::class.java)
-        mDependency.injectMockDependency(ActivityStarter::class.java)
-        mDependency.injectMockDependency(AssistManager::class.java)
-        mDependency.injectTestDependency(Executor::class.java, Executor { it.run() })
-        mDependency.injectMockDependency(FlashlightController::class.java)
-        mDependency.injectMockDependency(KeyguardStateController::class.java)
-        mDependency.injectMockDependency(TunerService::class.java)
-
-        mKeyguardBottomArea = LayoutInflater.from(mContext).inflate(
-                R.layout.keyguard_bottom_area, null, false) as KeyguardBottomAreaView
-    }
-
-    @Test
-    fun initFrom_doesntCrash() {
-        val other = LayoutInflater.from(mContext).inflate(R.layout.keyguard_bottom_area,
-                null, false) as KeyguardBottomAreaView
-
-        other.initFrom(mKeyguardBottomArea)
-    }
-}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
index 2dcdcfc..e790d85 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/phone/StatusBarKeyguardViewManagerTest.java
@@ -51,6 +51,7 @@
 import com.android.systemui.shade.ShadeController;
 import com.android.systemui.statusbar.NotificationMediaManager;
 import com.android.systemui.statusbar.NotificationShadeWindowController;
+import com.android.systemui.statusbar.StatusBarState;
 import com.android.systemui.statusbar.SysuiStatusBarStateController;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionChangeEvent;
 import com.android.systemui.statusbar.phone.panelstate.PanelExpansionStateManager;
@@ -277,6 +278,17 @@
     }
 
     @Test
+    public void onPanelExpansionChanged_neverTranslatesBouncerWhenShadeLocked() {
+        when(mStatusBarStateController.getState()).thenReturn(StatusBarState.SHADE_LOCKED);
+        mStatusBarKeyguardViewManager.onPanelExpansionChanged(
+                expansionEvent(
+                        /* fraction= */ KeyguardBouncer.EXPANSION_VISIBLE,
+                        /* expanded= */ true,
+                        /* tracking= */ false));
+        verify(mBouncer, never()).setExpansion(anyFloat());
+    }
+
+    @Test
     public void setOccluded_animatesPanelExpansion_onlyIfBouncerHidden() {
         mStatusBarKeyguardViewManager.setOccluded(false /* occluded */, true /* animated */);
         verify(mCentralSurfaces).animateKeyguardUnoccluding();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
index 6c6d9e1..43103a0 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/pipeline/wifi/ui/viewmodel/WifiViewModelTest.kt
@@ -17,7 +17,10 @@
 package com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel
 
 import androidx.test.filters.SmallTest
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_CONNECTION_STRENGTH
+import com.android.settingslib.AccessibilityContentDescriptions.WIFI_NO_CONNECTION
 import com.android.systemui.SysuiTestCase
+import com.android.systemui.common.shared.model.ContentDescription
 import com.android.systemui.common.shared.model.Icon
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_FULL_ICONS
 import com.android.systemui.statusbar.connectivity.WifiIcons.WIFI_NO_INTERNET_ICONS
@@ -31,6 +34,7 @@
 import com.android.systemui.statusbar.pipeline.wifi.data.repository.FakeWifiRepository
 import com.android.systemui.statusbar.pipeline.wifi.domain.interactor.WifiInteractor
 import com.android.systemui.statusbar.pipeline.wifi.shared.WifiConstants
+import com.android.systemui.statusbar.pipeline.wifi.ui.viewmodel.WifiViewModel.Companion.NO_INTERNET
 import com.google.common.truth.Truth.assertThat
 import kotlinx.coroutines.Dispatchers
 import kotlinx.coroutines.ExperimentalCoroutinesApi
@@ -67,6 +71,7 @@
         underTest = WifiViewModel(
             statusBarPipelineFlags,
             constants,
+            context,
             logger,
             interactor
         )
@@ -115,7 +120,12 @@
                 .launchIn(this)
 
         assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-        assertThat((latest as Icon.Resource).res).isEqualTo(WIFI_NO_NETWORK)
+        val icon = latest as Icon.Resource
+        assertThat(icon.res).isEqualTo(WIFI_NO_NETWORK)
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(WIFI_NO_CONNECTION))
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(NO_INTERNET))
 
         job.cancel()
     }
@@ -169,7 +179,12 @@
             .launchIn(this)
 
         assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-        assertThat((latest as Icon.Resource).res).isEqualTo(WIFI_FULL_ICONS[level])
+        val icon = latest as Icon.Resource
+        assertThat(icon.res).isEqualTo(WIFI_FULL_ICONS[level])
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
+        assertThat(icon.contentDescription?.getAsString())
+            .doesNotContain(context.getString(NO_INTERNET))
 
         job.cancel()
     }
@@ -193,7 +208,12 @@
             .launchIn(this)
 
         assertThat(latest).isInstanceOf(Icon.Resource::class.java)
-        assertThat((latest as Icon.Resource).res).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
+        val icon = latest as Icon.Resource
+        assertThat(icon.res).isEqualTo(WIFI_NO_INTERNET_ICONS[level])
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(WIFI_CONNECTION_STRENGTH[level]))
+        assertThat(icon.contentDescription?.getAsString())
+            .contains(context.getString(NO_INTERNET))
 
         job.cancel()
     }
@@ -261,6 +281,13 @@
         job.cancel()
     }
 
+    private fun ContentDescription.getAsString(): String? {
+        return when (this) {
+            is ContentDescription.Loaded -> this.description
+            is ContentDescription.Resource -> context.getString(this.res)
+        }
+    }
+
     companion object {
         private const val NETWORK_ID = 2
         private val ACTIVE_VALID_WIFI_NETWORK = WifiNetworkModel.Active(NETWORK_ID, ssid = "AB")
diff --git a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
index 4a8170f..8f363ef 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/statusbar/policy/KeyguardStateControllerTest.java
@@ -31,6 +31,7 @@
 
 import com.android.internal.widget.LockPatternUtils;
 import com.android.keyguard.KeyguardUpdateMonitor;
+import com.android.keyguard.logging.KeyguardUpdateMonitorLogger;
 import com.android.systemui.SysuiTestCase;
 import com.android.systemui.dump.DumpManager;
 import com.android.systemui.keyguard.KeyguardUnlockAnimationController;
@@ -57,6 +58,8 @@
     private DumpManager mDumpManager;
     @Mock
     private Lazy<KeyguardUnlockAnimationController> mKeyguardUnlockAnimationControllerLazy;
+    @Mock
+    private KeyguardUpdateMonitorLogger mLogger;
 
     @Before
     public void setup() {
@@ -66,6 +69,7 @@
                 mKeyguardUpdateMonitor,
                 mLockPatternUtils,
                 mKeyguardUnlockAnimationControllerLazy,
+                mLogger,
                 mDumpManager);
     }
 
diff --git a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
similarity index 61%
rename from packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
rename to packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
index f133068..e616c26 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/media/taptotransfer/common/MediaTttChipControllerCommonTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/temporarydisplay/TemporaryViewDisplayControllerTest.kt
@@ -14,7 +14,7 @@
  * limitations under the License.
  */
 
-package com.android.systemui.media.taptotransfer.common
+package com.android.systemui.temporarydisplay
 
 import android.content.Context
 import android.content.pm.ApplicationInfo
@@ -30,6 +30,7 @@
 import com.android.systemui.R
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.dagger.qualifiers.Main
+import com.android.systemui.media.taptotransfer.common.MediaTttLogger
 import com.android.systemui.statusbar.policy.ConfigurationController
 import com.android.systemui.statusbar.policy.ConfigurationController.ConfigurationListener
 import com.android.systemui.util.concurrency.DelayableExecutor
@@ -38,7 +39,6 @@
 import com.android.systemui.util.mockito.argumentCaptor
 import com.android.systemui.util.mockito.capture
 import com.android.systemui.util.time.FakeSystemClock
-import com.android.systemui.util.view.ViewUtil
 import com.google.common.truth.Truth.assertThat
 import org.junit.Before
 import org.junit.Test
@@ -52,8 +52,8 @@
 import org.mockito.MockitoAnnotations
 
 @SmallTest
-class MediaTttChipControllerCommonTest : SysuiTestCase() {
-    private lateinit var controllerCommon: TestControllerCommon
+class TemporaryViewDisplayControllerTest : SysuiTestCase() {
+    private lateinit var underTest: TestController
 
     private lateinit var fakeClock: FakeSystemClock
     private lateinit var fakeExecutor: FakeExecutor
@@ -72,8 +72,6 @@
     @Mock
     private lateinit var windowManager: WindowManager
     @Mock
-    private lateinit var viewUtil: ViewUtil
-    @Mock
     private lateinit var powerManager: PowerManager
 
     @Before
@@ -97,11 +95,10 @@
         fakeClock = FakeSystemClock()
         fakeExecutor = FakeExecutor(fakeClock)
 
-        controllerCommon = TestControllerCommon(
+        underTest = TestController(
                 context,
                 logger,
                 windowManager,
-                viewUtil,
                 fakeExecutor,
                 accessibilityManager,
                 configurationController,
@@ -110,43 +107,43 @@
     }
 
     @Test
-    fun displayChip_chipAdded() {
-        controllerCommon.displayChip(getState())
+    fun displayView_viewAdded() {
+        underTest.displayView(getState())
 
         verify(windowManager).addView(any(), any())
     }
 
     @Test
-    fun displayChip_screenOff_screenWakes() {
+    fun displayView_screenOff_screenWakes() {
         whenever(powerManager.isScreenOn).thenReturn(false)
 
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
         verify(powerManager).wakeUp(any(), any(), any())
     }
 
     @Test
-    fun displayChip_screenAlreadyOn_screenNotWoken() {
+    fun displayView_screenAlreadyOn_screenNotWoken() {
         whenever(powerManager.isScreenOn).thenReturn(true)
 
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
         verify(powerManager, never()).wakeUp(any(), any(), any())
     }
 
     @Test
-    fun displayChip_twice_chipNotAddedTwice() {
-        controllerCommon.displayChip(getState())
+    fun displayView_twice_viewNotAddedTwice() {
+        underTest.displayView(getState())
         reset(windowManager)
 
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
         verify(windowManager, never()).addView(any(), any())
     }
 
     @Test
-    fun displayChip_chipDoesNotDisappearsBeforeTimeout() {
+    fun displayView_viewDoesNotDisappearsBeforeTimeout() {
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
         reset(windowManager)
 
         fakeClock.advanceTime(TIMEOUT_MS - 1)
@@ -155,9 +152,9 @@
     }
 
     @Test
-    fun displayChip_chipDisappearsAfterTimeout() {
+    fun displayView_viewDisappearsAfterTimeout() {
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
         reset(windowManager)
 
         fakeClock.advanceTime(TIMEOUT_MS + 1)
@@ -166,176 +163,176 @@
     }
 
     @Test
-    fun displayChip_calledAgainBeforeTimeout_timeoutReset() {
-        // First, display the chip
+    fun displayView_calledAgainBeforeTimeout_timeoutReset() {
+        // First, display the view
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
 
-        // After some time, re-display the chip
+        // After some time, re-display the view
         val waitTime = 1000L
         fakeClock.advanceTime(waitTime)
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
         // Wait until the timeout for the first display would've happened
         fakeClock.advanceTime(TIMEOUT_MS - waitTime + 1)
 
-        // Verify we didn't hide the chip
+        // Verify we didn't hide the view
         verify(windowManager, never()).removeView(any())
     }
 
     @Test
-    fun displayChip_calledAgainBeforeTimeout_eventuallyTimesOut() {
-        // First, display the chip
+    fun displayView_calledAgainBeforeTimeout_eventuallyTimesOut() {
+        // First, display the view
         val state = getState()
-        controllerCommon.displayChip(state)
+        underTest.displayView(state)
 
-        // After some time, re-display the chip
+        // After some time, re-display the view
         fakeClock.advanceTime(1000L)
-        controllerCommon.displayChip(getState())
+        underTest.displayView(getState())
 
-        // Ensure we still hide the chip eventually
+        // Ensure we still hide the view eventually
         fakeClock.advanceTime(TIMEOUT_MS + 1)
 
         verify(windowManager).removeView(any())
     }
 
     @Test
-    fun displayScaleChange_chipReinflatedWithMostRecentState() {
-        controllerCommon.displayChip(getState(name = "First name"))
-        controllerCommon.displayChip(getState(name = "Second name"))
+    fun displayScaleChange_viewReinflatedWithMostRecentState() {
+        underTest.displayView(getState(name = "First name"))
+        underTest.displayView(getState(name = "Second name"))
         reset(windowManager)
 
         getConfigurationListener().onDensityOrFontScaleChanged()
 
         verify(windowManager).removeView(any())
         verify(windowManager).addView(any(), any())
-        assertThat(controllerCommon.mostRecentChipInfo?.name).isEqualTo("Second name")
+        assertThat(underTest.mostRecentViewInfo?.name).isEqualTo("Second name")
     }
 
     @Test
-    fun removeChip_chipRemovedAndRemovalLogged() {
-        // First, add the chip
-        controllerCommon.displayChip(getState())
+    fun removeView_viewRemovedAndRemovalLogged() {
+        // First, add the view
+        underTest.displayView(getState())
 
         // Then, remove it
         val reason = "test reason"
-        controllerCommon.removeChip(reason)
+        underTest.removeView(reason)
 
         verify(windowManager).removeView(any())
         verify(logger).logChipRemoval(reason)
     }
 
     @Test
-    fun removeChip_noAdd_viewNotRemoved() {
-        controllerCommon.removeChip("reason")
+    fun removeView_noAdd_viewNotRemoved() {
+        underTest.removeView("reason")
 
         verify(windowManager, never()).removeView(any())
     }
 
     @Test
     fun setIcon_nullAppIconDrawableAndNullPackageName_stillHasIcon() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, appPackageName = null, appIconDrawableOverride = null)
+        underTest.setIcon(view, appPackageName = null, appIconDrawableOverride = null)
 
-        assertThat(chipView.getAppIconView().drawable).isNotNull()
+        assertThat(view.getAppIconView().drawable).isNotNull()
     }
 
     @Test
     fun setIcon_nullAppIconDrawableAndInvalidPackageName_stillHasIcon() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(
-            chipView, appPackageName = "fakePackageName", appIconDrawableOverride = null
+        underTest.setIcon(
+            view, appPackageName = "fakePackageName", appIconDrawableOverride = null
         )
 
-        assertThat(chipView.getAppIconView().drawable).isNotNull()
+        assertThat(view.getAppIconView().drawable).isNotNull()
     }
 
     @Test
     fun setIcon_nullAppIconDrawable_iconIsFromPackageName() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, appIconDrawableOverride = null, null)
+        underTest.setIcon(view, PACKAGE_NAME, appIconDrawableOverride = null, null)
 
-        assertThat(chipView.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
+        assertThat(view.getAppIconView().drawable).isEqualTo(appIconFromPackageName)
     }
 
     @Test
     fun setIcon_hasAppIconDrawable_iconIsDrawable() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
         val drawable = context.getDrawable(R.drawable.ic_alarm)!!
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, drawable, null)
+        underTest.setIcon(view, PACKAGE_NAME, drawable, null)
 
-        assertThat(chipView.getAppIconView().drawable).isEqualTo(drawable)
+        assertThat(view.getAppIconView().drawable).isEqualTo(drawable)
     }
 
     @Test
     fun setIcon_nullAppNameAndNullPackageName_stillHasContentDescription() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, appPackageName = null, appNameOverride = null)
+        underTest.setIcon(view, appPackageName = null, appNameOverride = null)
 
-        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+        assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
     }
 
     @Test
     fun setIcon_nullAppNameAndInvalidPackageName_stillHasContentDescription() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(
-            chipView, appPackageName = "fakePackageName", appNameOverride = null
+        underTest.setIcon(
+            view, appPackageName = "fakePackageName", appNameOverride = null
         )
 
-        assertThat(chipView.getAppIconView().contentDescription.toString()).isNotEmpty()
+        assertThat(view.getAppIconView().contentDescription.toString()).isNotEmpty()
     }
 
     @Test
     fun setIcon_nullAppName_iconContentDescriptionIsFromPackageName() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appNameOverride = null)
+        underTest.setIcon(view, PACKAGE_NAME, null, appNameOverride = null)
 
-        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(APP_NAME)
+        assertThat(view.getAppIconView().contentDescription).isEqualTo(APP_NAME)
     }
 
     @Test
     fun setIcon_hasAppName_iconContentDescriptionIsAppNameOverride() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
         val appName = "Override App Name"
-        controllerCommon.setIcon(chipView, PACKAGE_NAME, null, appName)
+        underTest.setIcon(view, PACKAGE_NAME, null, appName)
 
-        assertThat(chipView.getAppIconView().contentDescription).isEqualTo(appName)
+        assertThat(view.getAppIconView().contentDescription).isEqualTo(appName)
     }
 
     @Test
     fun setIcon_iconSizeMatchesGetIconSize() {
-        controllerCommon.displayChip(getState())
-        val chipView = getChipView()
+        underTest.displayView(getState())
+        val view = getView()
 
-        controllerCommon.setIcon(chipView, PACKAGE_NAME)
-        chipView.measure(
+        underTest.setIcon(view, PACKAGE_NAME)
+        view.measure(
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED),
             View.MeasureSpec.makeMeasureSpec(0, View.MeasureSpec.UNSPECIFIED)
         )
 
-        assertThat(chipView.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
-        assertThat(chipView.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
+        assertThat(view.getAppIconView().measuredWidth).isEqualTo(ICON_SIZE)
+        assertThat(view.getAppIconView().measuredHeight).isEqualTo(ICON_SIZE)
     }
 
-    private fun getState(name: String = "name") = ChipInfo(name)
+    private fun getState(name: String = "name") = ViewInfo(name)
 
-    private fun getChipView(): ViewGroup {
+    private fun getView(): ViewGroup {
         val viewCaptor = ArgumentCaptor.forClass(View::class.java)
         verify(windowManager).addView(viewCaptor.capture(), any())
         return viewCaptor.value as ViewGroup
@@ -349,37 +346,35 @@
         return callbackCaptor.value
     }
 
-    inner class TestControllerCommon(
+    inner class TestController(
         context: Context,
         logger: MediaTttLogger,
         windowManager: WindowManager,
-        viewUtil: ViewUtil,
         @Main mainExecutor: DelayableExecutor,
         accessibilityManager: AccessibilityManager,
         configurationController: ConfigurationController,
         powerManager: PowerManager,
-    ) : MediaTttChipControllerCommon<ChipInfo>(
+    ) : TemporaryViewDisplayController<ViewInfo>(
         context,
         logger,
         windowManager,
-        viewUtil,
         mainExecutor,
         accessibilityManager,
         configurationController,
         powerManager,
         R.layout.media_ttt_chip,
     ) {
-        var mostRecentChipInfo: ChipInfo? = null
+        var mostRecentViewInfo: ViewInfo? = null
 
         override val windowLayoutParams = commonWindowLayoutParams
-        override fun updateChipView(newChipInfo: ChipInfo, currentChipView: ViewGroup) {
-            super.updateChipView(newChipInfo, currentChipView)
-            mostRecentChipInfo = newChipInfo
+        override fun updateView(newInfo: ViewInfo, currentView: ViewGroup) {
+            super.updateView(newInfo, currentView)
+            mostRecentViewInfo = newInfo
         }
         override fun getIconSize(isAppIcon: Boolean): Int = ICON_SIZE
     }
 
-    inner class ChipInfo(val name: String) : ChipInfoCommon {
+    inner class ViewInfo(val name: String) : TemporaryViewInfo {
         override fun getTimeoutMs() = 1L
     }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
index f51f783..8645298 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/unfold/FoldAodAnimationControllerTest.kt
@@ -18,24 +18,28 @@
 
 import android.hardware.devicestate.DeviceStateManager
 import android.hardware.devicestate.DeviceStateManager.FoldStateListener
-import android.os.Handler
 import android.os.PowerManager
 import android.testing.AndroidTestingRunner
-import android.testing.TestableLooper
-import android.testing.TestableLooper.RunWithLooper
 import android.view.ViewGroup
 import android.view.ViewTreeObserver
 import androidx.test.filters.SmallTest
 import com.android.internal.util.LatencyTracker
 import com.android.systemui.SysuiTestCase
 import com.android.systemui.keyguard.WakefulnessLifecycle
+import com.android.systemui.keyguard.data.repository.FakeKeyguardRepository
+import com.android.systemui.keyguard.domain.interactor.KeyguardInteractor
 import com.android.systemui.shade.NotificationPanelViewController
 import com.android.systemui.statusbar.LightRevealScrim
 import com.android.systemui.statusbar.phone.CentralSurfaces
 import com.android.systemui.unfold.util.FoldableDeviceStates
 import com.android.systemui.unfold.util.FoldableTestUtils
+import com.android.systemui.util.concurrency.FakeExecutor
 import com.android.systemui.util.mockito.any
 import com.android.systemui.util.settings.GlobalSettings
+import com.android.systemui.util.time.FakeSystemClock
+import kotlinx.coroutines.Dispatchers
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
 import org.junit.Before
 import org.junit.Test
 import org.junit.runner.RunWith
@@ -49,7 +53,6 @@
 
 @RunWith(AndroidTestingRunner::class)
 @SmallTest
-@RunWithLooper
 class FoldAodAnimationControllerTest : SysuiTestCase() {
 
     @Mock lateinit var deviceStateManager: DeviceStateManager
@@ -74,26 +77,15 @@
 
     private lateinit var deviceStates: FoldableDeviceStates
 
-    private lateinit var testableLooper: TestableLooper
+    lateinit var keyguardRepository: FakeKeyguardRepository
 
-    lateinit var foldAodAnimationController: FoldAodAnimationController
+    lateinit var underTest: FoldAodAnimationController
+    private val fakeExecutor = FakeExecutor(FakeSystemClock())
 
     @Before
     fun setup() {
         MockitoAnnotations.initMocks(this)
-        testableLooper = TestableLooper.get(this)
 
-        foldAodAnimationController =
-            FoldAodAnimationController(
-                    Handler(testableLooper.looper),
-                    context.mainExecutor,
-                    context,
-                    deviceStateManager,
-                    wakefulnessLifecycle,
-                    globalSettings,
-                    latencyTracker,
-                )
-                .apply { initialize(centralSurfaces, lightRevealScrim) }
         deviceStates = FoldableTestUtils.findDeviceStates(context)
 
         whenever(notificationPanelViewController.view).thenReturn(viewGroup)
@@ -107,60 +99,102 @@
                 val onActionStarted = it.arguments[0] as Runnable
                 onActionStarted.run()
             }
-        verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
 
-        foldAodAnimationController.setIsDozing(dozing = true)
-        setAodEnabled(enabled = true)
-        sendFoldEvent(folded = false)
+        keyguardRepository = FakeKeyguardRepository()
+        val keyguardInteractor = KeyguardInteractor(repository = keyguardRepository)
+
+        // Needs to be run on the main thread
+        runBlocking(IMMEDIATE) {
+            underTest =
+                FoldAodAnimationController(
+                        fakeExecutor,
+                        context,
+                        deviceStateManager,
+                        wakefulnessLifecycle,
+                        globalSettings,
+                        latencyTracker,
+                        { keyguardInteractor },
+                    )
+                    .apply { initialize(centralSurfaces, lightRevealScrim) }
+
+            verify(deviceStateManager).registerCallback(any(), foldStateListenerCaptor.capture())
+
+            setAodEnabled(enabled = true)
+            sendFoldEvent(folded = false)
+        }
     }
 
     @Test
-    fun onFolded_aodDisabled_doesNotLogLatency() {
-        setAodEnabled(enabled = false)
+    fun onFolded_aodDisabled_doesNotLogLatency() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozing(this)
+            keyguardRepository.setDozing(true)
+            setAodEnabled(enabled = false)
 
-        fold()
-        simulateScreenTurningOn()
+            yield()
 
-        verifyNoMoreInteractions(latencyTracker)
-    }
+            fold()
+            simulateScreenTurningOn()
+
+            verifyNoMoreInteractions(latencyTracker)
+
+            job.cancel()
+        }
 
     @Test
-    fun onFolded_aodEnabled_logsLatency() {
-        setAodEnabled(enabled = true)
+    fun onFolded_aodEnabled_logsLatency() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozing(this)
+            keyguardRepository.setDozing(true)
+            setAodEnabled(enabled = true)
 
-        fold()
-        simulateScreenTurningOn()
+            yield()
 
-        verify(latencyTracker).onActionStart(any())
-        verify(latencyTracker).onActionEnd(any())
-    }
+            fold()
+            simulateScreenTurningOn()
+
+            verify(latencyTracker).onActionStart(any())
+            verify(latencyTracker).onActionEnd(any())
+
+            job.cancel()
+        }
 
     @Test
-    fun onFolded_animationCancelled_doesNotLogLatency() {
-        setAodEnabled(enabled = true)
+    fun onFolded_animationCancelled_doesNotLogLatency() =
+        runBlocking(IMMEDIATE) {
+            val job = underTest.listenForDozing(this)
+            keyguardRepository.setDozing(true)
+            setAodEnabled(enabled = true)
 
-        fold()
-        foldAodAnimationController.onScreenTurningOn({})
-        foldAodAnimationController.onStartedWakingUp()
-        testableLooper.processAllMessages()
+            yield()
 
-        verify(latencyTracker).onActionStart(any())
-        verify(latencyTracker).onActionCancel(any())
-    }
+            fold()
+            underTest.onScreenTurningOn({})
+            underTest.onStartedWakingUp()
+            fakeExecutor.runAllReady()
+
+            verify(latencyTracker).onActionStart(any())
+            verify(latencyTracker).onActionCancel(any())
+
+            job.cancel()
+        }
 
     private fun simulateScreenTurningOn() {
-        foldAodAnimationController.onScreenTurningOn({})
-        foldAodAnimationController.onScreenTurnedOn()
-        testableLooper.processAllMessages()
+        underTest.onScreenTurningOn({})
+        underTest.onScreenTurnedOn()
+        fakeExecutor.runAllReady()
     }
 
     private fun fold() = sendFoldEvent(folded = true)
 
-    private fun setAodEnabled(enabled: Boolean) =
-        foldAodAnimationController.onAlwaysOnChanged(alwaysOn = enabled)
+    private fun setAodEnabled(enabled: Boolean) = underTest.onAlwaysOnChanged(alwaysOn = enabled)
 
     private fun sendFoldEvent(folded: Boolean) {
         val state = if (folded) deviceStates.folded else deviceStates.unfolded
         foldStateListenerCaptor.value.onStateChanged(state)
     }
+
+    companion object {
+        private val IMMEDIATE = Dispatchers.Main.immediate
+    }
 }
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
index 092e82c..7df7077 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/FlowUtilTests.kt
@@ -28,12 +28,14 @@
 import kotlinx.coroutines.flow.asFlow
 import kotlinx.coroutines.flow.emptyFlow
 import kotlinx.coroutines.flow.filterIsInstance
+import kotlinx.coroutines.flow.flow
 import kotlinx.coroutines.flow.flowOf
 import kotlinx.coroutines.flow.merge
 import kotlinx.coroutines.flow.takeWhile
 import kotlinx.coroutines.flow.toList
 import kotlinx.coroutines.launch
 import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.yield
 import org.junit.Test
 import org.junit.runner.RunWith
 
@@ -127,6 +129,53 @@
                 )
             )
     }
+
+    @Test
+    fun dontEmitFirstEvent() = runBlocking {
+        assertThatFlow(flowOf(setOf(1, 2), setOf(2, 3)).setChanges(emitFirstEvent = false))
+            .emitsExactly(
+                SetChanges(
+                    removed = setOf(1),
+                    added = setOf(3),
+                )
+            )
+    }
+}
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class SampleFlowTest : SysuiTestCase() {
+    @Test
+    fun simple() = runBlocking {
+        assertThatFlow(flow { yield(); emit(1) }.sample(flowOf(2)) { a, b -> a to b })
+            .emitsExactly(1 to 2)
+    }
+
+    @Test
+    fun otherFlowNoValueYet() = runBlocking {
+        assertThatFlow(flowOf(1).sample(emptyFlow<Unit>()))
+            .emitsNothing()
+    }
+
+    @Test
+    fun multipleSamples() = runBlocking {
+        val samplee = MutableSharedFlow<Int>()
+        val sampler = flow {
+            emit(1)
+            samplee.emit(1)
+            emit(2)
+            samplee.emit(2)
+            samplee.emit(3)
+            emit(3)
+            emit(4)
+        }
+        assertThatFlow(sampler.sample(samplee) { a, b -> a to b })
+            .emitsExactly(
+                2 to 1,
+                3 to 3,
+                4 to 3,
+            )
+    }
 }
 
 private fun <T> assertThatFlow(flow: Flow<T>) = object {
diff --git a/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
new file mode 100644
index 0000000..6848b83
--- /dev/null
+++ b/packages/SystemUI/tests/src/com/android/systemui/util/kotlin/SuspendUtilTests.kt
@@ -0,0 +1,55 @@
+/*
+ * Copyright (C) 2022 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.systemui.util.kotlin
+
+import android.testing.AndroidTestingRunner
+import androidx.test.filters.SmallTest
+import com.android.systemui.SysuiTestCase
+import com.google.common.truth.Truth.assertThat
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.async
+import kotlinx.coroutines.awaitCancellation
+import kotlinx.coroutines.runBlocking
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidTestingRunner::class)
+class RaceSuspendTest : SysuiTestCase() {
+    @Test
+    fun raceSimple() = runBlocking {
+        val winner = CompletableDeferred<Int>()
+        val result = async {
+            race(
+                { winner.await() },
+                { awaitCancellation() },
+            )
+        }
+        winner.complete(1)
+        assertThat(result.await()).isEqualTo(1)
+    }
+
+    @Test
+    fun raceImmediate() = runBlocking {
+        assertThat(
+            race<Int>(
+                { 1 },
+                { 2 },
+            )
+        ).isEqualTo(1)
+    }
+}
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
similarity index 99%
rename from packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
index 11eb4e3..42b434a 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/keyguard/data/repository/FakeKeyguardRepository.kt
@@ -12,6 +12,7 @@
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  * See the License for the specific language governing permissions and
  * limitations under the License.
+ *
  */
 
 package com.android.systemui.keyguard.data.repository
diff --git a/packages/SystemUI/tests/src/com/android/systemui/power/data/repository/FakePowerRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/power/data/repository/FakePowerRepository.kt
diff --git a/packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserRepository.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
similarity index 100%
rename from packages/SystemUI/tests/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
rename to packages/SystemUI/tests/utils/src/com/android/systemui/user/data/repository/FakeUserRepository.kt
diff --git a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
index f539dbd..8d171be 100644
--- a/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
+++ b/packages/SystemUI/tests/utils/src/com/android/systemui/util/mockito/KotlinMockitoHelpers.kt
@@ -26,6 +26,7 @@
 import org.mockito.ArgumentCaptor
 import org.mockito.ArgumentMatcher
 import org.mockito.Mockito
+import org.mockito.stubbing.OngoingStubbing
 
 /**
  * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when
@@ -77,8 +78,18 @@
  * Helper function for creating new mocks, without the need to pass in a [Class] instance.
  *
  * Generic T is nullable because implicitly bounded by Any?.
+ *
+ * @param apply builder function to simplify stub configuration by improving type inference.
  */
-inline fun <reified T : Any> mock(): T = Mockito.mock(T::class.java)
+inline fun <reified T : Any> mock(apply: T.() -> Unit = {}): T = Mockito.mock(T::class.java)
+        .apply(apply)
+
+/**
+ * Helper function for stubbing methods without the need to use backticks.
+ *
+ * @see Mockito.when
+ */
+fun <T> whenever(methodCall: T): OngoingStubbing<T> = Mockito.`when`(methodCall)
 
 /**
  * A kotlin implemented wrapper of [ArgumentCaptor] which prevents the following exception when
@@ -118,3 +129,17 @@
  */
 inline fun <reified T : Any> withArgCaptor(block: KotlinArgumentCaptor<T>.() -> Unit): T =
         kotlinArgumentCaptor<T>().apply { block() }.value
+
+/**
+ * Variant of [withArgCaptor] for capturing multiple arguments.
+ *
+ *    val captor = argumentCaptor<Foo>()
+ *    verify(...).someMethod(captor.capture())
+ *    val captured: List<Foo> = captor.allValues
+ *
+ * becomes:
+ *
+ *    val capturedList = captureMany<Foo> { verify(...).someMethod(capture()) }
+ */
+inline fun <reified T : Any> captureMany(block: KotlinArgumentCaptor<T>.() -> Unit): List<T> =
+        kotlinArgumentCaptor<T>().apply{ block() }.allValues
diff --git a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
index 01cee33..b5fdaca 100644
--- a/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
+++ b/services/autofill/java/com/android/server/autofill/PresentationStatsEventLogger.java
@@ -41,7 +41,12 @@
 
 import android.annotation.IntDef;
 import android.annotation.Nullable;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.pm.PackageManager;
+import android.provider.Settings;
 import android.service.autofill.Dataset;
+import android.text.TextUtils;
 import android.util.Slog;
 import android.view.autofill.AutofillId;
 import android.view.autofill.AutofillManager;
@@ -61,7 +66,7 @@
      * Reasons why presentation was not shown. These are wrappers around
      * {@link com.android.os.AtomsProto.AutofillPresentationEventReported.PresentationEventResult}.
      */
-    @IntDef(prefix = { "NOT_SHOWN_REASON" }, value = {
+    @IntDef(prefix = {"NOT_SHOWN_REASON"}, value = {
             NOT_SHOWN_REASON_ANY_SHOWN,
             NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED,
             NOT_SHOWN_REASON_VIEW_CHANGED,
@@ -72,6 +77,7 @@
     })
     @Retention(RetentionPolicy.SOURCE)
     public @interface NotShownReason {}
+
     public static final int NOT_SHOWN_REASON_ANY_SHOWN = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__ANY_SHOWN;
     public static final int NOT_SHOWN_REASON_VIEW_FOCUS_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_FOCUS_CHANGED;
     public static final int NOT_SHOWN_REASON_VIEW_CHANGED = AUTOFILL_PRESENTATION_EVENT_REPORTED__PRESENTATION_EVENT_RESULT__NONE_SHOWN_VIEW_CHANGED;
@@ -172,6 +178,45 @@
         });
     }
 
+    public void maybeSetInlinePresentationAndSuggestionHostUid(Context context, int userId) {
+        mEventInternal.ifPresent(event -> {
+            event.mDisplayPresentationType = UI_TYPE_INLINE;
+            String imeString = Settings.Secure.getStringForUser(context.getContentResolver(),
+                    Settings.Secure.DEFAULT_INPUT_METHOD, userId);
+            if (TextUtils.isEmpty(imeString)) {
+                Slog.w(TAG, "No default IME found");
+                return;
+            }
+            ComponentName imeComponent = ComponentName.unflattenFromString(imeString);
+            if (imeComponent == null) {
+                Slog.w(TAG, "No default IME found");
+                return;
+            }
+            int imeUid;
+            String packageName = imeComponent.getPackageName();
+            try {
+                imeUid = context.getPackageManager().getApplicationInfoAsUser(packageName,
+                        PackageManager.ApplicationInfoFlags.of(0), userId).uid;
+            } catch (PackageManager.NameNotFoundException e) {
+                Slog.w(TAG, "Couldn't find packageName: " + packageName);
+                return;
+            }
+            event.mInlineSuggestionHostUid = imeUid;
+        });
+    }
+
+    public void maybeSetAutofillServiceUid(int uid) {
+        mEventInternal.ifPresent(event -> {
+            event.mAutofillServiceUid = uid;
+        });
+    }
+
+    public void maybeSetIsNewRequest(boolean isRequestTriggered) {
+        mEventInternal.ifPresent(event -> {
+            event.mIsRequestTriggered = isRequestTriggered;
+        });
+    }
+
     public void logAndEndEvent() {
         if (!mEventInternal.isPresent()) {
             Slog.w(TAG, "Shouldn't be logging AutofillPresentationEventReported again for same "
@@ -190,7 +235,10 @@
                     + " mCountNotShownImePresentationNotDrawn="
                     + event.mCountNotShownImePresentationNotDrawn
                     + " mCountNotShownImeUserNotSeen=" + event.mCountNotShownImeUserNotSeen
-                    + " mDisplayPresentationType=" + event.mDisplayPresentationType);
+                    + " mDisplayPresentationType=" + event.mDisplayPresentationType
+                    + " mAutofillServiceUid=" + event.mAutofillServiceUid
+                    + " mInlineSuggestionHostUid=" + event.mInlineSuggestionHostUid
+                    + " mIsRequestTriggered=" + event.mIsRequestTriggered);
         }
 
         // TODO(b/234185326): Distinguish empty responses from other no presentation reasons.
@@ -208,7 +256,10 @@
                 event.mCountFilteredUserTyping,
                 event.mCountNotShownImePresentationNotDrawn,
                 event.mCountNotShownImeUserNotSeen,
-                event.mDisplayPresentationType);
+                event.mDisplayPresentationType,
+                event.mAutofillServiceUid,
+                event.mInlineSuggestionHostUid,
+                event.mIsRequestTriggered);
         mEventInternal = Optional.empty();
     }
 
@@ -222,6 +273,9 @@
         int mCountNotShownImePresentationNotDrawn;
         int mCountNotShownImeUserNotSeen;
         int mDisplayPresentationType = AUTOFILL_PRESENTATION_EVENT_REPORTED__DISPLAY_PRESENTATION_TYPE__UNKNOWN_AUTOFILL_DISPLAY_PRESENTATION_TYPE;
+        int mAutofillServiceUid = -1;
+        int mInlineSuggestionHostUid = -1;
+        boolean mIsRequestTriggered;
 
         PresentationStatsEventInternal() {}
     }
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 0fe9f8f..bd9c03a 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -66,6 +66,7 @@
 import android.content.Intent;
 import android.content.IntentFilter;
 import android.content.IntentSender;
+import android.content.pm.ServiceInfo;
 import android.graphics.Bitmap;
 import android.graphics.Rect;
 import android.graphics.drawable.Drawable;
@@ -77,6 +78,7 @@
 import android.os.IBinder;
 import android.os.IBinder.DeathRecipient;
 import android.os.Parcelable;
+import android.os.Process;
 import android.os.RemoteCallback;
 import android.os.RemoteException;
 import android.os.SystemClock;
@@ -2968,6 +2970,7 @@
                     mSessionFlags.mFillDialogDisabled = true;
                 }
                 mPresentationStatsEventLogger.startNewEvent();
+                mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
                 requestNewFillResponseLocked(viewState, ViewState.STATE_STARTED_SESSION, flags);
                 break;
             case ACTION_VALUE_CHANGED:
@@ -3057,6 +3060,7 @@
                 }
 
                 mPresentationStatsEventLogger.startNewEvent();
+                mPresentationStatsEventLogger.maybeSetAutofillServiceUid(getAutofillServiceUid());
                 if (requestNewFillResponseOnViewEnteredIfNecessaryLocked(id, viewState, flags)) {
                     return;
                 }
@@ -3292,7 +3296,8 @@
                     // shown, inflated, and filtered.
                     mPresentationStatsEventLogger.maybeSetCountShown(
                             response.getDatasets(), mCurrentViewId);
-                    mPresentationStatsEventLogger.maybeSetDisplayPresentationType(UI_TYPE_INLINE);
+                    mPresentationStatsEventLogger.maybeSetInlinePresentationAndSuggestionHostUid(
+                            mContext, userId);
                     return;
                 }
             }
@@ -4639,4 +4644,9 @@
                 return "UNKNOWN_SESSION_STATE_" + sessionState;
         }
     }
+
+    private int getAutofillServiceUid() {
+        ServiceInfo serviceInfo = mService.getServiceInfo();
+        return serviceInfo == null ? Process.INVALID_UID : serviceInfo.applicationInfo.uid;
+    }
 }
diff --git a/services/core/java/com/android/server/am/OWNERS b/services/core/java/com/android/server/am/OWNERS
index c4efbd7..7fa1e13 100644
--- a/services/core/java/com/android/server/am/OWNERS
+++ b/services/core/java/com/android/server/am/OWNERS
@@ -40,3 +40,7 @@
 per-file CarUserSwitchingDialog.java = keunyoung@google.com, felipeal@google.com, gurunagarajan@google.com
 
 per-file ContentProviderHelper.java = varunshah@google.com, omakoto@google.com, jsharkey@google.com, yamasani@google.com
+
+# Multiuser
+per-file User* = file:/MULTIUSER_OWNERS
+
diff --git a/services/core/java/com/android/server/audio/AudioService.java b/services/core/java/com/android/server/audio/AudioService.java
index 0c4ea97..202250d 100644
--- a/services/core/java/com/android/server/audio/AudioService.java
+++ b/services/core/java/com/android/server/audio/AudioService.java
@@ -3355,8 +3355,7 @@
                 dispatchAbsoluteVolumeChanged(streamType, info, newIndex);
             }
 
-            if ((device == AudioSystem.DEVICE_OUT_BLE_HEADSET
-                    || device == AudioSystem.DEVICE_OUT_BLE_BROADCAST)
+            if (AudioSystem.isLeAudioDeviceType(device)
                     && streamType == getBluetoothContextualVolumeStream()
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
@@ -4112,8 +4111,7 @@
                 dispatchAbsoluteVolumeChanged(streamType, info, index);
             }
 
-            if ((device == AudioSystem.DEVICE_OUT_BLE_HEADSET
-                    || device == AudioSystem.DEVICE_OUT_BLE_BROADCAST)
+            if (AudioSystem.isLeAudioDeviceType(device)
                     && streamType == getBluetoothContextualVolumeStream()
                     && (flags & AudioManager.FLAG_BLUETOOTH_ABS_VOLUME) == 0) {
                 if (DEBUG_VOL) {
@@ -6952,7 +6950,8 @@
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE_MULTI_MODE;
         }
         if (isAbsoluteVolumeDevice(audioSystemDeviceOut)
-                || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)) {
+                || isA2dpAbsoluteVolumeDevice(audioSystemDeviceOut)
+                || AudioSystem.isLeAudioDeviceType(audioSystemDeviceOut)) {
             return AudioManager.DEVICE_VOLUME_BEHAVIOR_ABSOLUTE;
         }
         return AudioManager.DEVICE_VOLUME_BEHAVIOR_VARIABLE;
@@ -7719,7 +7718,9 @@
             int index;
             if (isFullyMuted()) {
                 index = 0;
-            } else if (isAbsoluteVolumeDevice(device) || isA2dpAbsoluteVolumeDevice(device)) {
+            } else if (isAbsoluteVolumeDevice(device)
+                    || isA2dpAbsoluteVolumeDevice(device)
+                    || AudioSystem.isLeAudioDeviceType(device)) {
                 index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
             } else if (isFullVolumeDevice(device)) {
                 index = (mIndexMax + 5)/10;
@@ -7741,7 +7742,8 @@
                         if (isFullyMuted()) {
                             index = 0;
                         } else if (isAbsoluteVolumeDevice(device)
-                                || isA2dpAbsoluteVolumeDevice(device)) {
+                                || isA2dpAbsoluteVolumeDevice(device)
+                                || AudioSystem.isLeAudioDeviceType(device)) {
                             index = getAbsoluteVolumeIndex((getIndex(device) + 5)/10);
                         } else if (isFullVolumeDevice(device)) {
                             index = (mIndexMax + 5)/10;
@@ -8162,7 +8164,8 @@
                     int streamDevice = getDeviceForStream(streamType);
                     if ((device != streamDevice)
                             && (isAbsoluteVolumeDevice(device)
-                            || isA2dpAbsoluteVolumeDevice(device))) {
+                                || isA2dpAbsoluteVolumeDevice(device)
+                                || AudioSystem.isLeAudioDeviceType(device))) {
                         mStreamStates[streamType].applyDeviceVolume_syncVSS(device);
                     }
                     mStreamStates[streamType].applyDeviceVolume_syncVSS(streamDevice);
diff --git a/services/core/java/com/android/server/audio/AudioServiceEvents.java b/services/core/java/com/android/server/audio/AudioServiceEvents.java
index b5835ce..30a9e0a7 100644
--- a/services/core/java/com/android/server/audio/AudioServiceEvents.java
+++ b/services/core/java/com/android/server/audio/AudioServiceEvents.java
@@ -433,7 +433,7 @@
                 case VOL_SET_LE_AUDIO_VOL:
                     return new StringBuilder("setLeAudioVolume:")
                             .append(" index:").append(mVal1)
-                            .append(" gain dB:").append(mVal2)
+                            .append(" maxIndex:").append(mVal2)
                             .toString();
                 case VOL_SET_AVRCP_VOL:
                     return new StringBuilder("setAvrcpVolume:")
diff --git a/services/core/java/com/android/server/audio/BtHelper.java b/services/core/java/com/android/server/audio/BtHelper.java
index 9a7c6626..d0f5470 100644
--- a/services/core/java/com/android/server/audio/BtHelper.java
+++ b/services/core/java/com/android/server/audio/BtHelper.java
@@ -412,9 +412,8 @@
             }
             return;
         }
-        /* leaudio expect volume value in range 0 to 255
-         */
-        int volume = (index * (BT_LE_AUDIO_MAX_VOL - BT_LE_AUDIO_MIN_VOL)) / maxIndex ;
+        /* leaudio expect volume value in range 0 to 255 */
+        int volume = (int) Math.round((double) index * BT_LE_AUDIO_MAX_VOL / maxIndex);
 
         if (AudioService.DEBUG_VOL) {
             Log.i(TAG, "setLeAudioVolume: calling mLeAudio.setVolume idx="
diff --git a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
index b3e7e31..93841fe 100644
--- a/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
+++ b/services/core/java/com/android/server/audio/PlaybackActivityMonitor.java
@@ -49,6 +49,7 @@
 import java.util.Iterator;
 import java.util.List;
 import java.util.Set;
+import java.util.concurrent.ConcurrentLinkedQueue;
 import java.util.function.Consumer;
 
 /**
@@ -104,11 +105,7 @@
     private static final VolumeShaper.Operation PLAY_SKIP_RAMP =
             new VolumeShaper.Operation.Builder(PLAY_CREATE_IF_NEEDED).setXOffset(1.0f).build();
 
-    private final ArrayList<PlayMonitorClient> mClients = new ArrayList<PlayMonitorClient>();
-    // a public client is one that needs an anonymized version of the playback configurations, we
-    // keep track of whether there is at least one to know when we need to create the list of
-    // playback configurations that do not contain uid/pid/package name information.
-    private boolean mHasPublicClients = false;
+    private final ConcurrentLinkedQueue<PlayMonitorClient> mClients = new ConcurrentLinkedQueue<>();
 
     private final Object mPlayerLock = new Object();
     @GuardedBy("mPlayerLock")
@@ -458,11 +455,9 @@
                 + DateFormat.getTimeInstance().format(new Date()));
         synchronized(mPlayerLock) {
             pw.println("\n  playback listeners:");
-            synchronized(mClients) {
-                for (PlayMonitorClient pmc : mClients) {
-                    pw.print(" " + (pmc.mIsPrivileged ? "(S)" : "(P)")
-                            + pmc.toString());
-                }
+            for (PlayMonitorClient pmc : mClients) {
+                pw.print(" " + (pmc.isPrivileged() ? "(S)" : "(P)")
+                        + pmc.toString());
             }
             pw.println("\n");
             // all players
@@ -534,48 +529,33 @@
      * @param iplayerReleased indicates if the change was due to a player being released
      */
     private void dispatchPlaybackChange(boolean iplayerReleased) {
-        synchronized (mClients) {
-            // typical use case, nobody is listening, don't do any work
-            if (mClients.isEmpty()) {
-                return;
-            }
-        }
         if (DEBUG) { Log.v(TAG, "dispatchPlaybackChange to " + mClients.size() + " clients"); }
         final List<AudioPlaybackConfiguration> configsSystem;
-        // list of playback configurations for "public consumption". It is only computed if there
+        // list of playback configurations for "public consumption". It is computed lazy if there
         // are non-system playback activity listeners.
-        final List<AudioPlaybackConfiguration> configsPublic;
+        List<AudioPlaybackConfiguration> configsPublic = null;
         synchronized (mPlayerLock) {
             if (mPlayers.isEmpty()) {
                 return;
             }
-            configsSystem = new ArrayList<AudioPlaybackConfiguration>(mPlayers.values());
+            configsSystem = new ArrayList<>(mPlayers.values());
         }
-        synchronized (mClients) {
-            // was done at beginning of method, but could have changed
-            if (mClients.isEmpty()) {
-                return;
-            }
-            configsPublic = mHasPublicClients ? anonymizeForPublicConsumption(configsSystem) : null;
-            final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
-            while (clientIterator.hasNext()) {
-                final PlayMonitorClient pmc = clientIterator.next();
-                try {
-                    // do not spam the logs if there are problems communicating with this client
-                    if (pmc.mErrorCount < PlayMonitorClient.MAX_ERRORS) {
-                        if (pmc.mIsPrivileged) {
-                            pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsSystem,
-                                    iplayerReleased);
-                        } else {
-                            // non-system clients don't have the control interface IPlayer, so
-                            // they don't need to flush commands when a player was released
-                            pmc.mDispatcherCb.dispatchPlaybackConfigChange(configsPublic, false);
-                        }
+
+        final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
+        while (clientIterator.hasNext()) {
+            final PlayMonitorClient pmc = clientIterator.next();
+            // do not spam the logs if there are problems communicating with this client
+            if (!pmc.reachedMaxErrorCount()) {
+                if (pmc.isPrivileged()) {
+                    pmc.dispatchPlaybackConfigChange(configsSystem,
+                            iplayerReleased);
+                } else {
+                    if (configsPublic == null) {
+                        configsPublic = anonymizeForPublicConsumption(configsSystem);
                     }
-                } catch (RemoteException e) {
-                    pmc.mErrorCount++;
-                    Log.e(TAG, "Error (" + pmc.mErrorCount +
-                            ") trying to dispatch playback config change to " + pmc, e);
+                    // non-system clients don't have the control interface IPlayer, so
+                    // they don't need to flush commands when a player was released
+                    pmc.dispatchPlaybackConfigChange(configsPublic, false);
                 }
             }
         }
@@ -798,14 +778,9 @@
         if (pcdb == null) {
             return;
         }
-        synchronized(mClients) {
-            final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
-            if (pmc.init()) {
-                if (!isPrivileged) {
-                    mHasPublicClients = true;
-                }
-                mClients.add(pmc);
-            }
+        final PlayMonitorClient pmc = new PlayMonitorClient(pcdb, isPrivileged);
+        if (pmc.init()) {
+            mClients.add(pmc);
         }
     }
 
@@ -813,23 +788,14 @@
         if (pcdb == null) {
             return;
         }
-        synchronized(mClients) {
-            final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
-            boolean hasPublicClients = false;
-            // iterate over the clients to remove the dispatcher to remove, and reevaluate at
-            // the same time if we still have a public client.
-            while (clientIterator.hasNext()) {
-                PlayMonitorClient pmc = clientIterator.next();
-                if (pcdb.asBinder().equals(pmc.mDispatcherCb.asBinder())) {
-                    pmc.release();
-                    clientIterator.remove();
-                } else {
-                    if (!pmc.mIsPrivileged) {
-                        hasPublicClients = true;
-                    }
-                }
+        final Iterator<PlayMonitorClient> clientIterator = mClients.iterator();
+        // iterate over the clients to remove the dispatcher
+        while (clientIterator.hasNext()) {
+            PlayMonitorClient pmc = clientIterator.next();
+            if (pmc.equalsDispatcher(pcdb)) {
+                pmc.release();
+                clientIterator.remove();
             }
-            mHasPublicClients = hasPublicClients;
         }
     }
 
@@ -857,24 +823,34 @@
         // can afford to be static because only one PlaybackActivityMonitor ever instantiated
         static PlaybackActivityMonitor sListenerDeathMonitor;
 
-        final IPlaybackConfigDispatcher mDispatcherCb;
-        final boolean mIsPrivileged;
-
-        int mErrorCount = 0;
         // number of errors after which we don't update this client anymore to not spam the logs
-        static final int MAX_ERRORS = 5;
+        private static final int MAX_ERRORS = 5;
+
+        private final IPlaybackConfigDispatcher mDispatcherCb;
+
+        @GuardedBy("this")
+        private final boolean mIsPrivileged;
+        @GuardedBy("this")
+        private boolean mIsReleased = false;
+        @GuardedBy("this")
+        private int mErrorCount = 0;
 
         PlayMonitorClient(IPlaybackConfigDispatcher pcdb, boolean isPrivileged) {
             mDispatcherCb = pcdb;
             mIsPrivileged = isPrivileged;
         }
 
+        @Override
         public void binderDied() {
             Log.w(TAG, "client died");
             sListenerDeathMonitor.unregisterPlaybackCallback(mDispatcherCb);
         }
 
-        boolean init() {
+        synchronized boolean init() {
+            if (mIsReleased) {
+                // Do not init after release
+                return false;
+            }
             try {
                 mDispatcherCb.asBinder().linkToDeath(this, 0);
                 return true;
@@ -884,8 +860,43 @@
             }
         }
 
-        void release() {
+        synchronized void release() {
             mDispatcherCb.asBinder().unlinkToDeath(this, 0);
+            mIsReleased = true;
+        }
+
+        void dispatchPlaybackConfigChange(List<AudioPlaybackConfiguration> configs,
+                boolean flush) {
+            synchronized (this) {
+                if (mIsReleased) {
+                    // Do not dispatch anything after release
+                    return;
+                }
+            }
+            try {
+                mDispatcherCb.dispatchPlaybackConfigChange(configs, flush);
+            } catch (RemoteException e) {
+                synchronized (this) {
+                    mErrorCount++;
+                    Log.e(TAG, "Error (" + mErrorCount
+                            + ") trying to dispatch playback config change to " + this, e);
+                }
+            }
+        }
+
+        synchronized boolean isPrivileged() {
+            return mIsPrivileged;
+        }
+
+        synchronized boolean reachedMaxErrorCount() {
+            return mErrorCount >= MAX_ERRORS;
+        }
+
+        synchronized boolean equalsDispatcher(IPlaybackConfigDispatcher pcdb) {
+            if (pcdb == null) {
+                return false;
+            }
+            return pcdb.asBinder().equals(mDispatcherCb.asBinder());
         }
     }
 
diff --git a/services/core/java/com/android/server/camera/CameraServiceProxy.java b/services/core/java/com/android/server/camera/CameraServiceProxy.java
index b425420..aec60de 100644
--- a/services/core/java/com/android/server/camera/CameraServiceProxy.java
+++ b/services/core/java/com/android/server/camera/CameraServiceProxy.java
@@ -582,13 +582,18 @@
         }
 
         @Override
-        public boolean isCameraDisabled() {
+        public boolean isCameraDisabled(int userId) {
             DevicePolicyManager dpm = mContext.getSystemService(DevicePolicyManager.class);
             if (dpm == null) {
                 Slog.e(TAG, "Failed to get the device policy manager service");
                 return false;
             }
-            return dpm.getCameraDisabled(null);
+            try {
+                return dpm.getCameraDisabled(null, userId);
+            } catch (Exception e) {
+                e.printStackTrace();
+                return false;
+            }
         }
     };
 
diff --git a/services/core/java/com/android/server/notification/PreferencesHelper.java b/services/core/java/com/android/server/notification/PreferencesHelper.java
index 477b8da..d8aa469 100644
--- a/services/core/java/com/android/server/notification/PreferencesHelper.java
+++ b/services/core/java/com/android/server/notification/PreferencesHelper.java
@@ -106,7 +106,7 @@
     private static final String NON_BLOCKABLE_CHANNEL_DELIM = ":";
 
     @VisibleForTesting
-    static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 50000;
+    static final int NOTIFICATION_CHANNEL_COUNT_LIMIT = 5000;
     @VisibleForTesting
     static final int NOTIFICATION_CHANNEL_GROUP_COUNT_LIMIT = 50000;
 
diff --git a/services/core/java/com/android/server/trust/TrustManagerService.java b/services/core/java/com/android/server/trust/TrustManagerService.java
index 80ce70d..3707c8e 100644
--- a/services/core/java/com/android/server/trust/TrustManagerService.java
+++ b/services/core/java/com/android/server/trust/TrustManagerService.java
@@ -1211,7 +1211,7 @@
             if (info.userId == userId
                     && info.agent.isTrusted()
                     && info.agent.shouldDisplayTrustGrantedMessage()
-                    && !TextUtils.isEmpty(info.agent.getMessage())) {
+                    && info.agent.getMessage() != null) {
                 trustGrantedMessages.add(info.agent.getMessage().toString());
             }
         }
diff --git a/services/core/java/com/android/server/wm/ActivityRecord.java b/services/core/java/com/android/server/wm/ActivityRecord.java
index af22f80..6538ee3 100644
--- a/services/core/java/com/android/server/wm/ActivityRecord.java
+++ b/services/core/java/com/android/server/wm/ActivityRecord.java
@@ -2120,7 +2120,7 @@
 
         mActivityRecordInputSink = new ActivityRecordInputSink(this, sourceRecord);
 
-        updateEnterpriseThumbnailDrawable(mAtmService.mUiContext);
+        updateEnterpriseThumbnailDrawable(mAtmService.getUiContext());
     }
 
     /**
@@ -7433,7 +7433,7 @@
         }
         final Rect frame = win.getRelativeFrame();
         final Drawable thumbnailDrawable = task.mUserId == mWmService.mCurrentUserId
-                ? mAtmService.mUiContext.getDrawable(R.drawable.ic_account_circle)
+                ? mAtmService.getUiContext().getDrawable(R.drawable.ic_account_circle)
                 : mEnterpriseThumbnailDrawable;
         final HardwareBuffer thumbnail = getDisplayContent().mAppTransition
                 .createCrossProfileAppsThumbnail(thumbnailDrawable, frame);
diff --git a/services/core/java/com/android/server/wm/ActivityStartController.java b/services/core/java/com/android/server/wm/ActivityStartController.java
index 7c25b53..0707b81 100644
--- a/services/core/java/com/android/server/wm/ActivityStartController.java
+++ b/services/core/java/com/android/server/wm/ActivityStartController.java
@@ -384,6 +384,14 @@
                 callingUid, realCallingUid, UserHandle.USER_NULL);
         final SparseArray<String> startingUidPkgs = new SparseArray<>();
         final long origId = Binder.clearCallingIdentity();
+
+        SafeActivityOptions bottomOptions = null;
+        if (options != null) {
+            // To ensure the first N-1 activities (N == total # of activities) are also launched
+            // into the correct display, use a copy of the passed-in options (keeping only
+            // display-related info) for these activities.
+            bottomOptions = options.selectiveCloneDisplayOptions();
+        }
         try {
             intents = ArrayUtils.filterNotNull(intents, Intent[]::new);
             final ActivityStarter[] starters = new ActivityStarter[intents.length];
@@ -432,7 +440,7 @@
                 final boolean top = i == intents.length - 1;
                 final SafeActivityOptions checkedOptions = top
                         ? options
-                        : null;
+                        : bottomOptions;
                 starters[i] = obtainStarter(intent, reason)
                         .setIntentGrants(intentGrants)
                         .setCaller(caller)
diff --git a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
index e993496..75e24a8 100644
--- a/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
+++ b/services/core/java/com/android/server/wm/ActivityTaskManagerService.java
@@ -346,7 +346,7 @@
      * This Context is themable and meant for UI display (AlertDialogs, etc.). The theme can
      * change at runtime. Use mContext for non-UI purposes.
      */
-    final Context mUiContext;
+    private final Context mUiContext;
     final ActivityThread mSystemThread;
     H mH;
     UiHandler mUiHandler;
@@ -1041,6 +1041,10 @@
         }
     }
 
+    Context getUiContext() {
+        return mUiContext;
+    }
+
     UserManagerService getUserManager() {
         if (mUserManager == null) {
             IBinder b = ServiceManager.getService(Context.USER_SERVICE);
diff --git a/services/core/java/com/android/server/wm/AppTransition.java b/services/core/java/com/android/server/wm/AppTransition.java
index 53f2c71..5c1a877 100644
--- a/services/core/java/com/android/server/wm/AppTransition.java
+++ b/services/core/java/com/android/server/wm/AppTransition.java
@@ -39,6 +39,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -758,7 +759,8 @@
         if (isKeyguardGoingAwayTransitOld(transit) && enter) {
             a = mTransitionAnimation.loadKeyguardExitAnimation(mNextAppTransitionFlags,
                     transit == TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER);
-        } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE) {
+        } else if (transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM) {
             a = null;
         } else if (transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE && !enter) {
             a = mTransitionAnimation.loadKeyguardUnoccludeAnimation();
@@ -1170,6 +1172,9 @@
             case TRANSIT_OLD_KEYGUARD_OCCLUDE: {
                 return "TRANSIT_OLD_KEYGUARD_OCCLUDE";
             }
+            case TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM: {
+                return "TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM";
+            }
             case TRANSIT_OLD_KEYGUARD_UNOCCLUDE: {
                 return "TRANSIT_OLD_KEYGUARD_UNOCCLUDE";
             }
@@ -1425,6 +1430,7 @@
 
     static boolean isKeyguardOccludeTransitOld(@TransitionOldType int transit) {
         return transit == TRANSIT_OLD_KEYGUARD_OCCLUDE
+                || transit == TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM
                 || transit == TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
     }
 
diff --git a/services/core/java/com/android/server/wm/AppTransitionController.java b/services/core/java/com/android/server/wm/AppTransitionController.java
index 5ac5f2e..5599f2c 100644
--- a/services/core/java/com/android/server/wm/AppTransitionController.java
+++ b/services/core/java/com/android/server/wm/AppTransitionController.java
@@ -38,6 +38,7 @@
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_GOING_AWAY_ON_WALLPAPER;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE;
+import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
 import static android.view.WindowManager.TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
 import static android.view.WindowManager.TRANSIT_OLD_NONE;
 import static android.view.WindowManager.TRANSIT_OLD_TASK_CHANGE_WINDOWING_MODE;
@@ -363,8 +364,14 @@
                 // When there is a closing app, the keyguard has already been occluded by an
                 // activity, and another activity has started on top of that activity, so normal
                 // app transition animation should be used.
-                return closingApps.isEmpty() ? TRANSIT_OLD_KEYGUARD_OCCLUDE
-                        : TRANSIT_OLD_ACTIVITY_OPEN;
+                if (!closingApps.isEmpty()) {
+                    return TRANSIT_OLD_ACTIVITY_OPEN;
+                }
+                if (!openingApps.isEmpty() && openingApps.valueAt(0).getActivityType()
+                        == ACTIVITY_TYPE_DREAM) {
+                    return TRANSIT_OLD_KEYGUARD_OCCLUDE_BY_DREAM;
+                }
+                return TRANSIT_OLD_KEYGUARD_OCCLUDE;
             case TRANSIT_KEYGUARD_UNOCCLUDE:
                 return TRANSIT_OLD_KEYGUARD_UNOCCLUDE;
         }
diff --git a/services/core/java/com/android/server/wm/BackNavigationController.java b/services/core/java/com/android/server/wm/BackNavigationController.java
index 35a39c0..028d4b3 100644
--- a/services/core/java/com/android/server/wm/BackNavigationController.java
+++ b/services/core/java/com/android/server/wm/BackNavigationController.java
@@ -310,7 +310,7 @@
                         mBackNaviAnimationController = new BackNaviAnimationController(
                                 backAnimationAdaptor.getRunner(), this,
                                 currentActivity.getDisplayId());
-                        prepareBackToHomeTransition(currentTask, prevTask);
+                        prepareBackToHomeTransition(currentActivity, prevTask);
                         infoBuilder.setPrepareAnimation(true);
                     }
                 } else {
@@ -489,8 +489,8 @@
         mWindowManagerService = wm;
     }
 
-    private void prepareBackToHomeTransition(Task currentTask, Task homeTask) {
-        final DisplayContent dc = currentTask.getDisplayContent();
+    private void prepareBackToHomeTransition(ActivityRecord currentActivity, Task homeTask) {
+        final DisplayContent dc = currentActivity.getDisplayContent();
         final ActivityRecord homeActivity = homeTask.getTopNonFinishingActivity();
         if (!homeActivity.mVisibleRequested) {
             homeActivity.setVisibility(true);
@@ -499,7 +499,7 @@
         dc.ensureActivitiesVisible(
                 null /* starting */, 0 /* configChanges */,
                 false /* preserveWindows */, true);
-        mBackNaviAnimationController.initialize(homeActivity, currentTask.getTopMostActivity());
+        mBackNaviAnimationController.initialize(homeActivity, currentActivity);
     }
 
     void finishAnimation() {
diff --git a/services/core/java/com/android/server/wm/DisplayContent.java b/services/core/java/com/android/server/wm/DisplayContent.java
index 720b082..ca02e7d 100644
--- a/services/core/java/com/android/server/wm/DisplayContent.java
+++ b/services/core/java/com/android/server/wm/DisplayContent.java
@@ -1614,24 +1614,6 @@
             }
             config = new Configuration();
             computeScreenConfiguration(config);
-        } else if (!(mTransitionController.isCollecting(this)
-                // If waiting for a remote display change, don't prematurely update configuration.
-                || mRemoteDisplayChangeController.isWaitingForRemoteDisplayChange())) {
-            // No obvious action we need to take, but if our current state mismatches the
-            // activity manager's, update it, disregarding font scale, which should remain set
-            // to the value of the previous configuration.
-            // Here we're calling Configuration#unset() instead of setToDefaults() because we
-            // need to keep override configs clear of non-empty values (e.g. fontSize).
-            final Configuration currentConfig = getRequestedOverrideConfiguration();
-            mTmpConfiguration.unset();
-            mTmpConfiguration.updateFrom(currentConfig);
-            computeScreenConfiguration(mTmpConfiguration);
-            if (currentConfig.diff(mTmpConfiguration) != 0) {
-                mWaitingForConfig = true;
-                setLayoutNeeded();
-                mDisplayRotation.prepareNormalRotationAnimation();
-                config = new Configuration(mTmpConfiguration);
-            }
         }
 
         return config;
diff --git a/services/core/java/com/android/server/wm/DisplayPolicy.java b/services/core/java/com/android/server/wm/DisplayPolicy.java
index 1636d9f..b26de07 100644
--- a/services/core/java/com/android/server/wm/DisplayPolicy.java
+++ b/services/core/java/com/android/server/wm/DisplayPolicy.java
@@ -421,7 +421,7 @@
         mService = service;
         mContext = displayContent.isDefaultDisplay ? service.mContext
                 : service.mContext.createDisplayContext(displayContent.getDisplay());
-        mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.mUiContext
+        mUiContext = displayContent.isDefaultDisplay ? service.mAtmService.getUiContext()
                 : service.mAtmService.mSystemThread
                         .getSystemUiContext(displayContent.getDisplayId());
         mDisplayContent = displayContent;
diff --git a/services/core/java/com/android/server/wm/SafeActivityOptions.java b/services/core/java/com/android/server/wm/SafeActivityOptions.java
index 2879e33..8bacacd 100644
--- a/services/core/java/com/android/server/wm/SafeActivityOptions.java
+++ b/services/core/java/com/android/server/wm/SafeActivityOptions.java
@@ -116,6 +116,34 @@
     }
 
     /**
+     * To ensure that two activities, one using this object, and the other using the
+     * SafeActivityOptions returned from this function, are launched into the same display through
+     * ActivityStartController#startActivities, all display-related information, i.e.
+     * displayAreaToken, launchDisplayId and callerDisplayId, are cloned.
+     */
+    @Nullable SafeActivityOptions selectiveCloneDisplayOptions() {
+        final ActivityOptions options = cloneLaunchingDisplayOptions(mOriginalOptions);
+        final ActivityOptions callerOptions = cloneLaunchingDisplayOptions(mCallerOptions);
+        if (options == null && callerOptions == null) {
+            return null;
+        }
+
+        final SafeActivityOptions safeOptions = new SafeActivityOptions(options,
+                mOriginalCallingPid, mOriginalCallingUid);
+        safeOptions.mCallerOptions = callerOptions;
+        safeOptions.mRealCallingPid = mRealCallingPid;
+        safeOptions.mRealCallingUid = mRealCallingUid;
+        return safeOptions;
+    }
+
+    private ActivityOptions cloneLaunchingDisplayOptions(ActivityOptions options) {
+        return options == null ? null : ActivityOptions.makeBasic()
+                .setLaunchTaskDisplayArea(options.getLaunchTaskDisplayArea())
+                .setLaunchDisplayId(options.getLaunchDisplayId())
+                .setCallerDisplayId((options.getCallerDisplayId()));
+    }
+
+    /**
      * Overrides options with options from a caller and records {@link Binder#getCallingPid}/
      * {@link Binder#getCallingUid}. Thus, calling identity MUST NOT be cleared when calling this
      * method.
diff --git a/services/core/java/com/android/server/wm/Task.java b/services/core/java/com/android/server/wm/Task.java
index 436cc4d..91db278 100644
--- a/services/core/java/com/android/server/wm/Task.java
+++ b/services/core/java/com/android/server/wm/Task.java
@@ -4465,6 +4465,14 @@
             // transferring the transform on the leash to the task, reset this state once we're
             // moving out of pip
             setCanAffectSystemUiFlags(true);
+            // Turn on userLeaveHint so other app can enter PiP mode.
+            mTaskSupervisor.mUserLeaving = true;
+            // Allow entering PiP from current top most activity when we are leaving PiP.
+            final Task topFocused = mRootWindowContainer.getTopDisplayFocusedRootTask();
+            if (topFocused != null) {
+                final ActivityRecord ar = topFocused.getTopResumedActivity();
+                enableEnterPipOnTaskSwitch(ar, null /* toFrontTask */, ar, null /* opts */);
+            }
             mRootWindowContainer.notifyActivityPipModeChanged(this, null);
         }
         if (likelyResolvedMode == WINDOWING_MODE_PINNED) {
diff --git a/services/core/java/com/android/server/wm/Transition.java b/services/core/java/com/android/server/wm/Transition.java
index 135fcd4..0e1a6de 100644
--- a/services/core/java/com/android/server/wm/Transition.java
+++ b/services/core/java/com/android/server/wm/Transition.java
@@ -577,17 +577,16 @@
                 t.setLayer(targetLeash, target.getLastLayer());
                 target.getRelativePosition(tmpPos);
                 t.setPosition(targetLeash, tmpPos.x, tmpPos.y);
-                final Rect clipRect;
                 // No need to clip the display in case seeing the clipped content when during the
                 // display rotation. No need to clip activities because they rely on clipping on
                 // task layers.
                 if (target.asDisplayContent() != null || target.asActivityRecord() != null) {
-                    clipRect = null;
+                    t.setCrop(targetLeash, null /* crop */);
                 } else {
-                    clipRect = target.getRequestedOverrideBounds();
-                    clipRect.offset(-tmpPos.x, -tmpPos.y);
+                    // Crop to the requested bounds.
+                    final Rect clipRect = target.getRequestedOverrideBounds();
+                    t.setWindowCrop(targetLeash, clipRect.width(), clipRect.height());
                 }
-                t.setCrop(targetLeash, clipRect);
                 t.setCornerRadius(targetLeash, 0);
                 t.setShadowRadius(targetLeash, 0);
                 t.setMatrix(targetLeash, 1, 0, 0, 1);
diff --git a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
index 06fb4b0..6aca14f0 100644
--- a/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
+++ b/services/devicepolicy/java/com/android/server/devicepolicy/DevicePolicyManagerService.java
@@ -8178,7 +8178,8 @@
         }
 
         final CallerIdentity caller = getCallerIdentity(who);
-        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle));
+        Preconditions.checkCallAuthorization(hasFullCrossUsersPermission(caller, userHandle)
+                || isCameraServerUid(caller));
 
         if (parent) {
             Preconditions.checkCallAuthorization(
@@ -9689,6 +9690,10 @@
         return UserHandle.isSameApp(caller.getUid(), Process.SHELL_UID);
     }
 
+    private boolean isCameraServerUid(CallerIdentity caller) {
+        return UserHandle.isSameApp(caller.getUid(), Process.CAMERASERVER_UID);
+    }
+
     private @UserIdInt int getCurrentForegroundUserId() {
         try {
             UserInfo currentUser = mInjector.getIActivityManager().getCurrentUser();
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
index bbd7695..95e9f20 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityRecordTests.java
@@ -2993,6 +2993,7 @@
         // Add a decor insets provider window.
         final WindowState navbar = createNavBarWithProvidedInsets(squareDisplay);
         squareDisplay.getDisplayPolicy().updateDecorInsetsInfoIfNeeded(navbar);
+        squareDisplay.sendNewConfiguration();
         final Task task = new TaskBuilder(mSupervisor).setDisplay(squareDisplay).build();
 
         // create a fixed portrait activity
diff --git a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
index 20b1120..2fccd64 100644
--- a/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
+++ b/services/tests/wmtests/src/com/android/server/wm/ActivityTaskManagerServiceTests.java
@@ -220,10 +220,7 @@
         // Check that changes are reported
         Configuration c = new Configuration(newDisp1.getRequestedOverrideConfiguration());
         c.windowConfiguration.setBounds(new Rect(0, 0, 1000, 1300));
-        newDisp1.onRequestedOverrideConfigurationChanged(c);
-        mAtm.mRootWindowContainer.ensureVisibilityAndConfig(null /* starting */,
-                newDisp1.mDisplayId, false /* markFrozenIfConfigChanged */,
-                false /* deferResume */);
+        newDisp1.performDisplayOverrideConfigUpdate(c);
         assertEquals(0, added.size());
         assertEquals(1, changed.size());
         assertEquals(0, removed.size());
diff --git a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
index 7111852..e57ad5d 100644
--- a/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
+++ b/services/tests/wmtests/src/com/android/server/wm/SafeActivityOptionsTest.java
@@ -17,9 +17,12 @@
 package com.android.server.wm;
 
 import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertSame;
+import static org.mockito.Mockito.mock;
 
 import android.app.ActivityOptions;
 import android.platform.test.annotations.Presubmit;
+import android.window.WindowContainerToken;
 
 import androidx.test.filters.MediumTest;
 
@@ -43,4 +46,21 @@
         final ActivityOptions result = options.mergeActivityOptions(opts1, opts2);
         assertEquals(6, result.getLaunchDisplayId());
     }
+
+    @Test
+    public void test_selectiveCloneDisplayOptions() {
+        final WindowContainerToken token = mock(WindowContainerToken.class);
+        final int launchDisplayId = 5;
+        final int callerDisplayId = 6;
+
+        final SafeActivityOptions clone = new SafeActivityOptions(ActivityOptions.makeBasic()
+                .setLaunchTaskDisplayArea(token)
+                .setLaunchDisplayId(launchDisplayId)
+                .setCallerDisplayId(callerDisplayId))
+                .selectiveCloneDisplayOptions();
+
+        assertSame(clone.getOriginalOptions().getLaunchTaskDisplayArea(), token);
+        assertEquals(clone.getOriginalOptions().getLaunchDisplayId(), launchDisplayId);
+        assertEquals(clone.getOriginalOptions().getCallerDisplayId(), callerDisplayId);
+    }
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
index 25216a3..66ad6f1 100644
--- a/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
+++ b/tests/FlickerTests/test-apps/flickerapp/AndroidManifest.xml
@@ -173,5 +173,17 @@
                 <category android:name="android.intent.category.LAUNCHER"/>
             </intent-filter>
         </activity>
+        <activity android:name=".GameActivity"
+            android:taskAffinity="com.android.server.wm.flicker.testapp.GameActivity"
+            android:immersive="true"
+            android:theme="@android:style/Theme.NoTitleBar"
+            android:configChanges="screenSize"
+            android:label="GameApp"
+            android:exported="true">
+            <intent-filter>
+                <action android:name="android.intent.action.MAIN"/>
+                <category android:name="android.intent.category.LAUNCHER"/>
+            </intent-filter>
+        </activity>
     </application>
 </manifest>
diff --git a/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
new file mode 100644
index 0000000..0b4693d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/res/layout/activity_surfaceview.xml
@@ -0,0 +1,28 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!--
+ Copyright 2018 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.
+-->
+<LinearLayout
+    xmlns:android="http://schemas.android.com/apk/res/android"
+    android:id="@+id/container"
+    android:layout_width="match_parent"
+    android:layout_height="match_parent"
+    android:background="@android:color/holo_orange_light">
+
+    <SurfaceView
+        android:id="@+id/surface_view"
+        android:layout_width="match_parent"
+        android:layout_height="match_parent"/>
+</LinearLayout>
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
index 6cda482..42a37df 100644
--- a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/ActivityOptions.java
@@ -87,4 +87,9 @@
     public static final ComponentName NOTIFICATION_ACTIVITY_COMPONENT_NAME =
             new ComponentName(FLICKER_APP_PACKAGE,
                     FLICKER_APP_PACKAGE + ".NotificationActivity");
+
+    public static final String GAME_ACTIVITY_LAUNCHER_NAME = "GameApp";
+    public static final ComponentName GAME_ACTIVITY_COMPONENT_NAME =
+            new ComponentName(FLICKER_APP_PACKAGE,
+                   FLICKER_APP_PACKAGE + ".GameActivity");
 }
diff --git a/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
new file mode 100644
index 0000000..ef75d4d
--- /dev/null
+++ b/tests/FlickerTests/test-apps/flickerapp/src/com/android/server/wm/flicker/testapp/GameActivity.java
@@ -0,0 +1,77 @@
+/*
+ * 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.wm.flicker.testapp;
+
+import android.app.Activity;
+import android.graphics.Canvas;
+import android.graphics.Color;
+import android.graphics.PixelFormat;
+import android.os.Bundle;
+import android.view.SurfaceHolder;
+import android.view.SurfaceView;
+
+import androidx.core.view.ViewCompat;
+import androidx.core.view.WindowInsetsCompat;
+import androidx.core.view.WindowInsetsControllerCompat;
+
+public class GameActivity extends Activity implements SurfaceHolder.Callback {
+    private SurfaceHolder mSurfaceHolder;
+    private SurfaceView mSurfaceView;
+
+    @Override
+    public void onCreate(Bundle savedInstanceState) {
+        super.onCreate(savedInstanceState);
+
+        setContentView(R.layout.activity_surfaceview);
+
+        mSurfaceView = (SurfaceView) findViewById(R.id.surface_view);
+        mSurfaceView.setZOrderOnTop(true);
+        mSurfaceHolder = mSurfaceView.getHolder();
+        mSurfaceHolder.setFormat(PixelFormat.TRANSPARENT);
+        mSurfaceHolder.addCallback(this);
+    }
+
+    @Override
+    public void surfaceCreated(SurfaceHolder holder) {
+        hideSystemBars();
+    }
+
+    @Override
+    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
+        Canvas canvas = holder.lockCanvas();
+        canvas.drawColor(Color.BLUE);
+        holder.unlockCanvasAndPost(canvas);
+    }
+
+    @Override
+    public void surfaceDestroyed(SurfaceHolder holder) {
+    }
+
+    private void hideSystemBars() {
+        WindowInsetsControllerCompat windowInsetsController =
+                ViewCompat.getWindowInsetsController(getWindow().getDecorView());
+        if (windowInsetsController == null) {
+            return;
+        }
+        // Configure the behavior of the hidden system bars.
+        windowInsetsController.setSystemBarsBehavior(
+                WindowInsetsControllerCompat.BEHAVIOR_SHOW_TRANSIENT_BARS_BY_SWIPE
+        );
+        // Hide both the status bar and the navigation bar.
+        windowInsetsController.hide(WindowInsetsCompat.Type.systemBars());
+    }
+}