Loading core/java/android/credentials/selection/IntentCreationResult.java 0 → 100644 +155 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.credentials.selection; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; /** * Result of creating a Credential Manager UI intent. * * @hide */ public final class IntentCreationResult { @NonNull private final Intent mIntent; @Nullable private final String mFallbackUiPackageName; @Nullable private final String mOemUiPackageName; @NonNull private final OemUiUsageStatus mOemUiUsageStatus; private IntentCreationResult(@NonNull Intent intent, @Nullable String fallbackUiPackageName, @Nullable String oemUiPackageName, OemUiUsageStatus oemUiUsageStatus) { mIntent = intent; mFallbackUiPackageName = fallbackUiPackageName; mOemUiPackageName = oemUiPackageName; mOemUiUsageStatus = oemUiUsageStatus; } /** Returns the UI intent. */ @NonNull public Intent getIntent() { return mIntent; } /** * Returns the result of attempting to use the config_oemCredentialManagerDialogComponent * as the Credential Manager UI. */ @NonNull public OemUiUsageStatus getOemUiUsageStatus() { return mOemUiUsageStatus; } /** * Returns the package name of the ui component specified in * config_fallbackCredentialManagerDialogComponent, or null if unspecified / not parsable * successfully. */ @Nullable public String getFallbackUiPackageName() { return mFallbackUiPackageName; } /** * Returns the package name of the oem ui component specified in * config_oemCredentialManagerDialogComponent, or null if unspecified / not parsable. */ @Nullable public String getOemUiPackageName() { return mOemUiPackageName; } /** * Result of attempting to use the config_oemCredentialManagerDialogComponent as the Credential * Manager UI. */ public enum OemUiUsageStatus { UNKNOWN, // Success: the UI specified in config_oemCredentialManagerDialogComponent was used to // fulfill the request. SUCCESS, // The config value was not specified (e.g. left empty). OEM_UI_CONFIG_NOT_SPECIFIED, // The config value component was specified but not found (e.g. component doesn't exist or // component isn't a system app). OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND, // The config value component was found but not enabled. OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED, } /** * Builder for {@link IntentCreationResult}. * * @hide */ public static final class Builder { @NonNull private Intent mIntent; @Nullable private String mFallbackUiPackageName = null; @Nullable private String mOemUiPackageName = null; @NonNull private OemUiUsageStatus mOemUiUsageStatus = OemUiUsageStatus.UNKNOWN; public Builder(Intent intent) { mIntent = intent; } /** * Sets the package name of the ui component specified in * config_fallbackCredentialManagerDialogComponent, or null if unspecified / not parsable * successfully. */ @NonNull public Builder setFallbackUiPackageName(@Nullable String fallbackUiPackageName) { mFallbackUiPackageName = fallbackUiPackageName; return this; } /** * Sets the package name of the oem ui component specified in * config_oemCredentialManagerDialogComponent, or null if unspecified / not parsable. */ @NonNull public Builder setOemUiPackageName(@Nullable String oemUiPackageName) { mOemUiPackageName = oemUiPackageName; return this; } /** * Sets the result of attempting to use the config_oemCredentialManagerDialogComponent * as the Credential Manager UI. */ @NonNull public Builder setOemUiUsageStatus(OemUiUsageStatus oemUiUsageStatus) { mOemUiUsageStatus = oemUiUsageStatus; return this; } /** Builds a {@link IntentCreationResult}. */ @NonNull public IntentCreationResult build() { return new IntentCreationResult(mIntent, mFallbackUiPackageName, mOemUiPackageName, mOemUiUsageStatus); } } } core/java/android/credentials/selection/IntentFactory.java +127 −62 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ import android.os.ResultReceiver; import android.text.TextUtils; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; /** Loading @@ -57,48 +59,142 @@ public class IntentFactory { * @hide */ @NonNull public static Intent createCredentialSelectorIntentForAutofill( public static IntentCreationResult createCredentialSelectorIntentForAutofill( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { return createCredentialSelectorIntent(context, requestInfo, return createCredentialSelectorIntentInternal(context, requestInfo, disabledProviderDataList, resultReceiver); } /** * Generate a new launch intent to the Credential Selector UI. * * @param context the CredentialManager system service (only expected caller) * context that may be used to query existence of the key UI * application * @param disabledProviderDataList the list of disabled provider data that when non-empty the * UI should accordingly generate an entry suggesting the user * to navigate to settings and enable them * @param enabledProviderDataList the list of enabled provider that contain options for this * request; the UI should render each option to the user for * selection * @param requestInfo the display information about the given app request * @param resultReceiver used by the UI to send the UI selection result back * @hide */ @NonNull public static IntentCreationResult createCredentialSelectorIntentForCredMan( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<ProviderData> enabledProviderDataList, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { IntentCreationResult result = createCredentialSelectorIntentInternal(context, requestInfo, disabledProviderDataList, resultReceiver); result.getIntent().putParcelableArrayListExtra( ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList); return result; } /** * Generate a new launch intent to the Credential Selector UI. * * @param context the CredentialManager system service (only expected caller) * context that may be used to query existence of the key UI * application * @param disabledProviderDataList the list of disabled provider data that when non-empty the * UI should accordingly generate an entry suggesting the user * to navigate to settings and enable them * @param enabledProviderDataList the list of enabled provider that contain options for this * request; the UI should render each option to the user for * selection * @param requestInfo the display information about the given app request * @param resultReceiver used by the UI to send the UI selection result back */ @VisibleForTesting @NonNull private static Intent createCredentialSelectorIntent( public static Intent createCredentialSelectorIntent( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<ProviderData> enabledProviderDataList, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { return createCredentialSelectorIntentForCredMan(context, requestInfo, enabledProviderDataList, disabledProviderDataList, resultReceiver).getIntent(); } /** * Creates an Intent that cancels any UI matching the given request token id. */ @VisibleForTesting @NonNull public static Intent createCancelUiIntent(@NonNull Context context, @NonNull IBinder requestToken, boolean shouldShowCancellationUi, @NonNull String appPackageName) { Intent intent = new Intent(); setCredentialSelectorUiComponentName(context, intent); IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent); setCredentialSelectorUiComponentName(context, intent, intentResultBuilder); intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST, new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi, appPackageName)); return intent; } /** * Generate a new launch intent to the Credential Selector UI. */ @NonNull private static IntentCreationResult createCredentialSelectorIntentInternal( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { Intent intent = new Intent(); IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent); setCredentialSelectorUiComponentName(context, intent, intentResultBuilder); intent.putParcelableArrayListExtra( ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList); intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo); intent.putExtra( Constants.EXTRA_RESULT_RECEIVER, toIpcFriendlyResultReceiver(resultReceiver)); return intent; return intentResultBuilder.build(); } private static void setCredentialSelectorUiComponentName(@NonNull Context context, @NonNull Intent intent) { @NonNull Intent intent, @NonNull IntentCreationResult.Builder intentResultBuilder) { if (configurableSelectorUiEnabled()) { ComponentName componentName = getOemOverrideComponentName(context); if (componentName == null) { componentName = ComponentName.unflattenFromString(Resources.getSystem().getString( ComponentName componentName = getOemOverrideComponentName(context, intentResultBuilder); ComponentName fallbackUiComponentName = null; try { fallbackUiComponentName = ComponentName.unflattenFromString( Resources.getSystem().getString( com.android.internal.R.string .config_fallbackCredentialManagerDialogComponent)); intentResultBuilder.setFallbackUiPackageName( fallbackUiComponentName.getPackageName()); } catch (Exception e) { Slog.w(TAG, "Fallback CredMan IU not found: " + e); } if (componentName == null) { componentName = fallbackUiComponentName; } intent.setComponent(componentName); } else { ComponentName componentName = ComponentName.unflattenFromString(Resources.getSystem() Loading @@ -113,7 +209,8 @@ public class IntentFactory { * default platform UI component name should be used instead. */ @Nullable private static ComponentName getOemOverrideComponentName(@NonNull Context context) { private static ComponentName getOemOverrideComponentName(@NonNull Context context, @NonNull IntentCreationResult.Builder intentResultBuilder) { ComponentName result = null; String oemComponentString = Resources.getSystem() Loading @@ -121,85 +218,53 @@ public class IntentFactory { com.android.internal.R.string .config_oemCredentialManagerDialogComponent); if (!TextUtils.isEmpty(oemComponentString)) { ComponentName oemComponentName = ComponentName.unflattenFromString( ComponentName oemComponentName = null; try { oemComponentName = ComponentName.unflattenFromString( oemComponentString); } catch (Exception e) { Slog.i(TAG, "Failed to parse OEM component name " + oemComponentString + ": " + e); } if (oemComponentName != null) { try { intentResultBuilder.setOemUiPackageName(oemComponentName.getPackageName()); ActivityInfo info = context.getPackageManager().getActivityInfo( oemComponentName, PackageManager.ComponentInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY)); if (info.enabled && info.exported) { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult .OemUiUsageStatus.SUCCESS); Slog.i(TAG, "Found enabled oem CredMan UI component." + oemComponentString); result = oemComponentName; } else { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult .OemUiUsageStatus.OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED); Slog.i(TAG, "Found enabled oem CredMan UI component but it was not " + "enabled."); } } catch (PackageManager.NameNotFoundException e) { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND); Slog.i(TAG, "Unable to find oem CredMan UI component: " + oemComponentString + "."); } } else { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND); Slog.i(TAG, "Invalid OEM ComponentName format."); } } else { intentResultBuilder.setOemUiUsageStatus( IntentCreationResult.OemUiUsageStatus.OEM_UI_CONFIG_NOT_SPECIFIED); Slog.i(TAG, "Invalid empty OEM component name."); } return result; } /** * Generate a new launch intent to the Credential Selector UI. * * @param context the CredentialManager system service (only expected caller) * context that may be used to query existence of the key UI * application * @param disabledProviderDataList the list of disabled provider data that when non-empty the * UI should accordingly generate an entry suggesting the user * to navigate to settings and enable them * @param enabledProviderDataList the list of enabled provider that contain options for this * request; the UI should render each option to the user for * selection * @param requestInfo the display information about the given app request * @param resultReceiver used by the UI to send the UI selection result back */ @NonNull public static Intent createCredentialSelectorIntent( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<ProviderData> enabledProviderDataList, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { Intent intent = createCredentialSelectorIntent(context, requestInfo, disabledProviderDataList, resultReceiver); intent.putParcelableArrayListExtra( ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList); return intent; } /** * Creates an Intent that cancels any UI matching the given request token id. */ @NonNull public static Intent createCancelUiIntent(@NonNull Context context, @NonNull IBinder requestToken, boolean shouldShowCancellationUi, @NonNull String appPackageName) { Intent intent = new Intent(); setCredentialSelectorUiComponentName(context, intent); intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST, new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi, appPackageName)); return intent; } /** * Convert an instance of a "locally-defined" ResultReceiver to an instance of {@link * android.os.ResultReceiver} itself, which the receiving process will be able to unmarshall. Loading services/credentials/java/com/android/server/credentials/CreateRequestSession.java +2 −1 Original line number Diff line number Diff line Loading @@ -112,7 +112,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS), /*defaultProviderId=*/flattenedPrimaryProviders, /*isShowAllOptionsRequested=*/ false), providerDataList); providerDataList, mRequestSessionMetric); mClientCallback.onPendingIntent(mPendingIntent); } catch (RemoteException e) { mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); Loading services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +20 −9 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Intent; import android.credentials.CredentialManager; import android.credentials.CredentialProviderInfo; import android.credentials.selection.DisabledProviderData; import android.credentials.selection.IntentCreationResult; import android.credentials.selection.IntentFactory; import android.credentials.selection.ProviderData; import android.credentials.selection.RequestInfo; Loading @@ -37,6 +38,8 @@ import android.os.ResultReceiver; import android.os.UserHandle; import android.service.credentials.CredentialProviderInfoFactory; import com.android.server.credentials.metrics.RequestSessionMetric; import java.util.ArrayList; import java.util.HashSet; import java.util.List; Loading Loading @@ -159,7 +162,8 @@ public class CredentialManagerUi { * @param providerDataList the list of provider data from remote providers */ public PendingIntent createPendingIntent( RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) { RequestInfo requestInfo, ArrayList<ProviderData> providerDataList, RequestSessionMetric requestSessionMetric) { List<CredentialProviderInfo> allProviders = CredentialProviderInfoFactory.getCredentialProviderServices( mContext, Loading @@ -174,10 +178,12 @@ public class CredentialManagerUi { .map(disabledProvider -> new DisabledProviderData( disabledProvider.getComponentName().flattenToString())).toList(); Intent intent; intent = IntentFactory.createCredentialSelectorIntent( mContext, requestInfo, providerDataList, IntentCreationResult intentCreationResult = IntentFactory .createCredentialSelectorIntentForCredMan(mContext, requestInfo, providerDataList, new ArrayList<>(disabledProviderDataList), mResultReceiver); requestSessionMetric.collectUiConfigurationResults( mContext, intentCreationResult, mUserId); Intent intent = intentCreationResult.getIntent(); intent.setAction(UUID.randomUUID().toString()); //TODO: Create unique pending intent using request code and cancel any pre-existing pending // intents Loading @@ -197,10 +203,15 @@ public class CredentialManagerUi { * of the pinned entry. * * @param requestInfo the information about the request * @param requestSessionMetric the metric object for logging */ public Intent createIntentForAutofill(RequestInfo requestInfo) { return IntentFactory.createCredentialSelectorIntentForAutofill( mContext, requestInfo, new ArrayList<>(), public Intent createIntentForAutofill(RequestInfo requestInfo, RequestSessionMetric requestSessionMetric) { IntentCreationResult intentCreationResult = IntentFactory .createCredentialSelectorIntentForAutofill(mContext, requestInfo, new ArrayList<>(), mResultReceiver); requestSessionMetric.collectUiConfigurationResults( mContext, intentCreationResult, mUserId); return intentCreationResult.getIntent(); } } services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java +2 −1 Original line number Diff line number Diff line Loading @@ -122,7 +122,8 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ mRequestId, mClientRequest, mClientAppInfo.getPackageName(), PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS), /*isShowAllOptionsRequested=*/ true)); /*isShowAllOptionsRequested=*/ true), mRequestSessionMetric); List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); for (ProviderData providerData : providerDataList) { Loading Loading
core/java/android/credentials/selection/IntentCreationResult.java 0 → 100644 +155 −0 Original line number Diff line number Diff line /* * Copyright (C) 2024 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package android.credentials.selection; import android.annotation.NonNull; import android.annotation.Nullable; import android.content.Intent; /** * Result of creating a Credential Manager UI intent. * * @hide */ public final class IntentCreationResult { @NonNull private final Intent mIntent; @Nullable private final String mFallbackUiPackageName; @Nullable private final String mOemUiPackageName; @NonNull private final OemUiUsageStatus mOemUiUsageStatus; private IntentCreationResult(@NonNull Intent intent, @Nullable String fallbackUiPackageName, @Nullable String oemUiPackageName, OemUiUsageStatus oemUiUsageStatus) { mIntent = intent; mFallbackUiPackageName = fallbackUiPackageName; mOemUiPackageName = oemUiPackageName; mOemUiUsageStatus = oemUiUsageStatus; } /** Returns the UI intent. */ @NonNull public Intent getIntent() { return mIntent; } /** * Returns the result of attempting to use the config_oemCredentialManagerDialogComponent * as the Credential Manager UI. */ @NonNull public OemUiUsageStatus getOemUiUsageStatus() { return mOemUiUsageStatus; } /** * Returns the package name of the ui component specified in * config_fallbackCredentialManagerDialogComponent, or null if unspecified / not parsable * successfully. */ @Nullable public String getFallbackUiPackageName() { return mFallbackUiPackageName; } /** * Returns the package name of the oem ui component specified in * config_oemCredentialManagerDialogComponent, or null if unspecified / not parsable. */ @Nullable public String getOemUiPackageName() { return mOemUiPackageName; } /** * Result of attempting to use the config_oemCredentialManagerDialogComponent as the Credential * Manager UI. */ public enum OemUiUsageStatus { UNKNOWN, // Success: the UI specified in config_oemCredentialManagerDialogComponent was used to // fulfill the request. SUCCESS, // The config value was not specified (e.g. left empty). OEM_UI_CONFIG_NOT_SPECIFIED, // The config value component was specified but not found (e.g. component doesn't exist or // component isn't a system app). OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND, // The config value component was found but not enabled. OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED, } /** * Builder for {@link IntentCreationResult}. * * @hide */ public static final class Builder { @NonNull private Intent mIntent; @Nullable private String mFallbackUiPackageName = null; @Nullable private String mOemUiPackageName = null; @NonNull private OemUiUsageStatus mOemUiUsageStatus = OemUiUsageStatus.UNKNOWN; public Builder(Intent intent) { mIntent = intent; } /** * Sets the package name of the ui component specified in * config_fallbackCredentialManagerDialogComponent, or null if unspecified / not parsable * successfully. */ @NonNull public Builder setFallbackUiPackageName(@Nullable String fallbackUiPackageName) { mFallbackUiPackageName = fallbackUiPackageName; return this; } /** * Sets the package name of the oem ui component specified in * config_oemCredentialManagerDialogComponent, or null if unspecified / not parsable. */ @NonNull public Builder setOemUiPackageName(@Nullable String oemUiPackageName) { mOemUiPackageName = oemUiPackageName; return this; } /** * Sets the result of attempting to use the config_oemCredentialManagerDialogComponent * as the Credential Manager UI. */ @NonNull public Builder setOemUiUsageStatus(OemUiUsageStatus oemUiUsageStatus) { mOemUiUsageStatus = oemUiUsageStatus; return this; } /** Builds a {@link IntentCreationResult}. */ @NonNull public IntentCreationResult build() { return new IntentCreationResult(mIntent, mFallbackUiPackageName, mOemUiPackageName, mOemUiUsageStatus); } } }
core/java/android/credentials/selection/IntentFactory.java +127 −62 Original line number Diff line number Diff line Loading @@ -36,6 +36,8 @@ import android.os.ResultReceiver; import android.text.TextUtils; import android.util.Slog; import com.android.internal.annotations.VisibleForTesting; import java.util.ArrayList; /** Loading @@ -57,48 +59,142 @@ public class IntentFactory { * @hide */ @NonNull public static Intent createCredentialSelectorIntentForAutofill( public static IntentCreationResult createCredentialSelectorIntentForAutofill( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { return createCredentialSelectorIntent(context, requestInfo, return createCredentialSelectorIntentInternal(context, requestInfo, disabledProviderDataList, resultReceiver); } /** * Generate a new launch intent to the Credential Selector UI. * * @param context the CredentialManager system service (only expected caller) * context that may be used to query existence of the key UI * application * @param disabledProviderDataList the list of disabled provider data that when non-empty the * UI should accordingly generate an entry suggesting the user * to navigate to settings and enable them * @param enabledProviderDataList the list of enabled provider that contain options for this * request; the UI should render each option to the user for * selection * @param requestInfo the display information about the given app request * @param resultReceiver used by the UI to send the UI selection result back * @hide */ @NonNull public static IntentCreationResult createCredentialSelectorIntentForCredMan( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<ProviderData> enabledProviderDataList, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { IntentCreationResult result = createCredentialSelectorIntentInternal(context, requestInfo, disabledProviderDataList, resultReceiver); result.getIntent().putParcelableArrayListExtra( ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList); return result; } /** * Generate a new launch intent to the Credential Selector UI. * * @param context the CredentialManager system service (only expected caller) * context that may be used to query existence of the key UI * application * @param disabledProviderDataList the list of disabled provider data that when non-empty the * UI should accordingly generate an entry suggesting the user * to navigate to settings and enable them * @param enabledProviderDataList the list of enabled provider that contain options for this * request; the UI should render each option to the user for * selection * @param requestInfo the display information about the given app request * @param resultReceiver used by the UI to send the UI selection result back */ @VisibleForTesting @NonNull private static Intent createCredentialSelectorIntent( public static Intent createCredentialSelectorIntent( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<ProviderData> enabledProviderDataList, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { return createCredentialSelectorIntentForCredMan(context, requestInfo, enabledProviderDataList, disabledProviderDataList, resultReceiver).getIntent(); } /** * Creates an Intent that cancels any UI matching the given request token id. */ @VisibleForTesting @NonNull public static Intent createCancelUiIntent(@NonNull Context context, @NonNull IBinder requestToken, boolean shouldShowCancellationUi, @NonNull String appPackageName) { Intent intent = new Intent(); setCredentialSelectorUiComponentName(context, intent); IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent); setCredentialSelectorUiComponentName(context, intent, intentResultBuilder); intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST, new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi, appPackageName)); return intent; } /** * Generate a new launch intent to the Credential Selector UI. */ @NonNull private static IntentCreationResult createCredentialSelectorIntentInternal( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { Intent intent = new Intent(); IntentCreationResult.Builder intentResultBuilder = new IntentCreationResult.Builder(intent); setCredentialSelectorUiComponentName(context, intent, intentResultBuilder); intent.putParcelableArrayListExtra( ProviderData.EXTRA_DISABLED_PROVIDER_DATA_LIST, disabledProviderDataList); intent.putExtra(RequestInfo.EXTRA_REQUEST_INFO, requestInfo); intent.putExtra( Constants.EXTRA_RESULT_RECEIVER, toIpcFriendlyResultReceiver(resultReceiver)); return intent; return intentResultBuilder.build(); } private static void setCredentialSelectorUiComponentName(@NonNull Context context, @NonNull Intent intent) { @NonNull Intent intent, @NonNull IntentCreationResult.Builder intentResultBuilder) { if (configurableSelectorUiEnabled()) { ComponentName componentName = getOemOverrideComponentName(context); if (componentName == null) { componentName = ComponentName.unflattenFromString(Resources.getSystem().getString( ComponentName componentName = getOemOverrideComponentName(context, intentResultBuilder); ComponentName fallbackUiComponentName = null; try { fallbackUiComponentName = ComponentName.unflattenFromString( Resources.getSystem().getString( com.android.internal.R.string .config_fallbackCredentialManagerDialogComponent)); intentResultBuilder.setFallbackUiPackageName( fallbackUiComponentName.getPackageName()); } catch (Exception e) { Slog.w(TAG, "Fallback CredMan IU not found: " + e); } if (componentName == null) { componentName = fallbackUiComponentName; } intent.setComponent(componentName); } else { ComponentName componentName = ComponentName.unflattenFromString(Resources.getSystem() Loading @@ -113,7 +209,8 @@ public class IntentFactory { * default platform UI component name should be used instead. */ @Nullable private static ComponentName getOemOverrideComponentName(@NonNull Context context) { private static ComponentName getOemOverrideComponentName(@NonNull Context context, @NonNull IntentCreationResult.Builder intentResultBuilder) { ComponentName result = null; String oemComponentString = Resources.getSystem() Loading @@ -121,85 +218,53 @@ public class IntentFactory { com.android.internal.R.string .config_oemCredentialManagerDialogComponent); if (!TextUtils.isEmpty(oemComponentString)) { ComponentName oemComponentName = ComponentName.unflattenFromString( ComponentName oemComponentName = null; try { oemComponentName = ComponentName.unflattenFromString( oemComponentString); } catch (Exception e) { Slog.i(TAG, "Failed to parse OEM component name " + oemComponentString + ": " + e); } if (oemComponentName != null) { try { intentResultBuilder.setOemUiPackageName(oemComponentName.getPackageName()); ActivityInfo info = context.getPackageManager().getActivityInfo( oemComponentName, PackageManager.ComponentInfoFlags.of( PackageManager.MATCH_SYSTEM_ONLY)); if (info.enabled && info.exported) { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult .OemUiUsageStatus.SUCCESS); Slog.i(TAG, "Found enabled oem CredMan UI component." + oemComponentString); result = oemComponentName; } else { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult .OemUiUsageStatus.OEM_UI_CONFIG_SPECIFIED_FOUND_BUT_NOT_ENABLED); Slog.i(TAG, "Found enabled oem CredMan UI component but it was not " + "enabled."); } } catch (PackageManager.NameNotFoundException e) { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND); Slog.i(TAG, "Unable to find oem CredMan UI component: " + oemComponentString + "."); } } else { intentResultBuilder.setOemUiUsageStatus(IntentCreationResult.OemUiUsageStatus .OEM_UI_CONFIG_SPECIFIED_BUT_NOT_FOUND); Slog.i(TAG, "Invalid OEM ComponentName format."); } } else { intentResultBuilder.setOemUiUsageStatus( IntentCreationResult.OemUiUsageStatus.OEM_UI_CONFIG_NOT_SPECIFIED); Slog.i(TAG, "Invalid empty OEM component name."); } return result; } /** * Generate a new launch intent to the Credential Selector UI. * * @param context the CredentialManager system service (only expected caller) * context that may be used to query existence of the key UI * application * @param disabledProviderDataList the list of disabled provider data that when non-empty the * UI should accordingly generate an entry suggesting the user * to navigate to settings and enable them * @param enabledProviderDataList the list of enabled provider that contain options for this * request; the UI should render each option to the user for * selection * @param requestInfo the display information about the given app request * @param resultReceiver used by the UI to send the UI selection result back */ @NonNull public static Intent createCredentialSelectorIntent( @NonNull Context context, @NonNull RequestInfo requestInfo, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<ProviderData> enabledProviderDataList, @SuppressLint("ConcreteCollection") // Concrete collection needed for marshalling. @NonNull ArrayList<DisabledProviderData> disabledProviderDataList, @NonNull ResultReceiver resultReceiver) { Intent intent = createCredentialSelectorIntent(context, requestInfo, disabledProviderDataList, resultReceiver); intent.putParcelableArrayListExtra( ProviderData.EXTRA_ENABLED_PROVIDER_DATA_LIST, enabledProviderDataList); return intent; } /** * Creates an Intent that cancels any UI matching the given request token id. */ @NonNull public static Intent createCancelUiIntent(@NonNull Context context, @NonNull IBinder requestToken, boolean shouldShowCancellationUi, @NonNull String appPackageName) { Intent intent = new Intent(); setCredentialSelectorUiComponentName(context, intent); intent.putExtra(CancelSelectionRequest.EXTRA_CANCEL_UI_REQUEST, new CancelSelectionRequest(new RequestToken(requestToken), shouldShowCancellationUi, appPackageName)); return intent; } /** * Convert an instance of a "locally-defined" ResultReceiver to an instance of {@link * android.os.ResultReceiver} itself, which the receiving process will be able to unmarshall. Loading
services/credentials/java/com/android/server/credentials/CreateRequestSession.java +2 −1 Original line number Diff line number Diff line Loading @@ -112,7 +112,8 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS), /*defaultProviderId=*/flattenedPrimaryProviders, /*isShowAllOptionsRequested=*/ false), providerDataList); providerDataList, mRequestSessionMetric); mClientCallback.onPendingIntent(mPendingIntent); } catch (RemoteException e) { mRequestSessionMetric.collectUiReturnedFinalPhase(/*uiReturned=*/ false); Loading
services/credentials/java/com/android/server/credentials/CredentialManagerUi.java +20 −9 Original line number Diff line number Diff line Loading @@ -25,6 +25,7 @@ import android.content.Intent; import android.credentials.CredentialManager; import android.credentials.CredentialProviderInfo; import android.credentials.selection.DisabledProviderData; import android.credentials.selection.IntentCreationResult; import android.credentials.selection.IntentFactory; import android.credentials.selection.ProviderData; import android.credentials.selection.RequestInfo; Loading @@ -37,6 +38,8 @@ import android.os.ResultReceiver; import android.os.UserHandle; import android.service.credentials.CredentialProviderInfoFactory; import com.android.server.credentials.metrics.RequestSessionMetric; import java.util.ArrayList; import java.util.HashSet; import java.util.List; Loading Loading @@ -159,7 +162,8 @@ public class CredentialManagerUi { * @param providerDataList the list of provider data from remote providers */ public PendingIntent createPendingIntent( RequestInfo requestInfo, ArrayList<ProviderData> providerDataList) { RequestInfo requestInfo, ArrayList<ProviderData> providerDataList, RequestSessionMetric requestSessionMetric) { List<CredentialProviderInfo> allProviders = CredentialProviderInfoFactory.getCredentialProviderServices( mContext, Loading @@ -174,10 +178,12 @@ public class CredentialManagerUi { .map(disabledProvider -> new DisabledProviderData( disabledProvider.getComponentName().flattenToString())).toList(); Intent intent; intent = IntentFactory.createCredentialSelectorIntent( mContext, requestInfo, providerDataList, IntentCreationResult intentCreationResult = IntentFactory .createCredentialSelectorIntentForCredMan(mContext, requestInfo, providerDataList, new ArrayList<>(disabledProviderDataList), mResultReceiver); requestSessionMetric.collectUiConfigurationResults( mContext, intentCreationResult, mUserId); Intent intent = intentCreationResult.getIntent(); intent.setAction(UUID.randomUUID().toString()); //TODO: Create unique pending intent using request code and cancel any pre-existing pending // intents Loading @@ -197,10 +203,15 @@ public class CredentialManagerUi { * of the pinned entry. * * @param requestInfo the information about the request * @param requestSessionMetric the metric object for logging */ public Intent createIntentForAutofill(RequestInfo requestInfo) { return IntentFactory.createCredentialSelectorIntentForAutofill( mContext, requestInfo, new ArrayList<>(), public Intent createIntentForAutofill(RequestInfo requestInfo, RequestSessionMetric requestSessionMetric) { IntentCreationResult intentCreationResult = IntentFactory .createCredentialSelectorIntentForAutofill(mContext, requestInfo, new ArrayList<>(), mResultReceiver); requestSessionMetric.collectUiConfigurationResults( mContext, intentCreationResult, mUserId); return intentCreationResult.getIntent(); } }
services/credentials/java/com/android/server/credentials/GetCandidateRequestSession.java +2 −1 Original line number Diff line number Diff line Loading @@ -122,7 +122,8 @@ public class GetCandidateRequestSession extends RequestSession<GetCredentialRequ mRequestId, mClientRequest, mClientAppInfo.getPackageName(), PermissionUtils.hasPermission(mContext, mClientAppInfo.getPackageName(), Manifest.permission.CREDENTIAL_MANAGER_SET_ALLOWED_PROVIDERS), /*isShowAllOptionsRequested=*/ true)); /*isShowAllOptionsRequested=*/ true), mRequestSessionMetric); List<GetCredentialProviderData> candidateProviderDataList = new ArrayList<>(); for (ProviderData providerData : providerDataList) { Loading