Merge "Add another namespace to mapper." into main
diff --git a/core/java/android/service/contentcapture/ContentCaptureService.java b/core/java/android/service/contentcapture/ContentCaptureService.java
index 06e86af..78248d9 100644
--- a/core/java/android/service/contentcapture/ContentCaptureService.java
+++ b/core/java/android/service/contentcapture/ContentCaptureService.java
@@ -138,7 +138,8 @@
             new LocalDataShareAdapterResourceManager();
 
     private Handler mHandler;
-    private IContentCaptureServiceCallback mCallback;
+    @Nullable private IContentCaptureServiceCallback mContentCaptureServiceCallback;
+    @Nullable private IContentProtectionAllowlistCallback mContentProtectionAllowlistCallback;
 
     private long mCallerMismatchTimeout = 1000;
     private long mLastCallerMismatchLog;
@@ -215,6 +216,16 @@
                                     Binder.getCallingUid(),
                                     events));
                 }
+
+                @Override
+                public void onUpdateAllowlistRequest(IBinder callback) {
+                    mHandler.sendMessage(
+                            obtainMessage(
+                                    ContentCaptureService::handleOnUpdateAllowlistRequest,
+                                    ContentCaptureService.this,
+                                    Binder.getCallingUid(),
+                                    callback));
+                }
             };
 
     /** Binder that receives calls from the app in the content capture flow. */
@@ -278,14 +289,31 @@
      */
     public final void setContentCaptureWhitelist(@Nullable Set<String> packages,
             @Nullable Set<ComponentName> activities) {
-        final IContentCaptureServiceCallback callback = mCallback;
-        if (callback == null) {
-            Log.w(TAG, "setContentCaptureWhitelist(): no server callback");
+
+        IContentCaptureServiceCallback contentCaptureCallback = mContentCaptureServiceCallback;
+        IContentProtectionAllowlistCallback contentProtectionAllowlistCallback =
+                mContentProtectionAllowlistCallback;
+
+        if (contentCaptureCallback == null && contentProtectionAllowlistCallback == null) {
+            Log.w(TAG, "setContentCaptureWhitelist(): missing both server callbacks");
+            return;
+        }
+
+        if (contentCaptureCallback != null) {
+            if (contentProtectionAllowlistCallback != null) {
+                throw new IllegalStateException("Have both server callbacks");
+            }
+            try {
+                contentCaptureCallback.setContentCaptureWhitelist(
+                        toList(packages), toList(activities));
+            } catch (RemoteException e) {
+                e.rethrowFromSystemServer();
+            }
             return;
         }
 
         try {
-            callback.setContentCaptureWhitelist(toList(packages), toList(activities));
+            contentProtectionAllowlistCallback.setAllowlist(toList(packages));
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
@@ -314,7 +342,7 @@
      */
     public final void setContentCaptureConditions(@NonNull String packageName,
             @Nullable Set<ContentCaptureCondition> conditions) {
-        final IContentCaptureServiceCallback callback = mCallback;
+        final IContentCaptureServiceCallback callback = mContentCaptureServiceCallback;
         if (callback == null) {
             Log.w(TAG, "setContentCaptureConditions(): no server callback");
             return;
@@ -425,7 +453,7 @@
     public final void disableSelf() {
         if (sDebug) Log.d(TAG, "disableSelf()");
 
-        final IContentCaptureServiceCallback callback = mCallback;
+        final IContentCaptureServiceCallback callback = mContentCaptureServiceCallback;
         if (callback == null) {
             Log.w(TAG, "disableSelf(): no server callback");
             return;
@@ -464,13 +492,14 @@
     }
 
     private void handleOnConnected(@NonNull IBinder callback) {
-        mCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
+        mContentCaptureServiceCallback = IContentCaptureServiceCallback.Stub.asInterface(callback);
         onConnected();
     }
 
     private void handleOnDisconnected() {
         onDisconnected();
-        mCallback = null;
+        mContentCaptureServiceCallback = null;
+        mContentProtectionAllowlistCallback = null;
     }
 
     //TODO(b/111276913): consider caching the InteractionSessionId for the lifetime of the session,
@@ -583,6 +612,16 @@
         onContentCaptureEvent(sessionId, endEvent);
     }
 
+    private void handleOnUpdateAllowlistRequest(int uid, @NonNull IBinder callback) {
+        if (uid != Process.SYSTEM_UID) {
+            Log.e(TAG, "handleOnUpdateAllowlistRequest() not allowed for uid: " + uid);
+            return;
+        }
+        mContentProtectionAllowlistCallback =
+                IContentProtectionAllowlistCallback.Stub.asInterface(callback);
+        onConnected();
+    }
+
     private void handleOnActivitySnapshot(int sessionId, @NonNull SnapshotData snapshotData) {
         onActivitySnapshot(new ContentCaptureSessionId(sessionId), snapshotData);
     }
@@ -701,13 +740,14 @@
     private void writeFlushMetrics(int sessionId, @Nullable ComponentName app,
             @NonNull FlushMetrics flushMetrics, @Nullable ContentCaptureOptions options,
             int flushReason) {
-        if (mCallback == null) {
+        if (mContentCaptureServiceCallback == null) {
             Log.w(TAG, "writeSessionFlush(): no server callback");
             return;
         }
 
         try {
-            mCallback.writeSessionFlush(sessionId, app, flushMetrics, options, flushReason);
+            mContentCaptureServiceCallback.writeSessionFlush(
+                    sessionId, app, flushMetrics, options, flushReason);
         } catch (RemoteException e) {
             Log.e(TAG, "failed to write flush metrics: " + e);
         }
diff --git a/core/java/android/service/contentcapture/IContentProtectionAllowlistCallback.aidl b/core/java/android/service/contentcapture/IContentProtectionAllowlistCallback.aidl
new file mode 100644
index 0000000..8d5a15c
--- /dev/null
+++ b/core/java/android/service/contentcapture/IContentProtectionAllowlistCallback.aidl
@@ -0,0 +1,34 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package android.service.contentcapture;
+
+import android.content.ComponentName;
+import android.view.contentcapture.ContentCaptureCondition;
+import android.service.contentcapture.FlushMetrics;
+import android.content.ContentCaptureOptions;
+
+import java.util.List;
+
+/**
+ * Interface for the callback used by the content protection service to call the system server and
+ * update the allowlist.
+ *
+ * @hide
+ */
+oneway interface IContentProtectionAllowlistCallback {
+    void setAllowlist(in List<String> packages);
+}
diff --git a/core/java/android/service/contentcapture/IContentProtectionService.aidl b/core/java/android/service/contentcapture/IContentProtectionService.aidl
index 4a13c3f..25b248f 100644
--- a/core/java/android/service/contentcapture/IContentProtectionService.aidl
+++ b/core/java/android/service/contentcapture/IContentProtectionService.aidl
@@ -17,6 +17,7 @@
 package android.service.contentcapture;
 
 import android.content.pm.ParceledListSlice;
+import android.os.IBinder;
 import android.view.contentcapture.ContentCaptureEvent;
 
 /**
@@ -27,4 +28,6 @@
 oneway interface IContentProtectionService {
 
     void onLoginDetected(in ParceledListSlice events);
+
+    void onUpdateAllowlistRequest(in IBinder callback);
 }
diff --git a/core/java/android/view/IWindowManager.aidl b/core/java/android/view/IWindowManager.aidl
index c10fc9f..6c3b8ab 100644
--- a/core/java/android/view/IWindowManager.aidl
+++ b/core/java/android/view/IWindowManager.aidl
@@ -525,11 +525,11 @@
         out InputChannel inputChannel);
 
     /**
-     * Destroy an input consumer by name and display id.
+     * Destroy an input consumer by token and display id.
      * This method will also dispose the input channels associated with that InputConsumer.
      */
     @UnsupportedAppUsage
-    boolean destroyInputConsumer(String name, int displayId);
+    boolean destroyInputConsumer(IBinder token, int displayId);
 
     /**
      * Return the touch region for the current IME window, or an empty region if there is none.
diff --git a/core/java/android/view/contentcapture/ContentCaptureManager.java b/core/java/android/view/contentcapture/ContentCaptureManager.java
index 5f612d6b..970baf2 100644
--- a/core/java/android/view/contentcapture/ContentCaptureManager.java
+++ b/core/java/android/view/contentcapture/ContentCaptureManager.java
@@ -411,6 +411,15 @@
     public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS =
             "content_protection_allowlist_timeout_ms";
 
+    /**
+     * Sets the auto disconnect timeout for the content protection service in milliseconds.
+     *
+     * @hide
+     */
+    // Unit can't be in the name in order to pass the checkstyle hook, line would be too long.
+    public static final String DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT =
+            "content_protection_auto_disconnect_timeout_ms";
+
     /** @hide */
     @TestApi
     public static final int LOGGING_LEVEL_OFF = 0;
@@ -465,6 +474,8 @@
     public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS = 30000;
     /** @hide */
     public static final long DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS = 250;
+    /** @hide */
+    public static final long DEFAULT_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT_MS = 3000;
 
     private final Object mLock = new Object();
 
diff --git a/core/java/android/widget/RemoteViews.java b/core/java/android/widget/RemoteViews.java
index f19a2f9..3078801 100644
--- a/core/java/android/widget/RemoteViews.java
+++ b/core/java/android/widget/RemoteViews.java
@@ -104,7 +104,6 @@
 
 import com.android.internal.R;
 import com.android.internal.config.sysui.SystemUiDeviceConfigFlags;
-import com.android.internal.util.ContrastColorUtil;
 import com.android.internal.util.Preconditions;
 import com.android.internal.widget.IRemoteViewsFactory;
 
@@ -130,7 +129,6 @@
 import java.util.List;
 import java.util.Map;
 import java.util.Objects;
-import java.util.Stack;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.Executor;
 import java.util.concurrent.TimeUnit;
@@ -225,10 +223,8 @@
     private static final int BITMAP_REFLECTION_ACTION_TAG = 12;
     private static final int TEXT_VIEW_SIZE_ACTION_TAG = 13;
     private static final int VIEW_PADDING_ACTION_TAG = 14;
-    private static final int SET_REMOTE_VIEW_ADAPTER_LIST_TAG = 15;
     private static final int SET_REMOTE_INPUTS_ACTION_TAG = 18;
     private static final int LAYOUT_PARAM_ACTION_TAG = 19;
-    private static final int OVERRIDE_TEXT_COLORS_TAG = 20;
     private static final int SET_RIPPLE_DRAWABLE_COLOR_TAG = 21;
     private static final int SET_INT_TAG_TAG = 22;
     private static final int REMOVE_FROM_PARENT_ACTION_TAG = 23;
@@ -494,17 +490,6 @@
     }
 
     /**
-     * Override all text colors in this layout and replace them by the given text color.
-     *
-     * @param textColor The color to use.
-     *
-     * @hide
-     */
-    public void overrideTextColors(int textColor) {
-        addAction(new OverrideTextColorsAction(textColor));
-    }
-
-    /**
      * Sets an integer tag to the view.
      *
      * @hide
@@ -640,7 +625,7 @@
      *
      * SUBCLASSES MUST BE IMMUTABLE SO CLONE WORKS!!!!!
      */
-    private abstract static class Action implements Parcelable {
+    private abstract static class Action {
         @IdRes
         @UnsupportedAppUsage
         int mViewId;
@@ -652,10 +637,6 @@
         public static final int MERGE_APPEND = 1;
         public static final int MERGE_IGNORE = 2;
 
-        public int describeContents() {
-            return 0;
-        }
-
         public void setHierarchyRootData(HierarchyRootData root) {
             // Do nothing
         }
@@ -689,6 +670,8 @@
         public void visitUris(@NonNull Consumer<Uri> visitor) {
             // Nothing to visit by default.
         }
+
+        public abstract void writeToParcel(Parcel dest, int flags);
     }
 
     /**
@@ -1020,86 +1003,6 @@
         }
     }
 
-    private static class SetRemoteViewsAdapterList extends Action {
-        int mViewTypeCount;
-        ArrayList<RemoteViews> mList;
-
-        public SetRemoteViewsAdapterList(@IdRes int id, ArrayList<RemoteViews> list,
-                int viewTypeCount) {
-            this.mViewId = id;
-            this.mList = list;
-            this.mViewTypeCount = viewTypeCount;
-        }
-
-        public SetRemoteViewsAdapterList(Parcel parcel) {
-            mViewId = parcel.readInt();
-            mViewTypeCount = parcel.readInt();
-            mList = parcel.createTypedArrayList(RemoteViews.CREATOR);
-        }
-
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mViewId);
-            dest.writeInt(mViewTypeCount);
-            dest.writeTypedList(mList, flags);
-        }
-
-        @Override
-        public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            final View target = root.findViewById(mViewId);
-            if (target == null) return;
-
-            // Ensure that we are applying to an AppWidget root
-            if (!(rootParent instanceof AppWidgetHostView)) {
-                Log.e(LOG_TAG, "SetRemoteViewsAdapterIntent action can only be used for " +
-                        "AppWidgets (root id: " + mViewId + ")");
-                return;
-            }
-            // Ensure that we are calling setRemoteAdapter on an AdapterView that supports it
-            if (!(target instanceof AbsListView) && !(target instanceof AdapterViewAnimator)) {
-                Log.e(LOG_TAG, "Cannot setRemoteViewsAdapter on a view which is not " +
-                        "an AbsListView or AdapterViewAnimator (id: " + mViewId + ")");
-                return;
-            }
-
-            if (target instanceof AbsListView) {
-                AbsListView v = (AbsListView) target;
-                Adapter a = v.getAdapter();
-                if (a instanceof RemoteViewsListAdapter && mViewTypeCount <= a.getViewTypeCount()) {
-                    ((RemoteViewsListAdapter) a).setViewsList(mList);
-                } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), mList, mViewTypeCount,
-                            params.colorResources));
-                }
-            } else if (target instanceof AdapterViewAnimator) {
-                AdapterViewAnimator v = (AdapterViewAnimator) target;
-                Adapter a = v.getAdapter();
-                if (a instanceof RemoteViewsListAdapter && mViewTypeCount <= a.getViewTypeCount()) {
-                    ((RemoteViewsListAdapter) a).setViewsList(mList);
-                } else {
-                    v.setAdapter(new RemoteViewsListAdapter(v.getContext(), mList, mViewTypeCount,
-                            params.colorResources));
-                }
-            }
-        }
-
-        @Override
-        public int getActionTag() {
-            return SET_REMOTE_VIEW_ADAPTER_LIST_TAG;
-        }
-
-        @Override
-        public String getUniqueKey() {
-            return (SET_REMOTE_ADAPTER_TAG + "_" + mViewId);
-        }
-
-        @Override
-        public void visitUris(@NonNull Consumer<Uri> visitor) {
-            for (RemoteViews remoteViews : mList) {
-                remoteViews.visitUris(visitor);
-            }
-        }
-    }
-
     /**
      * Cache of {@link ApplicationInfo}s that can be used to ensure that the same
      * {@link ApplicationInfo} instance is used throughout the RemoteViews.
@@ -3491,51 +3394,6 @@
         }
     }
 
-    /**
-     * Helper action to override all textViewColors
-     */
-    private static class OverrideTextColorsAction extends Action {
-        private final int mTextColor;
-
-        public OverrideTextColorsAction(int textColor) {
-            this.mTextColor = textColor;
-        }
-
-        public OverrideTextColorsAction(Parcel parcel) {
-            mTextColor = parcel.readInt();
-        }
-
-        public void writeToParcel(Parcel dest, int flags) {
-            dest.writeInt(mTextColor);
-        }
-
-        @Override
-        public void apply(View root, ViewGroup rootParent, ActionApplyParams params) {
-            // Let's traverse the viewtree and override all textColors!
-            Stack<View> viewsToProcess = new Stack<>();
-            viewsToProcess.add(root);
-            while (!viewsToProcess.isEmpty()) {
-                View v = viewsToProcess.pop();
-                if (v instanceof TextView) {
-                    TextView textView = (TextView) v;
-                    textView.setText(ContrastColorUtil.clearColorSpans(textView.getText()));
-                    textView.setTextColor(mTextColor);
-                }
-                if (v instanceof ViewGroup) {
-                    ViewGroup viewGroup = (ViewGroup) v;
-                    for (int i = 0; i < viewGroup.getChildCount(); i++) {
-                        viewsToProcess.push(viewGroup.getChildAt(i));
-                    }
-                }
-            }
-        }
-
-        @Override
-        public int getActionTag() {
-            return OVERRIDE_TEXT_COLORS_TAG;
-        }
-    }
-
     private static class SetIntTagAction extends Action {
         @IdRes private final int mViewId;
         @IdRes private final int mKey;
@@ -4156,14 +4014,10 @@
                 return new ViewPaddingAction(parcel);
             case BITMAP_REFLECTION_ACTION_TAG:
                 return new BitmapReflectionAction(parcel);
-            case SET_REMOTE_VIEW_ADAPTER_LIST_TAG:
-                return new SetRemoteViewsAdapterList(parcel);
             case SET_REMOTE_INPUTS_ACTION_TAG:
                 return new SetRemoteInputsAction(parcel);
             case LAYOUT_PARAM_ACTION_TAG:
                 return new LayoutParamAction(parcel);
-            case OVERRIDE_TEXT_COLORS_TAG:
-                return new OverrideTextColorsAction(parcel);
             case SET_RIPPLE_DRAWABLE_COLOR_TAG:
                 return new SetRippleDrawableColor(parcel);
             case SET_INT_TAG_TAG:
@@ -4910,7 +4764,11 @@
     @Deprecated
     public void setRemoteAdapter(@IdRes int viewId, ArrayList<RemoteViews> list,
             int viewTypeCount) {
-        addAction(new SetRemoteViewsAdapterList(viewId, list, viewTypeCount));
+        RemoteCollectionItems.Builder b = new RemoteCollectionItems.Builder();
+        for (int i = 0; i < list.size(); i++) {
+            b.addItem(i, list.get(i));
+        }
+        setRemoteAdapter(viewId, b.setViewTypeCount(viewTypeCount).build());
     }
 
     /**
diff --git a/core/java/android/widget/RemoteViewsListAdapter.java b/core/java/android/widget/RemoteViewsListAdapter.java
deleted file mode 100644
index 46f80f3..0000000
--- a/core/java/android/widget/RemoteViewsListAdapter.java
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * Copyright (C) 2012 The Android Open Source Project
- *
- * Licensed under the Apache License, Version 2.0 (the "License");
- * you may not use this file except in compliance with the License.
- * You may obtain a copy of the License at
- *
- *      http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing, software
- * distributed under the License is distributed on an "AS IS" BASIS,
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
- * See the License for the specific language governing permissions and
- * limitations under the License.
- */
-
-package android.widget;
-
-import android.content.Context;
-import android.view.View;
-import android.view.ViewGroup;
-
-import java.util.ArrayList;
-
-/**
- * @hide
- */
-public class RemoteViewsListAdapter extends BaseAdapter {
-
-    private Context mContext;
-    private ArrayList<RemoteViews> mRemoteViewsList;
-    private ArrayList<Integer> mViewTypes = new ArrayList<Integer>();
-    private int mViewTypeCount;
-    private RemoteViews.ColorResources mColorResources;
-
-    public RemoteViewsListAdapter(Context context, ArrayList<RemoteViews> remoteViews,
-            int viewTypeCount, RemoteViews.ColorResources colorResources) {
-        mContext = context;
-        mRemoteViewsList = remoteViews;
-        mViewTypeCount = viewTypeCount;
-        mColorResources = colorResources;
-        init();
-    }
-
-    public void setViewsList(ArrayList<RemoteViews> remoteViews) {
-        mRemoteViewsList = remoteViews;
-        init();
-        notifyDataSetChanged();
-    }
-
-    private void init() {
-        if (mRemoteViewsList == null) return;
-
-        mViewTypes.clear();
-        for (RemoteViews rv: mRemoteViewsList) {
-            if (!mViewTypes.contains(rv.getLayoutId())) {
-                mViewTypes.add(rv.getLayoutId());
-            }
-        }
-
-        if (mViewTypes.size() > mViewTypeCount || mViewTypeCount < 1) {
-            throw new RuntimeException("Invalid view type count -- view type count must be >= 1" +
-                    "and must be as large as the total number of distinct view types");
-        }
-    }
-
-    @Override
-    public int getCount() {
-        if (mRemoteViewsList != null) {
-            return mRemoteViewsList.size();
-        } else {
-            return 0;
-        }
-    }
-
-    @Override
-    public Object getItem(int position) {
-        return null;
-    }
-
-    @Override
-    public long getItemId(int position) {
-        return position;
-    }
-
-    @Override
-    public View getView(int position, View convertView, ViewGroup parent) {
-        if (position < getCount()) {
-            RemoteViews rv = mRemoteViewsList.get(position);
-            rv.addFlags(RemoteViews.FLAG_WIDGET_IS_COLLECTION_CHILD);
-            View v;
-            if (convertView != null && convertView.getId() == rv.getLayoutId()) {
-                v = convertView;
-                rv.reapply(mContext, v, null /* handler */, null /* size */, mColorResources);
-            } else {
-                v = rv.apply(mContext, parent, null /* handler */, null /* size */,
-                        mColorResources);
-            }
-            return v;
-        } else {
-            return null;
-        }
-    }
-
-    @Override
-    public int getItemViewType(int position) {
-        if (position < getCount()) {
-            int layoutId = mRemoteViewsList.get(position).getLayoutId();
-            return mViewTypes.indexOf(layoutId);
-        } else {
-            return 0;
-        }
-    }
-
-    public int getViewTypeCount() {
-        return mViewTypeCount;
-    }
-
-    @Override
-    public boolean hasStableIds() {
-        return false;
-    }
-}
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
index cb5d1c4..03c546d 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/back/BackAnimationController.java
@@ -386,7 +386,8 @@
 
         // two gestures are waiting to be processed at the moment, skip any further user touches
         if (mCurrentTracker.isFinished() && mQueuedTracker.isFinished()) {
-            Log.d(TAG, "Ignoring MotionEvent because two gestures are already being queued.");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+                    "Ignoring MotionEvent because two gestures are already being queued.");
             return;
         }
 
@@ -420,7 +421,8 @@
         } else if (mQueuedTracker.isInInitialState()) {
             touchTracker = mQueuedTracker;
         } else {
-            Log.w(TAG, "Cannot start tracking new gesture with neither tracker in initial state.");
+            ProtoLog.w(WM_SHELL_BACK_PREVIEW,
+                    "Cannot start tracking new gesture with neither tracker in initial state.");
             return;
         }
         touchTracker.setGestureStartLocation(touchX, touchY, swipeEdge);
@@ -449,7 +451,7 @@
             @NonNull TouchTracker touchTracker) {
         ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Received backNavigationInfo:%s", backNavigationInfo);
         if (backNavigationInfo == null) {
-            Log.e(TAG, "Received BackNavigationInfo is null.");
+            ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Received BackNavigationInfo is null.");
             return;
         }
         final int backType = backNavigationInfo.getType();
@@ -475,7 +477,7 @@
     }
 
     private void injectBackKey() {
-        Log.d(TAG, "injectBackKey");
+        ProtoLog.d(WM_SHELL_BACK_PREVIEW, "injectBackKey");
         sendBackEvent(KeyEvent.ACTION_DOWN);
         sendBackEvent(KeyEvent.ACTION_UP);
     }
@@ -491,7 +493,7 @@
         ev.setDisplayId(mContext.getDisplay().getDisplayId());
         if (!mContext.getSystemService(InputManager.class)
                 .injectInputEvent(ev, InputManager.INJECT_INPUT_EVENT_MODE_ASYNC)) {
-            Log.e(TAG, "Inject input event fail");
+            ProtoLog.e(WM_SHELL_BACK_PREVIEW, "Inject input event fail");
         }
     }
 
@@ -669,7 +671,8 @@
         TouchTracker activeTouchTracker = getActiveTracker();
         if (!mBackGestureStarted || activeTouchTracker == null) {
             // This can happen when an unfinished gesture has been reset in resetTouchTracker
-            Log.d(TAG, "onGestureFinished called while no gesture is started");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+                    "onGestureFinished called while no gesture is started");
             return;
         }
         boolean triggerBack = activeTouchTracker.getTriggerBack();
@@ -687,8 +690,8 @@
             // No focus window found or core are running recents animation, inject back key as
             // legacy behavior, or new back gesture was started while previous has not finished yet
             if (!mQueuedTracker.isInInitialState()) {
-                Log.e(TAG, "mBackNavigationInfo is null AND there is another back animation in "
-                        + "progress");
+                ProtoLog.e(WM_SHELL_BACK_PREVIEW, "mBackNavigationInfo is null AND there is "
+                        + "another back animation in progress");
             }
             mCurrentTracker.reset();
             if (triggerBack) {
@@ -702,7 +705,7 @@
         // Simply trigger and finish back navigation when no animator defined.
         if (!shouldDispatchToAnimator()
                 || mShellBackAnimationRegistry.isAnimationCancelledOrNull(backType)) {
-            Log.d(TAG, "Trigger back without dispatching to animator.");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "Trigger back without dispatching to animator.");
             invokeOrCancelBack(mCurrentTracker);
             mCurrentTracker.reset();
             return;
@@ -748,13 +751,14 @@
         mShellExecutor.removeCallbacks(mAnimationTimeoutRunnable);
         mPostCommitAnimationInProgress = false;
 
-        Log.d(TAG, "BackAnimationController: onBackAnimationFinished()");
+        ProtoLog.d(WM_SHELL_BACK_PREVIEW, "BackAnimationController: onBackAnimationFinished()");
 
         if (mCurrentTracker.isActive() || mCurrentTracker.isFinished()) {
             // Trigger the real back.
             invokeOrCancelBack(mCurrentTracker);
         } else {
-            Log.d(TAG, "mCurrentBackGestureInfo was null when back animation finished");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+                    "mCurrentBackGestureInfo was null when back animation finished");
         }
         resetTouchTracker();
     }
@@ -773,23 +777,25 @@
                 mBackGestureStarted = false;
                 dispatchOnBackCancelled(mActiveCallback);
                 finishBackNavigation(false);
-                Log.d(TAG, "resetTouchTracker -> reset an unfinished gesture");
+                ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+                        "resetTouchTracker -> reset an unfinished gesture");
             } else {
-                Log.d(TAG, "resetTouchTracker -> no queued gesture");
+                ProtoLog.d(WM_SHELL_BACK_PREVIEW, "resetTouchTracker -> no queued gesture");
             }
             return;
         }
 
         if (mCurrentTracker.isFinished() && mCurrentTracker.getTriggerBack()) {
-            Log.d(TAG, "resetTouchTracker -> start queued back navigation AND post commit "
-                    + "animation");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "resetTouchTracker -> start queued back navigation "
+                    + "AND post commit animation");
             injectBackKey();
             finishBackNavigation(true);
             mCurrentTracker.reset();
         } else if (!mCurrentTracker.isFinished()) {
-            Log.d(TAG, "resetTouchTracker -> queued gesture not finished; do nothing");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW,
+                    "resetTouchTracker -> queued gesture not finished; do nothing");
         } else {
-            Log.d(TAG, "resetTouchTracker -> reset queued gesture");
+            ProtoLog.d(WM_SHELL_BACK_PREVIEW, "resetTouchTracker -> reset queued gesture");
             mCurrentTracker.reset();
         }
     }
@@ -821,7 +827,8 @@
                         mShellExecutor.execute(
                                 () -> {
                                     if (mBackNavigationInfo == null) {
-                                        Log.e(TAG, "Lack of navigation info to start animation.");
+                                        ProtoLog.e(WM_SHELL_BACK_PREVIEW,
+                                                "Lack of navigation info to start animation.");
                                         return;
                                     }
                                     final BackAnimationRunner runner =
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
index 8e3376f..f6cab48 100644
--- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
+++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipInputConsumer.java
@@ -139,7 +139,7 @@
         final InputChannel inputChannel = new InputChannel();
         try {
             // TODO(b/113087003): Support Picture-in-picture in multi-display.
-            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+            mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
             mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
         } catch (RemoteException e) {
             ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
@@ -163,7 +163,7 @@
         }
         try {
             // TODO(b/113087003): Support Picture-in-picture in multi-display.
-            mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+            mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
         } catch (RemoteException e) {
             ProtoLog.e(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE,
                     "%s: Failed to destroy input consumer, %s", TAG, e);
diff --git a/packages/SettingsLib/src/com/android/settingslib/Utils.java b/packages/SettingsLib/src/com/android/settingslib/Utils.java
index ce0772f..f074106 100644
--- a/packages/SettingsLib/src/com/android/settingslib/Utils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/Utils.java
@@ -607,6 +607,8 @@
                     userType = UserIconInfo.TYPE_CLONED;
                 } else if (ui.isManagedProfile()) {
                     userType = UserIconInfo.TYPE_WORK;
+                } else if (ui.isPrivateProfile()) {
+                    userType = UserIconInfo.TYPE_PRIVATE;
                 }
             }
         } catch (Exception e) {
diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 572f6ff..1a37e2d 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -977,4 +977,13 @@
     Width in pixels of the Side FPS sensor.
     -->
     <integer name="config_sfpsSensorWidth">200</integer>
+
+    <!--
+    They are service names that, if enabled, will cause the magnification settings button
+    to never hide after timeout.
+    -->
+    <string-array name="services_always_show_magnification_settings" translatable="false">
+        <item>com.android.switchaccess.SwitchAccessService</item>
+        <item>com.google.android.apps.accessibility.voiceaccess.JustSpeakService</item>
+    </string-array>
 </resources>
diff --git a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
index ba0a6d1..b406e72 100644
--- a/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
+++ b/packages/SystemUI/shared/src/com/android/systemui/shared/system/InputConsumerController.java
@@ -139,7 +139,7 @@
         if (mInputEventReceiver == null) {
             final InputChannel inputChannel = new InputChannel();
             try {
-                mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+                mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
                 mWindowManager.createInputConsumer(mToken, mName, DEFAULT_DISPLAY, inputChannel);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to create input consumer", e);
@@ -158,7 +158,7 @@
     public void unregisterInputConsumer() {
         if (mInputEventReceiver != null) {
             try {
-                mWindowManager.destroyInputConsumer(mName, DEFAULT_DISPLAY);
+                mWindowManager.destroyInputConsumer(mToken, DEFAULT_DISPLAY);
             } catch (RemoteException e) {
                 Log.e(TAG, "Failed to destroy input consumer", e);
             }
diff --git a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
index 84f1395..d9d9e37 100644
--- a/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
+++ b/packages/SystemUI/src/com/android/systemui/accessibility/MagnificationModeSwitch.java
@@ -20,12 +20,14 @@
 import static android.provider.Settings.Secure.ACCESSIBILITY_MAGNIFICATION_MODE_WINDOW;
 import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.annotation.NonNull;
 import android.annotation.UiContext;
 import android.content.ComponentCallbacks;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
 import android.content.res.Configuration;
+import android.content.res.Resources;
 import android.graphics.Insets;
 import android.graphics.PixelFormat;
 import android.graphics.Rect;
@@ -49,6 +51,8 @@
 import com.android.systemui.res.R;
 
 import java.util.Collections;
+import java.util.Optional;
+import java.util.Set;
 
 /**
  * Shows/hides a {@link android.widget.ImageView} on the screen and changes the values of
@@ -315,10 +319,46 @@
                     DEFAULT_FADE_OUT_ANIMATION_DELAY_MS,
                     AccessibilityManager.FLAG_CONTENT_ICONS
                             | AccessibilityManager.FLAG_CONTENT_CONTROLS);
+            if (shouldAlwaysShowSettings()) {
+                mUiTimeout = -1;
+            }
         }
         // Refresh the time slot of the fade-out task whenever this method is called.
         stopFadeOutAnimation();
-        mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout);
+        if (mUiTimeout >= 0) {
+            mImageView.postOnAnimationDelayed(mFadeOutAnimationTask, mUiTimeout);
+        }
+    }
+
+    private boolean shouldAlwaysShowSettings() {
+        try {
+            var serviceNamesArray = mContext.getResources().getStringArray(
+                    R.array.services_always_show_magnification_settings);
+            if (serviceNamesArray.length == 0) {
+                return false;
+            }
+            Set serviceNamesSet = Set.of(serviceNamesArray);
+
+            var serviceInfoList = mAccessibilityManager
+                    .getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK);
+            for (var serviceInfo : serviceInfoList) {
+                var serviceName = Optional.ofNullable(serviceInfo)
+                        .map(AccessibilityServiceInfo::getResolveInfo)
+                        .map(resolveInfo -> resolveInfo.serviceInfo)
+                        .map(resolvedServiceInfo -> resolvedServiceInfo.name)
+                        .orElse(null);
+                if (serviceName == null) {
+                    continue;
+                }
+
+                if (serviceNamesSet.contains(serviceName)) {
+                    return true;
+                }
+            }
+        } catch (Resources.NotFoundException nfe) {
+            // No-op. Do not crash for not finding resources.
+        }
+        return false;
     }
 
     private void stopFadeOutAnimation() {
diff --git a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
index 62c5988..755549b 100644
--- a/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
+++ b/packages/SystemUI/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSection.kt
@@ -60,8 +60,7 @@
     private val deviceEntryIconViewId = R.id.device_entry_icon_view
 
     override fun addViews(constraintLayout: ConstraintLayout) {
-        if (
-            !featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON) &&
+        if (!featureFlags.isEnabled(Flags.MIGRATE_LOCK_ICON) &&
                 !featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)
         ) {
             return
@@ -76,7 +75,7 @@
                 DeviceEntryIconView(context, null).apply { id = deviceEntryIconViewId }
             } else {
                 // Flags.MIGRATE_LOCK_ICON
-                LockIconView(context, null).apply { id = deviceEntryIconViewId }
+                LockIconView(context, null).apply { id = R.id.lock_icon_view }
             }
         constraintLayout.addView(view)
     }
@@ -91,7 +90,7 @@
                 )
             }
         } else {
-            constraintLayout.findViewById<LockIconView?>(deviceEntryIconViewId)?.let {
+            constraintLayout.findViewById<LockIconView?>(R.id.lock_icon_view)?.let {
                 lockIconViewController.get().setLockIconView(it)
             }
         }
@@ -133,7 +132,11 @@
     }
 
     override fun removeViews(constraintLayout: ConstraintLayout) {
-        constraintLayout.removeView(deviceEntryIconViewId)
+        if (featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)) {
+            constraintLayout.removeView(deviceEntryIconViewId)
+        } else {
+            constraintLayout.removeView(R.id.lock_icon_view)
+        }
     }
 
     @VisibleForTesting
@@ -148,18 +151,25 @@
                 )
             }
 
+        val iconId =
+            if (featureFlags.isEnabled(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS)) {
+                deviceEntryIconViewId
+            } else {
+                R.id.lock_icon_view
+            }
+
         constraintSet.apply {
-            constrainWidth(deviceEntryIconViewId, sensorRect.right - sensorRect.left)
-            constrainHeight(deviceEntryIconViewId, sensorRect.bottom - sensorRect.top)
+            constrainWidth(iconId, sensorRect.right - sensorRect.left)
+            constrainHeight(iconId, sensorRect.bottom - sensorRect.top)
             connect(
-                deviceEntryIconViewId,
+                iconId,
                 ConstraintSet.TOP,
                 ConstraintSet.PARENT_ID,
                 ConstraintSet.TOP,
                 sensorRect.top
             )
             connect(
-                deviceEntryIconViewId,
+                iconId,
                 ConstraintSet.START,
                 ConstraintSet.PARENT_ID,
                 ConstraintSet.START,
diff --git a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
index 8fd2bd6a..1a88545 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/accessibility/MagnificationModeSwitchTest.java
@@ -49,8 +49,11 @@
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
+import android.accessibilityservice.AccessibilityServiceInfo;
 import android.content.Context;
 import android.content.pm.ActivityInfo;
+import android.content.pm.ResolveInfo;
+import android.content.pm.ServiceInfo;
 import android.graphics.Insets;
 import android.graphics.Rect;
 import android.os.Handler;
@@ -71,8 +74,8 @@
 import androidx.test.filters.SmallTest;
 
 import com.android.internal.graphics.SfVsyncFrameCallbackProvider;
-import com.android.systemui.res.R;
 import com.android.systemui.SysuiTestCase;
+import com.android.systemui.res.R;
 
 import org.junit.After;
 import org.junit.Before;
@@ -186,6 +189,87 @@
     }
 
     @Test
+    public void showMagnificationButton_noA11yServicesRunning_postDelayedAnimationsWithTimeout() {
+        final int a11yTimeout = 12345;
+        when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
+                a11yTimeout);
+        when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+                .thenReturn(List.of());
+
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        verify(mAccessibilityManager).getRecommendedTimeoutMillis(
+                DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS
+                        | AccessibilityManager.FLAG_CONTENT_CONTROLS);
+        verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout));
+    }
+
+    @Test
+    public void showMagnificationButton_voiceAccessRunning_noTimeout() {
+        var serviceInfo = createServiceInfoWithName(
+                "com.google.android.apps.accessibility.voiceaccess.JustSpeakService");
+        when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+                .thenReturn(List.of(serviceInfo));
+
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong());
+    }
+
+    @Test
+    public void showMagnificationButton_switchAccessRunning_noTimeout() {
+        var serviceInfo = createServiceInfoWithName(
+                "com.android.switchaccess.SwitchAccessService");
+        when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+                .thenReturn(List.of(serviceInfo));
+
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong());
+    }
+
+    @Test
+    public void showMagnificationButton_switchAccessAndVoiceAccessBothRunning_noTimeout() {
+        var switchAccessServiceInfo = createServiceInfoWithName(
+                "com.android.switchaccess.SwitchAccessService");
+        var voiceAccessServiceInfo = createServiceInfoWithName(
+                "com.google.android.apps.accessibility.voiceaccess.JustSpeakService");
+        when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+                .thenReturn(List.of(switchAccessServiceInfo, voiceAccessServiceInfo));
+
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        verify(mSpyImageView, never()).postOnAnimationDelayed(any(Runnable.class), anyLong());
+    }
+
+    @Test
+    public void showMagnificationButton_someOtherServiceRunning_postDelayedAnimationsWithTimeout() {
+        final int a11yTimeout = 12345;
+        when(mAccessibilityManager.getRecommendedTimeoutMillis(anyInt(), anyInt())).thenReturn(
+                a11yTimeout);
+        var serviceInfo1 = createServiceInfoWithName("com.test.someService1");
+        var serviceInfo2 = createServiceInfoWithName("com.test.someService2");
+        when(mAccessibilityManager.getEnabledAccessibilityServiceList(anyInt()))
+                .thenReturn(List.of(serviceInfo1, serviceInfo2));
+
+        mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
+
+        verify(mAccessibilityManager).getRecommendedTimeoutMillis(
+                DEFAULT_FADE_OUT_ANIMATION_DELAY_MS, AccessibilityManager.FLAG_CONTENT_ICONS
+                        | AccessibilityManager.FLAG_CONTENT_CONTROLS);
+        verify(mSpyImageView).postOnAnimationDelayed(any(Runnable.class), eq((long) a11yTimeout));
+    }
+
+    private AccessibilityServiceInfo createServiceInfoWithName(String name) {
+        var resolveInfo = new ResolveInfo();
+        resolveInfo.serviceInfo = new ServiceInfo();
+        resolveInfo.serviceInfo.name = name;
+        var serviceInfo = new AccessibilityServiceInfo();
+        serviceInfo.setResolveInfo(resolveInfo);
+        return serviceInfo;
+    }
+
+    @Test
     public void showMagnificationButton_windowModeAndFadingOut_verifyAnimationEndAction() {
         mMagnificationModeSwitch.showButton(ACCESSIBILITY_MAGNIFICATION_MODE_FULLSCREEN);
         executeFadeOutAnimation();
diff --git a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
index 5f22c7d..c7f7c3c 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
+++ b/packages/SystemUI/tests/src/com/android/systemui/keyguard/ui/view/layout/sections/DefaultDeviceEntryIconSectionTest.kt
@@ -106,7 +106,20 @@
     }
 
     @Test
-    fun applyConstraints() {
+    fun applyConstraints_udfps_refactor_off() {
+        featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, false)
+        val cs = ConstraintSet()
+        underTest.applyConstraints(cs)
+
+        val constraint = cs.getConstraint(R.id.lock_icon_view)
+
+        assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
+        assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID)
+    }
+
+    @Test
+    fun applyConstraints_udfps_refactor_on() {
+        featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
         val cs = ConstraintSet()
         underTest.applyConstraints(cs)
 
@@ -117,7 +130,24 @@
     }
 
     @Test
-    fun testCenterIcon() {
+    fun testCenterIcon_udfps_refactor_off() {
+        featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, false)
+        val cs = ConstraintSet()
+        underTest.centerIcon(Point(5, 6), 1F, cs)
+
+        val constraint = cs.getConstraint(R.id.lock_icon_view)
+
+        assertThat(constraint.layout.mWidth).isEqualTo(2)
+        assertThat(constraint.layout.mHeight).isEqualTo(2)
+        assertThat(constraint.layout.topToTop).isEqualTo(ConstraintSet.PARENT_ID)
+        assertThat(constraint.layout.startToStart).isEqualTo(ConstraintSet.PARENT_ID)
+        assertThat(constraint.layout.topMargin).isEqualTo(5)
+        assertThat(constraint.layout.startMargin).isEqualTo(4)
+    }
+
+    @Test
+    fun testCenterIcon_udfps_refactor_on() {
+        featureFlags.set(Flags.REFACTOR_UDFPS_KEYGUARD_VIEWS, true)
         val cs = ConstraintSet()
         underTest.centerIcon(Point(5, 6), 1F, cs)
 
diff --git a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
index 9f4528b..b2ff3c3 100644
--- a/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
+++ b/services/contentcapture/java/com/android/server/contentcapture/ContentCaptureManagerService.java
@@ -22,9 +22,12 @@
 import static android.view.contentcapture.ContentCaptureHelper.toList;
 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS;
 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE;
 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG;
 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD;
 import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG;
+import static android.view.contentcapture.ContentCaptureManager.DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_FALSE;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_OK;
 import static android.view.contentcapture.ContentCaptureManager.RESULT_CODE_SECURITY_EXCEPTION;
@@ -227,6 +230,9 @@
     @GuardedBy("mLock")
     long mDevCfgContentProtectionAllowlistTimeoutMs;
 
+    @GuardedBy("mLock")
+    long mDevCfgContentProtectionAutoDisconnectTimeoutMs;
+
     private final Executor mDataShareExecutor = Executors.newCachedThreadPool();
     private final Handler mHandler = new Handler(Looper.getMainLooper());
 
@@ -435,14 +441,15 @@
                 case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_IDLE_UNBIND_TIMEOUT:
                 case ContentCaptureManager
                         .DEVICE_CONFIG_PROPERTY_DISABLE_FLUSH_FOR_VIEW_TREE_APPEARING:
-                case ContentCaptureManager
-                        .DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
-                case ContentCaptureManager.DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
+                    // Content protection below
+                case DEVICE_CONFIG_PROPERTY_ENABLE_CONTENT_PROTECTION_RECEIVER:
+                case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_REQUIRED_GROUPS_CONFIG:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_CONFIG:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_OPTIONAL_GROUPS_THRESHOLD:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_DELAY_MS:
                 case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS:
+                case DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT:
                     setFineTuneParamsFromDeviceConfig();
                     return;
                 default:
@@ -502,8 +509,7 @@
             mDevCfgContentProtectionBufferSize =
                     DeviceConfig.getInt(
                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
-                            ContentCaptureManager
-                                    .DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
+                            DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_BUFFER_SIZE,
                             ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_BUFFER_SIZE);
             contentProtectionRequiredGroupsConfig =
                     DeviceConfig.getString(
@@ -533,7 +539,12 @@
                             DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
                             DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS,
                             ContentCaptureManager.DEFAULT_CONTENT_PROTECTION_ALLOWLIST_TIMEOUT_MS);
-
+            mDevCfgContentProtectionAutoDisconnectTimeoutMs =
+                    DeviceConfig.getLong(
+                            DeviceConfig.NAMESPACE_CONTENT_CAPTURE,
+                            DEVICE_CONFIG_PROPERTY_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT,
+                            ContentCaptureManager
+                                    .DEFAULT_CONTENT_PROTECTION_AUTO_DISCONNECT_TIMEOUT_MS);
             contentProtectionAllowlistManagerOld = mContentProtectionAllowlistManager;
 
             if (verbose) {
@@ -565,7 +576,9 @@
                                 + ", contentProtectionAllowlistDelayMs="
                                 + contentProtectionAllowlistDelayMs
                                 + ", contentProtectionAllowlistTimeoutMs="
-                                + contentProtectionAllowlistTimeoutMs);
+                                + contentProtectionAllowlistTimeoutMs
+                                + ", contentProtectionAutoDisconnectTimeoutMs="
+                                + mDevCfgContentProtectionAutoDisconnectTimeoutMs);
             }
         }
 
@@ -893,6 +906,9 @@
         pw.print(prefix2);
         pw.print("contentProtectionAllowlistTimeoutMs: ");
         pw.println(mDevCfgContentProtectionAllowlistTimeoutMs);
+        pw.print(prefix2);
+        pw.print("contentProtectionAutoDisconnectTimeoutMs: ");
+        pw.println(mDevCfgContentProtectionAutoDisconnectTimeoutMs);
         pw.print(prefix);
         pw.println("Global Options:");
         mGlobalContentCaptureOptions.dump(prefix2, pw);
@@ -962,12 +978,14 @@
     @Nullable
     public RemoteContentProtectionService createRemoteContentProtectionService() {
         ComponentName componentName;
+        long autoDisconnectTimeoutMs;
         synchronized (mLock) {
             if (!mDevCfgEnableContentProtectionReceiver
                     || mContentProtectionServiceComponentName == null) {
                 return null;
             }
             componentName = mContentProtectionServiceComponentName;
+            autoDisconnectTimeoutMs = mDevCfgContentProtectionAutoDisconnectTimeoutMs;
         }
 
         // Check permissions by trying to construct {@link ContentCaptureServiceInfo}
@@ -978,19 +996,20 @@
             return null;
         }
 
-        return createRemoteContentProtectionService(componentName);
+        return createRemoteContentProtectionService(componentName, autoDisconnectTimeoutMs);
     }
 
     /** @hide */
     @VisibleForTesting(visibility = VisibleForTesting.Visibility.PRIVATE)
     @NonNull
     protected RemoteContentProtectionService createRemoteContentProtectionService(
-            @NonNull ComponentName componentName) {
+            @NonNull ComponentName componentName, long autoDisconnectTimeoutMs) {
         return new RemoteContentProtectionService(
                 getContext(),
                 componentName,
                 UserHandle.getCallingUserId(),
-                isBindInstantServiceAllowed());
+                isBindInstantServiceAllowed(),
+                autoDisconnectTimeoutMs);
     }
 
     /** @hide */
diff --git a/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java b/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
index dd5545d..bc11fc3 100644
--- a/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
+++ b/services/contentcapture/java/com/android/server/contentprotection/RemoteContentProtectionService.java
@@ -22,14 +22,13 @@
 import android.content.Intent;
 import android.content.pm.ParceledListSlice;
 import android.service.contentcapture.ContentCaptureService;
+import android.service.contentcapture.IContentProtectionAllowlistCallback;
 import android.service.contentcapture.IContentProtectionService;
 import android.util.Slog;
 import android.view.contentcapture.ContentCaptureEvent;
 
 import com.android.internal.infra.ServiceConnector;
 
-import java.time.Duration;
-
 /**
  * Connector for the remote content protection service.
  *
@@ -40,15 +39,16 @@
 
     private static final String TAG = RemoteContentProtectionService.class.getSimpleName();
 
-    private static final Duration AUTO_DISCONNECT_TIMEOUT = Duration.ofSeconds(3);
-
     @NonNull private final ComponentName mComponentName;
 
+    private final long mAutoDisconnectTimeoutMs;
+
     public RemoteContentProtectionService(
             @NonNull Context context,
             @NonNull ComponentName componentName,
             int userId,
-            boolean bindAllowInstant) {
+            boolean bindAllowInstant,
+            long autoDisconnectTimeoutMs) {
         super(
                 context,
                 new Intent(ContentCaptureService.PROTECTION_SERVICE_INTERFACE)
@@ -57,11 +57,12 @@
                 userId,
                 IContentProtectionService.Stub::asInterface);
         mComponentName = componentName;
+        mAutoDisconnectTimeoutMs = autoDisconnectTimeoutMs;
     }
 
     @Override // from ServiceConnector.Impl
     protected long getAutoDisconnectTimeoutMs() {
-        return AUTO_DISCONNECT_TIMEOUT.toMillis();
+        return mAutoDisconnectTimeoutMs;
     }
 
     @Override // from ServiceConnector.Impl
@@ -75,7 +76,13 @@
                         + (isConnected ? "connected" : "disconnected"));
     }
 
+    /** Calls the remote service when login is detected. */
     public void onLoginDetected(@NonNull ParceledListSlice<ContentCaptureEvent> events) {
         run(service -> service.onLoginDetected(events));
     }
+
+    /** Calls the remote service with a request to update allowlist. */
+    public void onUpdateAllowlistRequest(@NonNull IContentProtectionAllowlistCallback callback) {
+        run(service -> service.onUpdateAllowlistRequest(callback.asBinder()));
+    }
 }
diff --git a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
index cb4cf9d..4579cc1 100644
--- a/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
+++ b/services/core/java/com/android/server/wm/BackgroundActivityStartController.java
@@ -422,8 +422,9 @@
         }
 
         BalVerdict resultForCaller = checkBackgroundActivityStartAllowedByCaller(state);
-        BalVerdict resultForRealCaller = callingUid == realCallingUid
+        BalVerdict resultForRealCaller = callingUid == realCallingUid && resultForCaller.allows()
                 ? resultForCaller // no need to calculate again
+                // otherwise we might need to recalculate because the logic is not the same
                 : checkBackgroundActivityStartAllowedBySender(state, checkedOptions);
 
         if (resultForCaller.allows()
diff --git a/services/core/java/com/android/server/wm/InputConsumerImpl.java b/services/core/java/com/android/server/wm/InputConsumerImpl.java
index 1fa7d2a..34d7651 100644
--- a/services/core/java/com/android/server/wm/InputConsumerImpl.java
+++ b/services/core/java/com/android/server/wm/InputConsumerImpl.java
@@ -160,7 +160,7 @@
             if (dc == null) {
                 return;
             }
-            dc.getInputMonitor().destroyInputConsumer(mName);
+            dc.getInputMonitor().destroyInputConsumer(mToken);
             unlinkFromDeathRecipient();
         }
     }
diff --git a/services/core/java/com/android/server/wm/InputMonitor.java b/services/core/java/com/android/server/wm/InputMonitor.java
index 5c0bc28..61fea4d 100644
--- a/services/core/java/com/android/server/wm/InputMonitor.java
+++ b/services/core/java/com/android/server/wm/InputMonitor.java
@@ -73,6 +73,7 @@
 
 import java.io.PrintWriter;
 import java.lang.ref.WeakReference;
+import java.util.ArrayList;
 import java.util.Set;
 import java.util.function.Consumer;
 
@@ -104,7 +105,7 @@
      * The set of input consumer added to the window manager by name, which consumes input events
      * for the windows below it.
      */
-    private final ArrayMap<String, InputConsumerImpl> mInputConsumers = new ArrayMap();
+    private final ArrayList<InputConsumerImpl> mInputConsumers = new ArrayList<>();
 
     /**
      * Set when recents (overview) is active as part of a shell transition. While set, any focus
@@ -164,31 +165,35 @@
         mDisplayRemoved = true;
     }
 
-    private void addInputConsumer(String name, InputConsumerImpl consumer) {
-        mInputConsumers.put(name, consumer);
+    private void addInputConsumer(InputConsumerImpl consumer) {
+        mInputConsumers.add(consumer);
         consumer.linkToDeathRecipient();
         consumer.layout(mInputTransaction, mDisplayWidth, mDisplayHeight);
         updateInputWindowsLw(true /* force */);
     }
 
-    boolean destroyInputConsumer(String name) {
-        if (disposeInputConsumer(mInputConsumers.remove(name))) {
-            updateInputWindowsLw(true /* force */);
-            return true;
-        }
-        return false;
-    }
-
-    private boolean disposeInputConsumer(InputConsumerImpl consumer) {
-        if (consumer != null) {
-            consumer.disposeChannelsLw(mInputTransaction);
-            return true;
+    boolean destroyInputConsumer(IBinder token) {
+        for (int i = 0; i < mInputConsumers.size(); i++) {
+            final InputConsumerImpl consumer = mInputConsumers.get(i);
+            if (consumer != null && consumer.mToken == token) {
+                consumer.disposeChannelsLw(mInputTransaction);
+                mInputConsumers.remove(consumer);
+                updateInputWindowsLw(true /* force */);
+                return true;
+            }
         }
         return false;
     }
 
     InputConsumerImpl getInputConsumer(String name) {
-        return mInputConsumers.get(name);
+        // Search in reverse order as the latest input consumer with the name takes precedence
+        for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
+            final InputConsumerImpl consumer = mInputConsumers.get(i);
+            if (consumer.mName.equals(name)) {
+                return consumer;
+            }
+        }
+        return null;
     }
 
     void layoutInputConsumers(int dw, int dh) {
@@ -200,7 +205,7 @@
         try {
             Trace.traceBegin(TRACE_TAG_WINDOW_MANAGER, "layoutInputConsumer");
             for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
-                mInputConsumers.valueAt(i).layout(mInputTransaction, dw, dh);
+                mInputConsumers.get(i).layout(mInputTransaction, dw, dh);
             }
         } finally {
             Trace.traceEnd(TRACE_TAG_WINDOW_MANAGER);
@@ -212,15 +217,16 @@
     // (set so by this function) and must meet some condition for visibility on each update.
     void resetInputConsumers(SurfaceControl.Transaction t) {
         for (int i = mInputConsumers.size() - 1; i >= 0; i--) {
-            mInputConsumers.valueAt(i).hide(t);
+            mInputConsumers.get(i).hide(t);
         }
     }
 
     void createInputConsumer(IBinder token, String name, InputChannel inputChannel, int clientPid,
             UserHandle clientUser) {
-        if (mInputConsumers.containsKey(name)) {
+        final InputConsumerImpl existingConsumer = getInputConsumer(name);
+        if (existingConsumer != null && existingConsumer.mClientUser.equals(clientUser)) {
             throw new IllegalStateException("Existing input consumer found with name: " + name
-                    + ", display: " + mDisplayId);
+                    + ", display: " + mDisplayId + ", user: " + clientUser);
         }
 
         final InputConsumerImpl consumer = new InputConsumerImpl(mService, token, name,
@@ -239,7 +245,7 @@
                 throw new IllegalArgumentException("Illegal input consumer : " + name
                         + ", display: " + mDisplayId);
         }
-        addInputConsumer(name, consumer);
+        addInputConsumer(consumer);
     }
 
     @VisibleForTesting
@@ -541,11 +547,11 @@
     }
 
     void dump(PrintWriter pw, String prefix) {
-        final Set<String> inputConsumerKeys = mInputConsumers.keySet();
-        if (!inputConsumerKeys.isEmpty()) {
+        if (!mInputConsumers.isEmpty()) {
             pw.println(prefix + "InputConsumers:");
-            for (String key : inputConsumerKeys) {
-                mInputConsumers.get(key).dump(pw, key, prefix);
+            for (int i = 0; i < mInputConsumers.size(); i++) {
+                final InputConsumerImpl consumer = mInputConsumers.get(i);
+                consumer.dump(pw, consumer.mName, prefix);
             }
         }
     }
diff --git a/services/core/java/com/android/server/wm/RecentsAnimationController.java b/services/core/java/com/android/server/wm/RecentsAnimationController.java
index 82d4b90..ef25726 100644
--- a/services/core/java/com/android/server/wm/RecentsAnimationController.java
+++ b/services/core/java/com/android/server/wm/RecentsAnimationController.java
@@ -1021,7 +1021,11 @@
         synchronized (mService.getWindowManagerLock()) {
             // Clear associated input consumers on runner death
             final InputMonitor inputMonitor = mDisplayContent.getInputMonitor();
-            inputMonitor.destroyInputConsumer(INPUT_CONSUMER_RECENTS_ANIMATION);
+            final InputConsumerImpl consumer = inputMonitor.getInputConsumer(
+                    INPUT_CONSUMER_RECENTS_ANIMATION);
+            if (consumer != null) {
+                inputMonitor.destroyInputConsumer(consumer.mToken);
+            }
         }
     }
 
diff --git a/services/core/java/com/android/server/wm/WindowManagerService.java b/services/core/java/com/android/server/wm/WindowManagerService.java
index a90e08e..9fb7e8d 100644
--- a/services/core/java/com/android/server/wm/WindowManagerService.java
+++ b/services/core/java/com/android/server/wm/WindowManagerService.java
@@ -6553,7 +6553,7 @@
     }
 
     @Override
-    public boolean destroyInputConsumer(String name, int displayId) {
+    public boolean destroyInputConsumer(IBinder token, int displayId) {
         if (!mAtmService.isCallerRecents(Binder.getCallingUid())
                 && mContext.checkCallingOrSelfPermission(INPUT_CONSUMER) != PERMISSION_GRANTED) {
             throw new SecurityException("destroyInputConsumer requires INPUT_CONSUMER permission");
@@ -6562,7 +6562,7 @@
         synchronized (mGlobalLock) {
             DisplayContent display = mRoot.getDisplayContent(displayId);
             if (display != null) {
-                return display.getInputMonitor().destroyInputConsumer(name);
+                return display.getInputMonitor().destroyInputConsumer(token);
             }
             return false;
         }
diff --git a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
index 9a5241e..6d13d87 100644
--- a/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentcapture/ContentCaptureManagerServiceTest.java
@@ -662,7 +662,7 @@
 
         @Override
         protected RemoteContentProtectionService createRemoteContentProtectionService(
-                @NonNull ComponentName componentName) {
+                @NonNull ComponentName componentName, long autoDisconnectTimeoutMs) {
             mRemoteContentProtectionServicesCreated++;
             return mMockRemoteContentProtectionService;
         }
diff --git a/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java b/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
index 9135ef3..6a7e286 100644
--- a/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
+++ b/services/tests/servicestests/src/com/android/server/contentprotection/RemoteContentProtectionServiceTest.java
@@ -21,12 +21,16 @@
 import static org.junit.Assert.fail;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.verifyZeroInteractions;
+import static org.mockito.Mockito.when;
 
 import android.annotation.NonNull;
 import android.content.ComponentName;
 import android.content.Context;
 import android.content.pm.ParceledListSlice;
+import android.os.Binder;
+import android.os.IBinder;
 import android.os.UserHandle;
+import android.service.contentcapture.IContentProtectionAllowlistCallback;
 import android.service.contentcapture.IContentProtectionService;
 import android.view.contentcapture.ContentCaptureEvent;
 
@@ -57,21 +61,27 @@
 @SmallTest
 public class RemoteContentProtectionServiceTest {
 
-    private final Context mContext = ApplicationProvider.getApplicationContext();
+    private static final long AUTO_DISCONNECT_TIMEOUT_MS = 12345L;
+
+    private static final IBinder BINDER = new Binder();
+
+    private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
 
     @Rule public final MockitoRule mMockitoRule = MockitoJUnit.rule();
 
     @Mock private IContentProtectionService mMockContentProtectionService;
 
+    @Mock private IContentProtectionAllowlistCallback mMockContentProtectionAllowlistCallback;
+
     private RemoteContentProtectionService mRemoteContentProtectionService;
 
     private int mConnectCallCount = 0;
 
     @Before
     public void setup() {
-        ComponentName componentName = new ComponentName(mContext.getPackageName(), "TestClass");
+        ComponentName componentName = new ComponentName(CONTEXT.getPackageName(), "TestClass");
         mRemoteContentProtectionService =
-                new TestRemoteContentProtectionService(mContext, componentName);
+                new TestRemoteContentProtectionService(CONTEXT, componentName);
     }
 
     @Test
@@ -84,7 +94,7 @@
     public void getAutoDisconnectTimeoutMs() {
         long actual = mRemoteContentProtectionService.getAutoDisconnectTimeoutMs();
 
-        assertThat(actual).isEqualTo(3000L);
+        assertThat(actual).isEqualTo(AUTO_DISCONNECT_TIMEOUT_MS);
     }
 
     @Test
@@ -99,10 +109,43 @@
         verify(mMockContentProtectionService).onLoginDetected(events);
     }
 
+    @Test
+    public void onUpdateAllowlistRequest() throws Exception {
+        when(mMockContentProtectionAllowlistCallback.asBinder()).thenReturn(BINDER);
+
+        mRemoteContentProtectionService.onUpdateAllowlistRequest(
+                mMockContentProtectionAllowlistCallback);
+
+        verify(mMockContentProtectionService).onUpdateAllowlistRequest(BINDER);
+    }
+
+    @Test
+    public void onServiceConnectionStatusChanged_connected_noSideEffects() {
+        mRemoteContentProtectionService.onServiceConnectionStatusChanged(
+                mMockContentProtectionService, /* isConnected= */ true);
+
+        verifyZeroInteractions(mMockContentProtectionService);
+        assertThat(mConnectCallCount).isEqualTo(0);
+    }
+
+    @Test
+    public void onServiceConnectionStatusChanged_disconnected_noSideEffects() {
+        mRemoteContentProtectionService.onServiceConnectionStatusChanged(
+                mMockContentProtectionService, /* isConnected= */ false);
+
+        verifyZeroInteractions(mMockContentProtectionService);
+        assertThat(mConnectCallCount).isEqualTo(0);
+    }
+
     private final class TestRemoteContentProtectionService extends RemoteContentProtectionService {
 
         TestRemoteContentProtectionService(Context context, ComponentName componentName) {
-            super(context, componentName, UserHandle.myUserId(), /* bindAllowInstant= */ false);
+            super(
+                    context,
+                    componentName,
+                    UserHandle.myUserId(),
+                    /* bindAllowInstant= */ false,
+                    AUTO_DISCONNECT_TIMEOUT_MS);
         }
 
         @Override // from ServiceConnector