Adding authentication entry and remote entry piping
Test: Built & deployed locally Bug: 253155340 Change-Id: I5e0e0479960caa14b1b782054fa10e74d146e73e
This commit is contained in:
@@ -17,7 +17,10 @@
|
||||
package android.credentials.ui;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.PendingIntent;
|
||||
import android.app.slice.Slice;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
@@ -85,6 +88,8 @@ public class Entry implements Parcelable {
|
||||
|
||||
@NonNull private final String mKey;
|
||||
@NonNull private final String mSubkey;
|
||||
@Nullable private PendingIntent mPendingIntent;
|
||||
@Nullable private Intent mFrameworkExtrasIntent;
|
||||
|
||||
@NonNull
|
||||
private final Slice mSlice;
|
||||
@@ -100,14 +105,29 @@ public class Entry implements Parcelable {
|
||||
AnnotationValidations.validate(NonNull.class, null, mSubkey);
|
||||
mSlice = slice;
|
||||
AnnotationValidations.validate(NonNull.class, null, mSlice);
|
||||
mPendingIntent = in.readTypedObject(PendingIntent.CREATOR);
|
||||
mFrameworkExtrasIntent = in.readTypedObject(Intent.CREATOR);
|
||||
}
|
||||
|
||||
/** Constructor to be used for an entry that does not require further activities
|
||||
* to be invoked when selected.
|
||||
*/
|
||||
public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice) {
|
||||
mKey = key;
|
||||
mSubkey = subkey;
|
||||
mSlice = slice;
|
||||
}
|
||||
|
||||
/** Constructor to be used for an entry that requires a pending intent to be invoked
|
||||
* when clicked.
|
||||
*/
|
||||
public Entry(@NonNull String key, @NonNull String subkey, @NonNull Slice slice,
|
||||
@NonNull PendingIntent pendingIntent, @Nullable Intent intent) {
|
||||
this(key, subkey, slice);
|
||||
mPendingIntent = pendingIntent;
|
||||
mFrameworkExtrasIntent = intent;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the identifier of this entry that's unique within the context of the CredentialManager
|
||||
* request.
|
||||
@@ -133,11 +153,23 @@ public class Entry implements Parcelable {
|
||||
return mSlice;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public PendingIntent getPendingIntent() {
|
||||
return mPendingIntent;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public Intent getFrameworkExtrasIntent() {
|
||||
return mFrameworkExtrasIntent;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeString8(mKey);
|
||||
dest.writeString8(mSubkey);
|
||||
mSlice.writeToParcel(dest, flags);
|
||||
mPendingIntent.writeToParcel(dest, flags);
|
||||
mFrameworkExtrasIntent.writeToParcel(dest, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (C) 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.Nullable;
|
||||
import android.content.Intent;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
/**
|
||||
* Response from a provider's pending intent
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public final class ProviderPendingIntentResponse implements Parcelable {
|
||||
private final int mResultCode;
|
||||
@Nullable
|
||||
private final Intent mResultData;
|
||||
|
||||
public ProviderPendingIntentResponse(int resultCode, @Nullable Intent resultData) {
|
||||
mResultCode = resultCode;
|
||||
mResultData = resultData;
|
||||
}
|
||||
|
||||
protected ProviderPendingIntentResponse(Parcel in) {
|
||||
mResultCode = in.readInt();
|
||||
mResultData = in.readTypedObject(Intent.CREATOR);
|
||||
}
|
||||
|
||||
public static final Creator<ProviderPendingIntentResponse> CREATOR =
|
||||
new Creator<ProviderPendingIntentResponse>() {
|
||||
@Override
|
||||
public ProviderPendingIntentResponse createFromParcel(Parcel in) {
|
||||
return new ProviderPendingIntentResponse(in);
|
||||
}
|
||||
|
||||
@Override
|
||||
public ProviderPendingIntentResponse[] newArray(int size) {
|
||||
return new ProviderPendingIntentResponse[size];
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public int describeContents() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeToParcel(@NonNull Parcel dest, int flags) {
|
||||
dest.writeSerializable(mResultCode);
|
||||
dest.writeTypedObject(mResultData, flags);
|
||||
}
|
||||
|
||||
/** Returns the result code associated with this pending intent activity result. */
|
||||
public int getResultCode() {
|
||||
return mResultCode;
|
||||
}
|
||||
|
||||
/** Returns the result data associated with this pending intent activity result. */
|
||||
@NonNull public Intent getResultData() {
|
||||
return mResultData;
|
||||
}
|
||||
}
|
||||
@@ -57,6 +57,7 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
@NonNull private final String mProviderId;
|
||||
@NonNull private final String mEntryKey;
|
||||
@NonNull private final String mEntrySubkey;
|
||||
@Nullable private ProviderPendingIntentResponse mProviderPendingIntentResponse;
|
||||
|
||||
public UserSelectionDialogResult(
|
||||
@NonNull IBinder requestToken, @NonNull String providerId,
|
||||
@@ -67,6 +68,17 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
mEntrySubkey = entrySubkey;
|
||||
}
|
||||
|
||||
public UserSelectionDialogResult(
|
||||
@NonNull IBinder requestToken, @NonNull String providerId,
|
||||
@NonNull String entryKey, @NonNull String entrySubkey,
|
||||
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
|
||||
super(requestToken);
|
||||
mProviderId = providerId;
|
||||
mEntryKey = entryKey;
|
||||
mEntrySubkey = entrySubkey;
|
||||
mProviderPendingIntentResponse = providerPendingIntentResponse;
|
||||
}
|
||||
|
||||
/** Returns provider package name whose entry was selected by the user. */
|
||||
@NonNull
|
||||
public String getProviderId() {
|
||||
@@ -85,6 +97,12 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
return mEntrySubkey;
|
||||
}
|
||||
|
||||
/** Returns the pending intent response from the provider. */
|
||||
@Nullable
|
||||
public ProviderPendingIntentResponse getPendingIntentProviderResponse() {
|
||||
return mProviderPendingIntentResponse;
|
||||
}
|
||||
|
||||
protected UserSelectionDialogResult(@NonNull Parcel in) {
|
||||
super(in);
|
||||
String providerId = in.readString8();
|
||||
@@ -97,6 +115,7 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
AnnotationValidations.validate(NonNull.class, null, mEntryKey);
|
||||
mEntrySubkey = entrySubkey;
|
||||
AnnotationValidations.validate(NonNull.class, null, mEntrySubkey);
|
||||
mProviderPendingIntentResponse = in.readTypedObject(ProviderPendingIntentResponse.CREATOR);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -105,6 +124,7 @@ public class UserSelectionDialogResult extends BaseDialogResult implements Parce
|
||||
dest.writeString8(mProviderId);
|
||||
dest.writeString8(mEntryKey);
|
||||
dest.writeString8(mEntrySubkey);
|
||||
dest.writeTypedObject(mProviderPendingIntentResponse, flags);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -43,8 +43,13 @@ import java.util.Objects;
|
||||
public abstract class CredentialProviderService extends Service {
|
||||
/** Extra to be used by provider to populate the credential when ending the activity started
|
||||
* through the {@code pendingIntent} on the selected {@link SaveEntry}. **/
|
||||
public static final String EXTRA_SAVE_CREDENTIAL =
|
||||
"android.service.credentials.extra.SAVE_CREDENTIAL";
|
||||
public static final String EXTRA_CREATE_CREDENTIAL_RESPONSE =
|
||||
"android.service.credentials.extra.CREATE_CREDENTIAL_RESPONSE";
|
||||
|
||||
/** Extra to be used by provider to populate the {@link CredentialsDisplayContent} when
|
||||
* an authentication action entry is selected. **/
|
||||
public static final String EXTRA_GET_CREDENTIALS_DISPLAY_CONTENT =
|
||||
"android.service.credentials.extra.GET_CREDENTIALS_DISPLAY_CONTENT";
|
||||
|
||||
/**
|
||||
* Provider must read the value against this extra to receive the complete create credential
|
||||
@@ -53,6 +58,10 @@ public abstract class CredentialProviderService extends Service {
|
||||
public static final String EXTRA_CREATE_CREDENTIAL_REQUEST_PARAMS =
|
||||
"android.service.credentials.extra.CREATE_CREDENTIAL_REQUEST_PARAMS";
|
||||
|
||||
/** Extra to be used by the provider when setting the credential result. */
|
||||
public static final String EXTRA_GET_CREDENTIAL =
|
||||
"android.service.credentials.extra.GET_CREDENTIAL";
|
||||
|
||||
private static final String TAG = "CredProviderService";
|
||||
|
||||
public static final String CAPABILITY_META_DATA_KEY = "android.credentials.capabilities";
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
|
||||
package com.android.credentialmanager
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.credentials.ui.Entry
|
||||
@@ -146,9 +147,17 @@ class CreateFlowUtils {
|
||||
): List<com.android.credentialmanager.createflow.EnabledProviderInfo> {
|
||||
// TODO: get from the actual service info
|
||||
val packageManager = context.packageManager
|
||||
|
||||
return providerDataList.map {
|
||||
val componentName = ComponentName.unflattenFromString(it.providerFlattenedComponentName)
|
||||
var packageName = componentName?.packageName
|
||||
if (componentName == null) {
|
||||
// TODO: Remove once test data is fixed
|
||||
packageName = it.providerFlattenedComponentName
|
||||
}
|
||||
|
||||
val pkgInfo = packageManager
|
||||
.getPackageInfo(it.providerFlattenedComponentName,
|
||||
.getPackageInfo(packageName!!,
|
||||
PackageManager.PackageInfoFlags.of(0))
|
||||
com.android.credentialmanager.createflow.EnabledProviderInfo(
|
||||
// TODO: decide what to do when failed to load a provider icon
|
||||
|
||||
@@ -18,12 +18,15 @@ package com.android.server.credentials;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.credentials.CreateCredentialRequest;
|
||||
import android.credentials.CreateCredentialResponse;
|
||||
import android.credentials.CredentialManager;
|
||||
import android.credentials.ICreateCredentialCallback;
|
||||
import android.credentials.ui.ProviderData;
|
||||
import android.credentials.ui.RequestInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.service.credentials.CredentialProviderInfo;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -35,7 +38,8 @@ import java.util.ArrayList;
|
||||
* provider(s) state maintained in {@link ProviderCreateSession}.
|
||||
*/
|
||||
public final class CreateRequestSession extends RequestSession<CreateCredentialRequest,
|
||||
ICreateCredentialCallback> {
|
||||
ICreateCredentialCallback>
|
||||
implements ProviderSession.ProviderInternalCallback<CreateCredentialResponse> {
|
||||
private static final String TAG = "CreateRequestSession";
|
||||
|
||||
CreateRequestSession(@NonNull Context context, int userId,
|
||||
@@ -72,4 +76,29 @@ public final class CreateRequestSession extends RequestSession<CreateCredentialR
|
||||
mRequestId, mClientRequest, mIsFirstUiTurn, mClientCallingPackage),
|
||||
providerDataList));
|
||||
}
|
||||
|
||||
private void respondToClientAndFinish(CreateCredentialResponse response) {
|
||||
Log.i(TAG, "respondToClientAndFinish");
|
||||
try {
|
||||
mClientCallback.onResponse(response);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
finishSession();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderStatusChanged(ProviderSession.Status status,
|
||||
ComponentName componentName) {
|
||||
super.onProviderStatusChanged(status, componentName);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onFinalResponseReceived(ComponentName componentName,
|
||||
CreateCredentialResponse response) {
|
||||
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
|
||||
if (response != null) {
|
||||
respondToClientAndFinish(response);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,16 +17,14 @@
|
||||
package com.android.server.credentials;
|
||||
|
||||
import android.annotation.Nullable;
|
||||
import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.credentials.Credential;
|
||||
import android.credentials.GetCredentialRequest;
|
||||
import android.credentials.GetCredentialResponse;
|
||||
import android.credentials.IGetCredentialCallback;
|
||||
import android.credentials.ui.ProviderData;
|
||||
import android.credentials.ui.RequestInfo;
|
||||
import android.credentials.ui.UserSelectionDialogResult;
|
||||
import android.os.RemoteException;
|
||||
import android.service.credentials.CredentialEntry;
|
||||
import android.service.credentials.CredentialProviderInfo;
|
||||
import android.util.Log;
|
||||
|
||||
@@ -37,7 +35,8 @@ import java.util.ArrayList;
|
||||
* responses from providers, and the UX app, and updates the provider(S) state.
|
||||
*/
|
||||
public final class GetRequestSession extends RequestSession<GetCredentialRequest,
|
||||
IGetCredentialCallback> {
|
||||
IGetCredentialCallback>
|
||||
implements ProviderSession.ProviderInternalCallback<GetCredentialResponse> {
|
||||
private static final String TAG = "GetRequestSession";
|
||||
|
||||
public GetRequestSession(Context context, int userId,
|
||||
@@ -67,23 +66,6 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
|
||||
return providerGetSession;
|
||||
}
|
||||
|
||||
// TODO: Override for this method not needed once get selection logic is
|
||||
// moved to ProviderGetSession
|
||||
@Override
|
||||
public void onUiSelection(UserSelectionDialogResult selection) {
|
||||
String providerId = selection.getProviderId();
|
||||
ProviderGetSession providerSession = (ProviderGetSession) mProviders.get(providerId);
|
||||
if (providerSession != null) {
|
||||
CredentialEntry credentialEntry = providerSession.getCredentialEntry(
|
||||
selection.getEntrySubkey());
|
||||
if (credentialEntry != null && credentialEntry.getCredential() != null) {
|
||||
respondToClientAndFinish(credentialEntry.getCredential());
|
||||
}
|
||||
// TODO : Handle action chips and authentication selection
|
||||
}
|
||||
// TODO : finish session and respond to client if provider not found
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void launchUiWithProviderData(ArrayList<ProviderData> providerDataList) {
|
||||
mHandler.post(() -> mCredentialManagerUi.show(RequestInfo.newGetRequestInfo(
|
||||
@@ -91,9 +73,26 @@ public final class GetRequestSession extends RequestSession<GetCredentialRequest
|
||||
providerDataList));
|
||||
}
|
||||
|
||||
private void respondToClientAndFinish(Credential credential) {
|
||||
@Override // from provider session
|
||||
public void onProviderStatusChanged(ProviderSession.Status status,
|
||||
ComponentName componentName) {
|
||||
super.onProviderStatusChanged(status, componentName);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onFinalResponseReceived(ComponentName componentName,
|
||||
GetCredentialResponse response) {
|
||||
Log.i(TAG, "onFinalCredentialReceived from: " + componentName.flattenToString());
|
||||
if (response != null) {
|
||||
respondToClientAndFinish(response);
|
||||
}
|
||||
}
|
||||
|
||||
private void respondToClientAndFinish(GetCredentialResponse response) {
|
||||
Log.i(TAG, "respondToClientAndFinish");
|
||||
try {
|
||||
mClientCallback.onResponse(new GetCredentialResponse(credential));
|
||||
mClientCallback.onResponse(response);
|
||||
} catch (RemoteException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
/*
|
||||
* Copyright (C) 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 com.android.server.credentials;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Intent;
|
||||
import android.credentials.CreateCredentialResponse;
|
||||
import android.credentials.Credential;
|
||||
import android.credentials.ui.ProviderPendingIntentResponse;
|
||||
import android.service.credentials.CredentialProviderService;
|
||||
import android.service.credentials.CredentialsDisplayContent;
|
||||
|
||||
/**
|
||||
* Helper class for setting up pending intent, and extracting objects from it.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public class PendingIntentResultHandler {
|
||||
/** Returns true if the result is successful and may contain result extras. */
|
||||
public static boolean isSuccessfulResponse(
|
||||
ProviderPendingIntentResponse pendingIntentResponse) {
|
||||
//TODO: Differentiate based on extra_error in the resultData
|
||||
return pendingIntentResponse.getResultCode() == Activity.RESULT_OK;
|
||||
}
|
||||
|
||||
/** Extracts the {@link CredentialsDisplayContent} object added to the result data. */
|
||||
public static CredentialsDisplayContent extractCredentialsDisplayContent(Intent resultData) {
|
||||
if (resultData == null) {
|
||||
return null;
|
||||
}
|
||||
return resultData.getParcelableExtra(
|
||||
CredentialProviderService.EXTRA_GET_CREDENTIALS_DISPLAY_CONTENT,
|
||||
CredentialsDisplayContent.class);
|
||||
}
|
||||
|
||||
/** Extracts the {@link CreateCredentialResponse} object added to the result data. */
|
||||
public static CreateCredentialResponse extractCreateCredentialResponse(Intent resultData) {
|
||||
if (resultData == null) {
|
||||
return null;
|
||||
}
|
||||
return resultData.getParcelableExtra(
|
||||
CredentialProviderService.EXTRA_CREATE_CREDENTIAL_RESPONSE,
|
||||
CreateCredentialResponse.class);
|
||||
}
|
||||
|
||||
/** Extracts the {@link Credential} object added to the result data. */
|
||||
public static Credential extractCredential(Intent resultData) {
|
||||
if (resultData == null) {
|
||||
return null;
|
||||
}
|
||||
return resultData.getParcelableExtra(
|
||||
CredentialProviderService.EXTRA_GET_CREDENTIAL,
|
||||
Credential.class);
|
||||
}
|
||||
}
|
||||
@@ -19,10 +19,12 @@ package com.android.server.credentials;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.credentials.Credential;
|
||||
import android.content.Intent;
|
||||
import android.credentials.ui.CreateCredentialProviderData;
|
||||
import android.credentials.ui.Entry;
|
||||
import android.credentials.ui.ProviderPendingIntentResponse;
|
||||
import android.os.Bundle;
|
||||
import android.service.credentials.CreateCredentialRequest;
|
||||
import android.service.credentials.CreateCredentialResponse;
|
||||
@@ -166,33 +168,28 @@ public final class ProviderCreateSession extends ProviderSession<
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderIntentResult(Bundle resultData) {
|
||||
Credential credential = resultData.getParcelable(
|
||||
CredentialProviderService.EXTRA_SAVE_CREDENTIAL,
|
||||
Credential.class);
|
||||
if (credential == null) {
|
||||
Log.i(TAG, "Credential returned from intent is null");
|
||||
return;
|
||||
public void onUiEntrySelected(String entryType, String entryKey,
|
||||
ProviderPendingIntentResponse providerPendingIntentResponse) {
|
||||
switch (entryType) {
|
||||
case SAVE_ENTRY_KEY:
|
||||
if (mUiSaveEntries.containsKey(entryKey)) {
|
||||
onSaveEntrySelected(providerPendingIntentResponse);
|
||||
} else {
|
||||
//TODO: Handle properly
|
||||
Log.i(TAG, "Unexpected save entry key");
|
||||
}
|
||||
break;
|
||||
case REMOTE_ENTRY_KEY:
|
||||
if (mUiRemoteEntry.first.equals(entryKey)) {
|
||||
onRemoteEntrySelected(providerPendingIntentResponse);
|
||||
} else {
|
||||
//TODO: Handle properly
|
||||
Log.i(TAG, "Unexpected remote entry key");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.i(TAG, "Unsupported entry type selected");
|
||||
}
|
||||
updateFinalCredentialResponse(credential);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onUiEntrySelected(String entryType, String entryKey) {
|
||||
if (entryType.equals(SAVE_ENTRY_KEY)) {
|
||||
SaveEntry saveEntry = mUiSaveEntries.get(entryKey);
|
||||
if (saveEntry == null) {
|
||||
Log.i(TAG, "Save entry not found");
|
||||
return;
|
||||
}
|
||||
// TODO: Uncomment when pending intent works
|
||||
// onSaveEntrySelected(saveEntry);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderIntentCancelled() {
|
||||
//TODO (Implement)
|
||||
}
|
||||
|
||||
private List<Entry> prepareUiSaveEntries(@NonNull List<SaveEntry> saveEntries) {
|
||||
@@ -204,14 +201,17 @@ public final class ProviderCreateSession extends ProviderSession<
|
||||
String entryId = generateEntryId();
|
||||
mUiSaveEntries.put(entryId, saveEntry);
|
||||
Log.i(TAG, "in prepareUiProviderData creating ui entry with id " + entryId);
|
||||
uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, saveEntry.getSlice()));
|
||||
uiSaveEntries.add(new Entry(SAVE_ENTRY_KEY, entryId, saveEntry.getSlice(),
|
||||
saveEntry.getPendingIntent(), setUpFillInIntent(saveEntry.getPendingIntent())));
|
||||
}
|
||||
return uiSaveEntries;
|
||||
}
|
||||
|
||||
private void updateFinalCredentialResponse(@NonNull Credential credential) {
|
||||
mFinalCredentialResponse = credential;
|
||||
updateStatusAndInvokeCallback(Status.CREDENTIAL_RECEIVED_FROM_INTENT);
|
||||
private Intent setUpFillInIntent(PendingIntent pendingIntent) {
|
||||
Intent intent = pendingIntent.getIntent();
|
||||
intent.putExtra(CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST_PARAMS,
|
||||
mCompleteRequest.getData());
|
||||
return intent;
|
||||
}
|
||||
|
||||
private CreateCredentialProviderData prepareUiProviderData(List<Entry> saveEntries,
|
||||
@@ -223,9 +223,20 @@ public final class ProviderCreateSession extends ProviderSession<
|
||||
.build();
|
||||
}
|
||||
|
||||
private void onSaveEntrySelected(SaveEntry saveEntry) {
|
||||
mProviderIntentController.setupAndInvokePendingIntent(saveEntry.getPendingIntent(),
|
||||
mProviderRequest);
|
||||
setStatus(Status.PENDING_INTENT_INVOKED);
|
||||
private void onSaveEntrySelected(ProviderPendingIntentResponse pendingIntentResponse) {
|
||||
if (pendingIntentResponse == null) {
|
||||
return;
|
||||
//TODO: Handle failure if pending intent is null
|
||||
}
|
||||
if (PendingIntentResultHandler.isSuccessfulResponse(pendingIntentResponse)) {
|
||||
android.credentials.CreateCredentialResponse credentialResponse =
|
||||
PendingIntentResultHandler.extractCreateCredentialResponse(
|
||||
pendingIntentResponse.getResultData());
|
||||
if (credentialResponse != null) {
|
||||
mCallbacks.onFinalResponseReceived(mComponentName, credentialResponse);
|
||||
return;
|
||||
}
|
||||
}
|
||||
//TODO: Handle failure case is pending intent response does not have a credential
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,16 +20,20 @@ import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.content.Context;
|
||||
import android.credentials.Credential;
|
||||
import android.credentials.GetCredentialOption;
|
||||
import android.credentials.GetCredentialResponse;
|
||||
import android.credentials.ui.Entry;
|
||||
import android.credentials.ui.GetCredentialProviderData;
|
||||
import android.os.Bundle;
|
||||
import android.credentials.ui.ProviderPendingIntentResponse;
|
||||
import android.service.credentials.Action;
|
||||
import android.service.credentials.CredentialEntry;
|
||||
import android.service.credentials.CredentialProviderInfo;
|
||||
import android.service.credentials.CredentialsDisplayContent;
|
||||
import android.service.credentials.GetCredentialsRequest;
|
||||
import android.service.credentials.GetCredentialsResponse;
|
||||
import android.util.Log;
|
||||
import android.util.Pair;
|
||||
import android.util.Slog;
|
||||
|
||||
import java.util.ArrayList;
|
||||
@@ -53,11 +57,17 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
|
||||
// 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";
|
||||
|
||||
@NonNull
|
||||
private final Map<String, CredentialEntry> mUiCredentialEntries = new HashMap<>();
|
||||
@NonNull
|
||||
private final Map<String, Action> mUiActionsEntries = new HashMap<>();
|
||||
private Action mAuthenticationAction = null;
|
||||
@Nullable
|
||||
private Pair<String, Action> mUiAuthenticationAction = null;
|
||||
|
||||
/** Creates a new provider session to be used by the request session. */
|
||||
@Nullable public static ProviderGetSession createNewSession(
|
||||
@@ -85,7 +95,8 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
|
||||
List<GetCredentialOption> filteredOptions = new ArrayList<>();
|
||||
for (GetCredentialOption option : clientRequest.getGetCredentialOptions()) {
|
||||
if (providerCapabilities.contains(option.getType())) {
|
||||
Log.i(TAG, "In createProviderRequest - capability found : " + option.getType());
|
||||
Log.i(TAG, "In createProviderRequest - capability found : "
|
||||
+ option.getType());
|
||||
filteredOptions.add(option);
|
||||
} else {
|
||||
Log.i(TAG, "In createProviderRequest - capability not "
|
||||
@@ -139,19 +150,47 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Callback from the provider intent controller class
|
||||
public void onProviderIntentResult(Bundle resultData) {
|
||||
// TODO : Implement
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderIntentCancelled() {
|
||||
// TODO : Implement
|
||||
}
|
||||
|
||||
@Override // Selection call from the request provider
|
||||
protected void onUiEntrySelected(String entryType, String entryId) {
|
||||
// TODO: Implement
|
||||
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, "Credential entry not found");
|
||||
//TODO: Handle properly
|
||||
return;
|
||||
}
|
||||
onCredentialEntrySelected(credentialEntry, providerPendingIntentResponse);
|
||||
break;
|
||||
case ACTION_ENTRY_KEY:
|
||||
Action actionEntry = mUiActionsEntries.get(entryKey);
|
||||
if (actionEntry == null) {
|
||||
Log.i(TAG, "Action entry not found");
|
||||
//TODO: Handle properly
|
||||
return;
|
||||
}
|
||||
onActionEntrySelected(providerPendingIntentResponse);
|
||||
break;
|
||||
case AUTHENTICATION_ACTION_ENTRY_KEY:
|
||||
if (mUiAuthenticationAction.first.equals(entryKey)) {
|
||||
onAuthenticationEntrySelected(providerPendingIntentResponse);
|
||||
} else {
|
||||
//TODO: Handle properly
|
||||
Log.i(TAG, "Authentication entry not found");
|
||||
}
|
||||
break;
|
||||
case REMOTE_ENTRY_KEY:
|
||||
if (mUiRemoteEntry.first.equals(entryKey)) {
|
||||
onRemoteEntrySelected(providerPendingIntentResponse);
|
||||
} else {
|
||||
//TODO: Handle properly
|
||||
Log.i(TAG, "Remote entry not found");
|
||||
}
|
||||
break;
|
||||
default:
|
||||
Log.i(TAG, "Unsupported entry type selected");
|
||||
}
|
||||
}
|
||||
|
||||
@Override // Call from request session to data to be shown on the UI
|
||||
@@ -162,32 +201,46 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
|
||||
+ mComponentName.flattenToString());
|
||||
return null;
|
||||
}
|
||||
GetCredentialsResponse response = getProviderResponse();
|
||||
if (response == null) {
|
||||
if (mProviderResponse == null) {
|
||||
Log.i(TAG, "In prepareUiData response null");
|
||||
throw new IllegalStateException("Response must be in completion mode");
|
||||
}
|
||||
if (response.getAuthenticationAction() != null) {
|
||||
if (mProviderResponse.getAuthenticationAction() != null) {
|
||||
Log.i(TAG, "In prepareUiData - top level authentication mode");
|
||||
return prepareUiProviderData(null, null,
|
||||
prepareUiAuthenticationActionEntry(response.getAuthenticationAction()),
|
||||
prepareUiAuthenticationAction(mProviderResponse.getAuthenticationAction()),
|
||||
/*remoteEntry=*/null);
|
||||
}
|
||||
if (response.getCredentialsDisplayContent() != null){
|
||||
if (mProviderResponse.getCredentialsDisplayContent() != null) {
|
||||
Log.i(TAG, "In prepareUiData displayContent not null");
|
||||
return prepareUiProviderData(populateUiActionEntries(
|
||||
response.getCredentialsDisplayContent().getActions()),
|
||||
prepareUiCredentialEntries(response.getCredentialsDisplayContent()
|
||||
return prepareUiProviderData(prepareUiActionEntries(
|
||||
mProviderResponse.getCredentialsDisplayContent().getActions()),
|
||||
prepareUiCredentialEntries(mProviderResponse.getCredentialsDisplayContent()
|
||||
.getCredentialEntries()),
|
||||
/*authenticationActionEntry=*/null, /*remoteEntry=*/null);
|
||||
/*authenticationAction=*/null,
|
||||
prepareUiRemoteEntry(mProviderResponse
|
||||
.getCredentialsDisplayContent().getRemoteCredentialEntry()));
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private Entry prepareUiAuthenticationActionEntry(@NonNull Action authenticationAction) {
|
||||
private Entry prepareUiRemoteEntry(Action remoteCredentialEntry) {
|
||||
if (remoteCredentialEntry == null) {
|
||||
return null;
|
||||
}
|
||||
String entryId = generateEntryId();
|
||||
mUiActionsEntries.put(entryId, authenticationAction);
|
||||
return new Entry(ACTION_ENTRY_KEY, entryId, authenticationAction.getSlice());
|
||||
Entry remoteEntry = new Entry(REMOTE_ENTRY_KEY, entryId, remoteCredentialEntry.getSlice());
|
||||
mUiRemoteEntry = new Pair<>(entryId, remoteCredentialEntry);
|
||||
return remoteEntry;
|
||||
}
|
||||
|
||||
private Entry prepareUiAuthenticationAction(@NonNull Action authenticationAction) {
|
||||
String entryId = generateEntryId();
|
||||
Entry authEntry = new Entry(
|
||||
AUTHENTICATION_ACTION_ENTRY_KEY, entryId, authenticationAction.getSlice(),
|
||||
authenticationAction.getPendingIntent(), /*fillInIntent=*/null);
|
||||
mUiAuthenticationAction = new Pair<>(entryId, authenticationAction);
|
||||
return authEntry;
|
||||
}
|
||||
|
||||
private List<Entry> prepareUiCredentialEntries(@NonNull
|
||||
@@ -200,19 +253,28 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
|
||||
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()));
|
||||
if (credentialEntry.getPendingIntent() != null) {
|
||||
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
|
||||
credentialEntry.getSlice(), credentialEntry.getPendingIntent(),
|
||||
/*fillInIntent=*/null));
|
||||
} else if (credentialEntry.getCredential() != null) {
|
||||
credentialUiEntries.add(new Entry(CREDENTIAL_ENTRY_KEY, entryId,
|
||||
credentialEntry.getSlice()));
|
||||
} else {
|
||||
Log.i(TAG, "No credential or pending intent. Should not happen.");
|
||||
}
|
||||
}
|
||||
return credentialUiEntries;
|
||||
}
|
||||
|
||||
private List<Entry> populateUiActionEntries(@Nullable List<Action> actions) {
|
||||
private List<Entry> prepareUiActionEntries(@Nullable List<Action> actions) {
|
||||
List<Entry> actionEntries = new ArrayList<>();
|
||||
for (Action action : actions) {
|
||||
String entryId = UUID.randomUUID().toString();
|
||||
mUiActionsEntries.put(entryId, action);
|
||||
// TODO : Remove conversion of string to int after change in Entry class
|
||||
actionEntries.add(new Entry(ACTION_ENTRY_KEY, entryId, action.getSlice()));
|
||||
actionEntries.add(new Entry(ACTION_ENTRY_KEY, entryId, action.getSlice(),
|
||||
action.getPendingIntent(), /*fillInIntent=*/null));
|
||||
}
|
||||
return actionEntries;
|
||||
}
|
||||
@@ -224,16 +286,61 @@ public final class ProviderGetSession extends ProviderSession<GetCredentialsRequ
|
||||
mComponentName.flattenToString()).setActionChips(actionEntries)
|
||||
.setCredentialEntries(credentialEntries)
|
||||
.setAuthenticationEntry(authenticationActionEntry)
|
||||
.setRemoteEntry(remoteEntry)
|
||||
.build();
|
||||
}
|
||||
|
||||
private void onCredentialEntrySelected(CredentialEntry credentialEntry,
|
||||
ProviderPendingIntentResponse providerPendingIntentResponse) {
|
||||
if (credentialEntry.getCredential() != null) {
|
||||
mCallbacks.onFinalResponseReceived(mComponentName, new GetCredentialResponse(
|
||||
credentialEntry.getCredential()));
|
||||
return;
|
||||
} else if (providerPendingIntentResponse != null) {
|
||||
if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) {
|
||||
Credential credential = PendingIntentResultHandler.extractCredential(
|
||||
providerPendingIntentResponse.getResultData());
|
||||
if (credential != null) {
|
||||
mCallbacks.onFinalResponseReceived(mComponentName,
|
||||
new GetCredentialResponse(credential));
|
||||
return;
|
||||
}
|
||||
}
|
||||
// TODO: Handle other pending intent statuses
|
||||
}
|
||||
Log.i(TAG, "CredentialEntry does not have a credential or a pending intent result");
|
||||
// TODO: Propagate failure to client
|
||||
}
|
||||
|
||||
private void onAuthenticationEntrySelected(
|
||||
@Nullable ProviderPendingIntentResponse providerPendingIntentResponse) {
|
||||
if (providerPendingIntentResponse != null) {
|
||||
if (PendingIntentResultHandler.isSuccessfulResponse(providerPendingIntentResponse)) {
|
||||
CredentialsDisplayContent content = PendingIntentResultHandler
|
||||
.extractCredentialsDisplayContent(providerPendingIntentResponse
|
||||
.getResultData());
|
||||
if (content != null) {
|
||||
onUpdateResponse(GetCredentialsResponse.createWithDisplayContent(content));
|
||||
return;
|
||||
}
|
||||
}
|
||||
//TODO: Other provider intent statuses
|
||||
}
|
||||
Log.i(TAG, "Display content not present in pending intent result");
|
||||
// TODO: Propagate error to client
|
||||
}
|
||||
|
||||
private void onActionEntrySelected(ProviderPendingIntentResponse
|
||||
providerPendingIntentResponse) {
|
||||
//TODO: Implement if any result expected after an action
|
||||
}
|
||||
|
||||
|
||||
/** Updates the response being maintained in state by this provider session. */
|
||||
private void onUpdateResponse(GetCredentialsResponse response) {
|
||||
mProviderResponse = response;
|
||||
if (response.getAuthenticationAction() != null) {
|
||||
Log.i(TAG , "updateResponse with authentication entry");
|
||||
// TODO validate authentication action
|
||||
mAuthenticationAction = response.getAuthenticationAction();
|
||||
updateStatusAndInvokeCallback(Status.REQUIRES_AUTHENTICATION);
|
||||
} else if (response.getCredentialsDisplayContent() != null) {
|
||||
Log.i(TAG , "updateResponse with credentialEntries");
|
||||
|
||||
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright (C) 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 com.android.server.credentials;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.SuppressLint;
|
||||
import android.annotation.UserIdInt;
|
||||
import android.app.Activity;
|
||||
import android.app.PendingIntent;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
import android.os.Parcel;
|
||||
import android.os.ResultReceiver;
|
||||
import android.service.credentials.CreateCredentialRequest;
|
||||
import android.service.credentials.CredentialProviderService;
|
||||
import android.util.Log;
|
||||
|
||||
/**
|
||||
* Class that invokes providers' pending intents and listens to the responses.
|
||||
*/
|
||||
@SuppressLint("LongLogTag")
|
||||
public class ProviderIntentController {
|
||||
private static final String TAG = "ProviderIntentController";
|
||||
/**
|
||||
* Interface to be implemented by any class that wishes to get callbacks from the UI.
|
||||
*/
|
||||
public interface ProviderIntentControllerCallback {
|
||||
/** Called when the user makes a selection. */
|
||||
void onProviderIntentResult(Bundle resultData);
|
||||
/** Called when the user cancels the UI. */
|
||||
void onProviderIntentCancelled();
|
||||
}
|
||||
|
||||
private final int mUserId;
|
||||
private final Context mContext;
|
||||
private final ProviderIntentControllerCallback mCallback;
|
||||
private final ResultReceiver mResultReceiver = new ResultReceiver(
|
||||
new Handler(Looper.getMainLooper())) {
|
||||
@Override
|
||||
protected void onReceiveResult(int resultCode, Bundle resultData) {
|
||||
Log.i(TAG, "onReceiveResult in providerIntentController");
|
||||
|
||||
if (resultCode == Activity.RESULT_OK) {
|
||||
Log.i(TAG, "onReceiveResult - ACTIVITYOK");
|
||||
mCallback.onProviderIntentResult(resultData);
|
||||
} else if (resultCode == Activity.RESULT_CANCELED) {
|
||||
Log.i(TAG, "onReceiveResult - RESULTCANCELED");
|
||||
mCallback.onProviderIntentCancelled();
|
||||
}
|
||||
// Drop unknown result
|
||||
}
|
||||
};
|
||||
|
||||
public ProviderIntentController(@UserIdInt int userId,
|
||||
Context context,
|
||||
ProviderIntentControllerCallback callback) {
|
||||
mUserId = userId;
|
||||
mContext = context;
|
||||
mCallback = callback;
|
||||
}
|
||||
|
||||
/** Sets up the request data and invokes the given pending intent. */
|
||||
public void setupAndInvokePendingIntent(@NonNull PendingIntent pendingIntent,
|
||||
CreateCredentialRequest request) {
|
||||
Log.i(TAG, "in invokePendingIntent");
|
||||
setupIntent(pendingIntent, request);
|
||||
Log.i(TAG, "in invokePendingIntent receiver set up");
|
||||
Log.i(TAG, "creator package: " + pendingIntent.getIntentSender()
|
||||
.getCreatorPackage());
|
||||
|
||||
try {
|
||||
mContext.startIntentSender(pendingIntent.getIntentSender(),
|
||||
null, 0, 0, 0);
|
||||
} catch (IntentSender.SendIntentException e) {
|
||||
Log.i(TAG, "Error while invoking pending intent");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private void setupIntent(PendingIntent pendingIntent, CreateCredentialRequest request) {
|
||||
pendingIntent.getIntent().putExtra(Intent.EXTRA_RESULT_RECEIVER,
|
||||
toIpcFriendlyResultReceiver(mResultReceiver));
|
||||
pendingIntent.getIntent().putExtra(
|
||||
CredentialProviderService.EXTRA_CREATE_CREDENTIAL_REQUEST_PARAMS,
|
||||
request.getData());
|
||||
}
|
||||
|
||||
private <T extends ResultReceiver> ResultReceiver toIpcFriendlyResultReceiver(
|
||||
T resultReceiver) {
|
||||
final Parcel parcel = Parcel.obtain();
|
||||
resultReceiver.writeToParcel(parcel, 0);
|
||||
parcel.setDataPosition(0);
|
||||
|
||||
final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel);
|
||||
parcel.recycle();
|
||||
|
||||
return ipcFriendly;
|
||||
}
|
||||
}
|
||||
@@ -22,9 +22,11 @@ import android.content.ComponentName;
|
||||
import android.content.Context;
|
||||
import android.credentials.Credential;
|
||||
import android.credentials.ui.ProviderData;
|
||||
import android.os.Bundle;
|
||||
import android.credentials.ui.ProviderPendingIntentResponse;
|
||||
import android.service.credentials.Action;
|
||||
import android.service.credentials.CredentialProviderException;
|
||||
import android.service.credentials.CredentialProviderInfo;
|
||||
import android.util.Pair;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -33,10 +35,10 @@ import java.util.UUID;
|
||||
* @param <T> The request to be sent to the provider
|
||||
* @param <R> The response to be expected from the provider
|
||||
*/
|
||||
public abstract class ProviderSession<T, R> implements RemoteCredentialService.ProviderCallbacks<R>,
|
||||
ProviderIntentController.ProviderIntentControllerCallback {
|
||||
// Key to be used as the entry key for an action entry
|
||||
protected static final String ACTION_ENTRY_KEY = "action_key";
|
||||
public abstract class ProviderSession<T, R>
|
||||
implements RemoteCredentialService.ProviderCallbacks<R> {
|
||||
// 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;
|
||||
@@ -45,17 +47,18 @@ public abstract class ProviderSession<T, R> implements RemoteCredentialService.P
|
||||
@NonNull protected final int mUserId;
|
||||
@NonNull protected Status mStatus = Status.NOT_STARTED;
|
||||
@NonNull protected final ProviderInternalCallback mCallbacks;
|
||||
@NonNull protected final ProviderIntentController mProviderIntentController;
|
||||
@Nullable protected Credential mFinalCredentialResponse;
|
||||
@NonNull protected final T mProviderRequest;
|
||||
@Nullable protected R mProviderResponse;
|
||||
@Nullable protected Pair<String, Action> mUiRemoteEntry;
|
||||
|
||||
/**
|
||||
* Returns true if the given status reflects that the provider state is ready to be shown
|
||||
* on the credMan UI.
|
||||
*/
|
||||
public static boolean isUiInvokingStatus(Status status) {
|
||||
return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED;
|
||||
return status == Status.CREDENTIALS_RECEIVED || status == Status.SAVE_ENTRIES_RECEIVED
|
||||
|| status == Status.REQUIRES_AUTHENTICATION;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -86,12 +89,14 @@ public abstract class ProviderSession<T, R> implements RemoteCredentialService.P
|
||||
* Interface to be implemented by any class that wishes to get a callback when a particular
|
||||
* provider session's status changes. Typically, implemented by the {@link RequestSession}
|
||||
* class.
|
||||
* @param <V> the type of the final response expected
|
||||
*/
|
||||
public interface ProviderInternalCallback {
|
||||
/**
|
||||
* Called when status changes.
|
||||
*/
|
||||
public interface ProviderInternalCallback<V> {
|
||||
/** Called when status changes. */
|
||||
void onProviderStatusChanged(Status status, ComponentName componentName);
|
||||
|
||||
/** Called when the final credential to be returned to the client has been received. */
|
||||
void onFinalResponseReceived(ComponentName componentName, V response);
|
||||
}
|
||||
|
||||
protected ProviderSession(@NonNull Context context, @NonNull CredentialProviderInfo info,
|
||||
@@ -106,7 +111,6 @@ public abstract class ProviderSession<T, R> implements RemoteCredentialService.P
|
||||
mUserId = userId;
|
||||
mComponentName = info.getServiceInfo().getComponentName();
|
||||
mRemoteCredentialService = remoteCredentialService;
|
||||
mProviderIntentController = new ProviderIntentController(userId, context, this);
|
||||
}
|
||||
|
||||
/** Provider status at various states of the request session. */
|
||||
@@ -164,6 +168,11 @@ public abstract class ProviderSession<T, R> implements RemoteCredentialService.P
|
||||
mCallbacks.onProviderStatusChanged(status, mComponentName);
|
||||
}
|
||||
|
||||
protected void onRemoteEntrySelected(
|
||||
ProviderPendingIntentResponse providerPendingIntentResponse) {
|
||||
//TODO: Implement
|
||||
}
|
||||
|
||||
/** Get the request to be sent to the provider. */
|
||||
protected T getProviderRequest() {
|
||||
return mProviderRequest;
|
||||
@@ -179,12 +188,6 @@ public abstract class ProviderSession<T, R> implements RemoteCredentialService.P
|
||||
@Nullable protected abstract ProviderData prepareUiData();
|
||||
|
||||
/** Should be overridden to handle the selected entry from the UI. */
|
||||
protected abstract void onUiEntrySelected(String entryType, String entryId);
|
||||
|
||||
@Override
|
||||
public abstract void onProviderIntentResult(Bundle resultData);
|
||||
|
||||
@Override
|
||||
public abstract void onProviderIntentCancelled();
|
||||
|
||||
protected abstract void onUiEntrySelected(String entryType, String entryId,
|
||||
ProviderPendingIntentResponse providerPendingIntentResponse);
|
||||
}
|
||||
|
||||
@@ -37,8 +37,7 @@ import java.util.Map;
|
||||
* Base class of a request session, that listens to UI events. This class must be extended
|
||||
* every time a new response type is expected from the providers.
|
||||
*/
|
||||
abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialManagerUiCallback,
|
||||
ProviderSession.ProviderInternalCallback {
|
||||
abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialManagerUiCallback{
|
||||
private static final String TAG = "RequestSession";
|
||||
|
||||
// TODO: Revise access levels of attributes
|
||||
@@ -89,7 +88,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
|
||||
}
|
||||
Log.i(TAG, "Provider session found");
|
||||
providerSession.onUiEntrySelected(selection.getEntryKey(),
|
||||
selection.getEntrySubkey());
|
||||
selection.getEntrySubkey(), selection.getPendingIntentProviderResponse());
|
||||
}
|
||||
|
||||
@Override // from CredentialManagerUiCallbacks
|
||||
@@ -98,8 +97,7 @@ abstract class RequestSession<T, U> implements CredentialManagerUi.CredentialMan
|
||||
finishSession();
|
||||
}
|
||||
|
||||
@Override // from provider session
|
||||
public void onProviderStatusChanged(ProviderSession.Status status,
|
||||
protected void onProviderStatusChanged(ProviderSession.Status status,
|
||||
ComponentName componentName) {
|
||||
Log.i(TAG, "in onStatusChanged with status: " + status);
|
||||
if (ProviderSession.isTerminatingStatus(status)) {
|
||||
|
||||
Reference in New Issue
Block a user