diff options
5 files changed, 132 insertions, 3 deletions
diff --git a/core/java/android/credentials/ui/CancelUiRequest.java b/core/java/android/credentials/ui/CancelUiRequest.java new file mode 100644 index 000000000000..6bd9de481a79 --- /dev/null +++ b/core/java/android/credentials/ui/CancelUiRequest.java @@ -0,0 +1,79 @@ +/* + * Copyright 2022 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.ui; + +import android.annotation.NonNull; +import android.os.IBinder; +import android.os.Parcel; +import android.os.Parcelable; + +import com.android.internal.util.AnnotationValidations; + +/** + * A request to cancel any ongoing UI matching this request. + * + * @hide + */ +public final class CancelUiRequest implements Parcelable { + + /** + * The intent extra key for the {@code CancelUiRequest} object when launching the UX + * activities. + */ + @NonNull public static final String EXTRA_CANCEL_UI_REQUEST = + "android.credentials.ui.extra.EXTRA_CANCEL_UI_REQUEST"; + + @NonNull + private final IBinder mToken; + + /** Returns the request token matching the user request that should be cancelled. */ + @NonNull + public IBinder getToken() { + return mToken; + } + + public CancelUiRequest(@NonNull IBinder token) { + mToken = token; + } + + private CancelUiRequest(@NonNull Parcel in) { + mToken = in.readStrongBinder(); + AnnotationValidations.validate(NonNull.class, null, mToken); + } + + @Override + public void writeToParcel(@NonNull Parcel dest, int flags) { + dest.writeStrongBinder(mToken); + } + + @Override + public int describeContents() { + return 0; + } + + @NonNull public static final Creator<CancelUiRequest> CREATOR = new Creator<>() { + @Override + public CancelUiRequest createFromParcel(@NonNull Parcel in) { + return new CancelUiRequest(in); + } + + @Override + public CancelUiRequest[] newArray(int size) { + return new CancelUiRequest[size]; + } + }; +} diff --git a/core/java/android/credentials/ui/IntentFactory.java b/core/java/android/credentials/ui/IntentFactory.java index 3c10e8152efe..dcfef56f86a4 100644 --- a/core/java/android/credentials/ui/IntentFactory.java +++ b/core/java/android/credentials/ui/IntentFactory.java @@ -22,6 +22,7 @@ import android.annotation.TestApi; import android.content.ComponentName; import android.content.Intent; import android.content.res.Resources; +import android.os.IBinder; import android.os.Parcel; import android.os.ResultReceiver; @@ -66,6 +67,25 @@ public class IntentFactory { } /** + * Creates an Intent that cancels any UI matching the given request token id. + * + * @hide + */ + @NonNull + public static Intent createCancelUiIntent(@NonNull IBinder requestToken) { + Intent intent = new Intent(); + ComponentName componentName = + ComponentName.unflattenFromString( + Resources.getSystem() + .getString( + com.android.internal.R.string + .config_credentialManagerDialogComponent)); + intent.setComponent(componentName); + intent.putExtra(CancelUiRequest.EXTRA_CANCEL_UI_REQUEST, new CancelUiRequest(requestToken)); + return intent; + } + + /** * Notify the UI that providers have been enabled/disabled. * * @hide diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt index 89ce4511b47a..a6decc12d26b 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialManagerRepo.kt @@ -23,6 +23,7 @@ import android.credentials.Credential.TYPE_PASSWORD_CREDENTIAL import android.credentials.CredentialOption import android.credentials.GetCredentialRequest import android.credentials.ui.AuthenticationEntry +import android.credentials.ui.CancelUiRequest import android.credentials.ui.Constants import android.credentials.ui.Entry import android.credentials.ui.CreateCredentialProviderData @@ -214,6 +215,14 @@ class CredentialManagerRepo( resultReceiver.send(cancelCode, resultData) } } + + /** Return the request token whose UI should be cancelled, or null otherwise. */ + fun getCancelUiRequestToken(intent: Intent): IBinder? { + return intent.extras?.getParcelable( + CancelUiRequest.EXTRA_CANCEL_UI_REQUEST, + CancelUiRequest::class.java + )?.token + } } // TODO: below are prototype functionalities. To be removed for productionization. diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt index a3e4c81571a1..e8e39741c3bd 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorActivity.kt @@ -47,6 +47,12 @@ class CredentialSelectorActivity : ComponentActivity() { super.onCreate(savedInstanceState) Log.d(Constants.LOG_TAG, "Creating new CredentialSelectorActivity") try { + if (CredentialManagerRepo.getCancelUiRequestToken(intent) != null) { + Log.d( + Constants.LOG_TAG, "Received UI cancellation intent; cancelling the activity.") + this.finish() + return + } val userConfigRepo = UserConfigRepo(this) val credManRepo = CredentialManagerRepo(this, intent, userConfigRepo) setContent { @@ -67,10 +73,19 @@ class CredentialSelectorActivity : ComponentActivity() { setIntent(intent) Log.d(Constants.LOG_TAG, "Existing activity received new intent") try { - val userConfigRepo = UserConfigRepo(this) - val credManRepo = CredentialManagerRepo(this, intent, userConfigRepo) + val cancelUiRequestToken = CredentialManagerRepo.getCancelUiRequestToken(intent) val viewModel: CredentialSelectorViewModel by viewModels() - viewModel.onNewCredentialManagerRepo(credManRepo) + if (cancelUiRequestToken != null && + viewModel.shouldCancelCurrentUi(cancelUiRequestToken)) { + Log.d( + Constants.LOG_TAG, "Received UI cancellation intent; cancelling the activity.") + this.finish() + return + } else { + val userConfigRepo = UserConfigRepo(this) + val credManRepo = CredentialManagerRepo(this, intent, userConfigRepo) + viewModel.onNewCredentialManagerRepo(credManRepo) + } } catch (e: Exception) { onInitializationError(e, intent) } diff --git a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt index a1e0823e4f96..9b7139ccc26e 100644 --- a/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt +++ b/packages/CredentialManager/src/com/android/credentialmanager/CredentialSelectorViewModel.kt @@ -17,6 +17,7 @@ package com.android.credentialmanager import android.app.Activity +import android.os.IBinder import android.util.Log import androidx.activity.compose.ManagedActivityResultLauncher import androidx.activity.result.ActivityResult @@ -135,6 +136,11 @@ class CredentialSelectorViewModel( uiState = uiState.copy(dialogState = DialogState.COMPLETE) } + /** Return true if the current UI's request token matches the UI cancellation request token. */ + fun shouldCancelCurrentUi(cancelRequestToken: IBinder): Boolean { + return credManRepo.requestInfo.token.equals(cancelRequestToken) + } + /**************************************************************************/ /***** Get Flow Callbacks *****/ /**************************************************************************/ |