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;
/**