Merge "Add java_aconfig_library for Media BeTo host tests" into main
diff --git a/core/api/current.txt b/core/api/current.txt
index 7d5079a..15c054f 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -40512,7 +40512,6 @@
 
   public final class ZenPolicy implements android.os.Parcelable {
     method public int describeContents();
-    method @FlaggedApi("android.app.modes_api") public int getAllowedChannels();
     method public int getPriorityCallSenders();
     method public int getPriorityCategoryAlarms();
     method public int getPriorityCategoryCalls();
@@ -40523,6 +40522,7 @@
     method public int getPriorityCategoryReminders();
     method public int getPriorityCategoryRepeatCallers();
     method public int getPriorityCategorySystem();
+    method @FlaggedApi("android.app.modes_api") public int getPriorityChannels();
     method public int getPriorityConversationSenders();
     method public int getPriorityMessageSenders();
     method public int getVisualEffectAmbient();
@@ -40533,9 +40533,6 @@
     method public int getVisualEffectPeek();
     method public int getVisualEffectStatusBar();
     method public void writeToParcel(android.os.Parcel, int);
-    field @FlaggedApi("android.app.modes_api") public static final int CHANNEL_TYPE_NONE = 2; // 0x2
-    field @FlaggedApi("android.app.modes_api") public static final int CHANNEL_TYPE_PRIORITY = 1; // 0x1
-    field @FlaggedApi("android.app.modes_api") public static final int CHANNEL_TYPE_UNSET = 0; // 0x0
     field public static final int CONVERSATION_SENDERS_ANYONE = 1; // 0x1
     field public static final int CONVERSATION_SENDERS_IMPORTANT = 2; // 0x2
     field public static final int CONVERSATION_SENDERS_NONE = 3; // 0x3
@@ -40556,11 +40553,11 @@
     method @NonNull public android.service.notification.ZenPolicy.Builder allowAlarms(boolean);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowAllSounds();
     method @NonNull public android.service.notification.ZenPolicy.Builder allowCalls(int);
-    method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy.Builder allowChannels(int);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowConversations(int);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowEvents(boolean);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowMedia(boolean);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowMessages(int);
+    method @FlaggedApi("android.app.modes_api") @NonNull public android.service.notification.ZenPolicy.Builder allowPriorityChannels(boolean);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowReminders(boolean);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowRepeatCallers(boolean);
     method @NonNull public android.service.notification.ZenPolicy.Builder allowSystem(boolean);
@@ -41656,6 +41653,7 @@
     method public void sendEvent(@NonNull String, @NonNull android.os.Bundle);
     method public void setActive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
     method public void setInactive(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
+    method @FlaggedApi("com.android.server.telecom.flags.set_mute_state") public void setMuteState(boolean, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
     method public void startCallStreaming(@NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver<java.lang.Void,android.telecom.CallException>);
   }
 
diff --git a/core/java/android/content/AttributionSource.java b/core/java/android/content/AttributionSource.java
index a1357c9..bde562d 100644
--- a/core/java/android/content/AttributionSource.java
+++ b/core/java/android/content/AttributionSource.java
@@ -231,7 +231,7 @@
     }
 
     /** @hide */
-    public AttributionSource withToken(@NonNull Binder token) {
+    public AttributionSource withToken(@NonNull IBinder token) {
         return new AttributionSource(getUid(), getPid(), getPackageName(), getAttributionTag(),
                 token, mAttributionSourceState.renouncedPermissions, getDeviceId(), getNext());
     }
diff --git a/core/java/android/os/storage/StorageManagerInternal.java b/core/java/android/os/storage/StorageManagerInternal.java
index 8961846..6995ea8 100644
--- a/core/java/android/os/storage/StorageManagerInternal.java
+++ b/core/java/android/os/storage/StorageManagerInternal.java
@@ -193,7 +193,7 @@
      * @see com.android.server.pm.Installer#createFsveritySetupAuthToken()
      */
     public abstract IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken(
-            ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId) throws IOException;
+            ParcelFileDescriptor authFd, int uid) throws IOException;
 
     /**
      * A proxy call to the corresponding method in Installer.
diff --git a/core/java/android/permission/IPermissionManager.aidl b/core/java/android/permission/IPermissionManager.aidl
index 7cecfdc..471f95b 100644
--- a/core/java/android/permission/IPermissionManager.aidl
+++ b/core/java/android/permission/IPermissionManager.aidl
@@ -92,7 +92,7 @@
 
     boolean isAutoRevokeExempted(String packageName, int userId);
 
-    void registerAttributionSource(in AttributionSourceState source);
+    IBinder registerAttributionSource(in AttributionSourceState source);
 
     boolean isRegisteredAttributionSource(in AttributionSourceState source);
 
diff --git a/core/java/android/permission/PermissionManager.java b/core/java/android/permission/PermissionManager.java
index 91adc37..4af6e3a 100644
--- a/core/java/android/permission/PermissionManager.java
+++ b/core/java/android/permission/PermissionManager.java
@@ -23,6 +23,7 @@
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_FIXED;
 import static android.content.pm.PackageManager.FLAG_PERMISSION_USER_SET;
 import static android.os.Build.VERSION_CODES.S;
+import static android.permission.flags.Flags.serverSideAttributionRegistration;
 
 import android.Manifest;
 import android.annotation.CheckResult;
@@ -59,6 +60,7 @@
 import android.os.Binder;
 import android.os.Build;
 import android.os.Handler;
+import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
 import android.os.Process;
@@ -1464,13 +1466,19 @@
         // We use a shared static token for sources that are not registered since the token's
         // only used for process death detection. If we are about to use the source for security
         // enforcement we need to replace the binder with a unique one.
-        final AttributionSource registeredSource = source.withToken(new Binder());
         try {
-            mPermissionManager.registerAttributionSource(registeredSource.asState());
+            if (serverSideAttributionRegistration()) {
+                IBinder newToken = mPermissionManager.registerAttributionSource(source.asState());
+                return source.withToken(newToken);
+            } else {
+                AttributionSource registeredSource = source.withToken(new Binder());
+                mPermissionManager.registerAttributionSource(registeredSource.asState());
+                return registeredSource;
+            }
         } catch (RemoteException e) {
             e.rethrowFromSystemServer();
         }
-        return registeredSource;
+        return source;
     }
 
     /**
diff --git a/core/java/android/permission/flags.aconfig b/core/java/android/permission/flags.aconfig
index 60143cc..bced217 100644
--- a/core/java/android/permission/flags.aconfig
+++ b/core/java/android/permission/flags.aconfig
@@ -73,6 +73,13 @@
 }
 
 flag {
+    name: "server_side_attribution_registration"
+    namespace: "permissions"
+    description: "controls whether the binder representing an AttributionSource is created in the system server, or client process"
+    bug: "310953959"
+}
+
+flag {
     name: "wallet_role_enabled"
     namespace: "wallet_integration"
     description: "This flag is used to enabled the Wallet Role for all users on the device"
diff --git a/core/java/android/service/notification/ZenModeConfig.java b/core/java/android/service/notification/ZenModeConfig.java
index 54248be..d4d602d 100644
--- a/core/java/android/service/notification/ZenModeConfig.java
+++ b/core/java/android/service/notification/ZenModeConfig.java
@@ -205,7 +205,7 @@
     private static final String ALLOW_ATT_SCREEN_ON = "visualScreenOn";
     private static final String ALLOW_ATT_CONV = "convos";
     private static final String ALLOW_ATT_CONV_FROM = "convosFrom";
-    private static final String ALLOW_ATT_CHANNELS = "channels";
+    private static final String ALLOW_ATT_CHANNELS = "priorityChannels";
     private static final String USER_MODIFIED_FIELDS = "policyUserModifiedFields";
     private static final String DISALLOW_TAG = "disallow";
     private static final String DISALLOW_ATT_VISUAL_EFFECTS = "visualEffects";
@@ -919,9 +919,9 @@
         final int events = safeInt(parser, ALLOW_ATT_EVENTS, ZenPolicy.STATE_UNSET);
         final int reminders = safeInt(parser, ALLOW_ATT_REMINDERS, ZenPolicy.STATE_UNSET);
         if (Flags.modesApi()) {
-            final int channels = safeInt(parser, ALLOW_ATT_CHANNELS, ZenPolicy.CHANNEL_TYPE_UNSET);
-            if (channels != ZenPolicy.CHANNEL_TYPE_UNSET) {
-                builder.allowChannels(channels);
+            final int channels = safeInt(parser, ALLOW_ATT_CHANNELS, ZenPolicy.STATE_UNSET);
+            if (channels != ZenPolicy.STATE_UNSET) {
+                builder.allowPriorityChannels(channels == ZenPolicy.STATE_ALLOW);
                 policySet = true;
             }
             builder.setUserModifiedFields(safeInt(parser, USER_MODIFIED_FIELDS, 0));
@@ -1036,7 +1036,7 @@
                 out);
 
         if (Flags.modesApi()) {
-            writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getAllowedChannels(), out);
+            writeZenPolicyState(ALLOW_ATT_CHANNELS, policy.getPriorityChannels(), out);
             out.attributeInt(null, USER_MODIFIED_FIELDS, policy.getUserModifiedFields());
         }
     }
@@ -1053,7 +1053,7 @@
                 out.attributeInt(null, attr, val);
             }
         } else if (Flags.modesApi() && Objects.equals(attr, ALLOW_ATT_CHANNELS)) {
-            if (val != ZenPolicy.CHANNEL_TYPE_UNSET) {
+            if (val != ZenPolicy.STATE_UNSET) {
                 out.attributeInt(null, attr, val);
             }
         } else {
@@ -1238,8 +1238,7 @@
         }
 
         if (Flags.modesApi()) {
-            builder.allowChannels(allowPriorityChannels ? ZenPolicy.CHANNEL_TYPE_PRIORITY
-                    : ZenPolicy.CHANNEL_TYPE_NONE);
+            builder.allowPriorityChannels(allowPriorityChannels);
         }
         return builder.build();
     }
@@ -1369,7 +1368,7 @@
         int state = defaultPolicy.state;
         if (Flags.modesApi()) {
             state = Policy.policyState(defaultPolicy.hasPriorityChannels(),
-                    getAllowPriorityChannelsWithDefault(zenPolicy.getAllowedChannels(),
+                    ZenPolicy.stateToBoolean(zenPolicy.getPriorityChannels(),
                             DEFAULT_ALLOW_PRIORITY_CHANNELS));
         }
 
@@ -1412,24 +1411,6 @@
     }
 
     /**
-     * Gets whether priority channels are permitted by this channel type, with the specified
-     * default if the value is unset. This effectively converts the channel enum to a boolean,
-     * where "true" indicates priority channels are allowed to break through and "false" means
-     * they are not.
-     */
-    public static boolean getAllowPriorityChannelsWithDefault(
-            @ZenPolicy.ChannelType int channelType, boolean defaultAllowChannels) {
-        switch (channelType) {
-            case ZenPolicy.CHANNEL_TYPE_PRIORITY:
-                return true;
-            case ZenPolicy.CHANNEL_TYPE_NONE:
-                return false;
-            default:
-                return defaultAllowChannels;
-        }
-    }
-
-    /**
      * Maps NotificationManager.Policy senders type to ZenPolicy.PeopleType
      */
     public static @ZenPolicy.PeopleType int getZenPolicySenders(int senders) {
diff --git a/core/java/android/service/notification/ZenPolicy.java b/core/java/android/service/notification/ZenPolicy.java
index 8477eb7..2cda7c8 100644
--- a/core/java/android/service/notification/ZenPolicy.java
+++ b/core/java/android/service/notification/ZenPolicy.java
@@ -184,7 +184,8 @@
     private @PeopleType int mPriorityMessages = PEOPLE_TYPE_UNSET;
     private @PeopleType int mPriorityCalls = PEOPLE_TYPE_UNSET;
     private @ConversationSenders int mConversationSenders = CONVERSATION_SENDERS_UNSET;
-    private @ChannelType int mAllowChannels = CHANNEL_TYPE_UNSET;
+    @FlaggedApi(Flags.FLAG_MODES_API)
+    private @ChannelType int mAllowChannels = CHANNEL_POLICY_UNSET;
     private final @ModifiableField int mUserModifiedFields; // Bitwise representation
 
     /** @hide */
@@ -354,35 +355,34 @@
      */
     public static final int STATE_DISALLOW = 2;
 
-    /** @hide */
-    @IntDef(prefix = { "CHANNEL_TYPE_" }, value = {
-            CHANNEL_TYPE_UNSET,
-            CHANNEL_TYPE_PRIORITY,
-            CHANNEL_TYPE_NONE,
+    @IntDef(prefix = { "CHANNEL_POLICY_" }, value = {
+            CHANNEL_POLICY_UNSET,
+            CHANNEL_POLICY_PRIORITY,
+            CHANNEL_POLICY_NONE,
     })
     @Retention(RetentionPolicy.SOURCE)
-    public @interface ChannelType {}
+    private @interface ChannelType {}
 
     /**
      * Indicates no explicit setting for which channels may bypass DND when this policy is active.
-     * Defaults to {@link #CHANNEL_TYPE_PRIORITY}.
+     * Defaults to {@link #CHANNEL_POLICY_PRIORITY}.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
-    public static final int CHANNEL_TYPE_UNSET = 0;
+    private static final int CHANNEL_POLICY_UNSET = 0;
 
     /**
      * Indicates that channels marked as {@link NotificationChannel#canBypassDnd()} can bypass DND
      * when this policy is active.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
-    public static final int CHANNEL_TYPE_PRIORITY = 1;
+    private static final int CHANNEL_POLICY_PRIORITY = 1;
 
     /**
      * Indicates that no channels can bypass DND when this policy is active, even those marked as
      * {@link NotificationChannel#canBypassDnd()}.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
-    public static final int CHANNEL_TYPE_NONE = 2;
+    private static final int CHANNEL_POLICY_NONE = 2;
 
     /** @hide */
     public ZenPolicy() {
@@ -584,16 +584,21 @@
     }
 
     /**
-     * Which types of {@link NotificationChannel channels} this policy allows to bypass DND. When
-     * this value is {@link #CHANNEL_TYPE_PRIORITY priority} channels, any channel with
-     * canBypassDnd() may bypass DND; when it is {@link #CHANNEL_TYPE_NONE none}, even channels
-     * with canBypassDnd() will be intercepted.
-     * @return {@link #CHANNEL_TYPE_UNSET}, {@link #CHANNEL_TYPE_PRIORITY}, or
-     *   {@link #CHANNEL_TYPE_NONE}
+     * Whether this policy allows {@link NotificationChannel channels} marked as
+     * {@link NotificationChannel#canBypassDnd()} to bypass DND. If {@link #STATE_ALLOW}, these
+     * channels may bypass; if {@link #STATE_DISALLOW}, then even notifications from channels
+     * with {@link NotificationChannel#canBypassDnd()} will be intercepted.
      */
     @FlaggedApi(Flags.FLAG_MODES_API)
-    public @ChannelType int getAllowedChannels() {
-        return mAllowChannels;
+    public @State int getPriorityChannels() {
+        switch (mAllowChannels) {
+            case CHANNEL_POLICY_PRIORITY:
+                return STATE_ALLOW;
+            case CHANNEL_POLICY_NONE:
+                return STATE_DISALLOW;
+            default:
+                return STATE_UNSET;
+        }
     }
 
     /**
@@ -1016,8 +1021,8 @@
          * Set whether priority channels are permitted to break through DND.
          */
         @FlaggedApi(Flags.FLAG_MODES_API)
-        public @NonNull Builder allowChannels(@ChannelType int channelType) {
-            mZenPolicy.mAllowChannels = channelType;
+        public @NonNull Builder allowPriorityChannels(boolean allow) {
+            mZenPolicy.mAllowChannels = allow ? CHANNEL_POLICY_PRIORITY : CHANNEL_POLICY_NONE;
             return this;
         }
 
@@ -1305,11 +1310,11 @@
     @FlaggedApi(Flags.FLAG_MODES_API)
     public static String channelTypeToString(@ChannelType int channelType) {
         switch (channelType) {
-            case CHANNEL_TYPE_UNSET:
+            case CHANNEL_POLICY_UNSET:
                 return "unset";
-            case CHANNEL_TYPE_PRIORITY:
+            case CHANNEL_POLICY_PRIORITY:
                 return "priority";
-            case CHANNEL_TYPE_NONE:
+            case CHANNEL_POLICY_NONE:
                 return "none";
         }
         return "invalidChannelType{" + channelType + "}";
@@ -1389,11 +1394,11 @@
     }
 
     /** @hide */
-    public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) {
-        switch (getZenPolicyPriorityCategoryState(category)) {
-            case ZenPolicy.STATE_ALLOW:
+    public static boolean stateToBoolean(@State int state, boolean defaultVal) {
+        switch (state) {
+            case STATE_ALLOW:
                 return true;
-            case ZenPolicy.STATE_DISALLOW:
+            case STATE_DISALLOW:
                 return false;
             default:
                 return defaultVal;
@@ -1401,15 +1406,13 @@
     }
 
     /** @hide */
+    public boolean isCategoryAllowed(@PriorityCategory int category, boolean defaultVal) {
+        return stateToBoolean(getZenPolicyPriorityCategoryState(category), defaultVal);
+    }
+
+    /** @hide */
     public boolean isVisualEffectAllowed(@VisualEffect int effect, boolean defaultVal) {
-        switch (getZenPolicyVisualEffectState(effect)) {
-            case ZenPolicy.STATE_ALLOW:
-                return true;
-            case ZenPolicy.STATE_DISALLOW:
-                return false;
-            default:
-                return defaultVal;
-        }
+        return stateToBoolean(getZenPolicyVisualEffectState(effect), defaultVal);
     }
 
     /**
@@ -1463,8 +1466,8 @@
         // apply allowed channels
         if (Flags.modesApi()) {
             // if no channels are allowed, can't newly allow them
-            if (mAllowChannels != CHANNEL_TYPE_NONE
-                    && policyToApply.mAllowChannels != CHANNEL_TYPE_UNSET) {
+            if (mAllowChannels != CHANNEL_POLICY_NONE
+                    && policyToApply.mAllowChannels != CHANNEL_POLICY_UNSET) {
                 mAllowChannels = policyToApply.mAllowChannels;
             }
         }
@@ -1530,7 +1533,7 @@
         proto.write(DNDPolicyProto.ALLOW_CONVERSATIONS_FROM, getPriorityConversationSenders());
 
         if (Flags.modesApi()) {
-            proto.write(DNDPolicyProto.ALLOW_CHANNELS, getAllowedChannels());
+            proto.write(DNDPolicyProto.ALLOW_CHANNELS, getPriorityChannels());
         }
 
         proto.flush();
diff --git a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
index 4b5595f..cbf6367 100644
--- a/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
+++ b/core/java/android/window/flags/large_screen_experiences_app_compat.aconfig
@@ -43,3 +43,10 @@
   description: "Whether the API PackageManager.USER_MIN_ASPECT_RATIO_APP_DEFAULT is available"
   bug: "310816437"
 }
+
+flag {
+  name: "allow_hide_scm_button"
+  namespace: "large_screen_experiences_app_compat"
+  description: "Whether we should allow hiding the size compat restart button"
+  bug: "318840081"
+}
diff --git a/core/proto/android/service/notification.proto b/core/proto/android/service/notification.proto
index a2978be..ad36b1c 100644
--- a/core/proto/android/service/notification.proto
+++ b/core/proto/android/service/notification.proto
@@ -360,7 +360,7 @@
 
     optional ConversationType allow_conversations_from = 19;
 
-    optional ChannelType allow_channels = 20;
+    optional ChannelPolicy allow_channels = 20;
 }
 
 // Enum identifying the type of rule that changed; values set to match ones used in the
@@ -373,8 +373,8 @@
 
 // Enum used in DNDPolicyProto to indicate the type of channels permitted to
 // break through DND. Mirrors values in ZenPolicy.
-enum ChannelType {
-    CHANNEL_TYPE_UNSET = 0;
-    CHANNEL_TYPE_PRIORITY = 1;
-    CHANNEL_TYPE_NONE = 2;
+enum ChannelPolicy {
+    CHANNEL_POLICY_UNSET = 0;
+    CHANNEL_POLICY_PRIORITY = 1;
+    CHANNEL_POLICY_NONE = 2;
 }
diff --git a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
index 056ec89..50e1862 100644
--- a/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
+++ b/services/companion/java/com/android/server/companion/CompanionDeviceManagerService.java
@@ -21,6 +21,7 @@
 import static android.Manifest.permission.DELIVER_COMPANION_MESSAGES;
 import static android.Manifest.permission.MANAGE_COMPANION_DEVICES;
 import static android.Manifest.permission.REQUEST_OBSERVE_COMPANION_DEVICE_PRESENCE;
+import static android.Manifest.permission.REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION;
 import static android.Manifest.permission.USE_COMPANION_TRANSPORTS;
 import static android.app.ActivityManager.RunningAppProcessInfo.IMPORTANCE_VISIBLE;
 import static android.companion.AssociationRequest.DEVICE_PROFILE_AUTOMOTIVE_PROJECTION;
@@ -82,6 +83,7 @@
 import android.content.pm.PackageManager;
 import android.content.pm.PackageManagerInternal;
 import android.content.pm.UserInfo;
+import android.hardware.power.Mode;
 import android.net.MacAddress;
 import android.net.NetworkPolicyManager;
 import android.os.Binder;
@@ -90,6 +92,7 @@
 import android.os.Message;
 import android.os.Parcel;
 import android.os.ParcelFileDescriptor;
+import android.os.PowerManagerInternal;
 import android.os.PowerWhitelistManager;
 import android.os.RemoteCallbackList;
 import android.os.RemoteException;
@@ -175,6 +178,7 @@
     private final PowerWhitelistManager mPowerWhitelistManager;
     private final UserManager mUserManager;
     final PackageManagerInternal mPackageManagerInternal;
+    private final PowerManagerInternal mPowerManagerInternal;
 
     /**
      * A structure that consists of two nested maps, and effectively maps (userId + packageName) to
@@ -235,6 +239,7 @@
 
         mOnPackageVisibilityChangeListener =
                 new OnPackageVisibilityChangeListener(mActivityManager);
+        mPowerManagerInternal = LocalServices.getService(PowerManagerInternal.class);
     }
 
     @Override
@@ -949,6 +954,10 @@
             mAssociationStore.updateAssociation(association);
 
             mDevicePresenceMonitor.onSelfManagedDeviceConnected(associationId);
+
+            if (association.getDeviceProfile() == REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) {
+                mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, true);
+            }
         }
 
         @Override
@@ -963,6 +972,10 @@
             }
 
             mDevicePresenceMonitor.onSelfManagedDeviceDisconnected(associationId);
+
+            if (association.getDeviceProfile() == REQUEST_COMPANION_PROFILE_AUTOMOTIVE_PROJECTION) {
+                mPowerManagerInternal.setPowerMode(Mode.AUTOMOTIVE_PROJECTION, false);
+            }
         }
 
         @Override
diff --git a/services/core/java/com/android/server/StorageManagerService.java b/services/core/java/com/android/server/StorageManagerService.java
index 7a4ac6a..2b35231 100644
--- a/services/core/java/com/android/server/StorageManagerService.java
+++ b/services/core/java/com/android/server/StorageManagerService.java
@@ -5040,9 +5040,9 @@
 
         @Override
         public IFsveritySetupAuthToken createFsveritySetupAuthToken(ParcelFileDescriptor authFd,
-                int appUid, @UserIdInt int userId) throws IOException {
+                int uid) throws IOException {
             try {
-                return mInstaller.createFsveritySetupAuthToken(authFd, appUid, userId);
+                return mInstaller.createFsveritySetupAuthToken(authFd, uid);
             } catch (Installer.InstallerException e) {
                 throw new IOException(e);
             }
diff --git a/services/core/java/com/android/server/inputmethod/ClientController.java b/services/core/java/com/android/server/inputmethod/ClientController.java
index 2934640..21b952b 100644
--- a/services/core/java/com/android/server/inputmethod/ClientController.java
+++ b/services/core/java/com/android/server/inputmethod/ClientController.java
@@ -25,9 +25,13 @@
 import android.view.inputmethod.InputBinding;
 
 import com.android.internal.annotations.GuardedBy;
+import com.android.internal.annotations.VisibleForTesting;
 import com.android.internal.inputmethod.IInputMethodClient;
 import com.android.internal.inputmethod.IRemoteInputConnection;
 
+import java.util.ArrayList;
+import java.util.List;
+
 /**
  * Store and manage {@link InputMethodManagerService} clients. This class was designed to be a
  * singleton in {@link InputMethodManagerService} since it stores information about all clients,
@@ -37,9 +41,7 @@
  * As part of the re-architecture plan (described in go/imms-rearchitecture-plan), the following
  * fields and methods will be moved out from IMMS and placed here:
  * <ul>
- * <li>mCurClient (ClientState)</li>
  * <li>mClients (ArrayMap of ClientState indexed by IBinder)</li>
- * <li>mLastSwitchUserId</li>
  * </ul>
  * <p>
  * Nested Classes (to move from IMMS):
@@ -54,7 +56,6 @@
  * <li>removeClient</li>
  * <li>verifyClientAndPackageMatch</li>
  * <li>setImeTraceEnabledForAllClients (make it reactive)</li>
- * <li>unbindCurrentClient</li>
  * </ul>
  */
 // TODO(b/314150112): Update the Javadoc above, by removing the re-architecture steps, once this
@@ -65,18 +66,32 @@
     @GuardedBy("ImfLock.class")
     final ArrayMap<IBinder, ClientState> mClients = new ArrayMap<>();
 
+    @GuardedBy("ImfLock.class")
+    private final List<ClientControllerCallback> mCallbacks = new ArrayList<>();
+
     private final PackageManagerInternal mPackageManagerInternal;
 
+    interface ClientControllerCallback {
+
+        void onClientRemoved(ClientState client);
+    }
+
     ClientController(PackageManagerInternal packageManagerInternal) {
         mPackageManagerInternal = packageManagerInternal;
     }
 
     @GuardedBy("ImfLock.class")
-    void addClient(IInputMethodClientInvoker clientInvoker,
-            IRemoteInputConnection inputConnection,
-            int selfReportedDisplayId, IBinder.DeathRecipient deathRecipient, int callerUid,
+    ClientState addClient(IInputMethodClientInvoker clientInvoker,
+            IRemoteInputConnection inputConnection, int selfReportedDisplayId, int callerUid,
             int callerPid) {
-        // TODO: Optimize this linear search.
+        final IBinder.DeathRecipient deathRecipient = () -> {
+            // Exceptionally holding ImfLock here since this is a internal lambda expression.
+            synchronized (ImfLock.class) {
+                removeClientAsBinder(clientInvoker.asBinder());
+            }
+        };
+
+        // TODO(b/319457906): Optimize this linear search.
         final int numClients = mClients.size();
         for (int i = 0; i < numClients; ++i) {
             final ClientState state = mClients.valueAt(i);
@@ -101,14 +116,40 @@
         // have the client crash.  Thus we do not verify the display ID at all here.  Instead we
         // later check the display ID every time the client needs to interact with the specified
         // display.
-        mClients.put(clientInvoker.asBinder(), new ClientState(clientInvoker, inputConnection,
-                callerUid, callerPid, selfReportedDisplayId, deathRecipient));
+        final ClientState cs = new ClientState(clientInvoker, inputConnection,
+                callerUid, callerPid, selfReportedDisplayId, deathRecipient);
+        mClients.put(clientInvoker.asBinder(), cs);
+        return cs;
+    }
+
+    @VisibleForTesting
+    @GuardedBy("ImfLock.class")
+    boolean removeClient(IInputMethodClient client) {
+        return removeClientAsBinder(client.asBinder());
+    }
+
+    @GuardedBy("ImfLock.class")
+    private boolean removeClientAsBinder(IBinder binder) {
+        final ClientState cs = mClients.remove(binder);
+        if (cs == null) {
+            return false;
+        }
+        binder.unlinkToDeath(cs.mClientDeathRecipient, 0 /* flags */);
+        for (int i = 0; i < mCallbacks.size(); i++) {
+            mCallbacks.get(i).onClientRemoved(cs);
+        }
+        return true;
+    }
+
+    @GuardedBy("ImfLock.class")
+    void addClientControllerCallback(ClientControllerCallback callback) {
+        mCallbacks.add(callback);
     }
 
     @GuardedBy("ImfLock.class")
     boolean verifyClientAndPackageMatch(
             @NonNull IInputMethodClient client, @NonNull String packageName) {
-        ClientState cs = mClients.get(client.asBinder());
+        final ClientState cs = mClients.get(client.asBinder());
         if (cs == null) {
             throw new IllegalArgumentException("unknown client " + client.asBinder());
         }
diff --git a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
index 622a2de..8448fc2 100644
--- a/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
+++ b/services/core/java/com/android/server/inputmethod/InputMethodManagerService.java
@@ -478,7 +478,6 @@
     /**
      * The client that is currently bound to an input method.
      */
-    // TODO(b/314150112): Move this to ClientController.
     @Nullable
     private ClientState mCurClient;
 
@@ -1676,7 +1675,11 @@
 
         mVisibilityStateComputer = new ImeVisibilityStateComputer(this);
         mVisibilityApplier = new DefaultImeVisibilityApplier(this);
+
         mClientController = new ClientController(mPackageManagerInternal);
+        synchronized (ImfLock.class) {
+            mClientController.addClientControllerCallback(c -> onClientRemoved(c));
+        }
 
         mPreventImeStartupUnlessTextEditor = mRes.getBoolean(
                 com.android.internal.R.bool.config_preventImeStartupUnlessTextEditor);
@@ -2168,47 +2171,41 @@
         // actually running.
         final int callerUid = Binder.getCallingUid();
         final int callerPid = Binder.getCallingPid();
-
-        // TODO(b/314150112): Move the death recipient logic to ClientController when moving
-        //     removeClient method.
-        final IBinder.DeathRecipient deathRecipient = () -> removeClient(client);
         final IInputMethodClientInvoker clientInvoker =
                 IInputMethodClientInvoker.create(client, mHandler);
         synchronized (ImfLock.class) {
             mClientController.addClient(clientInvoker, inputConnection, selfReportedDisplayId,
-                    deathRecipient, callerUid, callerPid);
+                    callerUid, callerPid);
         }
     }
 
-    // TODO(b/314150112): Move this to ClientController.
-    void removeClient(IInputMethodClient client) {
+    // TODO(b/314150112): Move this method to InputMethodBindingController
+    /**
+     * Hide the IME if the removed user is the current user.
+     */
+    private void onClientRemoved(ClientController.ClientState client) {
         synchronized (ImfLock.class) {
-            ClientState cs = mClientController.mClients.remove(client.asBinder());
-            if (cs != null) {
-                client.asBinder().unlinkToDeath(cs.mClientDeathRecipient, 0 /* flags */);
-                clearClientSessionLocked(cs);
-                clearClientSessionForAccessibilityLocked(cs);
-
-                if (mCurClient == cs) {
-                    hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
-                            null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
-                    if (mBoundToMethod) {
-                        mBoundToMethod = false;
-                        IInputMethodInvoker curMethod = getCurMethodLocked();
-                        if (curMethod != null) {
-                            // When we unbind input, we are unbinding the client, so we always
-                            // unbind ime and a11y together.
-                            curMethod.unbindInput();
-                            AccessibilityManagerInternal.get().unbindInput();
-                        }
+            clearClientSessionLocked(client);
+            clearClientSessionForAccessibilityLocked(client);
+            if (mCurClient == client) {
+                hideCurrentInputLocked(mCurFocusedWindow, null /* statsToken */, 0 /* flags */,
+                        null /* resultReceiver */, SoftInputShowHideReason.HIDE_REMOVE_CLIENT);
+                if (mBoundToMethod) {
+                    mBoundToMethod = false;
+                    IInputMethodInvoker curMethod = getCurMethodLocked();
+                    if (curMethod != null) {
+                        // When we unbind input, we are unbinding the client, so we always
+                        // unbind ime and a11y together.
+                        curMethod.unbindInput();
+                        AccessibilityManagerInternal.get().unbindInput();
                     }
-                    mBoundToAccessibility = false;
-                    mCurClient = null;
                 }
-                if (mCurFocusedWindowClient == cs) {
-                    mCurFocusedWindowClient = null;
-                    mCurFocusedWindowEditorInfo = null;
-                }
+                mBoundToAccessibility = false;
+                mCurClient = null;
+            }
+            if (mCurFocusedWindowClient == client) {
+                mCurFocusedWindowClient = null;
+                mCurFocusedWindowEditorInfo = null;
             }
         }
     }
@@ -2218,8 +2215,7 @@
     void unbindCurrentClientLocked(@UnbindReason int unbindClientReason) {
         if (mCurClient != null) {
             if (DEBUG) {
-                Slog.v(TAG, "unbindCurrentInputLocked: client="
-                        + mCurClient.mClient.asBinder());
+                Slog.v(TAG, "unbindCurrentInputLocked: client=" + mCurClient.mClient.asBinder());
             }
             if (mBoundToMethod) {
                 mBoundToMethod = false;
@@ -2312,7 +2308,8 @@
         final StartInputInfo info = new StartInputInfo(mSettings.getCurrentUserId(),
                 getCurTokenLocked(),
                 mCurTokenDisplayId, getCurIdLocked(), startInputReason, restarting,
-                UserHandle.getUserId(mCurClient.mUid), mCurClient.mSelfReportedDisplayId,
+                UserHandle.getUserId(mCurClient.mUid),
+                mCurClient.mSelfReportedDisplayId,
                 mCurFocusedWindow, mCurEditorInfo, mCurFocusedWindowSoftInputMode,
                 getSequenceNumberLocked());
         mImeTargetWindowMap.put(startInputToken, mCurFocusedWindow);
@@ -2323,14 +2320,14 @@
         // same-user scenarios.
         // That said ignoring cross-user scenario will never affect IMEs that do not have
         // INTERACT_ACROSS_USERS(_FULL) permissions, which is actually almost always the case.
-        if (mSettings.getCurrentUserId() == UserHandle.getUserId(mCurClient.mUid)) {
+        if (mSettings.getCurrentUserId() == UserHandle.getUserId(
+                mCurClient.mUid)) {
             mPackageManagerInternal.grantImplicitAccess(mSettings.getCurrentUserId(),
                     null /* intent */, UserHandle.getAppId(getCurMethodUidLocked()),
                     mCurClient.mUid, true /* direct */);
         }
 
-        @InputMethodNavButtonFlags
-        final int navButtonFlags = getInputMethodNavButtonFlagsLocked();
+        @InputMethodNavButtonFlags final int navButtonFlags = getInputMethodNavButtonFlagsLocked();
         final SessionState session = mCurClient.mCurSession;
         setEnabledSessionLocked(session);
         session.mMethod.startInput(startInputToken, mCurInputConnection, mCurEditorInfo, restarting,
@@ -2750,8 +2747,8 @@
                         && curMethod.asBinder() == method.asBinder()) {
                     if (mCurClient != null) {
                         clearClientSessionLocked(mCurClient);
-                        mCurClient.mCurSession = new SessionState(mCurClient,
-                                method, session, channel);
+                        mCurClient.mCurSession = new SessionState(
+                                mCurClient, method, session, channel);
                         InputBindResult res = attachNewInputLocked(
                                 StartInputReason.SESSION_CREATED_BY_IME, true);
                         attachNewAccessibilityLocked(StartInputReason.SESSION_CREATED_BY_IME, true);
@@ -5776,8 +5773,10 @@
                 // TODO(b/305829876): Implement user ID verification
                 if (mCurClient != null) {
                     clearClientSessionForAccessibilityLocked(mCurClient, accessibilityConnectionId);
-                    mCurClient.mAccessibilitySessions.put(accessibilityConnectionId,
-                            new AccessibilitySessionState(mCurClient, accessibilityConnectionId,
+                    mCurClient.mAccessibilitySessions.put(
+                            accessibilityConnectionId,
+                            new AccessibilitySessionState(mCurClient,
+                                    accessibilityConnectionId,
                                     session));
 
                     attachNewAccessibilityLocked(StartInputReason.SESSION_CREATED_BY_ACCESSIBILITY,
@@ -5811,7 +5810,8 @@
                     }
                     // A11yManagerService unbinds the disabled accessibility service. We don't need
                     // to do it here.
-                    mCurClient.mClient.onUnbindAccessibilityService(getSequenceNumberLocked(),
+                    mCurClient.mClient.onUnbindAccessibilityService(
+                            getSequenceNumberLocked(),
                             accessibilityConnectionId);
                 }
                 // We only have sessions when we bound to an input method. Remove this session
diff --git a/services/core/java/com/android/server/notification/ZenAdapters.java b/services/core/java/com/android/server/notification/ZenAdapters.java
index 91df04c..37b263c 100644
--- a/services/core/java/com/android/server/notification/ZenAdapters.java
+++ b/services/core/java/com/android/server/notification/ZenAdapters.java
@@ -59,9 +59,7 @@
         }
 
         if (Flags.modesApi()) {
-            zenPolicyBuilder.allowChannels(
-                    policy.allowPriorityChannels()
-                            ? ZenPolicy.CHANNEL_TYPE_PRIORITY : ZenPolicy.CHANNEL_TYPE_NONE);
+            zenPolicyBuilder.allowPriorityChannels(policy.allowPriorityChannels());
         }
 
         return zenPolicyBuilder.build();
diff --git a/services/core/java/com/android/server/notification/ZenModeEventLogger.java b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
index 0145577..a90efe6 100644
--- a/services/core/java/com/android/server/notification/ZenModeEventLogger.java
+++ b/services/core/java/com/android/server/notification/ZenModeEventLogger.java
@@ -18,6 +18,8 @@
 
 import static android.app.NotificationManager.Policy.STATE_CHANNELS_BYPASSING_DND;
 import static android.provider.Settings.Global.ZEN_MODE_OFF;
+import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_PRIORITY;
+import static android.service.notification.NotificationServiceProto.CHANNEL_POLICY_NONE;
 import static android.service.notification.NotificationServiceProto.RULE_TYPE_AUTOMATIC;
 import static android.service.notification.NotificationServiceProto.RULE_TYPE_MANUAL;
 import static android.service.notification.NotificationServiceProto.RULE_TYPE_UNKNOWN;
@@ -551,8 +553,8 @@
                 if (Flags.modesApi()) {
                     proto.write(DNDPolicyProto.ALLOW_CHANNELS,
                             mNewPolicy.allowPriorityChannels()
-                                    ? ZenPolicy.CHANNEL_TYPE_PRIORITY
-                                    : ZenPolicy.CHANNEL_TYPE_NONE);
+                                    ? CHANNEL_POLICY_PRIORITY
+                                    : CHANNEL_POLICY_NONE);
                 }
             } else {
                 Log.wtf(TAG, "attempted to write zen mode log event with null policy");
diff --git a/services/core/java/com/android/server/notification/ZenModeHelper.java b/services/core/java/com/android/server/notification/ZenModeHelper.java
index afbf08d..c7f5703 100644
--- a/services/core/java/com/android/server/notification/ZenModeHelper.java
+++ b/services/core/java/com/android/server/notification/ZenModeHelper.java
@@ -1131,7 +1131,7 @@
                     != newPolicy.getPriorityConversationSenders()) {
                 userModifiedFields |= ZenPolicy.FIELD_CONVERSATIONS;
             }
-            if (oldPolicy.getAllowedChannels() != newPolicy.getAllowedChannels()) {
+            if (oldPolicy.getPriorityChannels() != newPolicy.getPriorityChannels()) {
                 userModifiedFields |= ZenPolicy.FIELD_ALLOW_CHANNELS;
             }
             if (oldPolicy.getPriorityCategoryReminders()
diff --git a/services/core/java/com/android/server/pm/Installer.java b/services/core/java/com/android/server/pm/Installer.java
index d5471cb0..34903d1 100644
--- a/services/core/java/com/android/server/pm/Installer.java
+++ b/services/core/java/com/android/server/pm/Installer.java
@@ -1183,8 +1183,7 @@
      * Returns an auth token for the provided writable FD.
      *
      * @param authFd a file descriptor to proof that the caller can write to the file.
-     * @param appUid uid of the calling app.
-     * @param userId id of the user whose app file to enable fs-verity.
+     * @param uid uid of the calling app.
      *
      * @return authToken, or null if a remote call shouldn't be continued. See {@link
      * #checkBeforeRemote}.
@@ -1192,13 +1191,12 @@
      * @throws InstallerException if the remote call failed.
      */
     public IInstalld.IFsveritySetupAuthToken createFsveritySetupAuthToken(
-            ParcelFileDescriptor authFd, int appUid, @UserIdInt int userId)
-            throws InstallerException {
+            ParcelFileDescriptor authFd, int uid) throws InstallerException {
         if (!checkBeforeRemote()) {
             return null;
         }
         try {
-            return mInstalld.createFsveritySetupAuthToken(authFd, appUid, userId);
+            return mInstalld.createFsveritySetupAuthToken(authFd, uid);
         } catch (Exception e) {
             throw InstallerException.from(e);
         }
diff --git a/services/core/java/com/android/server/pm/VerifyingSession.java b/services/core/java/com/android/server/pm/VerifyingSession.java
index c6435ae..f0ff85d 100644
--- a/services/core/java/com/android/server/pm/VerifyingSession.java
+++ b/services/core/java/com/android/server/pm/VerifyingSession.java
@@ -356,6 +356,11 @@
         if (verifierUser == UserHandle.ALL) {
             verifierUser = UserHandle.of(mPm.mUserManager.getCurrentUserId());
         }
+        // TODO(b/300965895): Remove when inconsistencies loading classpaths from apex for
+        // user > 1 are fixed.
+        if (pkgLite.isSdkLibrary) {
+            verifierUser = UserHandle.SYSTEM;
+        }
         final int verifierUserId = verifierUser.getIdentifier();
 
         List<String> requiredVerifierPackages = new ArrayList<>(
diff --git a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
index 5d710d2..ee40e18 100644
--- a/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
+++ b/services/core/java/com/android/server/pm/permission/PermissionManagerService.java
@@ -29,6 +29,7 @@
 import static android.app.AppOpsManager.OP_BLUETOOTH_CONNECT;
 import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISALLOWED;
 import static android.content.pm.ApplicationInfo.AUTO_REVOKE_DISCOURAGED;
+import static android.permission.flags.Flags.serverSideAttributionRegistration;
 
 import static com.android.server.pm.PackageManagerService.PLATFORM_PACKAGE_NAME;
 
@@ -439,10 +440,27 @@
         }
     }
 
+    /**
+     * Reference propagation over binder is affected by the ownership of the object. So if 
+     * the token is owned by client, references to the token on client side won't be 
+     * propagated to the server and the token may still be garbage collected on server side. 
+     * But if the token is owned by server, references to the token on client side will now 
+     * be propagated to the server since it's a foreign object to the client, and that will 
+     * keep the token referenced on the server side as long as the client is alive and 
+     * holding it.
+     */
     @Override
-    public void registerAttributionSource(@NonNull AttributionSourceState source) {
-        mAttributionSourceRegistry
-                .registerAttributionSource(new AttributionSource(source));
+    public IBinder registerAttributionSource(@NonNull AttributionSourceState source) {
+        if (serverSideAttributionRegistration()) {
+            Binder token = new Binder();
+            mAttributionSourceRegistry
+                    .registerAttributionSource(new AttributionSource(source).withToken(token));
+            return token;
+        } else {
+            mAttributionSourceRegistry
+                    .registerAttributionSource(new AttributionSource(source));
+            return source.token;
+        }
     }
 
     @Override
@@ -1218,7 +1236,6 @@
                 @Nullable String message, boolean forDataDelivery, boolean startDataDelivery,
                 boolean fromDatasource, int attributedOp) {
             PermissionInfo permissionInfo = sPlatformPermissions.get(permission);
-
             if (permissionInfo == null) {
                 try {
                     permissionInfo = context.getPackageManager().getPermissionInfo(permission, 0);
@@ -1346,8 +1363,8 @@
 
                 // If the call is from a datasource we need to vet only the chain before it. This
                 // way we can avoid the datasource creating an attribution context for every call.
-                if (!(fromDatasource && current.equals(attributionSource))
-                        && next != null && !current.isTrusted(context)) {
+                boolean isDatasource = fromDatasource && current.equals(attributionSource);
+                if (!isDatasource && next != null && !current.isTrusted(context)) {
                     return PermissionChecker.PERMISSION_HARD_DENIED;
                 }
 
diff --git a/services/core/java/com/android/server/security/FileIntegrityService.java b/services/core/java/com/android/server/security/FileIntegrityService.java
index a49df50..bb4876b 100644
--- a/services/core/java/com/android/server/security/FileIntegrityService.java
+++ b/services/core/java/com/android/server/security/FileIntegrityService.java
@@ -157,7 +157,7 @@
             Objects.requireNonNull(authFd);
             try {
                 var authToken = getStorageManagerInternal().createFsveritySetupAuthToken(authFd,
-                        Binder.getCallingUid(), Binder.getCallingUserHandle().getIdentifier());
+                        Binder.getCallingUid());
                 // fs-verity setup requires no writable fd to the file. Release the dup now that
                 // it's passed.
                 authFd.close();
diff --git a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
index 3c8f5c9..30afa72 100644
--- a/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
+++ b/services/tests/InputMethodSystemServerTests/src/com/android/server/inputmethod/ClientControllerTest.java
@@ -15,9 +15,16 @@
  */
 package com.android.server.inputmethod;
 
+import static com.android.server.inputmethod.ClientController.ClientControllerCallback;
+import static com.android.server.inputmethod.ClientController.ClientState;
+
 import static com.google.common.truth.Truth.assertThat;
+import static com.google.common.truth.Truth.assertWithMessage;
 
 import static org.junit.Assert.assertThrows;
+import static org.mockito.Mockito.any;
+import static org.mockito.Mockito.eq;
+import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
 
 import android.content.pm.PackageManagerInternal;
@@ -38,6 +45,8 @@
 import org.mockito.Mock;
 import org.mockito.MockitoAnnotations;
 
+import java.util.concurrent.CountDownLatch;
+import java.util.concurrent.TimeUnit;
 
 // This test is designed to run on both device and host (Ravenwood) side.
 public final class ClientControllerTest {
@@ -58,9 +67,6 @@
     @Mock
     private IRemoteInputConnection mConnection;
 
-    @Mock
-    private IBinder.DeathRecipient mDeathRecipient;
-
     private Handler mHandler;
 
     private ClientController mController;
@@ -68,9 +74,10 @@
     @Before
     public void setUp() {
         MockitoAnnotations.initMocks(this);
+        when(mClient.asBinder()).thenReturn((IBinder) mClient);
+
         mHandler = new Handler(Looper.getMainLooper());
         mController = new ClientController(mMockPackageManagerInternal);
-        when(mClient.asBinder()).thenReturn((IBinder) mClient);
     }
 
     @Test
@@ -80,18 +87,77 @@
         var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
 
         synchronized (ImfLock.class) {
-            mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, mDeathRecipient,
-                    ANY_CALLER_UID, ANY_CALLER_PID);
+            mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
+                    ANY_CALLER_PID);
 
             SecurityException thrown = assertThrows(SecurityException.class,
                     () -> {
                         synchronized (ImfLock.class) {
                             mController.addClient(invoker, mConnection, ANY_DISPLAY_ID,
-                                    mDeathRecipient, ANY_CALLER_UID, ANY_CALLER_PID);
+                                    ANY_CALLER_UID, ANY_CALLER_PID);
                         }
                     });
             assertThat(thrown.getMessage()).isEqualTo(
                     "uid=1/pid=1/displayId=0 is already registered");
         }
     }
+
+    @Test
+    // TODO(b/314150112): Enable host side mode for this test once b/315544364 is fixed.
+    @IgnoreUnderRavenwood(blockedBy = {InputBinding.class, IInputMethodClientInvoker.class})
+    public void testAddClient() throws Exception {
+        synchronized (ImfLock.class) {
+            var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
+            var added = mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
+                    ANY_CALLER_PID);
+
+            verify(invoker.asBinder()).linkToDeath(any(IBinder.DeathRecipient.class), eq(0));
+            assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+        }
+    }
+
+    @Test
+    // TODO(b/314150112): Enable host side mode for this test once b/315544364 is fixed.
+    @IgnoreUnderRavenwood(blockedBy = {InputBinding.class, IInputMethodClientInvoker.class})
+    public void testRemoveClient() {
+        var callback = new TestClientControllerCallback();
+        ClientState added;
+        synchronized (ImfLock.class) {
+            mController.addClientControllerCallback(callback);
+
+            var invoker = IInputMethodClientInvoker.create(mClient, mHandler);
+            added = mController.addClient(invoker, mConnection, ANY_DISPLAY_ID, ANY_CALLER_UID,
+                    ANY_CALLER_PID);
+            assertThat(mController.mClients).containsEntry(invoker.asBinder(), added);
+            assertThat(mController.removeClient(mClient)).isTrue();
+        }
+
+        // Test callback
+        var removed = callback.waitForRemovedClient(5, TimeUnit.SECONDS);
+        assertThat(removed).isSameInstanceAs(added);
+    }
+
+    private static class TestClientControllerCallback implements ClientControllerCallback {
+
+        private final CountDownLatch mLatch = new CountDownLatch(1);
+
+        private ClientState mRemoved;
+
+        @Override
+        public void onClientRemoved(ClientState removed) {
+            mRemoved = removed;
+            mLatch.countDown();
+        }
+
+        ClientState waitForRemovedClient(long timeout, TimeUnit unit) {
+            try {
+                assertWithMessage("ClientController callback wasn't called on user removed").that(
+                        mLatch.await(timeout, unit)).isTrue();
+            } catch (InterruptedException e) {
+                Thread.currentThread().interrupt();
+                throw new IllegalStateException("Unexpected thread interruption", e);
+            }
+            return mRemoved;
+        }
+    }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
index 08af09c..0e20daf 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenAdaptersTest.java
@@ -143,12 +143,12 @@
                 Policy.policyState(false, true), 0);
 
         ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
-        assertThat(zenPolicy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        assertThat(zenPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
 
         Policy notAllowed = new Policy(0, 0, 0, 0,
                 Policy.policyState(false, false), 0);
         ZenPolicy zenPolicyNotAllowed = notificationPolicyToZenPolicy(notAllowed);
-        assertThat(zenPolicyNotAllowed.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_NONE);
+        assertThat(zenPolicyNotAllowed.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -158,12 +158,11 @@
                 Policy.policyState(false, true), 0);
 
         ZenPolicy zenPolicy = notificationPolicyToZenPolicy(policy);
-        assertThat(zenPolicy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_UNSET);
+        assertThat(zenPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
 
         Policy notAllowed = new Policy(0, 0, 0, 0,
                 Policy.policyState(false, false), 0);
         ZenPolicy zenPolicyNotAllowed = notificationPolicyToZenPolicy(notAllowed);
-        assertThat(zenPolicyNotAllowed.getAllowedChannels())
-                .isEqualTo(ZenPolicy.CHANNEL_TYPE_UNSET);
+        assertThat(zenPolicyNotAllowed.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
     }
 }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
index dd252f3..db92719 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeConfigTest.java
@@ -164,7 +164,7 @@
                 .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
                 .showLights(false)
                 .showInAmbientDisplay(false)
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE)
+                .allowPriorityChannels(false)
                 .build();
 
         Policy originalPolicy = config.toNotificationPolicy();
@@ -255,7 +255,7 @@
                 .allowCalls(ZenPolicy.PEOPLE_TYPE_CONTACTS)
                 .allowMessages(ZenPolicy.PEOPLE_TYPE_STARRED)
                 .allowConversations(ZenPolicy.CONVERSATION_SENDERS_NONE)
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE)
+                .allowPriorityChannels(false)
                 .build();
 
         ZenModeConfig config = getMutedAllConfig();
@@ -284,7 +284,7 @@
                 actual.getPriorityConversationSenders());
         assertEquals(expected.getPriorityCallSenders(), actual.getPriorityCallSenders());
         assertEquals(expected.getPriorityMessageSenders(), actual.getPriorityMessageSenders());
-        assertEquals(expected.getAllowedChannels(), actual.getAllowedChannels());
+        assertEquals(expected.getPriorityChannels(), actual.getPriorityChannels());
         assertEquals(expected.getUserModifiedFields(), actual.getUserModifiedFields());
     }
 
@@ -694,7 +694,7 @@
                 .allowSystem(true)
                 .allowReminders(false)
                 .allowEvents(true)
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE)
+                .allowPriorityChannels(false)
                 .hideAllVisualEffects()
                 .showVisualEffect(ZenPolicy.VISUAL_EFFECT_AMBIENT, true)
                 .setUserModifiedFields(4)
@@ -721,7 +721,7 @@
         assertEquals(policy.getPriorityCategorySystem(), fromXml.getPriorityCategorySystem());
         assertEquals(policy.getPriorityCategoryReminders(), fromXml.getPriorityCategoryReminders());
         assertEquals(policy.getPriorityCategoryEvents(), fromXml.getPriorityCategoryEvents());
-        assertEquals(policy.getAllowedChannels(), fromXml.getAllowedChannels());
+        assertEquals(policy.getPriorityChannels(), fromXml.getPriorityChannels());
 
         assertEquals(policy.getVisualEffectFullScreenIntent(),
                 fromXml.getVisualEffectFullScreenIntent());
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
index 29208f4..7d6e12c 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeFilteringTest.java
@@ -546,13 +546,13 @@
         // Create a policy to allow channels through, which means shouldIntercept is false
         ZenModeConfig config = new ZenModeConfig();
         Policy policy = config.toNotificationPolicy(new ZenPolicy.Builder()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY)
+                .allowPriorityChannels(true)
                 .build());
         assertFalse(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, r));
 
         // Now create a policy which does not allow priority channels:
         policy = config.toNotificationPolicy(new ZenPolicy.Builder()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE)
+                .allowPriorityChannels(false)
                 .build());
         assertTrue(mZenModeFiltering.shouldIntercept(ZEN_MODE_IMPORTANT_INTERRUPTIONS, policy, r));
     }
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
index 9e3e336..78fe41f 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenModeHelperTest.java
@@ -1151,7 +1151,7 @@
                 .allowAlarms(true)
                 .allowRepeatCallers(false)
                 .allowCalls(PEOPLE_TYPE_STARRED)
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE)
+                .allowPriorityChannels(false)
                 .build();
         mZenModeHelper.mConfig.automaticRules.put(rule.id, rule);
         List<StatsEvent> events = new LinkedList<>();
@@ -1174,7 +1174,7 @@
                 assertThat(policy.getAllowCallsFrom().getNumber())
                         .isEqualTo(DNDProtoEnums.PEOPLE_STARRED);
                 assertThat(policy.getAllowChannels().getNumber())
-                        .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_NONE);
+                        .isEqualTo(DNDProtoEnums.CHANNEL_POLICY_NONE);
             }
         }
         assertTrue("couldn't find custom rule", foundCustomEvent);
@@ -3098,7 +3098,7 @@
         DNDPolicyProto origDndProto = mZenModeEventLogger.getPolicyProto(0);
         checkDndProtoMatchesSetupZenConfig(origDndProto);
         assertThat(origDndProto.getAllowChannels().getNumber())
-                .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_PRIORITY);
+                .isEqualTo(DNDProtoEnums.CHANNEL_POLICY_PRIORITY);
 
         // Second message where we change the policy:
         //   - DND_POLICY_CHANGED (indicates only the policy changed and nothing else)
@@ -3110,7 +3110,7 @@
                 .isEqualTo(DNDProtoEnums.UNKNOWN_RULE);
         DNDPolicyProto dndProto = mZenModeEventLogger.getPolicyProto(1);
         assertThat(dndProto.getAllowChannels().getNumber())
-                .isEqualTo(DNDProtoEnums.CHANNEL_TYPE_NONE);
+                .isEqualTo(DNDProtoEnums.CHANNEL_POLICY_NONE);
     }
 
     @Test
@@ -3299,7 +3299,7 @@
 
         // one rule, custom policy, allows channels
         ZenPolicy customPolicy = new ZenPolicy.Builder()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY)
+                .allowPriorityChannels(true)
                 .build();
 
         AutomaticZenRule zenRule = new AutomaticZenRule("name",
@@ -3321,7 +3321,7 @@
 
         // add new rule with policy that disallows channels
         ZenPolicy strictPolicy = new ZenPolicy.Builder()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE)
+                .allowPriorityChannels(false)
                 .build();
 
         AutomaticZenRule zenRule2 = new AutomaticZenRule("name2",
@@ -3552,7 +3552,7 @@
 
         // Modifies the zen policy and device effects
         ZenPolicy policy = new ZenPolicy.Builder(rule.getZenPolicy())
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY)
+                .allowPriorityChannels(true)
                 .build();
         ZenDeviceEffects deviceEffects =
                 new ZenDeviceEffects.Builder(rule.getDeviceEffects())
@@ -3575,8 +3575,7 @@
                 .isEqualTo(AutomaticZenRule.FIELD_INTERRUPTION_FILTER);
         assertThat(rule.getZenPolicy().getUserModifiedFields())
                 .isEqualTo(ZenPolicy.FIELD_ALLOW_CHANNELS);
-        assertThat(rule.getZenPolicy().getAllowedChannels())
-                .isEqualTo(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
         assertThat(rule.getDeviceEffects().getUserModifiedFields())
                 .isEqualTo(ZenDeviceEffects.FIELD_GRAYSCALE);
         assertThat(rule.getDeviceEffects().shouldDisplayGrayscale()).isTrue();
@@ -3864,7 +3863,7 @@
 
         // Create a fully populated ZenPolicy.
         ZenPolicy policy = new ZenPolicy.Builder()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_NONE) // Differs from the default
+                .allowPriorityChannels(false) // Differs from the default
                 .allowReminders(true) // Differs from the default
                 .allowEvents(true) // Differs from the default
                 .allowConversations(ZenPolicy.CONVERSATION_SENDERS_IMPORTANT)
@@ -3894,7 +3893,7 @@
 
         // New ZenPolicy differs from the default config
         assertThat(rule.getZenPolicy()).isNotNull();
-        assertThat(rule.getZenPolicy().getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_NONE);
+        assertThat(rule.getZenPolicy().getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
         assertThat(rule.canUpdate()).isFalse();
         assertThat(rule.getZenPolicy().getUserModifiedFields()).isEqualTo(
                 ZenPolicy.FIELD_ALLOW_CHANNELS
@@ -4756,7 +4755,7 @@
                 .allowCalls(PEOPLE_TYPE_CONTACTS)
                 .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
                 .hideAllVisualEffects()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY)
+                .allowPriorityChannels(true)
                 .build();
         assertThat(mZenModeHelper.mConfig.automaticRules.values())
                 .comparingElementsUsing(IGNORE_TIMESTAMPS)
@@ -4788,7 +4787,7 @@
                 .allowCalls(PEOPLE_TYPE_STARRED)
                 .allowConversations(CONVERSATION_SENDERS_IMPORTANT)
                 .hideAllVisualEffects()
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY)
+                .allowPriorityChannels(true)
                 .build();
         assertThat(mZenModeHelper.mConfig.automaticRules.values())
                 .comparingElementsUsing(IGNORE_TIMESTAMPS)
diff --git a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
index 21c96d6..7941eb4 100644
--- a/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
+++ b/services/tests/uiservicestests/src/com/android/server/notification/ZenPolicyTest.java
@@ -213,13 +213,12 @@
         ZenPolicy unset = builder.build();
 
         // priority channels allowed
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        builder.allowPriorityChannels(true);
         ZenPolicy channelsPriority = builder.build();
 
         // unset applied, channels setting keeps its state
         channelsPriority.apply(unset);
-        assertThat(channelsPriority.getAllowedChannels())
-                .isEqualTo(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        assertThat(channelsPriority.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
     }
 
     @Test
@@ -227,15 +226,15 @@
         mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
 
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_NONE);
+        builder.allowPriorityChannels(false);
         ZenPolicy none = builder.build();
 
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        builder.allowPriorityChannels(true);
         ZenPolicy priority = builder.build();
 
         // priority channels (less strict state) cannot override a setting that sets it to none
         none.apply(priority);
-        assertThat(none.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_NONE);
+        assertThat(none.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -243,15 +242,15 @@
         mSetFlagsRule.enableFlags(Flags.FLAG_MODES_API);
 
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_NONE);
+        builder.allowPriorityChannels(false);
         ZenPolicy none = builder.build();
 
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        builder.allowPriorityChannels(true);
         ZenPolicy priority = builder.build();
 
         // applying a policy with channelType=none overrides priority setting
         priority.apply(none);
-        assertThat(priority.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_NONE);
+        assertThat(priority.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -261,12 +260,12 @@
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
         ZenPolicy unset = builder.build();
 
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        builder.allowPriorityChannels(true);
         ZenPolicy priority = builder.build();
 
         // applying a policy with a set channel type actually goes through
         unset.apply(priority);
-        assertThat(unset.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        assertThat(unset.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
     }
 
     @Test
@@ -308,7 +307,7 @@
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
 
         ZenPolicy policy = builder.build();
-        assertThat(policy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_UNSET);
+        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
     }
 
     @Test
@@ -622,10 +621,10 @@
 
         // allowChannels should be unset, not be modifiable, and not show up in any output
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        builder.allowPriorityChannels(true);
         ZenPolicy policy = builder.build();
 
-        assertThat(policy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_UNSET);
+        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_UNSET);
         assertThat(policy.toString().contains("allowChannels")).isFalse();
     }
 
@@ -635,14 +634,14 @@
 
         // allow priority channels
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        builder.allowPriorityChannels(true);
         ZenPolicy policy = builder.build();
-        assertThat(policy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
 
         // disallow priority channels
-        builder.allowChannels(ZenPolicy.CHANNEL_TYPE_NONE);
+        builder.allowPriorityChannels(false);
         policy = builder.build();
-        assertThat(policy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_NONE);
+        assertThat(policy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_DISALLOW);
     }
 
     @Test
@@ -676,7 +675,7 @@
         ZenPolicy.Builder builder = new ZenPolicy.Builder();
         ZenPolicy policy = builder.allowRepeatCallers(true).allowAlarms(false)
                 .showLights(true).showBadges(false)
-                .allowChannels(ZenPolicy.CHANNEL_TYPE_PRIORITY)
+                .allowPriorityChannels(true)
                 .setUserModifiedFields(20).build();
 
         ZenPolicy newPolicy = new ZenPolicy.Builder(policy).build();
@@ -689,7 +688,7 @@
         assertThat(newPolicy.getVisualEffectBadge()).isEqualTo(ZenPolicy.STATE_DISALLOW);
         assertThat(newPolicy.getVisualEffectPeek()).isEqualTo(ZenPolicy.STATE_UNSET);
 
-        assertThat(newPolicy.getAllowedChannels()).isEqualTo(ZenPolicy.CHANNEL_TYPE_PRIORITY);
+        assertThat(newPolicy.getPriorityChannels()).isEqualTo(ZenPolicy.STATE_ALLOW);
         assertThat(newPolicy.getUserModifiedFields()).isEqualTo(20);
     }
 
diff --git a/telecomm/java/android/telecom/CallControl.java b/telecomm/java/android/telecom/CallControl.java
index 24d3918..fe699af 100644
--- a/telecomm/java/android/telecom/CallControl.java
+++ b/telecomm/java/android/telecom/CallControl.java
@@ -19,6 +19,7 @@
 import static android.telecom.CallException.TRANSACTION_EXCEPTION_KEY;
 
 import android.annotation.CallbackExecutor;
+import android.annotation.FlaggedApi;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.annotation.SuppressLint;
@@ -32,6 +33,7 @@
 
 import com.android.internal.telecom.ClientTransactionalServiceRepository;
 import com.android.internal.telecom.ICallControl;
+import com.android.server.telecom.flags.Flags;
 
 import java.util.List;
 import java.util.Objects;
@@ -292,6 +294,43 @@
     }
 
     /**
+     * Request a new mute state.  Note: {@link CallEventCallback#onMuteStateChanged(boolean)}
+     * will be called every time the mute state is changed and can be used to track the current
+     * mute state.
+     *
+     * @param isMuted  The new mute state.  Passing in a {@link Boolean#TRUE} for the isMuted
+     *                 parameter will mute the call.  {@link Boolean#FALSE} will unmute the call.
+     * @param executor The {@link Executor} on which the {@link OutcomeReceiver} callback
+     *                 will be called on.
+     * @param callback The {@link OutcomeReceiver} that will be completed on the Telecom side
+     *                 that details success or failure of the requested operation.
+     *
+     *                 {@link OutcomeReceiver#onResult} will be called if Telecom has
+     *                 successfully changed the mute state.
+     *
+     *                 {@link OutcomeReceiver#onError} will be called if Telecom has failed to
+     *                 switch to the mute state.  A {@link CallException} will be
+     *                 passed that details why the operation failed.
+     */
+    @FlaggedApi(Flags.FLAG_SET_MUTE_STATE)
+    public void setMuteState(boolean isMuted, @CallbackExecutor @NonNull Executor executor,
+            @NonNull OutcomeReceiver<Void, CallException> callback) {
+        Objects.requireNonNull(executor);
+        Objects.requireNonNull(callback);
+        if (mServerInterface != null) {
+            try {
+                mServerInterface.setMuteState(isMuted,
+                        new CallControlResultReceiver("setMuteState", executor, callback));
+
+            } catch (RemoteException e) {
+                throw e.rethrowAsRuntimeException();
+            }
+        } else {
+            throw new IllegalStateException(INTERFACE_ERROR_MSG);
+        }
+    }
+
+    /**
      * Raises an event to the {@link android.telecom.InCallService} implementations tracking this
      * call via {@link android.telecom.Call.Callback#onConnectionEvent(Call, String, Bundle)}.
      * These events and the associated extra keys for the {@code Bundle} parameter are mutually
diff --git a/telecomm/java/com/android/internal/telecom/ICallControl.aidl b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
index 5e2c923..372e4a12 100644
--- a/telecomm/java/com/android/internal/telecom/ICallControl.aidl
+++ b/telecomm/java/com/android/internal/telecom/ICallControl.aidl
@@ -32,5 +32,6 @@
     void disconnect(String callId, in DisconnectCause disconnectCause, in ResultReceiver callback);
     void startCallStreaming(String callId, in ResultReceiver callback);
     void requestCallEndpointChange(in CallEndpoint callEndpoint, in ResultReceiver callback);
+    void setMuteState(boolean isMuted, in ResultReceiver callback);
     void sendEvent(String callId, String event, in Bundle extras);
 }
\ No newline at end of file
diff --git a/tests/FsVerityTest/AndroidTest.xml b/tests/FsVerityTest/AndroidTest.xml
index d2537f6..f2d7990 100644
--- a/tests/FsVerityTest/AndroidTest.xml
+++ b/tests/FsVerityTest/AndroidTest.xml
@@ -15,6 +15,7 @@
 -->
 <configuration description="fs-verity end-to-end test">
     <option name="test-suite-tag" value="apct" />
+    <option name="config-descriptor:metadata" key="parameter" value="secondary_user"/>
 
     <object type="module_controller" class="com.android.tradefed.testtype.suite.module.ShippingApiLevelModuleController">
         <!-- fs-verity is required since R/30 -->