Loading core/java/android/app/assist/AssistStructure.java +2 −0 Original line number Diff line number Diff line Loading @@ -913,6 +913,7 @@ public class AssistStructure implements Parcelable { if ((flags&FLAGS_HAS_EXTRAS) != 0) { mExtras = in.readBundle(); } mGetCredentialRequest = in.readTypedObject(GetCredentialRequest.CREATOR); } /** Loading Loading @@ -1149,6 +1150,7 @@ public class AssistStructure implements Parcelable { if ((flags&FLAGS_HAS_EXTRAS) != 0) { out.writeBundle(mExtras); } out.writeTypedObject(mGetCredentialRequest, flags); return flags; } Loading core/java/android/view/View.java +11 −1 Original line number Diff line number Diff line Loading @@ -7034,7 +7034,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { Preconditions.checkNotNull(request, "request must not be null"); Preconditions.checkNotNull(callback, "request must not be null"); mViewCredentialHandler = new ViewCredentialHandler(request, callback); } Loading Loading @@ -9914,6 +9913,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } /** * @hide */ public void onGetCredentialResponse(GetCredentialResponse response) { if (getCredentialManagerCallback() == null) { Log.w(AUTOFILL_LOG_TAG, "onGetCredentialResponse called but no callback found"); return; } getCredentialManagerCallback().onResult(response); } /** * Gets the unique, logical identifier of this view in the activity, for autofill purposes. * core/java/android/view/autofill/AutofillManager.java +74 −13 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.credentials.GetCredentialResponse; import android.graphics.Rect; import android.metrics.LogMaker; import android.os.Build; Loading Loading @@ -2925,6 +2926,65 @@ public final class AutofillManager { } } private void onGetCredentialResponse(int sessionId, AutofillId id, GetCredentialResponse response) { synchronized (mLock) { if (sessionId != mSessionId) { Log.w(TAG, "onGetCredentialResponse afm sessionIds don't match"); return; } final AutofillClient client = getClient(); if (client == null) { Log.w(TAG, "onGetCredentialResponse afm client id null"); return; } ArrayList<AutofillId> failedIds = new ArrayList<>(); final View[] views = client.autofillClientFindViewsByAutofillIdTraversal( Helper.toArray(new ArrayList<>(Collections.singleton(id)))); if (views == null || views.length == 0) { Log.w(TAG, "onGetCredentialResponse afm client view not found"); return; } final View view = views[0]; if (view == null) { Log.i(TAG, "onGetCredentialResponse View is null"); // Most likely view has been removed after the initial request was sent to the // the service; this is fine, but we need to update the view status in the // server side so it can be triggered again. Log.d(TAG, "onGetCredentialResponse(): no View with id " + id); failedIds.add(id); } if (id.isVirtualInt()) { Log.i(TAG, "onGetCredentialResponse afm client id is virtual"); // TODO(b/326314286): Handle virtual views } else { Log.i(TAG, "onGetCredentialResponse afm client id is NOT virtual"); view.onGetCredentialResponse(response); } handleFailedIdsLocked(failedIds); } } @GuardedBy("mLock") private void handleFailedIdsLocked(ArrayList<AutofillId> failedIds) { if (failedIds != null && !failedIds.isEmpty()) { if (sVerbose) { Log.v(TAG, "autofill(): total failed views: " + failedIds); } try { mService.setAutofillFailure(mSessionId, failedIds, mContext.getUserId()); } catch (RemoteException e) { // In theory, we could ignore this error since it's not a big deal, but // in reality, we rather crash the app anyways, as the failure could be // a consequence of something going wrong on the server side... throw e.rethrowFromSystemServer(); } } } private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values, boolean hideHighlight) { synchronized (mLock) { Loading Loading @@ -2991,19 +3051,7 @@ public final class AutofillManager { } } if (failedIds != null) { if (sVerbose) { Log.v(TAG, "autofill(): total failed views: " + failedIds); } try { mService.setAutofillFailure(mSessionId, failedIds, mContext.getUserId()); } catch (RemoteException e) { // In theory, we could ignore this error since it's not a big deal, but // in reality, we rather crash the app anyways, as the failure could be // a consequence of something going wrong on the server side... throw e.rethrowFromSystemServer(); } } handleFailedIdsLocked(failedIds); if (virtualValues != null) { for (int i = 0; i < virtualValues.size(); i++) { Loading Loading @@ -3431,6 +3479,10 @@ public final class AutofillManager { if (view == null) { return false; } if (view.getViewCredentialHandler() != null) { return true; } String[] hints = view.getAutofillHints(); if (hints == null) { return false; Loading Loading @@ -4320,6 +4372,15 @@ public final class AutofillManager { } } @Override public void onGetCredentialResponse(int sessionId, AutofillId id, GetCredentialResponse response) { final AutofillManager afm = mAfm.get(); if (afm != null) { afm.post(() -> afm.onGetCredentialResponse(sessionId, id, response)); } } @Override public void autofillContent(int sessionId, AutofillId id, ClipData content) { final AutofillManager afm = mAfm.get(); Loading core/java/android/view/autofill/IAutoFillManagerClient.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.ClipData; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; import android.credentials.GetCredentialResponse; import android.graphics.Rect; import android.os.IBinder; import android.view.autofill.AutofillId; Loading @@ -48,6 +49,9 @@ oneway interface IAutoFillManagerClient { void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values, boolean hideHighlight); void onGetCredentialResponse(int sessionId, in AutofillId id, in GetCredentialResponse response); /** * Autofills the activity with rich content data (e.g. an image) from a dataset. */ Loading packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +6 −2 Original line number Diff line number Diff line Loading @@ -607,10 +607,14 @@ class CredentialAutofillService : AutofillService() { autofillId: AutofillId, responseClientState: Bundle ): MutableList<CredentialOption> { if (viewNode.credentialManagerRequest != null && viewNode.credentialManagerCallback != null) { if (viewNode.credentialManagerRequest != null) { val options = viewNode.credentialManagerRequest?.getCredentialOptions() if (options != null) { for (option in options) { option.candidateQueryData.putParcelable( CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId ) } return options } } Loading Loading
core/java/android/app/assist/AssistStructure.java +2 −0 Original line number Diff line number Diff line Loading @@ -913,6 +913,7 @@ public class AssistStructure implements Parcelable { if ((flags&FLAGS_HAS_EXTRAS) != 0) { mExtras = in.readBundle(); } mGetCredentialRequest = in.readTypedObject(GetCredentialRequest.CREATOR); } /** Loading Loading @@ -1149,6 +1150,7 @@ public class AssistStructure implements Parcelable { if ((flags&FLAGS_HAS_EXTRAS) != 0) { out.writeBundle(mExtras); } out.writeTypedObject(mGetCredentialRequest, flags); return flags; } Loading
core/java/android/view/View.java +11 −1 Original line number Diff line number Diff line Loading @@ -7034,7 +7034,6 @@ public class View implements Drawable.Callback, KeyEvent.Callback, @NonNull OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) { Preconditions.checkNotNull(request, "request must not be null"); Preconditions.checkNotNull(callback, "request must not be null"); mViewCredentialHandler = new ViewCredentialHandler(request, callback); } Loading Loading @@ -9914,6 +9913,17 @@ public class View implements Drawable.Callback, KeyEvent.Callback, } } /** * @hide */ public void onGetCredentialResponse(GetCredentialResponse response) { if (getCredentialManagerCallback() == null) { Log.w(AUTOFILL_LOG_TAG, "onGetCredentialResponse called but no callback found"); return; } getCredentialManagerCallback().onResult(response); } /** * Gets the unique, logical identifier of this view in the activity, for autofill purposes. *
core/java/android/view/autofill/AutofillManager.java +74 −13 Original line number Diff line number Diff line Loading @@ -50,6 +50,7 @@ import android.content.Intent; import android.content.IntentSender; import android.content.pm.PackageManager; import android.content.pm.ResolveInfo; import android.credentials.GetCredentialResponse; import android.graphics.Rect; import android.metrics.LogMaker; import android.os.Build; Loading Loading @@ -2925,6 +2926,65 @@ public final class AutofillManager { } } private void onGetCredentialResponse(int sessionId, AutofillId id, GetCredentialResponse response) { synchronized (mLock) { if (sessionId != mSessionId) { Log.w(TAG, "onGetCredentialResponse afm sessionIds don't match"); return; } final AutofillClient client = getClient(); if (client == null) { Log.w(TAG, "onGetCredentialResponse afm client id null"); return; } ArrayList<AutofillId> failedIds = new ArrayList<>(); final View[] views = client.autofillClientFindViewsByAutofillIdTraversal( Helper.toArray(new ArrayList<>(Collections.singleton(id)))); if (views == null || views.length == 0) { Log.w(TAG, "onGetCredentialResponse afm client view not found"); return; } final View view = views[0]; if (view == null) { Log.i(TAG, "onGetCredentialResponse View is null"); // Most likely view has been removed after the initial request was sent to the // the service; this is fine, but we need to update the view status in the // server side so it can be triggered again. Log.d(TAG, "onGetCredentialResponse(): no View with id " + id); failedIds.add(id); } if (id.isVirtualInt()) { Log.i(TAG, "onGetCredentialResponse afm client id is virtual"); // TODO(b/326314286): Handle virtual views } else { Log.i(TAG, "onGetCredentialResponse afm client id is NOT virtual"); view.onGetCredentialResponse(response); } handleFailedIdsLocked(failedIds); } } @GuardedBy("mLock") private void handleFailedIdsLocked(ArrayList<AutofillId> failedIds) { if (failedIds != null && !failedIds.isEmpty()) { if (sVerbose) { Log.v(TAG, "autofill(): total failed views: " + failedIds); } try { mService.setAutofillFailure(mSessionId, failedIds, mContext.getUserId()); } catch (RemoteException e) { // In theory, we could ignore this error since it's not a big deal, but // in reality, we rather crash the app anyways, as the failure could be // a consequence of something going wrong on the server side... throw e.rethrowFromSystemServer(); } } } private void autofill(int sessionId, List<AutofillId> ids, List<AutofillValue> values, boolean hideHighlight) { synchronized (mLock) { Loading Loading @@ -2991,19 +3051,7 @@ public final class AutofillManager { } } if (failedIds != null) { if (sVerbose) { Log.v(TAG, "autofill(): total failed views: " + failedIds); } try { mService.setAutofillFailure(mSessionId, failedIds, mContext.getUserId()); } catch (RemoteException e) { // In theory, we could ignore this error since it's not a big deal, but // in reality, we rather crash the app anyways, as the failure could be // a consequence of something going wrong on the server side... throw e.rethrowFromSystemServer(); } } handleFailedIdsLocked(failedIds); if (virtualValues != null) { for (int i = 0; i < virtualValues.size(); i++) { Loading Loading @@ -3431,6 +3479,10 @@ public final class AutofillManager { if (view == null) { return false; } if (view.getViewCredentialHandler() != null) { return true; } String[] hints = view.getAutofillHints(); if (hints == null) { return false; Loading Loading @@ -4320,6 +4372,15 @@ public final class AutofillManager { } } @Override public void onGetCredentialResponse(int sessionId, AutofillId id, GetCredentialResponse response) { final AutofillManager afm = mAfm.get(); if (afm != null) { afm.post(() -> afm.onGetCredentialResponse(sessionId, id, response)); } } @Override public void autofillContent(int sessionId, AutofillId id, ClipData content) { final AutofillManager afm = mAfm.get(); Loading
core/java/android/view/autofill/IAutoFillManagerClient.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -22,6 +22,7 @@ import android.content.ClipData; import android.content.ComponentName; import android.content.Intent; import android.content.IntentSender; import android.credentials.GetCredentialResponse; import android.graphics.Rect; import android.os.IBinder; import android.view.autofill.AutofillId; Loading @@ -48,6 +49,9 @@ oneway interface IAutoFillManagerClient { void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values, boolean hideHighlight); void onGetCredentialResponse(int sessionId, in AutofillId id, in GetCredentialResponse response); /** * Autofills the activity with rich content data (e.g. an image) from a dataset. */ Loading
packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt +6 −2 Original line number Diff line number Diff line Loading @@ -607,10 +607,14 @@ class CredentialAutofillService : AutofillService() { autofillId: AutofillId, responseClientState: Bundle ): MutableList<CredentialOption> { if (viewNode.credentialManagerRequest != null && viewNode.credentialManagerCallback != null) { if (viewNode.credentialManagerRequest != null) { val options = viewNode.credentialManagerRequest?.getCredentialOptions() if (options != null) { for (option in options) { option.candidateQueryData.putParcelable( CredentialProviderService.EXTRA_AUTOFILL_ID, autofillId ) } return options } } Loading