Merge "Propagate ancellation signal to cred man service"
diff --git a/core/api/current.txt b/core/api/current.txt
index 5f1ac76..ed67679 100644
--- a/core/api/current.txt
+++ b/core/api/current.txt
@@ -24636,7 +24636,7 @@
     field @NonNull public static final android.os.Parcelable.Creator<android.media.RouteListingPreference.Item> CREATOR;
     field public static final int FLAG_ONGOING_SESSION = 1; // 0x1
     field public static final int FLAG_ONGOING_SESSION_MANAGED = 2; // 0x2
-    field public static final int FLAG_SUGGESTED_ROUTE = 4; // 0x4
+    field public static final int FLAG_SUGGESTED = 4; // 0x4
     field public static final int SELECTION_BEHAVIOR_GO_TO_APP = 2; // 0x2
     field public static final int SELECTION_BEHAVIOR_NONE = 0; // 0x0
     field public static final int SELECTION_BEHAVIOR_TRANSFER = 1; // 0x1
diff --git a/media/java/android/media/RouteListingPreference.java b/media/java/android/media/RouteListingPreference.java
index ab78536..6caedda 100644
--- a/media/java/android/media/RouteListingPreference.java
+++ b/media/java/android/media/RouteListingPreference.java
@@ -259,7 +259,7 @@
         @IntDef(
                 flag = true,
                 prefix = {"FLAG_"},
-                value = {FLAG_ONGOING_SESSION, FLAG_SUGGESTED_ROUTE, FLAG_ONGOING_SESSION_MANAGED})
+                value = {FLAG_ONGOING_SESSION, FLAG_SUGGESTED, FLAG_ONGOING_SESSION_MANAGED})
         public @interface Flags {}
 
         /**
@@ -292,7 +292,7 @@
          * number supported by the UI, the routes listed first in {@link
          * RouteListingPreference#getItems()} will take priority.
          */
-        public static final int FLAG_SUGGESTED_ROUTE = 1 << 2;
+        public static final int FLAG_SUGGESTED = 1 << 2;
 
         /** @hide */
         @Retention(RetentionPolicy.SOURCE)
@@ -399,7 +399,7 @@
          * Returns the flags associated to the route that corresponds to this item.
          *
          * @see #FLAG_ONGOING_SESSION
-         * @see #FLAG_SUGGESTED_ROUTE
+         * @see #FLAG_SUGGESTED
          */
         @Flags
         public int getFlags() {
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
index d222b98..a97cbaf 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/InfoMediaManager.java
@@ -635,8 +635,8 @@
             List<RouteListingPreference.Item> finalizedItemList = new ArrayList<>();
             List<RouteListingPreference.Item> itemList = routeListingPreference.getItems();
             for (RouteListingPreference.Item item : itemList) {
-                //Put suggested devices on the top first before further organization
-                if (item.getFlags() == RouteListingPreference.Item.FLAG_SUGGESTED_ROUTE) {
+                // Put suggested devices on the top first before further organization
+                if (item.getFlags() == RouteListingPreference.Item.FLAG_SUGGESTED) {
                     finalizedItemList.add(0, item);
                 } else {
                     finalizedItemList.add(item);
diff --git a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
index 50f3713..2431080 100644
--- a/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
+++ b/packages/SettingsLib/src/com/android/settingslib/media/MediaDevice.java
@@ -31,7 +31,7 @@
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADPHONES;
 import static android.media.MediaRoute2Info.TYPE_WIRED_HEADSET;
 import static android.media.RouteListingPreference.Item.FLAG_ONGOING_SESSION;
-import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED_ROUTE;
+import static android.media.RouteListingPreference.Item.FLAG_SUGGESTED;
 import static android.media.RouteListingPreference.Item.SELECTION_BEHAVIOR_TRANSFER;
 import static android.media.RouteListingPreference.Item.SUBTEXT_AD_ROUTING_DISALLOWED;
 import static android.media.RouteListingPreference.Item.SUBTEXT_CUSTOM;
@@ -551,7 +551,7 @@
     private static class Api34Impl {
         @DoNotInline
         static boolean isSuggestedDevice(RouteListingPreference.Item item) {
-            return item != null && (item.getFlags() & FLAG_SUGGESTED_ROUTE) != 0;
+            return item != null && (item.getFlags() & FLAG_SUGGESTED) != 0;
         }
 
         @DoNotInline
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 31038cd..04c1c31 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
@@ -259,8 +259,10 @@
         ReflectionHelpers.setStaticField(Build.VERSION.class, "SDK_INT",
                 Build.VERSION_CODES.UPSIDE_DOWN_CAKE);
         final List<RouteListingPreference.Item> preferenceItemList = new ArrayList<>();
-        RouteListingPreference.Item item1 = new RouteListingPreference.Item.Builder(
-                TEST_ID_4).setFlags(RouteListingPreference.Item.FLAG_SUGGESTED_ROUTE).build();
+        RouteListingPreference.Item item1 =
+                new RouteListingPreference.Item.Builder(TEST_ID_4)
+                        .setFlags(RouteListingPreference.Item.FLAG_SUGGESTED)
+                        .build();
         RouteListingPreference.Item item2 = new RouteListingPreference.Item.Builder(
                 TEST_ID_3).build();
         preferenceItemList.add(item1);
diff --git a/services/core/java/com/android/server/pm/UserManagerInternal.java b/services/core/java/com/android/server/pm/UserManagerInternal.java
index a9edce1..3cbaebe 100644
--- a/services/core/java/com/android/server/pm/UserManagerInternal.java
+++ b/services/core/java/com/android/server/pm/UserManagerInternal.java
@@ -64,11 +64,12 @@
     })
     public @interface UserAssignmentResult {}
 
-    private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
+    // TODO(b/248408342): Move keep annotation to the method referencing these fields reflectively.
+    @Keep public static final int USER_START_MODE_FOREGROUND = 1;
+    @Keep public static final int USER_START_MODE_BACKGROUND = 2;
+    @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
 
-    /**
-     * Type used to indicate how a user started.
-     */
+    private static final String PREFIX_USER_START_MODE = "USER_START_MODE_";
     @IntDef(flag = false, prefix = {PREFIX_USER_START_MODE}, value = {
             USER_START_MODE_FOREGROUND,
             USER_START_MODE_BACKGROUND,
@@ -76,32 +77,6 @@
     })
     public @interface UserStartMode {}
 
-    // TODO(b/248408342): Move keep annotations below to the method referencing these fields
-    // reflectively.
-
-    /** (Full) user started on foreground (a.k.a. "current user"). */
-    @Keep public static final int USER_START_MODE_FOREGROUND = 1;
-
-    /**
-     * User (full or profile) started on background and is
-     * {@link UserManager#isUserVisible() invisible}.
-     *
-     * <p>This is the "traditional" way of starting a background user, and can be used to start
-     * profiles as well, although starting an invisible profile is not common from the System UI
-     * (it could be done through APIs or adb, though).
-     */
-    @Keep public static final int USER_START_MODE_BACKGROUND = 2;
-
-    /**
-     * User (full or profile) started on background and is
-     * {@link UserManager#isUserVisible() visible}.
-     *
-     * <p>This is the "traditional" way of starting a profile (i.e., when the profile of the current
-     * user is the current foreground user), but it can also be used to start a full user associated
-     * with a display (which is the case on automotives with passenger displays).
-     */
-    @Keep public static final int USER_START_MODE_BACKGROUND_VISIBLE = 3;
-
     public interface UserRestrictionsListener {
         /**
          * Called when a user restriction changes.
diff --git a/services/core/java/com/android/server/pm/UserVisibilityMediator.java b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
index fe8a500..d5cc7ca 100644
--- a/services/core/java/com/android/server/pm/UserVisibilityMediator.java
+++ b/services/core/java/com/android/server/pm/UserVisibilityMediator.java
@@ -42,7 +42,6 @@
 import android.util.EventLog;
 import android.util.IndentingPrintWriter;
 import android.util.IntArray;
-import android.util.Log;
 import android.util.SparseIntArray;
 import android.view.Display;
 
@@ -56,8 +55,6 @@
 import com.android.server.utils.Slogf;
 
 import java.io.PrintWriter;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.concurrent.CopyOnWriteArrayList;
 
 /**
@@ -80,11 +77,11 @@
  */
 public final class UserVisibilityMediator implements Dumpable {
 
-    private static final String TAG = UserVisibilityMediator.class.getSimpleName();
-
-    private static final boolean DBG = Log.isLoggable(TAG, Log.DEBUG);
+    private static final boolean DBG = false; // DO NOT SUBMIT WITH TRUE
     private static final boolean VERBOSE = false; // DO NOT SUBMIT WITH TRUE
 
+    private static final String TAG = UserVisibilityMediator.class.getSimpleName();
+
     private static final String PREFIX_SECONDARY_DISPLAY_MAPPING = "SECONDARY_DISPLAY_MAPPING_";
     public static final int SECONDARY_DISPLAY_MAPPING_NEEDED = 1;
     public static final int SECONDARY_DISPLAY_MAPPING_NOT_NEEDED = 2;
@@ -101,7 +98,7 @@
     })
     public @interface SecondaryDisplayMappingStatus {}
 
-    // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
+    // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
     @VisibleForTesting
     static final int INITIAL_CURRENT_USER_ID = USER_SYSTEM;
 
@@ -135,23 +132,10 @@
     private final SparseIntArray mExtraDisplaysAssignedToUsers;
 
     /**
-     * Mapping of each user that started visible (key) to its profile group id (value).
-     *
-     * <p>It's used to determine not just if the user is visible, but also
-     * {@link #isProfile(int, int) if it's a profile}.
+     * Mapping from each started user to its profile group.
      */
     @GuardedBy("mLock")
-    private final SparseIntArray mStartedVisibleProfileGroupIds = new SparseIntArray();
-
-    /**
-     * List of profiles that have explicitly started invisible.
-     *
-     * <p>Only used for debugging purposes (and set when {@link #DBG} is {@code true}), hence we
-     * don't care about autoboxing.
-     */
-    @GuardedBy("mLock")
-    @Nullable
-    private final List<Integer> mStartedInvisibleProfileUserIds;
+    private final SparseIntArray mStartedProfileGroupIds = new SparseIntArray();
 
     /**
      * Handler user to call listeners
@@ -180,14 +164,9 @@
             mUsersAssignedToDisplayOnStart = null;
             mExtraDisplaysAssignedToUsers = null;
         }
-        mStartedInvisibleProfileUserIds = DBG ? new ArrayList<>(4) : null;
         mHandler = handler;
-        // TODO(b/266158156): might need to change this if boot logic is refactored for HSUM devices
-        mStartedVisibleProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
-
-        if (DBG) {
-            Slogf.i(TAG, "UserVisibilityMediator created with DBG on");
-        }
+        // TODO(b/242195409): might need to change this if boot logic is refactored for HSUM devices
+        mStartedProfileGroupIds.put(INITIAL_CURRENT_USER_ID, INITIAL_CURRENT_USER_ID);
     }
 
     /**
@@ -198,8 +177,6 @@
             int displayId) {
         Preconditions.checkArgument(!isSpecialUserId(userId), "user id cannot be generic: %d",
                 userId);
-        validateUserStartMode(userStartMode);
-
         // This method needs to perform 4 actions:
         //
         // 1. Check if the user can be started given the provided arguments
@@ -247,29 +224,14 @@
 
             visibleUsersBefore = getVisibleUsers();
 
-            // Set current user / started users state
-            switch (userStartMode) {
-                case USER_START_MODE_FOREGROUND:
-                    mCurrentUserId = userId;
-                    // Fallthrough
-                case USER_START_MODE_BACKGROUND_VISIBLE:
-                    if (DBG) {
-                        Slogf.d(TAG, "adding visible user / profile group id mapping (%d -> %d)",
-                                userId, profileGroupId);
-                    }
-                    mStartedVisibleProfileGroupIds.put(userId, profileGroupId);
-                    break;
-                case USER_START_MODE_BACKGROUND:
-                    if (mStartedInvisibleProfileUserIds != null
-                            && isProfile(userId, profileGroupId)) {
-                        Slogf.d(TAG, "adding user %d to list of invisible profiles", userId);
-                        mStartedInvisibleProfileUserIds.add(userId);
-                    }
-                    break;
-                default:
-                    Slogf.wtf(TAG,  "invalid userStartMode passed to assignUserToDisplayOnStart: "
-                            + "%d", userStartMode);
+            // Set current user / profiles state
+            if (userStartMode == USER_START_MODE_FOREGROUND) {
+                mCurrentUserId = userId;
             }
+            if (DBG) {
+                Slogf.d(TAG, "adding user / profile mapping (%d -> %d)", userId, profileGroupId);
+            }
+            mStartedProfileGroupIds.put(userId, profileGroupId);
 
             //  Set user / display state
             switch (mappingResult) {
@@ -335,46 +297,39 @@
         boolean foreground = userStartMode == USER_START_MODE_FOREGROUND;
         if (displayId != DEFAULT_DISPLAY) {
             if (foreground) {
-                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot start "
+                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: cannot start "
                         + "foreground user on secondary display", userId, profileGroupId,
-                        userStartModeToString(userStartMode), displayId);
+                        foreground, displayId);
                 return USER_ASSIGNMENT_RESULT_FAILURE;
             }
             if (!mVisibleBackgroundUsersEnabled) {
-                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: called on "
+                Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %b, %d) failed: called on "
                         + "device that doesn't support multiple users on multiple displays",
-                        userId, profileGroupId, userStartModeToString(userStartMode), displayId);
+                        userId, profileGroupId, foreground, displayId);
                 return USER_ASSIGNMENT_RESULT_FAILURE;
             }
         }
 
         if (isProfile(userId, profileGroupId)) {
             if (displayId != DEFAULT_DISPLAY) {
-                Slogf.w(TAG, "canStartUserLocked(%d, %d, %s, %d) failed: cannot start profile user "
-                        + "on secondary display", userId, profileGroupId,
-                        userStartModeToString(userStartMode), displayId);
+                Slogf.w(TAG, "canStartUserLocked(%d, %d, %b, %d) failed: cannot start profile user "
+                        + "on secondary display", userId, profileGroupId, foreground,
+                        displayId);
                 return USER_ASSIGNMENT_RESULT_FAILURE;
             }
-            switch (userStartMode) {
-                case USER_START_MODE_FOREGROUND:
-                    Slogf.w(TAG, "startUser(%d, %d, %s, %d) failed: cannot start profile user in "
-                            + "foreground", userId, profileGroupId,
-                            userStartModeToString(userStartMode), displayId);
-                    return USER_ASSIGNMENT_RESULT_FAILURE;
-                case USER_START_MODE_BACKGROUND_VISIBLE:
-                    boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
-                    if (!isParentVisibleOnDisplay) {
-                        Slogf.w(TAG, "getUserVisibilityOnStartLocked(%d, %d, %s, %d) failed: cannot"
-                                + " start profile user visible when its parent is not visible in "
-                                + "that display", userId, profileGroupId,
-                                userStartModeToString(userStartMode), displayId);
-                        return USER_ASSIGNMENT_RESULT_FAILURE;
-                    }
-                    return USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE;
-                case USER_START_MODE_BACKGROUND:
-                    return USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
+            if (foreground) {
+                Slogf.w(TAG, "startUser(%d, %d, %b, %d) failed: cannot start profile user in "
+                        + "foreground", userId, profileGroupId, foreground, displayId);
+                return USER_ASSIGNMENT_RESULT_FAILURE;
+            } else {
+                boolean isParentVisibleOnDisplay = isUserVisible(profileGroupId, displayId);
+                if (DBG) {
+                    Slogf.d(TAG, "parent visible on display: %b", isParentVisibleOnDisplay);
+                }
+                return isParentVisibleOnDisplay
+                        ? USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE
+                        : USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE;
             }
-
         }
 
         return foreground || displayId != DEFAULT_DISPLAY
@@ -392,9 +347,8 @@
             if (mVisibleBackgroundUserOnDefaultDisplayAllowed
                     && userStartMode == USER_START_MODE_BACKGROUND_VISIBLE) {
                 int userStartedOnDefaultDisplay = getUserStartedOnDisplay(DEFAULT_DISPLAY);
-                if (userStartedOnDefaultDisplay != USER_NULL
-                        && userStartedOnDefaultDisplay != profileGroupId) {
-                    Slogf.w(TAG, "canAssignUserToDisplayLocked(): cannot start user %d visible on"
+                if (userStartedOnDefaultDisplay != USER_NULL) {
+                    Slogf.w(TAG, "getUserVisibilityOnStartLocked(): cannot start user %d visible on"
                             + " default display because user %d already did so", userId,
                             userStartedOnDefaultDisplay);
                     return SECONDARY_DISPLAY_MAPPING_FAILED;
@@ -500,7 +454,7 @@
                         userId, displayId);
                 return false;
             }
-            if (isStartedVisibleProfileLocked(userId)) {
+            if (isStartedProfile(userId)) {
                 Slogf.w(TAG, "assignUserToExtraDisplay(%d, %d): failed because user is a profile",
                         userId, displayId);
                 return false;
@@ -588,14 +542,10 @@
     @GuardedBy("mLock")
     private void unassignUserFromAllDisplaysOnStopLocked(@UserIdInt int userId) {
         if (DBG) {
-            Slogf.d(TAG, "Removing %d from mStartedVisibleProfileGroupIds (%s)", userId,
-                    mStartedVisibleProfileGroupIds);
+            Slogf.d(TAG, "Removing %d from mStartedProfileGroupIds (%s)", userId,
+                    mStartedProfileGroupIds);
         }
-        mStartedVisibleProfileGroupIds.delete(userId);
-        if (mStartedInvisibleProfileUserIds != null) {
-            Slogf.d(TAG, "Removing %d from list of invisible profiles", userId);
-            mStartedInvisibleProfileUserIds.remove(Integer.valueOf(userId));
-        }
+        mStartedProfileGroupIds.delete(userId);
 
         if (!mVisibleBackgroundUsersEnabled) {
             // Don't need to update mUsersAssignedToDisplayOnStart because methods (such as
@@ -625,8 +575,7 @@
      * See {@link UserManagerInternal#isUserVisible(int)}.
      */
     public boolean isUserVisible(@UserIdInt int userId) {
-        // For optimization (as most devices don't support visible background users), check for
-        // current foreground user and their profiles first
+        // First check current foreground user and their profiles (on main display)
         if (isCurrentUserOrRunningProfileOfCurrentUser(userId)) {
             if (VERBOSE) {
                 Slogf.v(TAG, "isUserVisible(%d): true to current user or profile", userId);
@@ -635,31 +584,19 @@
         }
 
         if (!mVisibleBackgroundUsersEnabled) {
-            if (VERBOSE) {
-                Slogf.v(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
+            if (DBG) {
+                Slogf.d(TAG, "isUserVisible(%d): false for non-current user (or its profiles) when"
                         + " device doesn't support visible background users", userId);
             }
             return false;
         }
 
-
+        boolean visible;
         synchronized (mLock) {
-            int profileGroupId;
-            synchronized (mLock) {
-                profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
-            }
-            if (isProfile(userId, profileGroupId)) {
-                return isUserAssignedToDisplayOnStartLocked(profileGroupId);
-            }
-            return isUserAssignedToDisplayOnStartLocked(userId);
+            visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
         }
-    }
-
-    @GuardedBy("mLock")
-    private boolean isUserAssignedToDisplayOnStartLocked(@UserIdInt int userId) {
-        boolean visible = mUsersAssignedToDisplayOnStart.indexOfKey(userId) >= 0;
-        if (VERBOSE) {
-            Slogf.v(TAG, "isUserAssignedToDisplayOnStartLocked(%d): %b", userId, visible);
+        if (DBG) {
+            Slogf.d(TAG, "isUserVisible(%d): %b from mapping", userId, visible);
         }
         return visible;
     }
@@ -672,8 +609,7 @@
             return false;
         }
 
-        // For optimization (as most devices don't support visible background users), check for
-        // current user and profile first. Current user is always visible on:
+        // Current user is always visible on:
         // - Default display
         // - Secondary displays when device doesn't support visible bg users
         //   - Or when explicitly added (which is checked below)
@@ -695,26 +631,14 @@
         }
 
         synchronized (mLock) {
-            int profileGroupId;
-            synchronized (mLock) {
-                profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+            if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
+                // User assigned to display on start
+                return true;
             }
-            if (isProfile(userId, profileGroupId)) {
-                return isFullUserVisibleOnBackgroundLocked(profileGroupId, displayId);
-            }
-            return isFullUserVisibleOnBackgroundLocked(userId, displayId);
-        }
-    }
 
-    // NOTE: it doesn't check if the userId is a full user, it's up to the caller to check that
-    @GuardedBy("mLock")
-    private boolean isFullUserVisibleOnBackgroundLocked(@UserIdInt int userId, int displayId) {
-        if (mUsersAssignedToDisplayOnStart.get(userId, Display.INVALID_DISPLAY) == displayId) {
-            // User assigned to display on start
-            return true;
+            // Check for extra display assignment
+            return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
         }
-        // Check for extra display assignment
-        return mExtraDisplaysAssignedToUsers.get(displayId, USER_NULL) == userId;
     }
 
     /**
@@ -782,7 +706,7 @@
                     continue;
                 }
                 int userId = mUsersAssignedToDisplayOnStart.keyAt(i);
-                if (!isStartedVisibleProfileLocked(userId)) {
+                if (!isStartedProfile(userId)) {
                     return userId;
                 } else if (DBG) {
                     Slogf.d(TAG, "getUserAssignedToDisplay(%d): skipping user %d because it's "
@@ -815,8 +739,8 @@
         // number of users is too small, the gain is probably not worth the increase on complexity.
         IntArray visibleUsers = new IntArray();
         synchronized (mLock) {
-            for (int i = 0; i < mStartedVisibleProfileGroupIds.size(); i++) {
-                int userId = mStartedVisibleProfileGroupIds.keyAt(i);
+            for (int i = 0; i < mStartedProfileGroupIds.size(); i++) {
+                int userId = mStartedProfileGroupIds.keyAt(i);
                 if (isUserVisible(userId)) {
                     visibleUsers.add(userId);
                 }
@@ -849,7 +773,7 @@
         }
     }
 
-    // TODO(b/266158156): remove this method if not needed anymore
+    // TODO(b/242195409): remove this method if not needed anymore
     /**
      * Nofify all listeners that the system user visibility changed.
      */
@@ -911,9 +835,6 @@
         ipw.println("UserVisibilityMediator");
         ipw.increaseIndent();
 
-        ipw.print("DBG: ");
-        ipw.println(DBG);
-
         synchronized (mLock) {
             ipw.print("Current user id: ");
             ipw.println(mCurrentUserId);
@@ -921,12 +842,8 @@
             ipw.print("Visible users: ");
             ipw.println(getVisibleUsers());
 
-            dumpSparseIntArray(ipw, mStartedVisibleProfileGroupIds,
-                    "started visible user / profile group", "u", "pg");
-            if (mStartedInvisibleProfileUserIds != null) {
-                ipw.print("Profiles started invisible: ");
-                ipw.println(mStartedInvisibleProfileUserIds);
-            }
+            dumpSparseIntArray(ipw, mStartedProfileGroupIds, "started user / profile group",
+                    "u", "pg");
 
             ipw.print("Supports visible background users on displays: ");
             ipw.println(mVisibleBackgroundUsersEnabled);
@@ -1034,25 +951,22 @@
             if (mCurrentUserId == userId) {
                 return true;
             }
-            return mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID)
-                    == mCurrentUserId;
+            return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID) == mCurrentUserId;
         }
     }
 
-    @GuardedBy("mLock")
-    private boolean isStartedVisibleProfileLocked(@UserIdInt int userId) {
-        int profileGroupId = mStartedVisibleProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+    private boolean isStartedProfile(@UserIdInt int userId) {
+        int profileGroupId;
+        synchronized (mLock) {
+            profileGroupId = mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
+        }
         return isProfile(userId, profileGroupId);
     }
 
-    private void validateUserStartMode(@UserStartMode int userStartMode) {
-        switch (userStartMode) {
-            case USER_START_MODE_FOREGROUND:
-            case USER_START_MODE_BACKGROUND:
-            case USER_START_MODE_BACKGROUND_VISIBLE:
-                return;
+    private @UserIdInt int getStartedProfileGroupId(@UserIdInt int userId) {
+        synchronized (mLock) {
+            return mStartedProfileGroupIds.get(userId, NO_PROFILE_GROUP_ID);
         }
-        throw new IllegalArgumentException("Invalid user start mode: " + userStartMode);
     }
 
     private static String secondaryDisplayMappingStatusToString(
diff --git a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
index fbdcc44..3d504ef 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialDescriptionRegistry.java
@@ -19,35 +19,72 @@
 import android.credentials.CredentialDescription;
 import android.credentials.RegisterCredentialDescriptionRequest;
 import android.credentials.UnregisterCredentialDescriptionRequest;
+import android.service.credentials.CredentialEntry;
 import android.util.SparseArray;
 
+import com.android.internal.annotations.GuardedBy;
+
 import java.util.HashMap;
 import java.util.HashSet;
+import java.util.List;
 import java.util.Map;
 import java.util.Set;
+import java.util.concurrent.locks.ReentrantLock;
 
 /** Contains information on what CredentialProvider has what provisioned Credential. */
-public class CredentialDescriptionRegistry {
+public final class CredentialDescriptionRegistry {
 
     private static final int MAX_ALLOWED_CREDENTIAL_DESCRIPTIONS = 128;
     private static final int MAX_ALLOWED_ENTRIES_PER_PROVIDER = 16;
-    private static SparseArray<CredentialDescriptionRegistry> sCredentialDescriptionSessionPerUser;
+    @GuardedBy("sLock")
+    private static final SparseArray<CredentialDescriptionRegistry>
+            sCredentialDescriptionSessionPerUser;
+    private static final ReentrantLock sLock;
 
     static {
         sCredentialDescriptionSessionPerUser = new SparseArray<>();
+        sLock = new ReentrantLock();
     }
 
-    // TODO(b/265992655): add a way to update CredentialRegistry when a user is removed.
-    /** Get and/or create a {@link  CredentialDescription} for the given user id. */
-    public static CredentialDescriptionRegistry forUser(int userId) {
-        CredentialDescriptionRegistry session =
-                sCredentialDescriptionSessionPerUser.get(userId, null);
+    /** Represents the results of a given query into the registry. */
+    public static final class FilterResult {
+        final String mPackageName;
+        final List<CredentialEntry> mCredentialEntries;
 
-        if (session == null) {
-            session = new CredentialDescriptionRegistry();
-            sCredentialDescriptionSessionPerUser.put(userId, session);
+        private FilterResult(String packageName,
+                List<CredentialEntry> credentialEntries) {
+            mPackageName = packageName;
+            mCredentialEntries = credentialEntries;
         }
-        return session;
+    }
+
+    /** Get and/or create a {@link  CredentialDescription} for the given user id. */
+    @GuardedBy("sLock")
+    public static CredentialDescriptionRegistry forUser(int userId) {
+        sLock.lock();
+        try {
+            CredentialDescriptionRegistry session =
+                    sCredentialDescriptionSessionPerUser.get(userId, null);
+
+            if (session == null) {
+                session = new CredentialDescriptionRegistry();
+                sCredentialDescriptionSessionPerUser.put(userId, session);
+            }
+            return session;
+        } finally {
+            sLock.unlock();
+        }
+    }
+
+    /** Clears an existing session for a given user identifier. */
+    @GuardedBy("sLock")
+    public static void clearUserSession(int userId) {
+        sLock.lock();
+        try {
+            sCredentialDescriptionSessionPerUser.remove(userId);
+        } finally {
+            sLock.unlock();
+        }
     }
 
     private Map<String, Set<CredentialDescription>> mCredentialDescriptions;
@@ -74,7 +111,7 @@
             int size = mCredentialDescriptions.get(callingPackageName).size();
             mCredentialDescriptions.get(callingPackageName)
                     .addAll(descriptions);
-            mTotalDescriptionCount += size - mCredentialDescriptions.get(callingPackageName).size();
+            mTotalDescriptionCount += mCredentialDescriptions.get(callingPackageName).size() - size;
         }
 
     }
@@ -93,21 +130,33 @@
         }
     }
 
+    /** Returns package names and entries of a CredentialProviders that can satisfy a given
+     * {@link CredentialDescription}. */
+    public Set<FilterResult> getFilteredResultForProvider(String packageName,
+            List<String> flatRequestStrings) {
+        Set<FilterResult> result = new HashSet<>();
+        Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName);
+        for (CredentialDescription containedDescription: currentSet) {
+            if (flatRequestStrings.contains(containedDescription.getFlattenedRequestString())) {
+                result.add(new FilterResult(packageName, containedDescription
+                        .getCredentialEntries()));
+            }
+        }
+        return result;
+    }
+
     /** Returns package names of CredentialProviders that can satisfy a given
      * {@link CredentialDescription}. */
-    public Set<String> filterCredentials(String flatRequestString) {
-
+    public Set<String> getMatchingProviders(Set<String> flatRequestString) {
         Set<String> result = new HashSet<>();
-
-        for (String componentName: mCredentialDescriptions.keySet()) {
-            Set<CredentialDescription> currentSet = mCredentialDescriptions.get(componentName);
-            for (CredentialDescription containedDescription: currentSet) {
-                if (flatRequestString.equals(containedDescription.getFlattenedRequestString())) {
-                    result.add(componentName);
+        for (String packageName: mCredentialDescriptions.keySet()) {
+            Set<CredentialDescription> currentSet = mCredentialDescriptions.get(packageName);
+            for (CredentialDescription containedDescription : currentSet) {
+                if (flatRequestString.contains(containedDescription.getFlattenedRequestString())) {
+                    result.add(packageName);
                 }
             }
         }
-
         return result;
     }
 
diff --git a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
index c9da4b2..ea63c30 100644
--- a/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
+++ b/services/credentials/java/com/android/server/credentials/CredentialManagerService.java
@@ -61,13 +61,11 @@
 import com.android.server.infra.SecureSettingsServiceNameResolver;
 
 import java.util.ArrayList;
-import java.util.Collection;
+import java.util.LinkedHashSet;
 import java.util.List;
 import java.util.Set;
 import java.util.function.Consumer;
-import java.util.function.Function;
 import java.util.stream.Collectors;
-import java.util.stream.Stream;
 
 /**
  * Entry point service for credential management.
@@ -235,6 +233,7 @@
         concatenatedServices.addAll(getOrConstructSystemServiceListLock(userId));
         return concatenatedServices;
     }
+
     public static boolean isCredentialDescriptionApiEnabled() {
         return DeviceConfig.getBoolean(
                 DeviceConfig.NAMESPACE_CREDENTIAL, DEVICE_CONFIG_ENABLE_CREDENTIAL_DESC_API, false);
@@ -243,44 +242,38 @@
     @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
     // to be guarded by 'service.mLock', which is the same as mLock.
     private List<ProviderSession> initiateProviderSessionsWithActiveContainers(
-            RequestSession session,
-            List<String> requestOptions, Set<ComponentName> activeCredentialContainers) {
+            GetRequestSession session,
+            List<String> requestOptions, Set<String> activeCredentialContainers) {
         List<ProviderSession> providerSessions = new ArrayList<>();
         // Invoke all services of a user to initiate a provider session
-        runForUser((service) -> {
-            if (activeCredentialContainers.contains(service.getComponentName())) {
-                ProviderSession providerSession = service
-                        .initiateProviderSessionForRequestLocked(session, requestOptions);
-                if (providerSession != null) {
-                    providerSessions.add(providerSession);
-                }
-            }
-        });
+        for (String packageName: activeCredentialContainers) {
+            providerSessions.add(ProviderRegistryGetSession.createNewSession(
+                    mContext,
+                    UserHandle.getCallingUserId(),
+                    session,
+                    packageName,
+                    requestOptions));
+        }
         return providerSessions;
     }
 
     @NonNull
-    private Set<String> getMatchingProviders(GetCredentialRequest request) {
+    private Set<String> getFilteredResultFromRegistry(List<CredentialOption> options) {
         // Session for active/provisioned credential descriptions;
         CredentialDescriptionRegistry registry = CredentialDescriptionRegistry
                 .forUser(UserHandle.getCallingUserId());
 
         // All requested credential descriptions based on the given request.
         Set<String> requestedCredentialDescriptions =
-                request.getCredentialOptions().stream().map(
-                        credentialOption -> credentialOption
+                options.stream().map(
+                        getCredentialOption -> getCredentialOption
                                         .getCredentialRetrievalData()
                                         .getString(CredentialOption
                                                 .FLATTENED_REQUEST))
                         .collect(Collectors.toSet());
 
         // All requested credential descriptions based on the given request.
-        return requestedCredentialDescriptions.stream()
-                .map(registry::filterCredentials)
-                .flatMap(
-                        (Function<Set<String>, Stream<String>>)
-                                Collection::stream)
-                .collect(Collectors.toSet());
+        return registry.getMatchingProviders(requestedCredentialDescriptions);
     }
 
     @SuppressWarnings("GuardedBy") // ErrorProne requires initiateProviderSessionForRequestLocked
@@ -303,6 +296,13 @@
         return providerSessions;
     }
 
+    @Override
+    @GuardedBy("CredentialDescriptionRegistry.sLock")
+    public void onUserStopped(@NonNull TargetUser user) {
+        super.onUserStopped(user);
+        CredentialDescriptionRegistry.clearUserSession(user.getUserIdentifier());
+    }
+
     private CallingAppInfo constructCallingAppInfo(String packageName, int userId) {
         final PackageInfo packageInfo;
         try {
@@ -340,13 +340,57 @@
                             constructCallingAppInfo(callingPackage, userId),
                             CancellationSignal.fromTransport(cancelTransport));
 
-            // Initiate all provider sessions
-            List<ProviderSession> providerSessions =
-                    initiateProviderSessions(
-                            session,
-                            request.getCredentialOptions().stream()
-                                    .map(CredentialOption::getType)
-                                    .collect(Collectors.toList()));
+            List<ProviderSession> providerSessions;
+
+            if (isCredentialDescriptionApiEnabled()) {
+                List<CredentialOption> optionsThatRequireActiveCredentials =
+                        request.getCredentialOptions().stream()
+                                .filter(getCredentialOption ->
+                                        !TextUtils.isEmpty(getCredentialOption
+                                                .getCredentialRetrievalData().getString(
+                                                CredentialOption
+                                                        .FLATTENED_REQUEST, null)))
+                                .toList();
+
+                List<CredentialOption> optionsThatDoNotRequireActiveCredentials =
+                        request.getCredentialOptions().stream()
+                                .filter(getCredentialOption ->
+                                        TextUtils.isEmpty(getCredentialOption
+                                                .getCredentialRetrievalData().getString(
+                                                        CredentialOption
+                                                                .FLATTENED_REQUEST, null)))
+                                .toList();
+
+                List<ProviderSession> sessionsWithoutRemoteService =
+                        initiateProviderSessionsWithActiveContainers(session,
+                                optionsThatRequireActiveCredentials
+                                        .stream().map(getCredentialOption ->
+                                                getCredentialOption.getCredentialRetrievalData()
+                                                        .getString(CredentialOption
+                                                .FLATTENED_REQUEST))
+                                        .collect(Collectors.toList()),
+                                getFilteredResultFromRegistry(optionsThatRequireActiveCredentials));
+
+                List<ProviderSession> sessionsWithRemoteService = initiateProviderSessions(
+                        session,
+                        optionsThatDoNotRequireActiveCredentials.stream()
+                                .map(CredentialOption::getType)
+                                .collect(Collectors.toList()));
+
+                Set<ProviderSession> all = new LinkedHashSet<>();
+                all.addAll(sessionsWithRemoteService);
+                all.addAll(sessionsWithoutRemoteService);
+
+                providerSessions = new ArrayList<>(all);
+            } else {
+                // Initiate all provider sessions
+                providerSessions =
+                        initiateProviderSessions(
+                                session,
+                                request.getCredentialOptions().stream()
+                                        .map(CredentialOption::getType)
+                                        .collect(Collectors.toList()));
+            }
 
             if (providerSessions.isEmpty()) {
                 try {
@@ -361,6 +405,7 @@
                 }
             }
             providerSessions.forEach(ProviderSession::invokeSession);
+
             return cancelTransport;
         }
 
diff --git a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
index b112649..b20f0cd 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderClearSession.java
@@ -118,8 +118,8 @@
 
     @Override
     protected void invokeSession() {
-        this.mRemoteCredentialService.onClearCredentialState(
-                this.getProviderRequest(),
-                /*callback=*/this);
+        if (mRemoteCredentialService != null) {
+            mRemoteCredentialService.onClearCredentialState(mProviderRequest, this);
+        }
     }
 }
diff --git a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
index cc5a8ab..ade40ad 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderCreateSession.java
@@ -51,6 +51,8 @@
 
     // Key to be used as an entry key for a save entry
     private static final String SAVE_ENTRY_KEY = "save_entry_key";
+    // Key to be used as an entry key for a remote entry
+    private static final String REMOTE_ENTRY_KEY = "remote_entry_key";
 
     @NonNull
     private final Map<String, CreateEntry> mUiSaveEntries = new HashMap<>();
@@ -199,9 +201,9 @@
 
     @Override
     protected void invokeSession() {
-        this.mRemoteCredentialService.onCreateCredential(
-                this.getProviderRequest(),
-                /*callback=*/this);
+        if (mRemoteCredentialService != null) {
+            mRemoteCredentialService.onCreateCredential(mProviderRequest, this);
+        }
     }
 
     private List<Entry> prepareUiSaveEntries(@NonNull List<CreateEntry> saveEntries) {
diff --git a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
index dec3432..3ccead1 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderGetSession.java
@@ -59,14 +59,14 @@
         implements
         RemoteCredentialService.ProviderCallbacks<BeginGetCredentialResponse> {
     private static final String TAG = "ProviderGetSession";
-
-    // Key to be used as an entry key for a credential entry
-    private static final String CREDENTIAL_ENTRY_KEY = "credential_key";
-
     // Key to be used as the entry key for an action entry
     private static final String ACTION_ENTRY_KEY = "action_key";
     // Key to be used as the entry key for the authentication entry
     private static final String AUTHENTICATION_ACTION_ENTRY_KEY = "authentication_action_key";
+    // Key to be used as an entry key for a remote entry
+    private static final String REMOTE_ENTRY_KEY = "remote_entry_key";
+    // Key to be used as an entry key for a credential entry
+    private static final String CREDENTIAL_ENTRY_KEY = "credential_key";
 
     @NonNull
     private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>();
@@ -101,23 +101,8 @@
         return null;
     }
 
-    private static BeginGetCredentialRequest constructQueryPhaseRequest(
-            android.credentials.GetCredentialRequest filteredRequest,
-            CallingAppInfo callingAppInfo
-    ) {
-        return new BeginGetCredentialRequest.Builder(callingAppInfo)
-                .setBeginGetCredentialOptions(
-                        filteredRequest.getCredentialOptions().stream().map(
-                                option -> {
-                                    return new BeginGetCredentialOption(
-                                            option.getType(),
-                                            option.getCandidateQueryData());
-                                }).collect(Collectors.toList()))
-                .build();
-    }
-
     @Nullable
-    private static android.credentials.GetCredentialRequest filterOptions(
+    protected static android.credentials.GetCredentialRequest filterOptions(
             List<String> providerCapabilities,
             android.credentials.GetCredentialRequest clientRequest
     ) {
@@ -142,6 +127,21 @@
         return null;
     }
 
+    private static BeginGetCredentialRequest constructQueryPhaseRequest(
+            android.credentials.GetCredentialRequest filteredRequest,
+            CallingAppInfo callingAppInfo
+    ) {
+        return new BeginGetCredentialRequest.Builder(callingAppInfo)
+                .setBeginGetCredentialOptions(
+                        filteredRequest.getCredentialOptions().stream().map(
+                                option -> {
+                                    return new BeginGetCredentialOption(
+                                            option.getType(),
+                                            option.getCandidateQueryData());
+                                }).collect(Collectors.toList()))
+                .build();
+    }
+
     public ProviderGetSession(Context context,
             CredentialProviderInfo info,
             ProviderInternalCallback<GetCredentialResponse> callbacks,
@@ -232,9 +232,9 @@
 
     @Override
     protected void invokeSession() {
-        this.mRemoteCredentialService.onBeginGetCredential(
-                        this.getProviderRequest(),
-                        /*callback=*/this);
+        if (mRemoteCredentialService != null) {
+            mRemoteCredentialService.onBeginGetCredential(mProviderRequest, this);
+        }
     }
 
     @Override // Call from request session to data to be shown on the UI
@@ -379,6 +379,28 @@
         invokeCallbackOnInternalInvalidState();
     }
 
+    @Nullable
+    protected GetCredentialException maybeGetPendingIntentException(
+            ProviderPendingIntentResponse pendingIntentResponse) {
+        if (pendingIntentResponse == null) {
+            Log.i(TAG, "pendingIntentResponse is null");
+            return null;
+        }
+        if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
+            GetCredentialException exception = PendingIntentResultHandler
+                    .extractGetCredentialException(pendingIntentResponse.getResultData());
+            if (exception != null) {
+                Log.i(TAG, "Pending intent contains provider exception");
+                return exception;
+            }
+        } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
+            return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
+        } else {
+            return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
+        }
+        return null;
+    }
+
     private void onAuthenticationEntrySelected(
             @Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
         //TODO: Other provider intent statuses
@@ -431,28 +453,6 @@
         updateStatusAndInvokeCallback(Status.NO_CREDENTIALS);
     }
 
-    @Nullable
-    private GetCredentialException maybeGetPendingIntentException(
-            ProviderPendingIntentResponse pendingIntentResponse) {
-        if (pendingIntentResponse == null) {
-            Log.i(TAG, "pendingIntentResponse is null");
-            return null;
-        }
-        if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
-            GetCredentialException exception = PendingIntentResultHandler
-                    .extractGetCredentialException(pendingIntentResponse.getResultData());
-            if (exception != null) {
-                Log.i(TAG, "Pending intent contains provider exception");
-                return exception;
-            }
-        } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
-            return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
-        } else {
-            return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
-        }
-        return null;
-    }
-
     /**
      * When an invalid state occurs, e.g. entry mismatch or no response from provider,
      * we send back a TYPE_UNKNOWN error as to the developer.
diff --git a/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
new file mode 100644
index 0000000..461f447
--- /dev/null
+++ b/services/credentials/java/com/android/server/credentials/ProviderRegistryGetSession.java
@@ -0,0 +1,261 @@
+/*
+ * Copyright (C) 2023 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.server.credentials;
+
+import android.annotation.NonNull;
+import android.annotation.Nullable;
+import android.annotation.UserIdInt;
+import android.content.Context;
+import android.content.Intent;
+import android.credentials.CredentialOption;
+import android.credentials.GetCredentialException;
+import android.credentials.GetCredentialRequest;
+import android.credentials.GetCredentialResponse;
+import android.credentials.ui.Entry;
+import android.credentials.ui.GetCredentialProviderData;
+import android.credentials.ui.ProviderData;
+import android.credentials.ui.ProviderPendingIntentResponse;
+import android.service.credentials.CallingAppInfo;
+import android.service.credentials.CredentialEntry;
+import android.service.credentials.CredentialProviderService;
+import android.telecom.Log;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.function.Function;
+import java.util.stream.Collectors;
+import java.util.stream.Stream;
+
+/**
+ * Central provider session that utilizes {@link CredentialDescriptionRegistry} and therefor is able
+ * to bypass having to use a {@link RemoteCredentialService}.
+ *
+ * @hide
+ */
+public class ProviderRegistryGetSession extends ProviderSession<GetCredentialRequest,
+        Set<CredentialDescriptionRegistry.FilterResult>> {
+
+    private static final String TAG = "ProviderRegistryGetSession";
+    private static final String CREDENTIAL_ENTRY_KEY = "credential_key";
+
+    /** Creates a new provider session to be used by the request session. */
+    @Nullable
+    public static ProviderRegistryGetSession createNewSession(
+            @NonNull Context context,
+            @UserIdInt int userId,
+            @NonNull GetRequestSession getRequestSession,
+            @NonNull String credentialProviderPackageName,
+            @NonNull List<String> requestOptions) {
+        return new ProviderRegistryGetSession(
+                context,
+                userId,
+                getRequestSession,
+                getRequestSession.mClientRequest,
+                getRequestSession.mClientAppInfo,
+                credentialProviderPackageName,
+                requestOptions);
+    }
+
+    @NonNull
+    private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>();
+    @NonNull
+    private final CredentialDescriptionRegistry mCredentialDescriptionRegistry;
+    @NonNull
+    private final CallingAppInfo mCallingAppInfo;
+    @NonNull
+    private final String mCredentialProviderPackageName;
+    @NonNull
+    private final GetRequestSession mGetRequestSession;
+    @NonNull
+    private final List<String> mRequestOptions;
+    private List<CredentialEntry> mCredentialEntries;
+
+    protected ProviderRegistryGetSession(@NonNull Context context,
+            @NonNull int userId,
+            @NonNull GetRequestSession session,
+            @NonNull GetCredentialRequest request,
+            @NonNull CallingAppInfo callingAppInfo,
+            @NonNull String servicePackageName,
+            @NonNull List<String> requestOptions) {
+        super(context, null, request, session, userId, null);
+        mGetRequestSession = session;
+        mCredentialDescriptionRegistry = CredentialDescriptionRegistry.forUser(userId);
+        mCallingAppInfo = callingAppInfo;
+        mCredentialProviderPackageName = servicePackageName;
+        mRequestOptions = requestOptions;
+    }
+
+    private List<Entry> prepareUiCredentialEntries(
+            @NonNull List<CredentialEntry> credentialEntries) {
+        Log.i(TAG, "in prepareUiProviderDataWithCredentials");
+        List<Entry> credentialUiEntries = new ArrayList<>();
+
+        // Populate the credential entries
+        for (CredentialEntry credentialEntry : credentialEntries) {
+            String entryId = generateEntryId();
+            mUiCredentialEntries.put(entryId, credentialEntry);
+            Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
+            credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
+                    credentialEntry.getSlice(),
+                    setUpFillInIntent(credentialEntry.getType())));
+        }
+        return credentialUiEntries;
+    }
+
+    private Intent setUpFillInIntent(String type) {
+        Intent intent = new Intent();
+        for (CredentialOption option : mProviderRequest.getCredentialOptions()) {
+            if (option.getType().equals(type)) {
+                intent.putExtra(
+                        CredentialProviderService
+                                .EXTRA_GET_CREDENTIAL_REQUEST,
+                        new android.service.credentials.GetCredentialRequest(
+                                mCallingAppInfo, option));
+                return intent;
+            }
+        }
+        return intent;
+    }
+
+    @Override
+    protected ProviderData prepareUiData() {
+        Log.i(TAG, "In prepareUiData");
+        if (!ProviderSession.isUiInvokingStatus(getStatus())) {
+            Log.i(TAG, "In prepareUiData - provider does not want to show UI: "
+                    + mComponentName.flattenToString());
+            return null;
+        }
+        if (mProviderResponse == null) {
+            Log.i(TAG, "In prepareUiData response null");
+            throw new IllegalStateException("Response must be in completion mode");
+        }
+        return new GetCredentialProviderData.Builder(
+                mComponentName.flattenToString()).setActionChips(null)
+                .setCredentialEntries(prepareUiCredentialEntries(
+                        mProviderResponse.stream().flatMap((Function<CredentialDescriptionRegistry
+                                        .FilterResult,
+                                        Stream<CredentialEntry>>) filterResult ->
+                                        filterResult.mCredentialEntries.stream())
+                                .collect(Collectors.toList())))
+                .build();
+    }
+
+    @Override // Selection call from the request provider
+    protected void onUiEntrySelected(String entryType, String entryKey,
+            ProviderPendingIntentResponse providerPendingIntentResponse) {
+        switch (entryType) {
+            case CREDENTIAL_ENTRY_KEY:
+                CredentialEntry credentialEntry = mUiCredentialEntries.get(entryKey);
+                if (credentialEntry == null) {
+                    Log.i(TAG, "Unexpected credential entry key");
+                    return;
+                }
+                onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
+                break;
+            default:
+                Log.i(TAG, "Unsupported entry type selected");
+        }
+    }
+
+    private void onCredentialEntrySelected(CredentialEntry credentialEntry,
+            ProviderPendingIntentResponse providerPendingIntentResponse) {
+        if (!mCredentialEntries.contains(credentialEntry)) {
+            invokeCallbackWithError("",
+                    "");
+        }
+
+        if (providerPendingIntentResponse != null) {
+            // Check if pending intent has an error
+            GetCredentialException exception = maybeGetPendingIntentException(
+                    providerPendingIntentResponse);
+            if (exception != null) {
+                invokeCallbackWithError(exception.getType(),
+                        exception.getMessage());
+                return;
+            }
+
+            // Check if pending intent has a credential
+            GetCredentialResponse getCredentialResponse = PendingIntentResultHandler
+                    .extractGetCredentialResponse(
+                            providerPendingIntentResponse.getResultData());
+            if (getCredentialResponse != null) {
+                if (mCallbacks != null) {
+                    mCallbacks.onFinalResponseReceived(mComponentName,
+                            getCredentialResponse);
+                }
+                return;
+            }
+
+            Log.i(TAG, "Pending intent response contains no credential, or error");
+        }
+        Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result");
+    }
+
+    @Override
+    public void onProviderResponseSuccess(
+            @Nullable Set<CredentialDescriptionRegistry.FilterResult> response) {
+        // No need to do anything since this class does not rely on a remote service.
+    }
+
+    @Override
+    public void onProviderResponseFailure(int internalErrorCode, @Nullable Exception e) {
+        // No need to do anything since this class does not rely on a remote service.
+    }
+
+    @Override
+    public void onProviderServiceDied(RemoteCredentialService service) {
+        // No need to do anything since this class does not rely on a remote service.
+    }
+
+    @Override
+    protected void invokeSession() {
+        mProviderResponse = mCredentialDescriptionRegistry
+                .getFilteredResultForProvider(mCredentialProviderPackageName,
+                        mRequestOptions);
+        mCredentialEntries = mProviderResponse.stream().flatMap(
+                        (Function<CredentialDescriptionRegistry.FilterResult,
+                                Stream<CredentialEntry>>) filterResult
+                        -> filterResult.mCredentialEntries.stream())
+                .collect(Collectors.toList());
+        setStatus(Status.CREDENTIALS_RECEIVED);
+    }
+
+    @Nullable
+    protected GetCredentialException maybeGetPendingIntentException(
+            ProviderPendingIntentResponse pendingIntentResponse) {
+        if (pendingIntentResponse == null) {
+            android.util.Log.i(TAG, "pendingIntentResponse is null");
+            return null;
+        }
+        if (PendingIntentResultHandler.isValidResponse(pendingIntentResponse)) {
+            GetCredentialException exception = PendingIntentResultHandler
+                    .extractGetCredentialException(pendingIntentResponse.getResultData());
+            if (exception != null) {
+                android.util.Log.i(TAG, "Pending intent contains provider exception");
+                return exception;
+            }
+        } else if (PendingIntentResultHandler.isCancelledResponse(pendingIntentResponse)) {
+            return new GetCredentialException(GetCredentialException.TYPE_USER_CANCELED);
+        } else {
+            return new GetCredentialException(GetCredentialException.TYPE_NO_CREDENTIAL);
+        }
+        return null;
+    }
+}
diff --git a/services/credentials/java/com/android/server/credentials/ProviderSession.java b/services/credentials/java/com/android/server/credentials/ProviderSession.java
index 58596b8..d6f97ff 100644
--- a/services/credentials/java/com/android/server/credentials/ProviderSession.java
+++ b/services/credentials/java/com/android/server/credentials/ProviderSession.java
@@ -41,16 +41,14 @@
         implements RemoteCredentialService.ProviderCallbacks<R> {
 
     private static final String TAG = "ProviderSession";
-    // Key to be used as an entry key for a remote entry
-    protected static final String REMOTE_ENTRY_KEY = "remote_entry_key";
 
     @NonNull protected final Context mContext;
     @NonNull protected final ComponentName mComponentName;
-    @NonNull protected final CredentialProviderInfo mProviderInfo;
-    @NonNull protected final RemoteCredentialService mRemoteCredentialService;
+    @Nullable protected final CredentialProviderInfo mProviderInfo;
+    @Nullable protected final RemoteCredentialService mRemoteCredentialService;
     @NonNull protected final int mUserId;
     @NonNull protected Status mStatus = Status.NOT_STARTED;
-    @NonNull protected final ProviderInternalCallback mCallbacks;
+    @Nullable protected final ProviderInternalCallback mCallbacks;
     @Nullable protected Credential mFinalCredentialResponse;
     @Nullable protected ICancellationSignal mProviderCancellationSignal;
     @NonNull protected final T mProviderRequest;
@@ -113,9 +111,9 @@
 
     protected ProviderSession(@NonNull Context context, @NonNull CredentialProviderInfo info,
             @NonNull T providerRequest,
-            @NonNull ProviderInternalCallback callbacks,
+            @Nullable ProviderInternalCallback callbacks,
             @NonNull int userId,
-            @NonNull RemoteCredentialService remoteCredentialService) {
+            @Nullable RemoteCredentialService remoteCredentialService) {
         mContext = context;
         mProviderInfo = info;
         mProviderRequest = providerRequest;
@@ -181,7 +179,7 @@
         return mComponentName;
     }
 
-    @NonNull
+    @Nullable
     protected RemoteCredentialService getRemoteCredentialService() {
         return mRemoteCredentialService;
     }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
index 8979585..38cf634 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorMUPANDTest.java
@@ -75,8 +75,8 @@
         assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
 
         // Make sure another user cannot be started on default display
-        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE,
-                DEFAULT_DISPLAY);
+        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId,
+                BG_VISIBLE, DEFAULT_DISPLAY);
         assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE,
                 "when user (%d) is starting on default display after it was started by user %d",
                 otherUserId, visibleBgUserId);
@@ -119,8 +119,8 @@
         assertUserCanBeAssignedExtraDisplay(USER_ID, OTHER_SECONDARY_DISPLAY_ID);
 
         // Make sure another user cannot be started on default display
-        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, otherUserId, BG_VISIBLE,
-                DEFAULT_DISPLAY);
+        int result2 = mMediator.assignUserToDisplayOnStart(otherUserId, visibleBgUserId,
+                BG_VISIBLE, DEFAULT_DISPLAY);
         assertStartUserResult(result2, USER_ASSIGNMENT_RESULT_FAILURE,
                 "when user (%d) is starting on default display after it was started by user %d",
                 otherUserId, visibleBgUserId);
@@ -128,6 +128,7 @@
 
         listener.verify();
     }
+  /* TODO: re-add
 
     @Test
     public void
@@ -226,4 +227,5 @@
 
         listener.verify();
     }
+  */
 }
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
index 566084a..5176d68 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorTestCase.java
@@ -44,6 +44,7 @@
 import android.util.IntArray;
 import android.util.Log;
 
+import com.android.internal.util.Preconditions;
 import com.android.server.ExtendedMockitoTestCase;
 
 import org.junit.Before;
@@ -148,12 +149,6 @@
     }
 
     @Test
-    public final void testAssignUserToDisplayOnStart_invalidUserStartMode() {
-        assertThrows(IllegalArgumentException.class, () -> mMediator
-                .assignUserToDisplayOnStart(USER_ID, USER_ID, 666, DEFAULT_DISPLAY));
-    }
-
-    @Test
     public final void testStartFgUser_onSecondaryDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -288,7 +283,7 @@
 
         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                 BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
 
         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
@@ -304,14 +299,14 @@
 
         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                 BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
 
         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
 
         expectNoDisplayAssignedToUser(PROFILE_USER_ID);
         expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
 
-        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
 
         listener.verify();
     }
@@ -337,41 +332,6 @@
     }
 
     @Test
-    public final void testStartBgProfile_onDefaultDisplay_whenParentIsNotStarted()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForNoEvents();
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
-                DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
-
-        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
-        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
-
-        listener.verify();
-    }
-
-    @Test
-    public final void testStartBgProfile_onDefaultDisplay_whenParentIsStartedOnBg()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForNoEvents();
-        startBackgroundUser(PARENT_USER_ID);
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
-                DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
-
-        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
-
-        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
-        expectInitialCurrentUserAssignedToDisplay(DEFAULT_DISPLAY);
-
-        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-
-        listener.verify();
-    }
-
-    @Test
     public final void testStartBgProfile_onSecondaryDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -525,6 +485,8 @@
      * se.
      */
     protected final void startUserInSecondaryDisplay(@UserIdInt int userId, int displayId) {
+        Preconditions.checkArgument(displayId != INVALID_DISPLAY && displayId != DEFAULT_DISPLAY,
+                "must pass a secondary display, not %d", displayId);
         Log.d(TAG, "startUserInSecondaryDisplay(" + userId + ", " + displayId + ")");
         int result = mMediator.assignUserToDisplayOnStart(userId, userId, BG_VISIBLE, displayId);
         if (result != USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE) {
diff --git a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
index f084063..49c6a88 100644
--- a/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
+++ b/services/tests/mockingservicestests/src/com/android/server/pm/UserVisibilityMediatorVisibleBackgroundUserTestCase.java
@@ -108,6 +108,34 @@
     }
 
     @Test
+    public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
+            throws Exception {
+        AsyncUserVisibilityListener listener = addListenerForEvents(
+                onInvisible(INITIAL_CURRENT_USER_ID),
+                onVisible(PARENT_USER_ID),
+                onVisible(PROFILE_USER_ID));
+        startForegroundUser(PARENT_USER_ID);
+
+        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
+                BG_VISIBLE, DEFAULT_DISPLAY);
+        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
+        expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+
+        expectUserIsVisible(PROFILE_USER_ID);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
+        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
+
+        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
+        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
+
+        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
+
+        listener.verify();
+    }
+
+    @Test
     public final void testStartFgUser_onInvalidDisplay() throws Exception {
         AsyncUserVisibilityListener listener = addListenerForNoEvents();
 
@@ -240,83 +268,14 @@
     }
 
     @Test
-    public final void testStartVisibleBgProfile_onDefaultDisplay_whenParentIsCurrentUser()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForEvents(
-                onInvisible(INITIAL_CURRENT_USER_ID),
-                onVisible(PARENT_USER_ID),
-                onVisible(PROFILE_USER_ID));
-        startForegroundUser(PARENT_USER_ID);
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
-                BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_VISIBLE);
-        expectUserCannotBeUnassignedFromDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
-
-        expectUserIsVisible(PROFILE_USER_ID);
-        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, INVALID_DISPLAY);
-        expectUserIsNotVisibleOnDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-        expectUserIsVisibleOnDisplay(PROFILE_USER_ID, DEFAULT_DISPLAY);
-        expectVisibleUsers(PARENT_USER_ID, PROFILE_USER_ID);
-
-        expectDisplayAssignedToUser(PROFILE_USER_ID, DEFAULT_DISPLAY);
-        expectUserAssignedToDisplay(DEFAULT_DISPLAY, PARENT_USER_ID);
-
-        assertUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-
-        listener.verify();
-    }
-
-    @Test
     public final void
-            testStartVisibleBgProfile_onDefaultDisplay_whenParentIsStartedVisibleOnAnotherDisplay()
-            throws Exception {
+            testStartVisibleBgProfile_onDefaultDisplay_whenParentVisibleOnSecondaryDisplay()
+                    throws Exception {
         AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
         startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
 
         int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
                 BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
-
-        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
-        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
-        expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
-
-        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-
-        listener.verify();
-    }
-
-    // Not supported - profiles can only be started on default display
-    @Test
-    public final void
-            testStartVisibleBgProfile_onSecondaryDisplay_whenParentIsStartedVisibleOnThatDisplay()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
-        startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID,
-                BG_VISIBLE, DEFAULT_DISPLAY);
-        assertStartUserResult(result, USER_ASSIGNMENT_RESULT_FAILURE);
-
-        expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
-        expectNoDisplayAssignedToUser(PROFILE_USER_ID);
-        expectUserAssignedToDisplay(OTHER_SECONDARY_DISPLAY_ID, PARENT_USER_ID);
-
-        assertInvisibleUserCannotBeAssignedExtraDisplay(PROFILE_USER_ID, SECONDARY_DISPLAY_ID);
-
-        listener.verify();
-    }
-
-    @Test
-    public final void
-            testStartProfile_onDefaultDisplay_whenParentIsStartedVisibleOnSecondaryDisplay()
-            throws Exception {
-        AsyncUserVisibilityListener listener = addListenerForEvents(onVisible(PARENT_USER_ID));
-        startUserInSecondaryDisplay(PARENT_USER_ID, OTHER_SECONDARY_DISPLAY_ID);
-
-        int result = mMediator.assignUserToDisplayOnStart(PROFILE_USER_ID, PARENT_USER_ID, BG,
-                DEFAULT_DISPLAY);
         assertStartUserResult(result, USER_ASSIGNMENT_RESULT_SUCCESS_INVISIBLE);
 
         expectUserIsNotVisibleAtAll(PROFILE_USER_ID);
diff --git a/telephony/java/android/telephony/CallState.java b/telephony/java/android/telephony/CallState.java
index 51ecfb0..836cb53 100644
--- a/telephony/java/android/telephony/CallState.java
+++ b/telephony/java/android/telephony/CallState.java
@@ -285,12 +285,12 @@
     /**
      * Builder of {@link CallState}
      *
-     * <p>The example below shows how you might create a new {@code CallState}:
+     * <p>The example below shows how you might create a new {@code CallState}. A precise call state
+     * {@link PreciseCallStates} is mandatory to build a CallState.
      *
      * <pre><code>
      *
-     * CallState = new CallState.Builder()
-     *     .setCallState(3)
+     * CallState = new CallState.Builder({@link PreciseCallStates})
      *     .setNetworkType({@link TelephonyManager#NETWORK_TYPE_LTE})
      *     .setCallQuality({@link CallQuality})
      *     .setImsCallSessionId({@link String})
diff --git a/telephony/java/android/telephony/ims/ImsCallProfile.java b/telephony/java/android/telephony/ims/ImsCallProfile.java
index 1ea7fdc..d07edeb 100644
--- a/telephony/java/android/telephony/ims/ImsCallProfile.java
+++ b/telephony/java/android/telephony/ims/ImsCallProfile.java
@@ -27,6 +27,7 @@
 import android.os.Parcel;
 import android.os.Parcelable;
 import android.telecom.VideoProfile;
+import android.telephony.CallState;
 import android.telephony.emergency.EmergencyNumber;
 import android.telephony.emergency.EmergencyNumber.EmergencyCallRouting;
 import android.telephony.emergency.EmergencyNumber.EmergencyServiceCategories;
@@ -78,7 +79,9 @@
     public static final int SERVICE_TYPE_EMERGENCY = 2;
 
     /**
-     * Call type none
+     * This value is returned if there is no valid IMS call type defined for the call. For example,
+     * if an ongoing call is circuit-switched and {@link CallState#getImsCallType()} is called, this
+     * value will be returned.
      */
     public static final int CALL_TYPE_NONE = 0;
     /**