Merge "Allow to finish session when all views are gone" into oc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
3440e92009
@@ -37160,6 +37160,7 @@ package android.service.autofill {
|
||||
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
|
||||
method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender);
|
||||
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
|
||||
method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean);
|
||||
}
|
||||
|
||||
public final class SaveRequest implements android.os.Parcelable {
|
||||
|
||||
@@ -40270,6 +40270,7 @@ package android.service.autofill {
|
||||
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
|
||||
method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender);
|
||||
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
|
||||
method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean);
|
||||
}
|
||||
|
||||
public final class SaveRequest implements android.os.Parcelable {
|
||||
|
||||
@@ -37313,6 +37313,7 @@ package android.service.autofill {
|
||||
method public android.service.autofill.SaveInfo.Builder setDescription(java.lang.CharSequence);
|
||||
method public android.service.autofill.SaveInfo.Builder setNegativeAction(java.lang.CharSequence, android.content.IntentSender);
|
||||
method public android.service.autofill.SaveInfo.Builder setOptionalIds(android.view.autofill.AutofillId[]);
|
||||
method public android.service.autofill.SaveInfo.Builder setSaveOnAllViewsInvisible(boolean);
|
||||
}
|
||||
|
||||
public final class SaveRequest implements android.os.Parcelable {
|
||||
|
||||
@@ -16,21 +16,16 @@
|
||||
|
||||
package android.app;
|
||||
|
||||
import android.metrics.LogMaker;
|
||||
import android.graphics.Rect;
|
||||
import android.os.SystemClock;
|
||||
import android.view.ViewRootImpl.ActivityConfigCallback;
|
||||
import android.view.autofill.AutofillId;
|
||||
import android.view.autofill.AutofillManager;
|
||||
import android.view.autofill.AutofillPopupWindow;
|
||||
import android.view.autofill.AutofillValue;
|
||||
import android.view.autofill.IAutofillWindowPresenter;
|
||||
import com.android.internal.annotations.GuardedBy;
|
||||
import com.android.internal.app.IVoiceInteractor;
|
||||
import com.android.internal.app.ToolbarActionBar;
|
||||
import com.android.internal.app.WindowDecorActionBar;
|
||||
import com.android.internal.logging.MetricsLogger;
|
||||
import com.android.internal.logging.nano.MetricsProto;
|
||||
import com.android.internal.policy.PhoneWindow;
|
||||
|
||||
import android.annotation.CallSuper;
|
||||
@@ -1234,6 +1229,13 @@ public class Activity extends ContextThemeWrapper
|
||||
mFragments.doLoaderStart();
|
||||
|
||||
getApplication().dispatchActivityStarted(this);
|
||||
|
||||
if (mAutoFillResetNeeded) {
|
||||
AutofillManager afm = getAutofillManager();
|
||||
if (afm != null) {
|
||||
afm.onVisibleForAutofill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -7407,6 +7409,54 @@ public class Activity extends ContextThemeWrapper
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean getViewVisibility(int viewId) {
|
||||
Window window = getWindow();
|
||||
if (window == null) {
|
||||
Log.i(TAG, "no window");
|
||||
return false;
|
||||
}
|
||||
|
||||
View decorView = window.peekDecorView();
|
||||
if (decorView == null) {
|
||||
Log.i(TAG, "no decorView");
|
||||
return false;
|
||||
}
|
||||
|
||||
View view = decorView.findViewByAccessibilityIdTraversal(viewId);
|
||||
if (view == null) {
|
||||
Log.i(TAG, "cannot find view");
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if the view is visible by checking all parents
|
||||
while (view != null) {
|
||||
if (view == decorView) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (view.getVisibility() != View.VISIBLE) {
|
||||
Log.i(TAG, view + " is not visible");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (view.getParent() instanceof View) {
|
||||
view = (View) view.getParent();
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@Override
|
||||
public boolean isVisibleForAutofill() {
|
||||
return !mStopped;
|
||||
}
|
||||
|
||||
/**
|
||||
* If set to true, this indicates to the system that it should never take a
|
||||
* screenshot of the activity to be used as a representation while it is not in a started state.
|
||||
|
||||
@@ -21,6 +21,7 @@ import static android.view.autofill.Helper.DEBUG;
|
||||
import android.annotation.IntDef;
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.app.assist.AssistStructure;
|
||||
import android.content.IntentSender;
|
||||
import android.os.Bundle;
|
||||
import android.os.Parcel;
|
||||
@@ -158,6 +159,7 @@ public final class SaveInfo implements Parcelable {
|
||||
private final AutofillId[] mRequiredIds;
|
||||
private final AutofillId[] mOptionalIds;
|
||||
private final CharSequence mDescription;
|
||||
private final boolean mSaveOnAllViewsInvisible;
|
||||
|
||||
private SaveInfo(Builder builder) {
|
||||
mType = builder.mType;
|
||||
@@ -166,6 +168,7 @@ public final class SaveInfo implements Parcelable {
|
||||
mRequiredIds = builder.mRequiredIds;
|
||||
mOptionalIds = builder.mOptionalIds;
|
||||
mDescription = builder.mDescription;
|
||||
mSaveOnAllViewsInvisible = builder.mSaveOnAllViewsInvisible;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
@@ -193,6 +196,11 @@ public final class SaveInfo implements Parcelable {
|
||||
return mType;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public boolean saveOnAllViewsInvisible() {
|
||||
return mSaveOnAllViewsInvisible;
|
||||
}
|
||||
|
||||
/** @hide */
|
||||
public CharSequence getDescription() {
|
||||
return mDescription;
|
||||
@@ -211,6 +219,7 @@ public final class SaveInfo implements Parcelable {
|
||||
private AutofillId[] mOptionalIds;
|
||||
private CharSequence mDescription;
|
||||
private boolean mDestroyed;
|
||||
private boolean mSaveOnAllViewsInvisible;
|
||||
|
||||
/**
|
||||
* Creates a new builder.
|
||||
@@ -258,6 +267,21 @@ public final class SaveInfo implements Parcelable {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Usually {@link AutofillService#onSaveRequest(AssistStructure, Bundle, SaveCallback)}
|
||||
* is called once the activity finishes. If this property is set it is called once all
|
||||
* autofillable or saved views become invisible.
|
||||
*
|
||||
* @param saveOnAllViewsInvisible Set to {@code true} if the data should be saved once
|
||||
* all the views become invisible.
|
||||
* @return This builder.
|
||||
*/
|
||||
public @NonNull Builder setSaveOnAllViewsInvisible(boolean saveOnAllViewsInvisible) {
|
||||
throwIfDestroyed();
|
||||
mSaveOnAllViewsInvisible = saveOnAllViewsInvisible;
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the ids of additional, optional views the service would be interested to save.
|
||||
*
|
||||
@@ -354,6 +378,7 @@ public final class SaveInfo implements Parcelable {
|
||||
.append(", requiredIds=").append(Arrays.toString(mRequiredIds))
|
||||
.append(", optionalIds=").append(Arrays.toString(mOptionalIds))
|
||||
.append(", description=").append(mDescription)
|
||||
.append(", saveOnNoVisibleTrackedViews=").append(mSaveOnAllViewsInvisible)
|
||||
.append("]").toString();
|
||||
}
|
||||
|
||||
@@ -374,6 +399,7 @@ public final class SaveInfo implements Parcelable {
|
||||
parcel.writeParcelable(mNegativeActionListener, flags);
|
||||
parcel.writeParcelableArray(mOptionalIds, flags);
|
||||
parcel.writeCharSequence(mDescription);
|
||||
parcel.writeBoolean(mSaveOnAllViewsInvisible);
|
||||
}
|
||||
|
||||
public static final Parcelable.Creator<SaveInfo> CREATOR = new Parcelable.Creator<SaveInfo>() {
|
||||
@@ -387,6 +413,7 @@ public final class SaveInfo implements Parcelable {
|
||||
builder.setNegativeAction(parcel.readCharSequence(), parcel.readParcelable(null));
|
||||
builder.setOptionalIds(parcel.readParcelableArray(null, AutofillId.class));
|
||||
builder.setDescription(parcel.readCharSequence());
|
||||
builder.setSaveOnAllViewsInvisible(parcel.readBoolean());
|
||||
return builder.build();
|
||||
}
|
||||
|
||||
|
||||
@@ -66,6 +66,7 @@ import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.IBinder;
|
||||
import android.os.Message;
|
||||
import android.os.Parcel;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
@@ -4380,6 +4381,9 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
@Nullable
|
||||
private RoundScrollbarRenderer mRoundScrollbarRenderer;
|
||||
|
||||
/** Used to delay visibility updates sent to the autofill manager */
|
||||
private Handler mVisibilityChangeForAutofillHandler;
|
||||
|
||||
/**
|
||||
* Simple constructor to use when creating a view from code.
|
||||
*
|
||||
@@ -11696,6 +11700,30 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
if (fg != null && isVisible != fg.isVisible()) {
|
||||
fg.setVisible(isVisible, false);
|
||||
}
|
||||
|
||||
if (isAutofillable()) {
|
||||
AutofillManager afm = getAutofillManager();
|
||||
|
||||
if (afm != null && getAccessibilityViewId() > LAST_APP_ACCESSIBILITY_ID) {
|
||||
if (mVisibilityChangeForAutofillHandler != null) {
|
||||
mVisibilityChangeForAutofillHandler.removeMessages(0);
|
||||
}
|
||||
|
||||
// If the view is in the background but still part of the hierarchy this is called
|
||||
// with isVisible=false. Hence visibility==false requires further checks
|
||||
if (isVisible) {
|
||||
afm.notifyViewVisibilityChange(this, true);
|
||||
} else {
|
||||
if (mVisibilityChangeForAutofillHandler == null) {
|
||||
mVisibilityChangeForAutofillHandler =
|
||||
new VisibilityChangeForAutofillHandler(afm, this);
|
||||
}
|
||||
// Let current operation (e.g. removal of the view from the hierarchy)
|
||||
// finish before checking state
|
||||
mVisibilityChangeForAutofillHandler.obtainMessage(0, this).sendToTarget();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -24491,6 +24519,27 @@ public class View implements Drawable.Callback, KeyEvent.Callback,
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When a view becomes invisible checks if autofill considers the view invisible too. This
|
||||
* happens after the regular removal operation to make sure the operation is finished by the
|
||||
* time this is called.
|
||||
*/
|
||||
private static class VisibilityChangeForAutofillHandler extends Handler {
|
||||
private final AutofillManager mAfm;
|
||||
private final View mView;
|
||||
|
||||
private VisibilityChangeForAutofillHandler(@NonNull AutofillManager afm,
|
||||
@NonNull View view) {
|
||||
mAfm = afm;
|
||||
mView = view;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void handleMessage(Message msg) {
|
||||
mAfm.notifyViewVisibilityChange(mView, mView.isShown());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Base class for derived classes that want to save and restore their own
|
||||
* state in {@link android.view.View#onSaveInstanceState()}.
|
||||
|
||||
@@ -32,6 +32,7 @@ import android.os.IBinder;
|
||||
import android.os.Parcelable;
|
||||
import android.os.RemoteException;
|
||||
import android.util.ArrayMap;
|
||||
import android.util.ArraySet;
|
||||
import android.util.Log;
|
||||
import android.util.SparseArray;
|
||||
import android.view.View;
|
||||
@@ -143,6 +144,10 @@ public final class AutofillManager {
|
||||
@GuardedBy("mLock")
|
||||
@Nullable private ParcelableMap mLastAutofilledData;
|
||||
|
||||
/** If view tracking is enabled, contains the tracking state */
|
||||
@GuardedBy("mLock")
|
||||
@Nullable private TrackedViews mTrackedViews;
|
||||
|
||||
/** @hide */
|
||||
public interface AutofillClient {
|
||||
/**
|
||||
@@ -177,6 +182,20 @@ public final class AutofillManager {
|
||||
* @return Whether the UI was hidden.
|
||||
*/
|
||||
boolean autofillCallbackRequestHideFillUi();
|
||||
|
||||
/**
|
||||
* Checks if the view is currently attached and visible.
|
||||
*
|
||||
* @return {@code true} iff the view is attached or visible
|
||||
*/
|
||||
boolean getViewVisibility(int viewId);
|
||||
|
||||
/**
|
||||
* Checks is the client is currently visible as understood by autofill.
|
||||
*
|
||||
* @return {@code true} if the client is currently visible
|
||||
*/
|
||||
boolean isVisibleForAutofill();
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -259,6 +278,21 @@ public final class AutofillManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once the client becomes visible.
|
||||
*
|
||||
* @see AutofillClient#isVisibleForAutofill()
|
||||
*
|
||||
* {@hide}
|
||||
*/
|
||||
public void onVisibleForAutofill() {
|
||||
synchronized (mLock) {
|
||||
if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) {
|
||||
mTrackedViews.onVisibleForAutofill();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save state before activity lifecycle
|
||||
*
|
||||
@@ -411,6 +445,22 @@ public final class AutofillManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a {@link View view's} visibility changes.
|
||||
*
|
||||
* @param view {@link View} that was exited.
|
||||
* @param isVisible visible if the view is visible in the view hierarchy.
|
||||
*
|
||||
* @hide
|
||||
*/
|
||||
public void notifyViewVisibilityChange(@NonNull View view, boolean isVisible) {
|
||||
synchronized (mLock) {
|
||||
if (mEnabled && mSessionId != NO_SESSION && mTrackedViews != null) {
|
||||
mTrackedViews.notifyViewVisibilityChange(view, isVisible);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a virtual view that supports autofill is entered.
|
||||
*
|
||||
@@ -669,6 +719,7 @@ public final class AutofillManager {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
mTrackedViews = null;
|
||||
mSessionId = NO_SESSION;
|
||||
}
|
||||
|
||||
@@ -683,6 +734,7 @@ public final class AutofillManager {
|
||||
throw e.rethrowFromSystemServer();
|
||||
}
|
||||
|
||||
mTrackedViews = null;
|
||||
mSessionId = NO_SESSION;
|
||||
}
|
||||
|
||||
@@ -903,6 +955,25 @@ public final class AutofillManager {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tracked views.
|
||||
*
|
||||
* @param trackedIds The views to be tracked
|
||||
* @param saveOnAllViewsInvisible Finish the session once all tracked views are invisible.
|
||||
*/
|
||||
private void setTrackedViews(int sessionId, List<AutofillId> trackedIds,
|
||||
boolean saveOnAllViewsInvisible) {
|
||||
synchronized (mLock) {
|
||||
if (mEnabled && mSessionId == sessionId) {
|
||||
if (saveOnAllViewsInvisible) {
|
||||
mTrackedViews = new TrackedViews(trackedIds);
|
||||
} else {
|
||||
mTrackedViews = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void requestHideFillUi(int sessionId, IBinder windowToken, AutofillId id) {
|
||||
final View anchor = findAchorView(windowToken, id);
|
||||
|
||||
@@ -968,6 +1039,195 @@ public final class AutofillManager {
|
||||
return mService != null;
|
||||
}
|
||||
|
||||
/**
|
||||
* View tracking information. Once all tracked views become invisible the session is finished.
|
||||
*/
|
||||
private class TrackedViews {
|
||||
/** Visible tracked views */
|
||||
@Nullable private ArraySet<AutofillId> mVisibleTrackedIds;
|
||||
|
||||
/** Invisible tracked views */
|
||||
@Nullable private ArraySet<AutofillId> mInvisibleTrackedIds;
|
||||
|
||||
/**
|
||||
* Check if set is null or value is in set.
|
||||
*
|
||||
* @param set The set or null (== empty set)
|
||||
* @param value The value that might be in the set
|
||||
*
|
||||
* @return {@code true} iff set is not empty and value is in set
|
||||
*/
|
||||
private <T> boolean isInSet(@Nullable ArraySet<T> set, T value) {
|
||||
return set != null && set.contains(value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a value to a set. If set is null, create a new set.
|
||||
*
|
||||
* @param set The set or null (== empty set)
|
||||
* @param valueToAdd The value to add
|
||||
*
|
||||
* @return The set including the new value. If set was {@code null}, a set containing only
|
||||
* the new value.
|
||||
*/
|
||||
@NonNull
|
||||
private <T> ArraySet<T> addToSet(@Nullable ArraySet<T> set, T valueToAdd) {
|
||||
if (set == null) {
|
||||
set = new ArraySet<>(1);
|
||||
}
|
||||
|
||||
set.add(valueToAdd);
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a value from a set.
|
||||
*
|
||||
* @param set The set or null (== empty set)
|
||||
* @param valueToRemove The value to remove
|
||||
*
|
||||
* @return The set without the removed value. {@code null} if set was null, or is empty
|
||||
* after removal.
|
||||
*/
|
||||
@Nullable
|
||||
private <T> ArraySet<T> removeFromSet(@Nullable ArraySet<T> set, T valueToRemove) {
|
||||
if (set == null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
set.remove(valueToRemove);
|
||||
|
||||
if (set.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return set;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the tracked views.
|
||||
*
|
||||
* @param trackedIds The views to be tracked
|
||||
*/
|
||||
TrackedViews(@NonNull List<AutofillId> trackedIds) {
|
||||
mVisibleTrackedIds = null;
|
||||
mInvisibleTrackedIds = null;
|
||||
|
||||
AutofillClient client = getClientLocked();
|
||||
if (trackedIds != null) {
|
||||
int numIds = trackedIds.size();
|
||||
for (int i = 0; i < numIds; i++) {
|
||||
AutofillId id = trackedIds.get(i);
|
||||
|
||||
boolean isVisible = true;
|
||||
if (client != null && client.isVisibleForAutofill()) {
|
||||
isVisible = client.getViewVisibility(id.getViewId());
|
||||
}
|
||||
|
||||
if (isVisible) {
|
||||
mVisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
|
||||
} else {
|
||||
mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "TrackedViews(trackedIds=" + trackedIds + "): "
|
||||
+ " mVisibleTrackedIds=" + mVisibleTrackedIds
|
||||
+ " mInvisibleTrackedIds=" + mInvisibleTrackedIds);
|
||||
}
|
||||
|
||||
if (mVisibleTrackedIds == null) {
|
||||
finishSessionLocked();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a {@link View view's} visibility changes.
|
||||
*
|
||||
* @param view {@link View} that was exited.
|
||||
* @param isVisible visible if the view is visible in the view hierarchy.
|
||||
*/
|
||||
void notifyViewVisibilityChange(@NonNull View view, boolean isVisible) {
|
||||
AutofillId id = getAutofillId(view);
|
||||
AutofillClient client = getClientLocked();
|
||||
|
||||
if (DEBUG) {
|
||||
Log.d(TAG, "notifyViewVisibilityChange(): id=" + id + " isVisible="
|
||||
+ isVisible);
|
||||
}
|
||||
|
||||
if (client != null && client.isVisibleForAutofill()) {
|
||||
if (isVisible) {
|
||||
if (isInSet(mInvisibleTrackedIds, id)) {
|
||||
mInvisibleTrackedIds = removeFromSet(mInvisibleTrackedIds, id);
|
||||
mVisibleTrackedIds = addToSet(mVisibleTrackedIds, id);
|
||||
}
|
||||
} else {
|
||||
if (isInSet(mVisibleTrackedIds, id)) {
|
||||
mVisibleTrackedIds = removeFromSet(mVisibleTrackedIds, id);
|
||||
mInvisibleTrackedIds = addToSet(mInvisibleTrackedIds, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mVisibleTrackedIds == null) {
|
||||
finishSessionLocked();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Called once the client becomes visible.
|
||||
*
|
||||
* @see AutofillClient#isVisibleForAutofill()
|
||||
*/
|
||||
void onVisibleForAutofill() {
|
||||
// The visibility of the views might have changed while the client was not started,
|
||||
// hence update the visibility state for all views.
|
||||
AutofillClient client = getClientLocked();
|
||||
ArraySet<AutofillId> updatedVisibleTrackedIds = null;
|
||||
ArraySet<AutofillId> updatedInvisibleTrackedIds = null;
|
||||
if (client != null) {
|
||||
if (mInvisibleTrackedIds != null) {
|
||||
for (AutofillId id : mInvisibleTrackedIds) {
|
||||
if (client.getViewVisibility(id.getViewId())) {
|
||||
updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "onVisibleForAutofill() " + id + " became visible");
|
||||
}
|
||||
} else {
|
||||
updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (mVisibleTrackedIds != null) {
|
||||
for (AutofillId id : mVisibleTrackedIds) {
|
||||
if (client.getViewVisibility(id.getViewId())) {
|
||||
updatedVisibleTrackedIds = addToSet(updatedVisibleTrackedIds, id);
|
||||
} else {
|
||||
updatedInvisibleTrackedIds = addToSet(updatedInvisibleTrackedIds, id);
|
||||
|
||||
if (DEBUG) {
|
||||
Log.i(TAG, "onVisibleForAutofill() " + id + " became invisible");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mInvisibleTrackedIds = updatedInvisibleTrackedIds;
|
||||
mVisibleTrackedIds = updatedVisibleTrackedIds;
|
||||
}
|
||||
|
||||
if (mVisibleTrackedIds == null) {
|
||||
finishSessionLocked();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback for auto-fill related events.
|
||||
*
|
||||
@@ -1106,5 +1366,16 @@ public final class AutofillManager {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setTrackedViews(int sessionId, List<AutofillId> ids,
|
||||
boolean saveOnAllViewsInvisible) {
|
||||
final AutofillManager afm = mAfm.get();
|
||||
if (afm != null) {
|
||||
afm.mContext.getMainThreadHandler().post(
|
||||
() -> afm.setTrackedViews(sessionId, ids, saveOnAllViewsInvisible)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,6 +48,13 @@ oneway interface IAutoFillManagerClient {
|
||||
*/
|
||||
void authenticate(int sessionId, in IntentSender intent, in Intent fillInIntent);
|
||||
|
||||
/**
|
||||
* Sets the views to track. If saveOnAllViewsInvisible is set and all these view are invisible
|
||||
* the session is finished automatically.
|
||||
*/
|
||||
void setTrackedViews(int sessionId, in List<AutofillId> ids,
|
||||
boolean saveOnAllViewsInvisible);
|
||||
|
||||
/**
|
||||
* Requests showing the fill UI.
|
||||
*/
|
||||
|
||||
@@ -68,6 +68,7 @@ import com.android.server.autofill.ui.AutoFillUI;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Map;
|
||||
import java.util.Map.Entry;
|
||||
|
||||
@@ -220,6 +221,9 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
synchronized (mLock) {
|
||||
mActivityToken = newActivity;
|
||||
mClient = IAutoFillManagerClient.Stub.asInterface(newClient);
|
||||
|
||||
// The tracked id are not persisted in the client, hence update them
|
||||
updateTrackedIdsLocked();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -749,6 +753,38 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
}
|
||||
|
||||
private void updateTrackedIdsLocked() {
|
||||
if (mResponses == null || mResponses.size() == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Only track the views of the last response as only those are reported back to the
|
||||
// service, see #showSaveLocked
|
||||
ArrayList<AutofillId> trackedViews = new ArrayList<>();
|
||||
boolean saveOnAllViewsInvisible = false;
|
||||
SaveInfo saveInfo = mResponses.valueAt(getLastResponseIndex()).getSaveInfo();
|
||||
if (saveInfo != null) {
|
||||
saveOnAllViewsInvisible = saveInfo.saveOnAllViewsInvisible();
|
||||
|
||||
// We only need to track views if we want to save once they become invisible.
|
||||
if (saveOnAllViewsInvisible) {
|
||||
if (saveInfo.getRequiredIds() != null) {
|
||||
Collections.addAll(trackedViews, saveInfo.getRequiredIds());
|
||||
}
|
||||
|
||||
if (saveInfo.getOptionalIds() != null) {
|
||||
Collections.addAll(trackedViews, saveInfo.getOptionalIds());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
try {
|
||||
mClient.setTrackedViews(id, trackedViews, saveOnAllViewsInvisible);
|
||||
} catch (RemoteException e) {
|
||||
Slog.w(TAG, "Cannot set tracked ids", e);
|
||||
}
|
||||
}
|
||||
|
||||
private void processResponseLocked(FillResponse response, int requestId) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "processResponseLocked(mCurrentViewId=" + mCurrentViewId + "):" + response);
|
||||
@@ -763,6 +799,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
|
||||
}
|
||||
|
||||
setViewStatesLocked(response, ViewState.STATE_FILLABLE);
|
||||
updateTrackedIdsLocked();
|
||||
|
||||
if (mCurrentViewId == null) {
|
||||
return;
|
||||
|
||||
Reference in New Issue
Block a user