From e31d0c0e56dba6fc8213816f7e5cbcac1f9fd2da Mon Sep 17 00:00:00 2001 From: Helen Qin Date: Mon, 27 Mar 2023 18:12:14 +0000 Subject: [PATCH] Switch the activity parameter to context. Per api review feedback, switch the activity parameter in the Credential Manager APIs to context. Bug: 273932308 Test: CTS tested Change-Id: I5e98821c6fb2e7a5585dfc429523e36f171119f2 --- core/api/current.txt | 6 +- .../credentials/CredentialManager.java | 174 +++++++++++++----- .../PrepareGetCredentialResponse.java | 7 +- .../credentials/CredentialManagerTest.java | 32 ++-- 4 files changed, 150 insertions(+), 69 deletions(-) diff --git a/core/api/current.txt b/core/api/current.txt index 51c6f6a5eeccb..e7d139dc49245 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -13655,9 +13655,9 @@ package android.credentials { public final class CredentialManager { method public void clearCredentialState(@NonNull android.credentials.ClearCredentialStateRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - method public void createCredential(@NonNull android.credentials.CreateCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - method public void getCredential(@NonNull android.credentials.GetCredentialRequest, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); - method public void getCredential(@NonNull android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle, @NonNull android.app.Activity, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); + method public void createCredential(@NonNull android.content.Context, @NonNull android.credentials.CreateCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); + method public void getCredential(@NonNull android.content.Context, @NonNull android.credentials.GetCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); + method public void getCredential(@NonNull android.content.Context, @NonNull android.credentials.PrepareGetCredentialResponse.PendingGetCredentialHandle, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public boolean isEnabledCredentialProviderService(@NonNull android.content.ComponentName); method public void prepareGetCredential(@NonNull android.credentials.GetCredentialRequest, @Nullable android.os.CancellationSignal, @NonNull java.util.concurrent.Executor, @NonNull android.os.OutcomeReceiver); method public void registerCredentialDescription(@NonNull android.credentials.RegisterCredentialDescriptionRequest); diff --git a/core/java/android/credentials/CredentialManager.java b/core/java/android/credentials/CredentialManager.java index 5579d2263d066..00ce17adfda60 100644 --- a/core/java/android/credentials/CredentialManager.java +++ b/core/java/android/credentials/CredentialManager.java @@ -25,11 +25,11 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.annotation.SystemService; import android.annotation.TestApi; -import android.app.Activity; import android.app.PendingIntent; import android.content.ComponentName; import android.content.Context; import android.content.IntentSender; +import android.os.Binder; import android.os.CancellationSignal; import android.os.ICancellationSignal; import android.os.OutcomeReceiver; @@ -126,20 +126,21 @@ public final class CredentialManager { * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN} * to use this functionality * + * @param context the context used to launch any UI needed; use an activity context to make sure + * the UI will be launched within the same task stack * @param request the request specifying type(s) of credentials to get from the user - * @param activity the activity used to launch any UI needed * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param callback the callback invoked when the request succeeds or fails */ public void getCredential( + @NonNull Context context, @NonNull GetCredentialRequest request, - @NonNull Activity activity, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver callback) { requireNonNull(request, "request must not be null"); - requireNonNull(activity, "activity must not be null"); + requireNonNull(context, "context must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); @@ -153,7 +154,7 @@ public final class CredentialManager { cancelRemote = mService.executeGetCredential( request, - new GetCredentialTransport(activity, executor, callback), + new GetCredentialTransport(context, executor, callback), mContext.getOpPackageName()); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -175,21 +176,22 @@ public final class CredentialManager { * request through the {@link #prepareGetCredential( * GetCredentialRequest, CancellationSignal, Executor, OutcomeReceiver)} API. * + * @param context the context used to launch any UI needed; use an activity context to make sure + * the UI will be launched within the same task stack * @param pendingGetCredentialHandle the handle representing the pending operation to resume - * @param activity the activity used to launch any UI needed * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param callback the callback invoked when the request succeeds or fails */ public void getCredential( + @NonNull Context context, @NonNull PrepareGetCredentialResponse.PendingGetCredentialHandle - pendingGetCredentialHandle, - @NonNull Activity activity, + pendingGetCredentialHandle, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver callback) { requireNonNull(pendingGetCredentialHandle, "pendingGetCredentialHandle must not be null"); - requireNonNull(activity, "activity must not be null"); + requireNonNull(context, "context must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); @@ -198,7 +200,7 @@ public final class CredentialManager { return; } - pendingGetCredentialHandle.show(activity, cancellationSignal, executor, callback); + pendingGetCredentialHandle.show(context, cancellationSignal, executor, callback); } /** @@ -207,9 +209,9 @@ public final class CredentialManager { * *

This API doesn't invoke any UI. It only performs the preparation work so that you can * later launch the remaining get-credential operation (involves UIs) through the {@link - * #getCredential(PrepareGetCredentialResponse.PendingGetCredentialHandle, Activity, + * #getCredential(PrepareGetCredentialResponse.PendingGetCredentialHandle, Context, * CancellationSignal, Executor, OutcomeReceiver)} API which incurs less latency compared to - * the {@link #getCredential(GetCredentialRequest, Activity, CancellationSignal, Executor, + * the {@link #getCredential(GetCredentialRequest, Context, CancellationSignal, Executor, * OutcomeReceiver)} API that executes the whole operation in one call. * * @param request the request specifying type(s) of credentials to get from the user @@ -262,21 +264,22 @@ public final class CredentialManager { * need additional permission {@link CREDENTIAL_MANAGER_SET_ORIGIN} * to use this functionality * + * @param context the context used to launch any UI needed; use an activity context to make sure + * the UI will be launched within the same task stack * @param request the request specifying type(s) of credentials to get from the user - * @param activity the activity used to launch any UI needed * @param cancellationSignal an optional signal that allows for cancelling this call * @param executor the callback will take place on this {@link Executor} * @param callback the callback invoked when the request succeeds or fails */ public void createCredential( + @NonNull Context context, @NonNull CreateCredentialRequest request, - @NonNull Activity activity, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver callback) { requireNonNull(request, "request must not be null"); - requireNonNull(activity, "activity must not be null"); + requireNonNull(context, "context must not be null"); requireNonNull(executor, "executor must not be null"); requireNonNull(callback, "callback must not be null"); @@ -290,7 +293,7 @@ public final class CredentialManager { cancelRemote = mService.executeCreateCredential( request, - new CreateCredentialTransport(activity, executor, callback), + new CreateCredentialTransport(context, executor, callback), mContext.getOpPackageName()); } catch (RemoteException e) { e.rethrowFromSystemServer(); @@ -547,14 +550,24 @@ public final class CredentialManager { @Override public void onResponse(PrepareGetCredentialResponseInternal response) { - mExecutor.execute(() -> mCallback.onResult( - new PrepareGetCredentialResponse(response, mGetCredentialTransport))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult( + new PrepareGetCredentialResponse(response, mGetCredentialTransport))); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new GetCredentialException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError(new GetCredentialException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -587,7 +600,12 @@ public final class CredentialManager { @Override public void onResponse(GetCredentialResponse response) { if (mCallback != null) { - mCallback.onResponse(response); + final long identity = Binder.clearCallingIdentity(); + try { + mCallback.onResponse(response); + } finally { + Binder.restoreCallingIdentity(identity); + } } else { Log.d(TAG, "Unexpected onResponse call before the show invocation"); } @@ -596,7 +614,12 @@ public final class CredentialManager { @Override public void onError(String errorType, String message) { if (mCallback != null) { - mCallback.onError(errorType, message); + final long identity = Binder.clearCallingIdentity(); + try { + mCallback.onError(errorType, message); + } finally { + Binder.restoreCallingIdentity(identity); + } } else { Log.d(TAG, "Unexpected onError call before the show invocation"); } @@ -606,15 +629,15 @@ public final class CredentialManager { private static class GetCredentialTransport extends IGetCredentialCallback.Stub { // TODO: listen for cancellation to release callback. - private final Activity mActivity; + private final Context mContext; private final Executor mExecutor; private final OutcomeReceiver mCallback; private GetCredentialTransport( - Activity activity, + Context context, Executor executor, OutcomeReceiver callback) { - mActivity = activity; + mContext = context; mExecutor = executor; mCallback = callback; } @@ -622,42 +645,57 @@ public final class CredentialManager { @Override public void onPendingIntent(PendingIntent pendingIntent) { try { - mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); + mContext.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e( TAG, "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(), e); - mExecutor.execute(() -> mCallback.onError( - new GetCredentialException(GetCredentialException.TYPE_UNKNOWN))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onError( + new GetCredentialException(GetCredentialException.TYPE_UNKNOWN))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override public void onResponse(GetCredentialResponse response) { - mExecutor.execute(() -> mCallback.onResult(response)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(response)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new GetCredentialException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError(new GetCredentialException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } private static class CreateCredentialTransport extends ICreateCredentialCallback.Stub { // TODO: listen for cancellation to release callback. - private final Activity mActivity; + private final Context mContext; private final Executor mExecutor; private final OutcomeReceiver mCallback; private CreateCredentialTransport( - Activity activity, + Context context, Executor executor, OutcomeReceiver callback) { - mActivity = activity; + mContext = context; mExecutor = executor; mCallback = callback; } @@ -665,26 +703,41 @@ public final class CredentialManager { @Override public void onPendingIntent(PendingIntent pendingIntent) { try { - mActivity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); + mContext.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e( TAG, "startIntentSender() failed for intent:" + pendingIntent.getIntentSender(), e); - mExecutor.execute(() -> mCallback.onError( - new CreateCredentialException(CreateCredentialException.TYPE_UNKNOWN))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onError( + new CreateCredentialException(CreateCredentialException.TYPE_UNKNOWN))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @Override public void onResponse(CreateCredentialResponse response) { - mExecutor.execute(() -> mCallback.onResult(response)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(response)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new CreateCredentialException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError(new CreateCredentialException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -702,13 +755,24 @@ public final class CredentialManager { @Override public void onSuccess() { - mCallback.onResult(null); + final long identity = Binder.clearCallingIdentity(); + try { + mCallback.onResult(null); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new ClearCredentialStateException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError( + new ClearCredentialStateException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } @@ -725,18 +789,34 @@ public final class CredentialManager { } public void onResponse(Void result) { - mExecutor.execute(() -> mCallback.onResult(result)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(result)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onResponse() { - mExecutor.execute(() -> mCallback.onResult(null)); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute(() -> mCallback.onResult(null)); + } finally { + Binder.restoreCallingIdentity(identity); + } } @Override public void onError(String errorType, String message) { - mExecutor.execute( - () -> mCallback.onError(new SetEnabledProvidersException(errorType, message))); + final long identity = Binder.clearCallingIdentity(); + try { + mExecutor.execute( + () -> mCallback.onError( + new SetEnabledProvidersException(errorType, message))); + } finally { + Binder.restoreCallingIdentity(identity); + } } } } diff --git a/core/java/android/credentials/PrepareGetCredentialResponse.java b/core/java/android/credentials/PrepareGetCredentialResponse.java index 81e906859cb84..056b18a51b6d0 100644 --- a/core/java/android/credentials/PrepareGetCredentialResponse.java +++ b/core/java/android/credentials/PrepareGetCredentialResponse.java @@ -24,6 +24,7 @@ import android.annotation.Nullable; import android.annotation.RequiresPermission; import android.app.Activity; import android.app.PendingIntent; +import android.content.Context; import android.content.IntentSender; import android.os.CancellationSignal; import android.os.OutcomeReceiver; @@ -67,7 +68,7 @@ public final class PrepareGetCredentialResponse { } /** @hide */ - void show(@NonNull Activity activity, @Nullable CancellationSignal cancellationSignal, + void show(@NonNull Context context, @Nullable CancellationSignal cancellationSignal, @CallbackExecutor @NonNull Executor executor, @NonNull OutcomeReceiver callback) { if (mPendingIntent == null) { @@ -80,7 +81,7 @@ public final class PrepareGetCredentialResponse { @Override public void onPendingIntent(PendingIntent pendingIntent) { try { - activity.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); + context.startIntentSender(pendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "startIntentSender() failed for intent for show()", e); executor.execute(() -> callback.onError( @@ -101,7 +102,7 @@ public final class PrepareGetCredentialResponse { }); try { - activity.startIntentSender(mPendingIntent.getIntentSender(), null, 0, 0, 0); + context.startIntentSender(mPendingIntent.getIntentSender(), null, 0, 0, 0); } catch (IntentSender.SendIntentException e) { Log.e(TAG, "startIntentSender() failed for intent for show()", e); executor.execute(() -> callback.onError( diff --git a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java index c7e0261234870..b0d5240c61ba5 100644 --- a/core/tests/coretests/src/android/credentials/CredentialManagerTest.java +++ b/core/tests/coretests/src/android/credentials/CredentialManagerTest.java @@ -144,7 +144,7 @@ public class CredentialManagerTest { public void testGetCredential_nullRequest() { GetCredentialRequest nullRequest = null; assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(nullRequest, mMockActivity, null, mExecutor, + () -> mCredentialManager.getCredential(mMockActivity, nullRequest, null, mExecutor, result -> { })); } @@ -152,7 +152,7 @@ public class CredentialManagerTest { @Test public void testGetCredential_nullActivity() { assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(mGetRequest, null, null, mExecutor, + () -> mCredentialManager.getCredential(null, mGetRequest, null, mExecutor, result -> { })); } @@ -160,7 +160,7 @@ public class CredentialManagerTest { @Test public void testGetCredential_nullExecutor() { assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null, + () -> mCredentialManager.getCredential(mMockActivity, mGetRequest, null, null, result -> { })); } @@ -168,7 +168,7 @@ public class CredentialManagerTest { @Test public void testGetCredential_nullCallback() { assertThrows(NullPointerException.class, - () -> mCredentialManager.getCredential(mGetRequest, mMockActivity, null, null, + () -> mCredentialManager.getCredential(mMockActivity, mGetRequest, null, null, null)); } @@ -184,7 +184,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback); + mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); callbackCaptor.getValue().onError(GetCredentialException.TYPE_NO_CREDENTIAL, @@ -200,7 +200,7 @@ public class CredentialManagerTest { final CancellationSignal cancellation = new CancellationSignal(); cancellation.cancel(); - mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.getCredential(mMockActivity, mGetRequest, cancellation, mExecutor, result -> { }); @@ -218,7 +218,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeGetCredential(any(), any(), any())).thenReturn( serviceSignal); - mCredentialManager.getCredential(mGetRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.getCredential(mMockActivity, mGetRequest, cancellation, mExecutor, callback); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); @@ -241,7 +241,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeGetCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.getCredential(mGetRequest, mMockActivity, null, mExecutor, callback); + mCredentialManager.getCredential(mMockActivity, mGetRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeGetCredential(any(), any(), eq(mPackageName)); callbackCaptor.getValue().onResponse(new GetCredentialResponse(cred)); @@ -253,7 +253,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullRequest() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(null, mMockActivity, null, mExecutor, + () -> mCredentialManager.createCredential(mMockActivity, null, null, mExecutor, result -> { })); } @@ -261,7 +261,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullActivity() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(mCreateRequest, null, null, mExecutor, + () -> mCredentialManager.createCredential(null, mCreateRequest, null, mExecutor, result -> { })); } @@ -269,7 +269,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullExecutor() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, null, + () -> mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, null, result -> { })); } @@ -277,7 +277,7 @@ public class CredentialManagerTest { @Test public void testCreateCredential_nullCallback() { assertThrows(NullPointerException.class, - () -> mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, + () -> mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, null)); } @@ -286,7 +286,7 @@ public class CredentialManagerTest { final CancellationSignal cancellation = new CancellationSignal(); cancellation.cancel(); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, cancellation, mExecutor, result -> { }); @@ -304,7 +304,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeCreateCredential(any(), any(), any())).thenReturn( serviceSignal); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, cancellation, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, cancellation, mExecutor, callback); verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), @@ -326,7 +326,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), eq(mPackageName)); @@ -353,7 +353,7 @@ public class CredentialManagerTest { when(mMockCredentialManagerService.executeCreateCredential(any(), callbackCaptor.capture(), any())).thenReturn(mock(ICancellationSignal.class)); - mCredentialManager.createCredential(mCreateRequest, mMockActivity, null, mExecutor, + mCredentialManager.createCredential(mMockActivity, mCreateRequest, null, mExecutor, callback); verify(mMockCredentialManagerService).executeCreateCredential(any(), any(), eq(mPackageName));