Merge "Add support for virtual views" into main
diff --git a/core/java/android/app/assist/AssistStructure.java b/core/java/android/app/assist/AssistStructure.java
index fb1b17b..89199ca 100644
--- a/core/java/android/app/assist/AssistStructure.java
+++ b/core/java/android/app/assist/AssistStructure.java
@@ -1,5 +1,7 @@
package android.app.assist;
+import static android.credentials.Constants.FAILURE_CREDMAN_SELECTOR;
+import static android.credentials.Constants.SUCCESS_CREDMAN_SELECTOR;
import static android.service.autofill.Flags.FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION;
import android.annotation.FlaggedApi;
@@ -20,14 +22,17 @@
import android.os.BadParcelableException;
import android.os.Binder;
import android.os.Bundle;
+import android.os.Handler;
import android.os.IBinder;
import android.os.LocaleList;
+import android.os.Looper;
import android.os.OutcomeReceiver;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.PooledStringReader;
import android.os.PooledStringWriter;
import android.os.RemoteException;
+import android.os.ResultReceiver;
import android.os.SystemClock;
import android.service.autofill.FillRequest;
import android.service.credentials.CredentialProviderService;
@@ -37,6 +42,7 @@
import android.util.ArrayMap;
import android.util.Log;
import android.util.Pair;
+import android.util.Slog;
import android.view.View;
import android.view.View.AutofillImportance;
import android.view.ViewRootImpl;
@@ -652,6 +658,9 @@
@Nullable OutcomeReceiver<GetCredentialResponse, GetCredentialException>
mGetCredentialCallback;
+ @Nullable ResultReceiver mGetCredentialResultReceiver;
+
+
AutofillValue mAutofillValue;
CharSequence[] mAutofillOptions;
boolean mSanitized;
@@ -916,6 +925,7 @@
mExtras = in.readBundle();
}
mGetCredentialRequest = in.readTypedObject(GetCredentialRequest.CREATOR);
+ mGetCredentialResultReceiver = in.readTypedObject(ResultReceiver.CREATOR);
}
/**
@@ -1153,6 +1163,7 @@
out.writeBundle(mExtras);
}
out.writeTypedObject(mGetCredentialRequest, flags);
+ out.writeTypedObject(mGetCredentialResultReceiver, flags);
return flags;
}
@@ -1295,9 +1306,8 @@
*/
@FlaggedApi(FLAG_AUTOFILL_CREDMAN_DEV_INTEGRATION)
@Nullable
- public OutcomeReceiver<GetCredentialResponse,
- GetCredentialException> getCredentialManagerCallback() {
- return mGetCredentialCallback;
+ public ResultReceiver getCredentialManagerCallback() {
+ return mGetCredentialResultReceiver;
}
/**
@@ -1894,6 +1904,7 @@
final AssistStructure mAssist;
final ViewNode mNode;
final boolean mAsync;
+ private Handler mHandler;
/**
* Used to instantiate a builder for a stand-alone {@link ViewNode} which is not associated
@@ -2271,6 +2282,56 @@
option.getCandidateQueryData()
.putParcelableArrayList(CredentialProviderService.EXTRA_AUTOFILL_ID, ids);
}
+ setUpResultReceiver(callback);
+ }
+
+ private void setUpResultReceiver(
+ OutcomeReceiver<GetCredentialResponse, GetCredentialException> callback) {
+
+ if (mHandler == null) {
+ mHandler = new Handler(Looper.getMainLooper(), null, true);
+ }
+ final ResultReceiver resultReceiver = new ResultReceiver(mHandler) {
+ @Override
+ protected void onReceiveResult(int resultCode, Bundle resultData) {
+ if (resultCode == SUCCESS_CREDMAN_SELECTOR) {
+ Slog.d(TAG, "onReceiveResult from Credential Manager");
+ GetCredentialResponse getCredentialResponse =
+ resultData.getParcelable(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
+ GetCredentialResponse.class);
+
+ callback.onResult(getCredentialResponse);
+ } else if (resultCode == FAILURE_CREDMAN_SELECTOR) {
+ String[] exception = resultData.getStringArray(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_EXCEPTION);
+ if (exception != null && exception.length >= 2) {
+ Slog.w(TAG, "Credman bottom sheet from pinned "
+ + "entry failed with: + " + exception[0] + " , "
+ + exception[1]);
+ callback.onError(new GetCredentialException(
+ exception[0], exception[1]));
+ }
+ } else {
+ Slog.d(TAG, "Unknown resultCode from credential "
+ + "manager bottom sheet: " + resultCode);
+ }
+ }
+ };
+ ResultReceiver ipcFriendlyResultReceiver =
+ toIpcFriendlyResultReceiver(resultReceiver);
+ mNode.mGetCredentialResultReceiver = ipcFriendlyResultReceiver;
+ }
+
+ private ResultReceiver toIpcFriendlyResultReceiver(ResultReceiver resultReceiver) {
+ final Parcel parcel = Parcel.obtain();
+ resultReceiver.writeToParcel(parcel, 0);
+ parcel.setDataPosition(0);
+
+ final ResultReceiver ipcFriendly = ResultReceiver.CREATOR.createFromParcel(parcel);
+ parcel.recycle();
+
+ return ipcFriendly;
}
@Override
diff --git a/core/java/android/view/ViewStructure.java b/core/java/android/view/ViewStructure.java
index 131fca7..1efd375 100644
--- a/core/java/android/view/ViewStructure.java
+++ b/core/java/android/view/ViewStructure.java
@@ -315,7 +315,8 @@
/**
* Add to this view's child count. This increases the current child count by
* <var>num</var> children beyond what was last set by {@link #setChildCount}
- * or {@link #addChildCount}. The index at which the new child starts in the child
+ * or {@link #addChildCount}. The index at which the new
+ * child starts in the child
* array is returned.
*
* @param num The number of new children to add.
diff --git a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
index 3363ac0..d7a2e36 100644
--- a/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
+++ b/packages/CredentialManager/src/com/android/credentialmanager/autofill/CredentialAutofillService.kt
@@ -21,8 +21,6 @@
import android.content.Context
import android.credentials.CredentialManager
import android.credentials.GetCredentialRequest
-import android.credentials.GetCredentialResponse
-import android.credentials.GetCredentialException
import android.credentials.GetCandidateCredentialsResponse
import android.credentials.GetCandidateCredentialsException
import android.credentials.CredentialOption
@@ -124,13 +122,10 @@
// TODO(b/324635774): Use callback for validating. If the request is coming
// directly from the view, there should be a corresponding callback, otherwise
// we should fail fast,
- val getCredCallback = getCredManCallback(structure)
if (getCredRequest == null) {
Log.i(TAG, "No credential manager request found")
callback.onFailure("No credential manager request found")
return
- } else if (getCredCallback == null) {
- Log.i(TAG, "No credential manager callback found")
}
val credentialManager: CredentialManager =
getSystemService(Context.CREDENTIAL_SERVICE) as CredentialManager
@@ -528,42 +523,6 @@
TODO("Not yet implemented")
}
- private fun getCredManCallback(structure: AssistStructure): OutcomeReceiver<
- GetCredentialResponse, GetCredentialException>? {
- return traverseStructureForCallback(structure)
- }
-
- private fun traverseStructureForCallback(
- structure: AssistStructure
- ): OutcomeReceiver<GetCredentialResponse, GetCredentialException>? {
- val windowNodes: List<AssistStructure.WindowNode> =
- structure.run {
- (0 until windowNodeCount).map { getWindowNodeAt(it) }
- }
-
- windowNodes.forEach { windowNode: AssistStructure.WindowNode ->
- return traverseNodeForCallback(windowNode.rootViewNode)
- }
- return null
- }
-
- private fun traverseNodeForCallback(
- viewNode: AssistStructure.ViewNode
- ): OutcomeReceiver<GetCredentialResponse, GetCredentialException>? {
- val children: List<AssistStructure.ViewNode> =
- viewNode.run {
- (0 until childCount).map { getChildAt(it) }
- }
-
- children.forEach { childNode: AssistStructure.ViewNode ->
- if (childNode.isFocused() && childNode.credentialManagerCallback != null) {
- return childNode.credentialManagerCallback
- }
- return traverseNodeForCallback(childNode)
- }
- return null
- }
-
private fun getCredManRequest(
structure: AssistStructure,
sessionId: Int,
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index 551297b..7afb780 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -3935,6 +3935,24 @@
*/
@GuardedBy("mLock")
@Nullable
+ private ViewNode getViewNodeFromContextsLocked(@NonNull AutofillId autofillId) {
+ final int numContexts = mContexts.size();
+ for (int i = numContexts - 1; i >= 0; i--) {
+ final FillContext context = mContexts.get(i);
+ final ViewNode node = Helper.findViewNodeByAutofillId(context.getStructure(),
+ autofillId);
+ if (node != null) {
+ return node;
+ }
+ }
+ return null;
+ }
+
+ /**
+ * Gets the latest non-empty value for the given id in the autofill contexts.
+ */
+ @GuardedBy("mLock")
+ @Nullable
private AutofillValue getValueFromContextsLocked(@NonNull AutofillId autofillId) {
final int numContexts = mContexts.size();
for (int i = numContexts - 1; i >= 0; i--) {
@@ -6417,7 +6435,21 @@
mClient.onGetCredentialException(id, viewId, exception.getType(),
exception.getMessage());
} else if (response != null) {
- mClient.onGetCredentialResponse(id, viewId, response);
+ if (viewId.isVirtualInt()) {
+ ViewNode viewNode = getViewNodeFromContextsLocked(viewId);
+ if (viewNode != null && viewNode.getCredentialManagerCallback() != null) {
+ Bundle resultData = new Bundle();
+ resultData.putParcelable(
+ CredentialProviderService.EXTRA_GET_CREDENTIAL_RESPONSE,
+ response);
+ viewNode.getCredentialManagerCallback().send(SUCCESS_CREDMAN_SELECTOR,
+ resultData);
+ } else {
+ Slog.w(TAG, "View node not found after GetCredentialResponse");
+ }
+ } else {
+ mClient.onGetCredentialResponse(id, viewId, response);
+ }
} else {
Slog.w(TAG, "sendCredentialManagerResponseToApp called with null response"
+ "and exception");