Merge "Introduce a new output stream that is capable of tracking the number of bytes that are written to the output stream."
diff --git a/core/java/android/content/pm/parsing/AndroidPackage.java b/core/java/android/content/pm/parsing/AndroidPackage.java
index 35df474..0562dff 100644
--- a/core/java/android/content/pm/parsing/AndroidPackage.java
+++ b/core/java/android/content/pm/parsing/AndroidPackage.java
@@ -403,6 +403,8 @@
 
     boolean isEnabled();
 
+    boolean isCrossProfile();
+
     boolean isEncryptionAware();
 
     boolean isExternal();
diff --git a/core/java/android/content/pm/parsing/ApkParseUtils.java b/core/java/android/content/pm/parsing/ApkParseUtils.java
index 7732316..3f22967 100644
--- a/core/java/android/content/pm/parsing/ApkParseUtils.java
+++ b/core/java/android/content/pm/parsing/ApkParseUtils.java
@@ -2070,6 +2070,9 @@
                             sa.getBoolean(R.styleable.AndroidManifestApplication_enabled,
                                     true));
 
+            parsingPackage.setCrossProfile(
+                    sa.getBoolean(R.styleable.AndroidManifestApplication_crossProfile, false));
+
             parsingPackage.setIsGame(sa.getBoolean(
                     R.styleable.AndroidManifestApplication_isGame, false));
 
diff --git a/core/java/android/content/pm/parsing/PackageImpl.java b/core/java/android/content/pm/parsing/PackageImpl.java
index 0e736d5..18dee23 100644
--- a/core/java/android/content/pm/parsing/PackageImpl.java
+++ b/core/java/android/content/pm/parsing/PackageImpl.java
@@ -240,6 +240,7 @@
     private int descriptionRes;
     private String deviceProtectedDataDir;
     private boolean enabled;
+    private boolean crossProfile;
     private int flags;
     private int fullBackupContent;
     private boolean hiddenUntilInstalled;
@@ -1636,6 +1637,12 @@
     }
 
     @Override
+    public PackageImpl setCrossProfile(boolean crossProfile) {
+        this.crossProfile = crossProfile;
+        return this;
+    }
+
+    @Override
     public PackageImpl setUiOptions(int uiOptions) {
         this.uiOptions = uiOptions;
         return this;
@@ -2835,6 +2842,11 @@
     }
 
     @Override
+    public boolean isCrossProfile() {
+        return crossProfile;
+    }
+
+    @Override
     public String getManageSpaceActivityName() {
         return manageSpaceActivityName;
     }
@@ -3042,6 +3054,7 @@
         dest.writeInt(this.descriptionRes);
         dest.writeString(this.deviceProtectedDataDir);
         dest.writeBoolean(this.enabled);
+        dest.writeBoolean(this.crossProfile);
         dest.writeInt(this.flags);
         dest.writeInt(this.fullBackupContent);
         dest.writeBoolean(this.hiddenUntilInstalled);
@@ -3194,6 +3207,7 @@
         this.descriptionRes = in.readInt();
         this.deviceProtectedDataDir = in.readString();
         this.enabled = in.readBoolean();
+        this.crossProfile = in.readBoolean();
         this.flags = in.readInt();
         this.fullBackupContent = in.readInt();
         this.hiddenUntilInstalled = in.readBoolean();
diff --git a/core/java/android/content/pm/parsing/ParsingPackage.java b/core/java/android/content/pm/parsing/ParsingPackage.java
index aff1b2e..47dac55 100644
--- a/core/java/android/content/pm/parsing/ParsingPackage.java
+++ b/core/java/android/content/pm/parsing/ParsingPackage.java
@@ -229,6 +229,8 @@
 
     ParsingPackage setEnabled(boolean enabled);
 
+    ParsingPackage setCrossProfile(boolean crossProfile);
+
     ParsingPackage setFullBackupContent(int fullBackupContent);
 
     ParsingPackage setHasDomainUrls(boolean hasDomainUrls);
diff --git a/core/java/android/service/controls/Control.java b/core/java/android/service/controls/Control.java
index df18eb6..43a308c 100644
--- a/core/java/android/service/controls/Control.java
+++ b/core/java/android/service/controls/Control.java
@@ -16,6 +16,7 @@
 
 package android.service.controls;
 
+import android.annotation.IntDef;
 import android.annotation.NonNull;
 import android.annotation.Nullable;
 import android.app.PendingIntent;
@@ -28,28 +29,26 @@
 
 import com.android.internal.util.Preconditions;
 
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
 /**
  * Represents a physical object that can be represented by a {@link ControlTemplate} and whose
  * properties may be modified through a {@link ControlAction}.
  *
- * The information is provided by a {@link ControlProviderService} and represents static
+ * The information is provided by a {@link ControlsProviderService} and represents static
  * information (not current status) about the device.
  * <p>
  * Each control needs a unique (per provider) identifier that is persistent across reboots of the
  * system.
  * <p>
  * Each {@link Control} will have a name, a subtitle and will optionally belong to a structure
- * and zone. Some of these values are defined by the user and/or the {@link ControlProviderService}
+ * and zone. Some of these values are defined by the user and/or the {@link ControlsProviderService}
  * and will be used to display the control as well as group them for management.
  * <p>
  * Each object will have an associated {@link DeviceTypes.DeviceType}. This will determine the icons and colors
  * used to display it.
  * <p>
- * The {@link ControlTemplate.TemplateType} provided will be used as a hint when displaying this in
- * non-interactive situations (for example when there's no state to display). This template is not
- * the one that will be shown with the current state and provide interactions. That template is set
- * using {@link ControlState}.
- * <p>
  * An {@link Intent} linking to the provider Activity that expands on this {@link Control} and
  * allows for further actions should be provided.
  * @hide
@@ -57,17 +56,52 @@
 public class Control implements Parcelable {
     private static final String TAG = "Control";
 
-    ;
+    private static final int NUM_STATUS = 5;
+    /**
+     * @hide
+     */
+    @Retention(RetentionPolicy.SOURCE)
+    @IntDef({
+            STATUS_UNKNOWN,
+            STATUS_OK,
+            STATUS_NOT_FOUND,
+            STATUS_ERROR,
+            STATUS_DISABLED,
+    })
+    public @interface Status {};
+
+    public static final int STATUS_UNKNOWN = 0;
+
+    /**
+     * The device corresponding to the {@link Control} is responding correctly.
+     */
+    public static final int STATUS_OK = 1;
+
+    /**
+     * The device corresponding to the {@link Control} cannot be found or was removed.
+     */
+    public static final int STATUS_NOT_FOUND = 2;
+
+    /**
+     * The device corresponding to the {@link Control} is in an error state.
+     */
+    public static final int STATUS_ERROR = 3;
+
+    /**
+     * The {@link Control} is currently disabled.
+     */
+    public static final int STATUS_DISABLED = 4;
 
     private final @NonNull String mControlId;
-    private final @DeviceTypes.DeviceType
-    int mDeviceType;
+    private final @DeviceTypes.DeviceType int mDeviceType;
     private final @NonNull CharSequence mTitle;
     private final @NonNull CharSequence mSubtitle;
     private final @Nullable CharSequence mStructure;
     private final @Nullable CharSequence mZone;
     private final @NonNull PendingIntent mAppIntent;
-    private final @ControlTemplate.TemplateType int mPrimaryType;
+    private final @Status int mStatus;
+    private final @NonNull ControlTemplate mControlTemplate;
+    private final @NonNull CharSequence mStatusText;
 
     /**
      * @param controlId the unique persistent identifier for this object.
@@ -79,7 +113,6 @@
      * @param zone
      * @param appIntent a {@link PendingIntent} linking to a page to interact with the
      *                  corresponding device.
-     * @param primaryType the primary template for this type.
      */
     public Control(@NonNull String controlId,
             @DeviceTypes.DeviceType int deviceType,
@@ -88,11 +121,15 @@
             @Nullable CharSequence structure,
             @Nullable CharSequence zone,
             @NonNull PendingIntent appIntent,
-            int primaryType) {
+            @Status int status,
+            @NonNull ControlTemplate controlTemplate,
+            @NonNull CharSequence statusText) {
         Preconditions.checkNotNull(controlId);
         Preconditions.checkNotNull(title);
         Preconditions.checkNotNull(subtitle);
         Preconditions.checkNotNull(appIntent);
+        Preconditions.checkNotNull(controlTemplate);
+        Preconditions.checkNotNull(statusText);
         mControlId = controlId;
         if (!DeviceTypes.validDeviceType(deviceType)) {
             Log.e(TAG, "Invalid device type:" + deviceType);
@@ -105,7 +142,14 @@
         mStructure = structure;
         mZone = zone;
         mAppIntent = appIntent;
-        mPrimaryType = primaryType;
+        if (status < 0 || status >= NUM_STATUS) {
+            mStatus = STATUS_UNKNOWN;
+            Log.e(TAG, "Status unknown:" + status);
+        } else {
+            mStatus = status;
+        }
+        mControlTemplate = controlTemplate;
+        mStatusText = statusText;
     }
 
     public Control(Parcel in) {
@@ -124,7 +168,9 @@
             mZone = null;
         }
         mAppIntent = PendingIntent.CREATOR.createFromParcel(in);
-        mPrimaryType = in.readInt();
+        mStatus = in.readInt();
+        mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in);
+        mStatusText = in.readCharSequence();
     }
 
     @NonNull
@@ -162,9 +208,19 @@
         return mAppIntent;
     }
 
-    @android.service.controls.templates.ControlTemplate.TemplateType
-    public int getPrimaryType() {
-        return mPrimaryType;
+    @Status
+    public int getStatus() {
+        return mStatus;
+    }
+
+    @NonNull
+    public ControlTemplate getControlTemplate() {
+        return mControlTemplate;
+    }
+
+    @NonNull
+    public CharSequence getStatusText() {
+        return mStatusText;
     }
 
     @Override
@@ -191,7 +247,9 @@
             dest.writeByte((byte) 0);
         }
         mAppIntent.writeToParcel(dest, flags);
-        dest.writeInt(mPrimaryType);
+        dest.writeInt(mStatus);
+        mControlTemplate.writeToParcel(dest, flags);
+        dest.writeCharSequence(mStatusText);
     }
 
     public static final Creator<Control> CREATOR = new Creator<Control>() {
@@ -209,32 +267,39 @@
     /**
      * Builder class for {@link Control}.
      *
-     * This class facilitates the creation of {@link Control}. It provides the following
-     * defaults for non-optional parameters:
+     * This class facilitates the creation of {@link Control} with no state.
+     * It provides the following defaults for non-optional parameters:
      * <ul>
      *     <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN}
      *     <li> Title: {@code ""}
      *     <li> Subtitle: {@code ""}
-     *     <li> Primary template: {@link ControlTemplate#TYPE_NONE}
+     * </ul>
+     * This fixes the values relating to state of the {@link Control} as required by
+     * {@link ControlsProviderService#onLoad}:
+     * <ul>
+     *     <li> Status: {@link Status#STATUS_UNKNOWN}
+     *     <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
+     *     <li> Status text: {@code ""}
      * </ul>
      */
-    public static class Builder {
-        private static final String TAG = "Control.Builder";
-        private @NonNull String mControlId;
-        private @DeviceTypes.DeviceType
-        int mDeviceType = DeviceTypes.TYPE_UNKNOWN;
-        private @NonNull CharSequence mTitle = "";
-        private @NonNull CharSequence mSubtitle = "";
-        private @Nullable CharSequence mStructure;
-        private @Nullable CharSequence mZone;
-        private @NonNull PendingIntent mAppIntent;
-        private @ControlTemplate.TemplateType int mPrimaryType = ControlTemplate.TYPE_NONE;
+    public static class StatelessBuilder {
+        private static final String TAG = "StatelessBuilder";
+        protected @NonNull String mControlId;
+        protected @DeviceTypes.DeviceType int mDeviceType = DeviceTypes.TYPE_UNKNOWN;
+        protected @NonNull CharSequence mTitle = "";
+        protected @NonNull CharSequence mSubtitle = "";
+        protected @Nullable CharSequence mStructure;
+        protected @Nullable CharSequence mZone;
+        protected @NonNull PendingIntent mAppIntent;
+        protected @Status int mStatus = STATUS_UNKNOWN;
+        protected @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE;
+        protected @NonNull CharSequence mStatusText = "";
 
         /**
          * @param controlId the identifier for the {@link Control}.
          * @param appIntent the pending intent linking to the device Activity.
          */
-        public Builder(@NonNull String controlId,
+        public StatelessBuilder(@NonNull String controlId,
                 @NonNull PendingIntent appIntent) {
             Preconditions.checkNotNull(controlId);
             Preconditions.checkNotNull(appIntent);
@@ -243,10 +308,10 @@
         }
 
         /**
-         * Creates a {@link Builder} using an existing {@link Control} as a base.
+         * Creates a {@link StatelessBuilder} using an existing {@link Control} as a base.
          * @param control base for the builder.
          */
-        public Builder(@NonNull Control control) {
+        public StatelessBuilder(@NonNull Control control) {
             Preconditions.checkNotNull(control);
             mControlId = control.mControlId;
             mDeviceType = control.mDeviceType;
@@ -255,7 +320,6 @@
             mStructure = control.mStructure;
             mZone = control.mZone;
             mAppIntent = control.mAppIntent;
-            mPrimaryType = control.mPrimaryType;
         }
 
         /**
@@ -263,14 +327,14 @@
          * @return {@code this}
          */
         @NonNull
-        public Builder setControlId(@NonNull String controlId) {
+        public StatelessBuilder setControlId(@NonNull String controlId) {
             Preconditions.checkNotNull(controlId);
             mControlId = controlId;
             return this;
         }
 
         @NonNull
-        public Builder setDeviceType(@DeviceTypes.DeviceType int deviceType) {
+        public StatelessBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) {
             if (!DeviceTypes.validDeviceType(deviceType)) {
                 Log.e(TAG, "Invalid device type:" + deviceType);
                 mDeviceType = DeviceTypes.TYPE_UNKNOWN;
@@ -285,27 +349,27 @@
          * @return {@code this}
          */
         @NonNull
-        public Builder setTitle(@NonNull CharSequence title) {
+        public StatelessBuilder setTitle(@NonNull CharSequence title) {
             Preconditions.checkNotNull(title);
             mTitle = title;
             return this;
         }
 
         @NonNull
-        public Builder setSubtitle(@NonNull CharSequence subtitle) {
+        public StatelessBuilder setSubtitle(@NonNull CharSequence subtitle) {
             Preconditions.checkNotNull(subtitle);
             mSubtitle = subtitle;
             return this;
         }
 
         @NonNull
-        public Builder setStructure(@Nullable CharSequence structure) {
+        public StatelessBuilder setStructure(@Nullable CharSequence structure) {
             mStructure = structure;
             return this;
         }
 
         @NonNull
-        public Builder setZone(@Nullable CharSequence zone) {
+        public StatelessBuilder setZone(@Nullable CharSequence zone) {
             mZone = zone;
             return this;
         }
@@ -315,23 +379,13 @@
          * @return {@code this}
          */
         @NonNull
-        public Builder setAppIntent(@NonNull PendingIntent appIntent) {
+        public StatelessBuilder setAppIntent(@NonNull PendingIntent appIntent) {
             Preconditions.checkNotNull(appIntent);
             mAppIntent = appIntent;
             return this;
         }
 
         /**
-         * @param type type to use as default in the {@link Control}
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setPrimaryType(@ControlTemplate.TemplateType int type) {
-            mPrimaryType = type;
-            return this;
-        }
-
-        /**
          * Build a {@link Control}
          * @return a valid {@link Control}
          */
@@ -344,7 +398,108 @@
                     mStructure,
                     mZone,
                     mAppIntent,
-                    mPrimaryType);
+                    mStatus,
+                    mControlTemplate,
+                    mStatusText);
+        }
+    }
+
+    public static class StatefulBuilder extends StatelessBuilder {
+        private static final String TAG = "StatefulBuilder";
+
+        /**
+         * @param controlId the identifier for the {@link Control}.
+         * @param appIntent the pending intent linking to the device Activity.
+         */
+        public StatefulBuilder(@NonNull String controlId,
+                @NonNull PendingIntent appIntent) {
+            super(controlId, appIntent);
+        }
+
+        public StatefulBuilder(@NonNull Control control) {
+            super(control);
+            mStatus = control.mStatus;
+            mControlTemplate = control.mControlTemplate;
+            mStatusText = control.mStatusText;
+        }
+
+        /**
+         * @param controlId the identifier for the {@link Control}.
+         * @return {@code this}
+         */
+        @NonNull
+        public StatefulBuilder setControlId(@NonNull String controlId) {
+            super.setControlId(controlId);
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setDeviceType(@DeviceTypes.DeviceType int deviceType) {
+            super.setDeviceType(deviceType);
+            return this;
+        }
+
+        /**
+         * @param title the user facing name of the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public StatefulBuilder setTitle(@NonNull CharSequence title) {
+            super.setTitle(title);
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setSubtitle(@NonNull CharSequence subtitle) {
+            super.setSubtitle(subtitle);
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setStructure(@Nullable CharSequence structure) {
+            super.setStructure(structure);
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setZone(@Nullable CharSequence zone) {
+            super.setZone(zone);
+            return this;
+        }
+
+        /**
+         * @param appIntent an {@link Intent} linking to an Activity for the {@link Control}
+         * @return {@code this}
+         */
+        @NonNull
+        public StatefulBuilder setAppIntent(@NonNull PendingIntent appIntent) {
+            super.setAppIntent(appIntent);
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setStatus(@Status int status) {
+            if (status < 0 || status >= NUM_STATUS) {
+                mStatus = STATUS_UNKNOWN;
+                Log.e(TAG, "Status unknown:" + status);
+            } else {
+                mStatus = status;
+            }
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setControlTemplate(@NonNull ControlTemplate controlTemplate) {
+            Preconditions.checkNotNull(controlTemplate);
+            mControlTemplate = controlTemplate;
+            return this;
+        }
+
+        @NonNull
+        public StatefulBuilder setStatusText(@NonNull CharSequence statusText) {
+            Preconditions.checkNotNull(statusText);
+            mStatusText = statusText;
+            return this;
         }
     }
 }
diff --git a/core/java/android/service/controls/ControlState.aidl b/core/java/android/service/controls/ControlState.aidl
deleted file mode 100644
index 520d85b..0000000
--- a/core/java/android/service/controls/ControlState.aidl
+++ /dev/null
@@ -1,19 +0,0 @@
-/*
- * Copyright (c) 2019, 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.controls;
-
-parcelable ControlState;
\ No newline at end of file
diff --git a/core/java/android/service/controls/ControlState.java b/core/java/android/service/controls/ControlState.java
deleted file mode 100644
index 998fb54..0000000
--- a/core/java/android/service/controls/ControlState.java
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- * Copyright (C) 2019 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.controls;
-
-import android.annotation.IntDef;
-import android.annotation.NonNull;
-import android.annotation.Nullable;
-import android.app.PendingIntent;
-import android.os.Parcel;
-import android.os.Parcelable;
-import android.service.controls.templates.ControlTemplate;
-import android.util.Log;
-
-import com.android.internal.util.Preconditions;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-
-/**
- * Current state for a {@link Control}.
- *
- * Collects information to render the current state of a {@link Control} as well as possible action
- * that can be performed on it.
- * <p>
- * Additionally, this object is used to modify elements from the {@link Control} such as device
- * type, and intents. This information will last until it is again modified by a
- * {@link ControlState}.
- * @hide
- */
-public final class ControlState implements Parcelable {
-
-    private static final String TAG = "ControlState";
-
-    /**
-     * @hide
-     */
-    @Retention(RetentionPolicy.SOURCE)
-    @IntDef({
-            STATUS_OK,
-            STATUS_NOT_FOUND,
-            STATUS_ERROR,
-            STATUS_DISABLED,
-    })
-    public @interface Status {};
-
-    /**
-     * The device corresponding to the {@link Control} is responding correctly.
-     */
-    public static final int STATUS_OK = 0;
-
-    /**
-     * The device corresponding to the {@link Control} cannot be found or was removed.
-     */
-    public static final int STATUS_NOT_FOUND = 1;
-
-    /**
-     * The device corresponding to the {@link Control} is in an error state.
-     */
-    public static final int STATUS_ERROR = 2;
-
-    /**
-     * The {@link Control} is currently disabled.
-     */
-    public static final int STATUS_DISABLED = 3;
-
-    private final @NonNull String mControlId;
-    private final @DeviceTypes.DeviceType int mDeviceType;
-    private final @Status int mStatus;
-    private final @NonNull ControlTemplate mControlTemplate;
-    private final @NonNull CharSequence mStatusText;
-    private final @Nullable PendingIntent mAppIntent;
-
-    /**
-     * @param controlId the identifier of the {@link Control} this object refers to.
-     * @param status the current status of the {@link Control}.
-     * @param deviceType the {@link DeviceTypes.DeviceType} to replace the one set in the
-     *                   {@link Control} or set in the last {@link ControlState}. In order to keep
-     *                   the current device type for this {@link Control}, the old value must be
-     *                   passed.
-     * @param controlTemplate the template to be used to render the {@link Control}. This can be
-     *                        of a different {@link ControlTemplate.TemplateType} than the
-     *                        one defined in {@link Control#getPrimaryType}
-     * @param statusText the user facing text describing the current status.
-     * @param appIntent the {@link PendingIntent} to replace the one set in the {@link Control} or
-     *                  set in the last {@link ControlState}. Pass {@code null} to use the last
-     *                  value set for this {@link Control}.
-     */
-    public ControlState(@NonNull String controlId,
-            @DeviceTypes.DeviceType int deviceType,
-            @Status int status,
-            @NonNull ControlTemplate controlTemplate,
-            @NonNull CharSequence statusText,
-            @Nullable PendingIntent appIntent) {
-        Preconditions.checkNotNull(controlId);
-        Preconditions.checkNotNull(controlTemplate);
-        Preconditions.checkNotNull(statusText);
-        mControlId = controlId;
-        if (!DeviceTypes.validDeviceType(deviceType)) {
-            Log.e(TAG, "Invalid device type:" + deviceType);
-            mDeviceType = DeviceTypes.TYPE_UNKNOWN;
-        } else {
-            mDeviceType = deviceType;
-        }
-        mStatus = status;
-        mControlTemplate = controlTemplate;
-        mStatusText = statusText;
-        mAppIntent = appIntent;
-    }
-
-    ControlState(Parcel in) {
-        mControlId = in.readString();
-        mDeviceType = in.readInt();
-        mStatus = in.readInt();
-        mControlTemplate = ControlTemplate.CREATOR.createFromParcel(in);
-        mStatusText = in.readCharSequence();
-        if (in.readByte() == 1) {
-            mAppIntent = PendingIntent.CREATOR.createFromParcel(in);
-        } else {
-            mAppIntent = null;
-        }
-    }
-
-    @Override
-    public int describeContents() {
-        return 0;
-    }
-
-    @NonNull
-    public String getControlId() {
-        return mControlId;
-    }
-
-    @DeviceTypes.DeviceType
-    public int getDeviceType() {
-        return mDeviceType;
-    }
-
-    @Nullable
-    public PendingIntent getAppIntent() {
-        return mAppIntent;
-    }
-
-    @Status
-    public int getStatus() {
-        return mStatus;
-    }
-
-    @NonNull
-    public ControlTemplate getControlTemplate() {
-        return mControlTemplate;
-    }
-
-    @NonNull
-    public CharSequence getStatusText() {
-        return mStatusText;
-    }
-
-    @Override
-    public void writeToParcel(Parcel dest, int flags) {
-        dest.writeString(mControlId);
-        dest.writeInt(mDeviceType);
-        dest.writeInt(mStatus);
-        mControlTemplate.writeToParcel(dest, flags);
-        dest.writeCharSequence(mStatusText);
-        if (mAppIntent != null) {
-            dest.writeByte((byte) 1);
-            mAppIntent.writeToParcel(dest, flags);
-        } else {
-            dest.writeByte((byte) 0);
-        }
-    }
-
-    public static final Creator<ControlState> CREATOR = new Creator<ControlState>() {
-        @Override
-        public ControlState createFromParcel(Parcel source) {
-            return new ControlState(source);
-        }
-
-        @Override
-        public ControlState[] newArray(int size) {
-            return new ControlState[size];
-        }
-    };
-
-    /**
-     * Builder class for {@link ControlState}.
-     *
-     * This class facilitates the creation of {@link ControlState}. It provides the following
-     * defaults for non-optional parameters:
-     * <ul>
-     *     <li> Device type: {@link DeviceTypes#TYPE_UNKNOWN}
-     *     <li> Status: {@link ControlState#STATUS_OK}
-     *     <li> Control template: {@link ControlTemplate#NO_TEMPLATE}
-     *     <li> Status text: {@code ""}
-     * </ul>
-     */
-    public static class Builder {
-        private static final String TAG = "ControlState.Builder";
-
-        private @NonNull String mControlId;
-        private @DeviceTypes.DeviceType
-        int mDeviceType = DeviceTypes.TYPE_UNKNOWN;
-        private @Status int mStatus = STATUS_OK;
-        private @NonNull ControlTemplate mControlTemplate = ControlTemplate.NO_TEMPLATE;
-        private @NonNull CharSequence mStatusText = "";
-        private @Nullable PendingIntent mAppIntent;
-
-        /**
-         * @param controlId the identifier of the {@link Control} that the resulting
-         *                  {@link ControlState} refers to.
-         */
-        public Builder(@NonNull String controlId) {
-            Preconditions.checkNotNull(controlId);
-            mControlId = controlId;
-        }
-
-        /**
-         * Creates a {@link Builder} using an existing {@link ControlState} as a base.
-         * @param controlState base for the builder.
-         */
-        public Builder(@NonNull ControlState controlState) {
-            Preconditions.checkNotNull(controlState);
-            mControlId = controlState.mControlId;
-            mDeviceType = controlState.mDeviceType;
-            mStatus = controlState.mStatus;
-            mControlTemplate = controlState.mControlTemplate;
-            mStatusText = controlState.mStatusText;
-            mAppIntent = controlState.mAppIntent;
-        }
-
-
-        /**
-         * @param controlId the identifier of the {@link Control} for the resulting object.
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setControlId(@NonNull String controlId) {
-            mControlId = controlId;
-            return this;
-        }
-
-        /**
-         * @param deviceType the device type of the {@link Control}.
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setDeviceType(@DeviceTypes.DeviceType int deviceType) {
-            if (!DeviceTypes.validDeviceType(deviceType)) {
-                Log.e(TAG, "Invalid device type:" + deviceType);
-                mDeviceType = DeviceTypes.TYPE_UNKNOWN;
-            } else {
-                mDeviceType = deviceType;
-            }
-            return this;
-        }
-
-        /**
-         * @param status the current status of the {@link Control}
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setStatus(@Status int status) {
-            mStatus = status;
-            return this;
-        }
-
-        /**
-         * @param controlTemplate the template to use when rendering the {@code Control}.
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setControlTemplate(@NonNull ControlTemplate controlTemplate) {
-            Preconditions.checkNotNull(controlTemplate);
-            mControlTemplate = controlTemplate;
-            return this;
-        }
-
-        /**
-         * @param statusText the user-visible description of the status.
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setStatusText(@NonNull CharSequence statusText) {
-            Preconditions.checkNotNull(statusText);
-            mStatusText = statusText;
-            return this;
-        }
-
-        /**
-         * @param appIntent the Pending Intent to replace the one defined in the corresponding
-         *                  {@link Control} or set by the last {@link ControlState}. Pass
-         *                  {@code null} to keep the last value.
-         * @return {@code this}
-         */
-        @NonNull
-        public Builder setAppIntent(@Nullable PendingIntent appIntent) {
-            mAppIntent = appIntent;
-            return this;
-        }
-
-        /**
-         * @return a new {@link ControlState}
-         */
-        public ControlState build() {
-            return new ControlState(mControlId, mDeviceType, mStatus, mControlTemplate, mStatusText,
-                    mAppIntent);
-        }
-
-        /**
-         * Creates a new {@link ControlState.Builder} for the given {@link Control}.
-         *
-         * This will set the corresponding identifier as well as the device type.
-         * @param control the {@link Control} to create a state for.
-         * @return a {@link ControlState.Builder} for a {@link Control}
-         */
-        public static Builder createForControl(Control control) {
-            return new Builder(control.getControlId()).setDeviceType(control.getDeviceType());
-        }
-    }
-}
-
diff --git a/core/java/android/service/controls/ControlsProviderService.java b/core/java/android/service/controls/ControlsProviderService.java
index 8a95f4d..2fd51a1 100644
--- a/core/java/android/service/controls/ControlsProviderService.java
+++ b/core/java/android/service/controls/ControlsProviderService.java
@@ -20,13 +20,21 @@
 import android.annotation.SdkConstant.SdkConstantType;
 import android.app.Service;
 import android.content.Intent;
+import android.os.Binder;
 import android.os.Bundle;
 import android.os.Handler;
 import android.os.IBinder;
 import android.os.Looper;
 import android.os.Message;
+import android.os.RemoteException;
 import android.service.controls.actions.ControlAction;
+import android.service.controls.templates.ControlTemplate;
+import android.text.TextUtils;
+import android.util.Log;
 
+import com.android.internal.util.Preconditions;
+
+import java.util.ArrayList;
 import java.util.List;
 
 /**
@@ -38,8 +46,14 @@
 
     @SdkConstant(SdkConstantType.SERVICE_ACTION)
     public static final String CONTROLS_ACTION = "android.service.controls.ControlsProviderService";
+    public static final String CALLBACK_BUNDLE = "CALLBACK_BUNDLE";
+    public static final String CALLBACK_BINDER = "CALLBACK_BINDER";
+    public static final String CALLBACK_TOKEN = "CALLBACK_TOKEN";
+
+    public final String TAG = getClass().getSimpleName();
 
     private IControlsProviderCallback mCallback;
+    private IBinder mToken;
     private RequestHandler mHandler;
 
     /**
@@ -67,16 +81,80 @@
      */
     public abstract void onAction(@NonNull String controlId, @NonNull ControlAction action);
 
-    protected IControlsProviderCallback getControlsProviderCallback() {
-        return mCallback;
+    /**
+     * Sends a list of the controls available from this service.
+     *
+     * The items in the list must not have state information (as created by
+     * {@link Control.StatelessBuilder}).
+     * @param controls
+     */
+    public void onLoad(@NonNull List<Control> controls) {
+        Preconditions.checkNotNull(controls);
+        List<Control> list = new ArrayList<>();
+        for (Control control: controls) {
+            if (control == null) {
+                Log.e(TAG, "onLoad: null control.");
+            }
+            if (isStateless(control)) {
+                list.add(control);
+            } else {
+                Log.w(TAG, "onLoad: control is not stateless.");
+                list.add(new Control.StatelessBuilder(control).build());
+            }
+        }
+        try {
+            mCallback.onLoad(mToken, list);
+        } catch (RemoteException ex) {
+            ex.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Sends a list of the controls requested by {@link ControlsProviderService#subscribe} with
+     * their state.
+     * @param statefulControls
+     */
+    public void onRefreshState(@NonNull List<Control> statefulControls) {
+        Preconditions.checkNotNull(statefulControls);
+        try {
+            mCallback.onRefreshState(mToken, statefulControls);
+        } catch (RemoteException ex) {
+            ex.rethrowAsRuntimeException();
+        }
+    }
+
+    /**
+     * Sends the response of a command in the specified {@link Control}.
+     * @param controlId
+     * @param response
+     */
+    public void onControlActionResponse(
+            @NonNull String controlId, @ControlAction.ResponseResult int response) {
+        Preconditions.checkNotNull(controlId);
+        if (!ControlAction.isValidResponse(response)) {
+            Log.e(TAG, "Not valid response result: " + response);
+            response = ControlAction.RESPONSE_UNKNOWN;
+        }
+        try {
+            mCallback.onControlActionResponse(mToken, controlId, response);
+        } catch (RemoteException ex) {
+            ex.rethrowAsRuntimeException();
+        }
+    }
+
+    private boolean isStateless(Control control) {
+        return (control.getStatus() == Control.STATUS_UNKNOWN
+                    && control.getControlTemplate().getTemplateType() == ControlTemplate.TYPE_NONE
+                    && TextUtils.isEmpty(control.getStatusText()));
     }
 
     @Override
     public IBinder onBind(Intent intent) {
         mHandler = new RequestHandler(Looper.getMainLooper());
 
-        Bundle bundle = intent.getBundleExtra("CALLBACK_BUNDLE");
-        IBinder callbackBinder = bundle.getBinder("CALLBACK_BINDER");
+        Bundle bundle = intent.getBundleExtra(CALLBACK_BUNDLE);
+        IBinder callbackBinder = bundle.getBinder(CALLBACK_BINDER);
+        mToken = bundle.getBinder(CALLBACK_TOKEN);
         mCallback = IControlsProviderCallback.Stub.asInterface(callbackBinder);
 
         return new IControlsProvider.Stub() {
diff --git a/core/java/android/service/controls/IControlsProviderCallback.aidl b/core/java/android/service/controls/IControlsProviderCallback.aidl
index 3dbb68c..91f6a79 100644
--- a/core/java/android/service/controls/IControlsProviderCallback.aidl
+++ b/core/java/android/service/controls/IControlsProviderCallback.aidl
@@ -17,13 +17,12 @@
 package android.service.controls;
 
 import android.service.controls.Control;
-import android.service.controls.ControlState;
 
 /** @hide */
 oneway interface IControlsProviderCallback {
-    void onLoad(in List<Control> controls);
+    void onLoad(in IBinder token, in List<Control> controls);
 
-    void onRefreshState(in List<ControlState> controlStates);
+    void onRefreshState(in IBinder token, in List<Control> statefulControls);
 
-    void onControlActionResponse(in String controlId, int response);
+    void onControlActionResponse(in IBinder token, in String controlId, int response);
 }
\ No newline at end of file
diff --git a/core/java/android/service/controls/actions/ControlAction.java b/core/java/android/service/controls/actions/ControlAction.java
index 63ae9bd..83d1cf8 100644
--- a/core/java/android/service/controls/actions/ControlAction.java
+++ b/core/java/android/service/controls/actions/ControlAction.java
@@ -23,8 +23,8 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.os.Parcelable;
-import android.service.controls.templates.ControlTemplate;
 import android.service.controls.IControlsProviderCallback;
+import android.service.controls.templates.ControlTemplate;
 
 import com.android.internal.util.Preconditions;
 
@@ -82,11 +82,17 @@
 
     public static final @ActionType int TYPE_COMMAND = 5;
 
+
+    public static final boolean isValidResponse(@ResponseResult int response) {
+        return (response >= 0 && response < NUM_RESPONSE_TYPES);
+    }
+    private static final int NUM_RESPONSE_TYPES = 6;
     /**
      * @hide
      */
     @Retention(RetentionPolicy.SOURCE)
     @IntDef({
+            RESPONSE_UNKNOWN,
             RESPONSE_OK,
             RESPONSE_FAIL,
             RESPONSE_CHALLENGE_ACK,
@@ -95,31 +101,33 @@
     })
     public @interface ResponseResult {};
 
+    public static final @ResponseResult int RESPONSE_UNKNOWN = 0;
+
     /**
      * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
      * the action has been performed. The action may still fail later and the state may not change.
      */
-    public static final @ResponseResult int RESPONSE_OK = 0;
+    public static final @ResponseResult int RESPONSE_OK = 1;
     /**
      * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
      * the action has failed.
      */
-    public static final @ResponseResult int RESPONSE_FAIL = 1;
+    public static final @ResponseResult int RESPONSE_FAIL = 2;
     /**
      * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
      * in order for the action to be performed, acknowledgment from the user is required.
      */
-    public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 2;
+    public static final @ResponseResult int RESPONSE_CHALLENGE_ACK = 3;
     /**
      * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
      * in order for the action to be performed, a PIN is required.
      */
-    public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 3;
+    public static final @ResponseResult int RESPONSE_CHALLENGE_PIN = 4;
     /**
      * Response code for {@link IControlsProviderCallback#onControlActionResponse} indicating that
      * in order for the action to be performed, an alphanumeric passphrase is required.
      */
-    public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 4;
+    public static final @ResponseResult int RESPONSE_CHALLENGE_PASSPHRASE = 5;
 
     /**
      * The {@link ActionType} associated with this class.
diff --git a/core/java/android/service/controls/templates/ControlTemplate.java b/core/java/android/service/controls/templates/ControlTemplate.java
index f39b26e..bf194f8 100644
--- a/core/java/android/service/controls/templates/ControlTemplate.java
+++ b/core/java/android/service/controls/templates/ControlTemplate.java
@@ -23,7 +23,6 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.service.controls.Control;
-import android.service.controls.ControlState;
 import android.service.controls.actions.ControlAction;
 
 import com.android.internal.util.Preconditions;
@@ -34,12 +33,11 @@
 /**
  * An abstract input template for a {@link Control}.
  *
- * Specifies what layout is presented to the user when a {@link ControlState} is assigned to a
- * particular {@link Control}.
+ * Specifies what layout is presented to the user for a given {@link Control}.
  * <p>
  * Some instances of {@link Control} can originate actions (via user interaction) to modify its
- * associated state. The actions available to a given {@link Control} in a particular
- * {@link ControlState} are determined by its {@link ControlTemplate}.
+ * associated state. The actions available to a given {@link Control} are determined by its
+ * {@link ControlTemplate}.
  * @see ControlAction
  * @hide
  */
diff --git a/core/java/android/service/controls/templates/RangeTemplate.java b/core/java/android/service/controls/templates/RangeTemplate.java
index 5624f88..bb79d83 100644
--- a/core/java/android/service/controls/templates/RangeTemplate.java
+++ b/core/java/android/service/controls/templates/RangeTemplate.java
@@ -21,7 +21,6 @@
 import android.os.Bundle;
 import android.os.Parcel;
 import android.service.controls.Control;
-import android.service.controls.ControlState;
 import android.service.controls.actions.FloatAction;
 
 /**
@@ -61,7 +60,7 @@
      * @param templateId the identifier for this template object
      * @param minValue minimum value for the input
      * @param maxValue maximum value for the input
-     * @param currentValue the current value of the {@link ControlState} containing this object.
+     * @param currentValue the current value of the {@link Control} containing this object.
      * @param stepValue minimum value of increments/decrements when interacting with this control.
      * @param formatString a formatting string as per {@link String#format} used to display the
      *                    {@code currentValue}. If {@code null} is passed, the "%.1f" is used.
diff --git a/core/res/res/values/attrs_manifest.xml b/core/res/res/values/attrs_manifest.xml
index 6350bf6..85f7d61 100644
--- a/core/res/res/values/attrs_manifest.xml
+++ b/core/res/res/values/attrs_manifest.xml
@@ -1756,6 +1756,12 @@
 
              The default value is {@code false}. -->
         <attr name="forceQueryable" format="boolean" />
+
+        <!-- If {@code true} indicates that this application is capable of presenting a unified
+             interface representing multiple profiles.
+
+             The default value is {@code false}. -->
+        <attr name="crossProfile" format="boolean" />
     </declare-styleable>
     <!-- The <code>permission</code> tag declares a security permission that can be
          used to control access from other packages to specific components or
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
index 732e8db..99c7dcf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaDevice.java
@@ -17,9 +17,8 @@
 
 import android.content.Context;
 import android.graphics.drawable.Drawable;
-import android.widget.Toast;
-
-import androidx.mediarouter.media.MediaRouter;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 
 import com.android.settingslib.R;
 import com.android.settingslib.bluetooth.BluetoothUtils;
@@ -31,22 +30,28 @@
 
     private static final String TAG = "InfoMediaDevice";
 
-    private MediaRouter.RouteInfo mRouteInfo;
+    private final MediaRoute2Info mRouteInfo;
+    private final MediaRouter2Manager mRouterManager;
+    private final String mPackageName;
 
-    InfoMediaDevice(Context context, MediaRouter.RouteInfo info) {
+    InfoMediaDevice(Context context, MediaRouter2Manager routerManager, MediaRoute2Info info,
+            String packageName) {
         super(context, MediaDeviceType.TYPE_CAST_DEVICE);
+        mRouterManager = routerManager;
         mRouteInfo = info;
+        mPackageName = packageName;
         initDeviceRecord();
     }
 
     @Override
     public String getName() {
-        return mRouteInfo.getName();
+        return mRouteInfo.getName().toString();
     }
 
     @Override
     public String getSummary() {
-        return null;
+        return mRouteInfo.getClientPackageName() != null
+                ? mContext.getString(R.string.bluetooth_active_no_battery_level) : null;
     }
 
     @Override
@@ -63,15 +68,14 @@
 
     @Override
     public boolean connect() {
-        //TODO(b/121083246): use SystemApi to transfer media
         setConnectedRecord();
-        Toast.makeText(mContext, "This is cast device !", Toast.LENGTH_SHORT).show();
-        return false;
+        mRouterManager.selectRoute(mPackageName, mRouteInfo);
+        return true;
     }
 
     @Override
     public void disconnect() {
-        //TODO(b/121083246): disconnected last select device
+        //TODO(b/144535188): disconnected last select device
     }
 
     @Override
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index bc8e2c3..e008cd03 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -17,13 +17,16 @@
 
 import android.app.Notification;
 import android.content.Context;
-import android.util.Log;
-
-import androidx.mediarouter.media.MediaRouteSelector;
-import androidx.mediarouter.media.MediaRouter;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
+import android.text.TextUtils;
 
 import com.android.internal.annotations.VisibleForTesting;
 
+import java.util.List;
+import java.util.concurrent.Executor;
+import java.util.concurrent.Executors;
+
 /**
  * InfoMediaManager provide interface to get InfoMediaDevice list.
  */
@@ -32,62 +35,75 @@
     private static final String TAG = "InfoMediaManager";
 
     @VisibleForTesting
-    final MediaRouterCallback mMediaRouterCallback = new MediaRouterCallback();
+    final RouterManagerCallback mMediaRouterCallback = new RouterManagerCallback();
     @VisibleForTesting
-    MediaRouteSelector mSelector;
+    final Executor mExecutor = Executors.newSingleThreadExecutor();
     @VisibleForTesting
-    MediaRouter mMediaRouter;
+    MediaRouter2Manager mRouterManager;
 
     private String mPackageName;
+    private MediaDevice mCurrentConnectedDevice;
 
-    InfoMediaManager(Context context, String packageName, Notification notification) {
+    public InfoMediaManager(Context context, String packageName, Notification notification) {
         super(context, notification);
 
-        mMediaRouter = MediaRouter.getInstance(context);
-        mPackageName = packageName;
-        mSelector = new MediaRouteSelector.Builder()
-                .addControlCategory(getControlCategoryByPackageName(mPackageName))
-                .build();
+        mRouterManager = MediaRouter2Manager.getInstance(context);
+        if (packageName != null) {
+            mPackageName = packageName;
+        }
     }
 
     @Override
     public void startScan() {
         mMediaDevices.clear();
-        mMediaRouter.addCallback(mSelector, mMediaRouterCallback,
-                MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+        mRouterManager.registerCallback(mExecutor, mMediaRouterCallback);
     }
 
     @VisibleForTesting
     String getControlCategoryByPackageName(String packageName) {
         //TODO(b/117129183): Use package name to get ControlCategory.
         //Since api not ready, return fixed ControlCategory for prototype.
-        return "com.google.android.gms.cast.CATEGORY_CAST/4F8B3483";
+        return "com.google.android.gms.cast.CATEGORY_CAST";
     }
 
     @Override
     public void stopScan() {
-        mMediaRouter.removeCallback(mMediaRouterCallback);
+        mRouterManager.unregisterCallback(mMediaRouterCallback);
     }
 
-    class MediaRouterCallback extends MediaRouter.Callback {
-        @Override
-        public void onRouteAdded(MediaRouter router, MediaRouter.RouteInfo route) {
-            MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route));
-            if (mediaDevice == null) {
-                mediaDevice = new InfoMediaDevice(mContext, route);
-                Log.d(TAG, "onRouteAdded() route : " + route.getName());
-                mMediaDevices.add(mediaDevice);
-                dispatchDeviceAdded(mediaDevice);
+    /**
+     * Get current device that played media.
+     * @return MediaDevice
+     */
+    public MediaDevice getCurrentConnectedDevice() {
+        return mCurrentConnectedDevice;
+    }
+
+    class RouterManagerCallback extends MediaRouter2Manager.Callback {
+
+        private void refreshDevices() {
+            mMediaDevices.clear();
+            mCurrentConnectedDevice = null;
+            for (MediaRoute2Info route : mRouterManager.getAvailableRoutes(mPackageName)) {
+                final MediaDevice device = new InfoMediaDevice(mContext, mRouterManager, route,
+                        mPackageName);
+                if (TextUtils.equals(route.getClientPackageName(), mPackageName)) {
+                    mCurrentConnectedDevice = device;
+                }
+                mMediaDevices.add(device);
             }
+            dispatchDeviceListAdded();
         }
 
         @Override
-        public void onRouteRemoved(MediaRouter router, MediaRouter.RouteInfo route) {
-            final MediaDevice mediaDevice = findMediaDevice(MediaDeviceUtils.getId(route));
-            if (mediaDevice != null) {
-                Log.d(TAG, "onRouteRemoved() route : " + route.getName());
-                mMediaDevices.remove(mediaDevice);
-                dispatchDeviceRemoved(mediaDevice);
+        public void onRoutesAdded(List<MediaRoute2Info> routes) {
+            refreshDevices();
+        }
+
+        @Override
+        public void onControlCategoriesChanged(String packageName, List<String> controlCategories) {
+            if (TextUtils.equals(mPackageName, packageName)) {
+                refreshDevices();
             }
         }
     }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
index 4e16c66..5b4ef3a 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/LocalMediaManager.java
@@ -18,6 +18,7 @@
 import android.app.Notification;
 import android.bluetooth.BluetoothProfile;
 import android.content.Context;
+import android.text.TextUtils;
 import android.util.Log;
 
 import androidx.annotation.IntDef;
@@ -59,6 +60,8 @@
     private Context mContext;
     private BluetoothMediaManager mBluetoothMediaManager;
     private LocalBluetoothManager mLocalBluetoothManager;
+    private InfoMediaManager mInfoMediaManager;
+    private String mPackageName;
 
     @VisibleForTesting
     List<MediaDevice> mMediaDevices = new ArrayList<>();
@@ -87,6 +90,7 @@
 
     public LocalMediaManager(Context context, String packageName, Notification notification) {
         mContext = context;
+        mPackageName = packageName;
         mLocalBluetoothManager =
                 LocalBluetoothManager.getInstance(context, /* onInitCallback= */ null);
         if (mLocalBluetoothManager == null) {
@@ -96,6 +100,7 @@
 
         mBluetoothMediaManager =
                 new BluetoothMediaManager(context, mLocalBluetoothManager, notification);
+        mInfoMediaManager = new InfoMediaManager(context, packageName, notification);
     }
 
     @VisibleForTesting
@@ -104,6 +109,7 @@
         mContext = context;
         mLocalBluetoothManager = localBluetoothManager;
         mBluetoothMediaManager = bluetoothMediaManager;
+        mInfoMediaManager = infoMediaManager;
     }
 
     /**
@@ -126,8 +132,7 @@
             return;
         }
 
-        //TODO(b/121083246): Update it once remote media API is ready.
-        if (mCurrentConnectedDevice != null && !(connectDevice instanceof InfoMediaDevice)) {
+        if (mCurrentConnectedDevice != null) {
             mCurrentConnectedDevice.disconnect();
         }
 
@@ -157,6 +162,10 @@
         mMediaDevices.clear();
         mBluetoothMediaManager.registerCallback(mMediaDeviceCallback);
         mBluetoothMediaManager.startScan();
+        if (!TextUtils.isEmpty(mPackageName)) {
+            mInfoMediaManager.registerCallback(mMediaDeviceCallback);
+            mInfoMediaManager.startScan();
+        }
     }
 
     private void addPhoneDeviceIfNecessary() {
@@ -191,6 +200,10 @@
     public void stopScan() {
         mBluetoothMediaManager.unregisterCallback(mMediaDeviceCallback);
         mBluetoothMediaManager.stopScan();
+        if (!TextUtils.isEmpty(mPackageName)) {
+            mInfoMediaManager.unregisterCallback(mMediaDeviceCallback);
+            mInfoMediaManager.stopScan();
+        }
     }
 
     /**
@@ -253,7 +266,9 @@
                 }
             }
             addPhoneDeviceIfNecessary();
-            mCurrentConnectedDevice = updateCurrentConnectedDevice();
+            final MediaDevice infoMediaDevice = mInfoMediaManager.getCurrentConnectedDevice();
+            mCurrentConnectedDevice = infoMediaDevice != null
+                    ? infoMediaDevice : updateCurrentConnectedDevice();
             updatePhoneMediaDeviceSummary();
             dispatchDeviceListUpdate();
         }
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
index 4b8e706..df6929e 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDeviceUtils.java
@@ -16,8 +16,7 @@
 package com.android.settingslib.media;
 
 import android.bluetooth.BluetoothDevice;
-
-import androidx.mediarouter.media.MediaRouter;
+import android.media.MediaRoute2Info;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
@@ -49,12 +48,12 @@
     }
 
     /**
-     * Use RouteInfo id to represent unique id
+     * Use MediaRoute2Info id to represent unique id
      *
-     * @param route the RouteInfo
-     * @return RouteInfo id
+     * @param route the MediaRoute2Info
+     * @return MediaRoute2Info id
      */
-    public static String getId(MediaRouter.RouteInfo route) {
+    public static String getId(MediaRoute2Info route) {
         return route.getId();
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
new file mode 100644
index 0000000..c9db0d1
--- /dev/null
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaDeviceTest.java
@@ -0,0 +1,98 @@
+/*
+ * Copyright 2019 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.settingslib.media;
+
+import static com.google.common.truth.Truth.assertThat;
+
+import static org.mockito.Mockito.verify;
+import static org.mockito.Mockito.when;
+
+import android.content.Context;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
+
+import com.android.settingslib.R;
+
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.mockito.Mock;
+import org.mockito.MockitoAnnotations;
+import org.robolectric.RobolectricTestRunner;
+import org.robolectric.RuntimeEnvironment;
+
+@RunWith(RobolectricTestRunner.class)
+public class InfoMediaDeviceTest {
+
+    private static final String TEST_PACKAGE_NAME = "com.test.packagename";
+    private static final String TEST_ID = "test_id";
+    private static final String TEST_NAME = "test_name";
+
+    @Mock
+    private MediaRouter2Manager mRouterManager;
+    @Mock
+    private MediaRoute2Info mRouteInfo;
+
+
+    private Context mContext;
+    private InfoMediaDevice mInfoMediaDevice;
+
+    @Before
+    public void setUp() {
+        MockitoAnnotations.initMocks(this);
+        mContext = RuntimeEnvironment.application;
+
+        mInfoMediaDevice = new InfoMediaDevice(mContext, mRouterManager, mRouteInfo,
+                TEST_PACKAGE_NAME);
+    }
+
+    @Test
+    public void getName_shouldReturnName() {
+        when(mRouteInfo.getName()).thenReturn(TEST_NAME);
+
+        assertThat(mInfoMediaDevice.getName()).isEqualTo(TEST_NAME);
+    }
+
+    @Test
+    public void getSummary_clientPackageNameIsNull_returnNull() {
+        when(mRouteInfo.getClientPackageName()).thenReturn(null);
+
+        assertThat(mInfoMediaDevice.getSummary()).isEqualTo(null);
+    }
+
+    @Test
+    public void getSummary_clientPackageNameIsNotNull_returnActive() {
+        when(mRouteInfo.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+        assertThat(mInfoMediaDevice.getSummary())
+                .isEqualTo(mContext.getString(R.string.bluetooth_active_no_battery_level));
+    }
+
+    @Test
+    public void getId_shouldReturnId() {
+        when(mRouteInfo.getId()).thenReturn(TEST_ID);
+
+        assertThat(mInfoMediaDevice.getId()).isEqualTo(TEST_ID);
+    }
+
+    @Test
+    public void connect_shouldSelectRoute() {
+        mInfoMediaDevice.connect();
+
+        verify(mRouterManager).selectRoute(TEST_PACKAGE_NAME, mRouteInfo);
+    }
+}
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
index b11cf69..67f6dd90 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/InfoMediaManagerTest.java
@@ -23,9 +23,8 @@
 import static org.mockito.Mockito.when;
 
 import android.content.Context;
-
-import androidx.mediarouter.media.MediaRouteSelector;
-import androidx.mediarouter.media.MediaRouter;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 
 import org.junit.Before;
 import org.junit.Test;
@@ -35,6 +34,9 @@
 import org.robolectric.RobolectricTestRunner;
 import org.robolectric.RuntimeEnvironment;
 
+import java.util.ArrayList;
+import java.util.List;
+
 @RunWith(RobolectricTestRunner.class)
 public class InfoMediaManagerTest {
 
@@ -42,9 +44,7 @@
     private static final String TEST_ID = "test_id";
 
     @Mock
-    private MediaRouter mMediaRouter;
-    @Mock
-    private MediaRouteSelector mSelector;
+    private MediaRouter2Manager mRouterManager;
 
     private InfoMediaManager mInfoMediaManager;
     private Context mContext;
@@ -55,82 +55,70 @@
         mContext = RuntimeEnvironment.application;
 
         mInfoMediaManager = new InfoMediaManager(mContext, TEST_PACKAGE_NAME, null);
-        mInfoMediaManager.mMediaRouter = mMediaRouter;
-        mInfoMediaManager.mSelector = mSelector;
+        mInfoMediaManager.mRouterManager = mRouterManager;
     }
 
     @Test
     public void stopScan_shouldRemoveCallback() {
         mInfoMediaManager.stopScan();
 
-        verify(mMediaRouter).removeCallback(mInfoMediaManager.mMediaRouterCallback);
+        verify(mRouterManager).unregisterCallback(mInfoMediaManager.mMediaRouterCallback);
     }
 
     @Test
     public void startScan_shouldAddCallback() {
         mInfoMediaManager.startScan();
 
-        verify(mMediaRouter).addCallback(mSelector, mInfoMediaManager.mMediaRouterCallback,
-                MediaRouter.CALLBACK_FLAG_REQUEST_DISCOVERY);
+        verify(mRouterManager).registerCallback(mInfoMediaManager.mExecutor,
+                mInfoMediaManager.mMediaRouterCallback);
     }
 
     @Test
-    public void onRouteAdded_mediaDeviceNotExistInList_addMediaDevice() {
-        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
+    public void onRouteAdded_shouldAddMediaDevice() {
+        final MediaRoute2Info info = mock(MediaRoute2Info.class);
         when(info.getId()).thenReturn(TEST_ID);
+        when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+        final List<MediaRoute2Info> routes = new ArrayList<>();
+        routes.add(info);
+        when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn(routes);
 
         final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
         assertThat(mediaDevice).isNull();
 
-        mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info);
+        mInfoMediaManager.mMediaRouterCallback.onRoutesAdded(routes);
 
         final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
         assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
+        assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
+        assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
     }
 
     @Test
-    public void onRouteAdded_mediaDeviceExistInList_doNothing() {
-        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
+    public void onControlCategoriesChanged_samePackageName_shouldAddMediaDevice() {
+        final MediaRoute2Info info = mock(MediaRoute2Info.class);
         when(info.getId()).thenReturn(TEST_ID);
-        final InfoMediaDevice infoDevice = new InfoMediaDevice(mContext, info);
-        mInfoMediaManager.mMediaDevices.add(infoDevice);
+        when(info.getClientPackageName()).thenReturn(TEST_PACKAGE_NAME);
+
+        final List<MediaRoute2Info> routes = new ArrayList<>();
+        routes.add(info);
+        when(mRouterManager.getAvailableRoutes(TEST_PACKAGE_NAME)).thenReturn(routes);
 
         final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
-        final int size = mInfoMediaManager.mMediaDevices.size();
-        assertThat(mediaDevice).isNotNull();
-
-        mInfoMediaManager.mMediaRouterCallback.onRouteAdded(mMediaRouter, info);
-
-        assertThat(mInfoMediaManager.mMediaDevices).hasSize(size);
-    }
-
-    @Test
-    public void onRouteRemoved_mediaDeviceExistInList_removeMediaDevice() {
-        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
-        when(info.getId()).thenReturn(TEST_ID);
-        final InfoMediaDevice infoDevice = new InfoMediaDevice(mContext, info);
-        mInfoMediaManager.mMediaDevices.add(infoDevice);
-
-        final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
-        assertThat(mediaDevice).isNotNull();
-        assertThat(mInfoMediaManager.mMediaDevices).hasSize(1);
-
-        mInfoMediaManager.mMediaRouterCallback.onRouteRemoved(mMediaRouter, info);
-
-        assertThat(mInfoMediaManager.mMediaDevices).isEmpty();
-    }
-
-    @Test
-    public void onRouteRemoved_mediaDeviceNotExistInList_doNothing() {
-        final MediaRouter.RouteInfo info = mock(MediaRouter.RouteInfo.class);
-        when(info.getId()).thenReturn(TEST_ID);
-
-        final MediaDevice mediaDevice = mInfoMediaManager.findMediaDevice(TEST_ID);
-        final int size = mInfoMediaManager.mMediaDevices.size();
         assertThat(mediaDevice).isNull();
 
-        mInfoMediaManager.mMediaRouterCallback.onRouteRemoved(mMediaRouter, info);
+        mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged(TEST_PACKAGE_NAME, null);
 
-        assertThat(mInfoMediaManager.mMediaDevices).hasSize(size);
+        final MediaDevice infoDevice = mInfoMediaManager.mMediaDevices.get(0);
+        assertThat(infoDevice.getId()).isEqualTo(TEST_ID);
+        assertThat(mInfoMediaManager.getCurrentConnectedDevice()).isEqualTo(infoDevice);
+        assertThat(mInfoMediaManager.mMediaDevices).hasSize(routes.size());
+    }
+
+    @Test
+    public void onControlCategoriesChanged_differentPackageName_doNothing() {
+        mInfoMediaManager.mMediaRouterCallback.onControlCategoriesChanged("com.fake.play", null);
+
+        assertThat(mInfoMediaManager.mMediaDevices).hasSize(0);
     }
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
index 23d2c74..02cb83e 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceTest.java
@@ -22,8 +22,8 @@
 import android.bluetooth.BluetoothClass;
 import android.bluetooth.BluetoothDevice;
 import android.content.Context;
-
-import androidx.mediarouter.media.MediaRouter;
+import android.media.MediaRoute2Info;
+import android.media.MediaRouter2Manager;
 
 import com.android.settingslib.bluetooth.A2dpProfile;
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
@@ -56,6 +56,7 @@
     private static final String ROUTER_ID_1 = "RouterId_1";
     private static final String ROUTER_ID_2 = "RouterId_2";
     private static final String ROUTER_ID_3 = "RouterId_3";
+    private static final String TEST_PACKAGE_NAME = "com.test.playmusic";
     private final BluetoothClass mHeadreeClass =
             new BluetoothClass(BluetoothClass.Device.AUDIO_VIDEO_HEADPHONES);
     private final BluetoothClass mCarkitClass =
@@ -76,11 +77,11 @@
     @Mock
     private LocalBluetoothManager mLocalBluetoothManager;
     @Mock
-    private MediaRouter.RouteInfo mRouteInfo1;
+    private MediaRoute2Info mRouteInfo1;
     @Mock
-    private MediaRouter.RouteInfo mRouteInfo2;
+    private MediaRoute2Info mRouteInfo2;
     @Mock
-    private MediaRouter.RouteInfo mRouteInfo3;
+    private MediaRoute2Info mRouteInfo3;
     @Mock
     private LocalBluetoothProfileManager mProfileManager;
     @Mock
@@ -99,6 +100,7 @@
     private InfoMediaDevice mInfoMediaDevice3;
     private List<MediaDevice> mMediaDevices = new ArrayList<>();
     private PhoneMediaDevice mPhoneMediaDevice;
+    private MediaRouter2Manager mMediaRouter2Manager;
 
     @Before
     public void setUp() {
@@ -134,9 +136,13 @@
         mBluetoothMediaDevice1 = new BluetoothMediaDevice(mContext, mCachedDevice1);
         mBluetoothMediaDevice2 = new BluetoothMediaDevice(mContext, mCachedDevice2);
         mBluetoothMediaDevice3 = new BluetoothMediaDevice(mContext, mCachedDevice3);
-        mInfoMediaDevice1 = new InfoMediaDevice(mContext, mRouteInfo1);
-        mInfoMediaDevice2 = new InfoMediaDevice(mContext, mRouteInfo2);
-        mInfoMediaDevice3 = new InfoMediaDevice(mContext, mRouteInfo3);
+        mMediaRouter2Manager = MediaRouter2Manager.getInstance(mContext);
+        mInfoMediaDevice1 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo1,
+                TEST_PACKAGE_NAME);
+        mInfoMediaDevice2 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo2,
+                TEST_PACKAGE_NAME);
+        mInfoMediaDevice3 = new InfoMediaDevice(mContext, mMediaRouter2Manager, mRouteInfo3,
+                TEST_PACKAGE_NAME);
         mPhoneMediaDevice = new PhoneMediaDevice(mContext, mLocalBluetoothManager);
     }
 
@@ -364,5 +370,4 @@
         assertThat(mMediaDevices.get(5)).isEqualTo(mBluetoothMediaDevice1);
         assertThat(mMediaDevices.get(6)).isEqualTo(mBluetoothMediaDevice2);
     }
-
 }
diff --git a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java
index 1e5545f..30a6ad2 100644
--- a/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java
+++ b/packages/SettingsLib/tests/robotests/src/com/android/settingslib/media/MediaDeviceUtilsTest.java
@@ -21,8 +21,7 @@
 import static org.mockito.Mockito.when;
 
 import android.bluetooth.BluetoothDevice;
-
-import androidx.mediarouter.media.MediaRouter;
+import android.media.MediaRoute2Info;
 
 import com.android.settingslib.bluetooth.CachedBluetoothDevice;
 
@@ -44,7 +43,7 @@
     @Mock
     private BluetoothDevice mBluetoothDevice;
     @Mock
-    private MediaRouter.RouteInfo mRouteInfo;
+    private MediaRoute2Info mRouteInfo;
 
     @Before
     public void setUp() {
diff --git a/services/print/java/com/android/server/print/PrintManagerService.java b/services/print/java/com/android/server/print/PrintManagerService.java
index c9b9f3e..d064f7e 100644
--- a/services/print/java/com/android/server/print/PrintManagerService.java
+++ b/services/print/java/com/android/server/print/PrintManagerService.java
@@ -78,6 +78,7 @@
 import java.util.ArrayList;
 import java.util.Iterator;
 import java.util.List;
+import java.util.Objects;
 
 /**
  * SystemService wrapper for the PrintManager implementation. Publishes
@@ -137,7 +138,7 @@
         @Override
         public Bundle print(String printJobName, IPrintDocumentAdapter adapter,
                 PrintAttributes attributes, String packageName, int appId, int userId) {
-            adapter = Preconditions.checkNotNull(adapter);
+            Objects.requireNonNull(adapter);
             if (!isPrintingEnabled()) {
                 CharSequence disabledMessage = null;
                 DevicePolicyManagerInternal dpmi =
@@ -239,7 +240,7 @@
 
         @Override
         public Icon getCustomPrinterIcon(PrinterId printerId, int userId) {
-            printerId = Preconditions.checkNotNull(printerId);
+            Objects.requireNonNull(printerId);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -349,7 +350,7 @@
                 return;
             }
 
-            service = Preconditions.checkNotNull(service);
+            Objects.requireNonNull(service);
 
             final UserState userState;
             synchronized (mLock) {
@@ -391,7 +392,7 @@
         @Override
         public void createPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
                 int userId) {
-            observer = Preconditions.checkNotNull(observer);
+            Objects.requireNonNull(observer);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -413,7 +414,7 @@
         @Override
         public void destroyPrinterDiscoverySession(IPrinterDiscoveryObserver observer,
                 int userId) {
-            observer = Preconditions.checkNotNull(observer);
+            Objects.requireNonNull(observer);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -435,7 +436,7 @@
         @Override
         public void startPrinterDiscovery(IPrinterDiscoveryObserver observer,
                 List<PrinterId> priorityList, int userId) {
-            observer = Preconditions.checkNotNull(observer);
+            Objects.requireNonNull(observer);
             if (priorityList != null) {
                 priorityList = Preconditions.checkCollectionElementsNotNull(priorityList,
                         "PrinterId");
@@ -460,7 +461,7 @@
 
         @Override
         public void stopPrinterDiscovery(IPrinterDiscoveryObserver observer, int userId) {
-            observer = Preconditions.checkNotNull(observer);
+            Objects.requireNonNull(observer);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -502,7 +503,7 @@
 
         @Override
         public void startPrinterStateTracking(PrinterId printerId, int userId) {
-            printerId = Preconditions.checkNotNull(printerId);
+            Objects.requireNonNull(printerId);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -523,7 +524,7 @@
 
         @Override
         public void stopPrinterStateTracking(PrinterId printerId, int userId) {
-            printerId = Preconditions.checkNotNull(printerId);
+            Objects.requireNonNull(printerId);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -545,7 +546,7 @@
         @Override
         public void addPrintJobStateChangeListener(IPrintJobStateChangeListener listener,
                 int appId, int userId) throws RemoteException {
-            listener = Preconditions.checkNotNull(listener);
+            Objects.requireNonNull(listener);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final int resolvedAppId;
@@ -569,7 +570,7 @@
         @Override
         public void removePrintJobStateChangeListener(IPrintJobStateChangeListener listener,
                 int userId) {
-            listener = Preconditions.checkNotNull(listener);
+            Objects.requireNonNull(listener);
 
             final int resolvedUserId = resolveCallingUserEnforcingPermissions(userId);
             final UserState userState;
@@ -591,7 +592,7 @@
         @Override
         public void addPrintServicesChangeListener(IPrintServicesChangeListener listener,
                 int userId) throws RemoteException {
-            listener = Preconditions.checkNotNull(listener);
+            Objects.requireNonNull(listener);
 
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRINT_SERVICES,
                     null);
@@ -615,7 +616,7 @@
         @Override
         public void removePrintServicesChangeListener(IPrintServicesChangeListener listener,
                 int userId) {
-            listener = Preconditions.checkNotNull(listener);
+            Objects.requireNonNull(listener);
 
             mContext.enforceCallingOrSelfPermission(android.Manifest.permission.READ_PRINT_SERVICES,
                     null);
@@ -640,7 +641,7 @@
         public void addPrintServiceRecommendationsChangeListener(
                 IRecommendationsChangeListener listener, int userId)
                 throws RemoteException {
-            listener = Preconditions.checkNotNull(listener);
+            Objects.requireNonNull(listener);
 
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS, null);
@@ -664,7 +665,7 @@
         @Override
         public void removePrintServiceRecommendationsChangeListener(
                 IRecommendationsChangeListener listener, int userId) {
-            listener = Preconditions.checkNotNull(listener);
+            Objects.requireNonNull(listener);
 
             mContext.enforceCallingOrSelfPermission(
                     android.Manifest.permission.READ_PRINT_SERVICE_RECOMMENDATIONS, null);
@@ -688,7 +689,7 @@
 
         @Override
         public void dump(FileDescriptor fd, PrintWriter pw, String[] args) {
-            fd = Preconditions.checkNotNull(fd);
+            Objects.requireNonNull(fd);
 
             if (!DumpUtils.checkDumpPermission(mContext, LOG_TAG, pw)) return;