summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/service/autofill/augmented/AugmentedAutofillService.java40
-rw-r--r--core/java/android/service/autofill/augmented/FillWindow.java183
-rw-r--r--core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl2
-rw-r--r--core/java/android/view/autofill/AutofillManager.java18
-rw-r--r--core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl23
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerService.java5
-rw-r--r--services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java9
-rw-r--r--services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java4
-rw-r--r--services/autofill/java/com/android/server/autofill/Session.java2
9 files changed, 205 insertions, 81 deletions
diff --git a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
index 01169612a201..aaba85bd36a7 100644
--- a/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
+++ b/core/java/android/service/autofill/augmented/AugmentedAutofillService.java
@@ -42,6 +42,7 @@ import android.util.TimeUtils;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
import android.view.autofill.IAugmentedAutofillManagerClient;
+import android.view.autofill.IAutofillWindowPresenter;
import com.android.internal.annotations.GuardedBy;
@@ -95,10 +96,10 @@ public abstract class AugmentedAutofillService extends Service {
}
@Override
- public void onDestroyFillWindowRequest(int sessionId) {
+ public void onDestroyAllFillWindowsRequest() {
mHandler.sendMessage(
- obtainMessage(AugmentedAutofillService::handleOnDestroyFillWindowRequest,
- AugmentedAutofillService.this, sessionId));
+ obtainMessage(AugmentedAutofillService::handleOnDestroyAllFillWindowsRequest,
+ AugmentedAutofillService.this));
}
};
@@ -185,18 +186,21 @@ public abstract class AugmentedAutofillService extends Service {
new FillCallback(proxy));
}
- private void handleOnDestroyFillWindowRequest(@NonNull int sessionId) {
- AutofillProxy proxy = null;
+ private void handleOnDestroyAllFillWindowsRequest() {
if (mAutofillProxies != null) {
- proxy = mAutofillProxies.get(sessionId);
- }
- if (proxy == null) {
- // TODO(b/111330312): this might be fine, in which case we should logv it
- Log.w(TAG, "No proxy for session " + sessionId);
- return;
+ final int size = mAutofillProxies.size();
+ for (int i = 0; i < size; i++) {
+ final int sessionId = mAutofillProxies.keyAt(i);
+ final AutofillProxy proxy = mAutofillProxies.valueAt(i);
+ if (proxy == null) {
+ // TODO(b/111330312): this might be fine, in which case we should logv it
+ Log.w(TAG, "No proxy for session " + sessionId);
+ return;
+ }
+ proxy.destroy();
+ }
+ mAutofillProxies.clear();
}
- proxy.destroy();
- mAutofillProxies.remove(sessionId);
}
private void handleOnUnbind() {
@@ -350,6 +354,16 @@ public abstract class AugmentedAutofillService extends Service {
}
}
+ public void requestShowFillUi(int width, int height, Rect anchorBounds,
+ IAutofillWindowPresenter presenter) throws RemoteException {
+ mClient.requestShowFillUi(mSessionId, mFocusedId, width, height, anchorBounds,
+ presenter);
+ }
+
+ public void requestHideFillUi() throws RemoteException {
+ mClient.requestHideFillUi(mSessionId, mFocusedId);
+ }
+
private void update(@NonNull AutofillId focusedId, @NonNull AutofillValue focusedValue) {
synchronized (mLock) {
// TODO(b/111330312): should we close the popupwindow if the focused id changed?
diff --git a/core/java/android/service/autofill/augmented/FillWindow.java b/core/java/android/service/autofill/augmented/FillWindow.java
index 33b88e42edb7..51b0f01af6ae 100644
--- a/core/java/android/service/autofill/augmented/FillWindow.java
+++ b/core/java/android/service/autofill/augmented/FillWindow.java
@@ -16,22 +16,25 @@
package android.service.autofill.augmented;
import static android.service.autofill.augmented.AugmentedAutofillService.DEBUG;
+import static android.service.autofill.augmented.AugmentedAutofillService.VERBOSE;
+
+import static com.android.internal.util.function.pooled.PooledLambda.obtainMessage;
import android.annotation.LongDef;
import android.annotation.NonNull;
import android.annotation.SystemApi;
import android.annotation.TestApi;
-import android.app.Dialog;
import android.graphics.Rect;
+import android.os.Handler;
+import android.os.Looper;
+import android.os.RemoteException;
import android.service.autofill.augmented.AugmentedAutofillService.AutofillProxy;
import android.service.autofill.augmented.PresentationParams.Area;
import android.util.Log;
-import android.view.Gravity;
import android.view.MotionEvent;
import android.view.View;
-import android.view.ViewGroup;
-import android.view.Window;
import android.view.WindowManager;
+import android.view.autofill.IAutofillWindowPresenter;
import com.android.internal.annotations.GuardedBy;
import com.android.internal.util.Preconditions;
@@ -71,7 +74,7 @@ public final class FillWindow implements AutoCloseable {
/** Indicates the data being shown is a physical address */
public static final long FLAG_METADATA_ADDRESS = 0x1;
- // TODO(b/111330312): add moar flags
+ // TODO(b/111330312): add more flags
/** @hide */
@LongDef(prefix = { "FLAG" }, value = {
@@ -83,8 +86,17 @@ public final class FillWindow implements AutoCloseable {
private final Object mLock = new Object();
private final CloseGuard mCloseGuard = CloseGuard.get();
+ private final @NonNull Handler mUiThreadHandler = new Handler(Looper.getMainLooper());
+ private final @NonNull FillWindowPresenter mFillWindowPresenter = new FillWindowPresenter();
+
+ @GuardedBy("mLock")
+ private WindowManager mWm;
@GuardedBy("mLock")
- private Dialog mDialog;
+ private View mFillView;
+ @GuardedBy("mLock")
+ private boolean mShowing;
+ @GuardedBy("mLock")
+ private Rect mBounds;
@GuardedBy("mLock")
private boolean mDestroyed;
@@ -140,51 +152,28 @@ public final class FillWindow implements AutoCloseable {
// window instead of destroying. In fact, it might be better to allocate a full window
// initially, which is transparent (and let touches get through) everywhere but in the
// rect boundaries.
- destroy();
// TODO(b/111330312): make sure all touch events are handled, window is always closed,
// etc.
- mDialog = new Dialog(rootView.getContext()) {
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- if (event.getAction() == MotionEvent.ACTION_OUTSIDE) {
- FillWindow.this.destroy();
+ mWm = rootView.getContext().getSystemService(WindowManager.class);
+ mFillView = rootView;
+ // Listen to the touch outside to destroy the window when typing is detected.
+ mFillView.setOnTouchListener(
+ (view, motionEvent) -> {
+ if (motionEvent.getAction() == MotionEvent.ACTION_OUTSIDE) {
+ if (VERBOSE) Log.v(TAG, "Outside touch detected, hiding the window");
+ hide();
+ }
+ return false;
}
- return false;
- }
- };
- mCloseGuard.open("destroy");
- final Window window = mDialog.getWindow();
- window.setType(WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY);
- // Makes sure touch outside the dialog is received by the window behind the dialog.
- window.addFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL);
- // Makes sure the touch outside the dialog is received by the dialog to dismiss it.
- window.addFlags(WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH);
- // Makes sure keyboard shows up.
- window.addFlags(WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM);
-
- final int height = rect.bottom - rect.top;
- final int width = rect.right - rect.left;
- final WindowManager.LayoutParams windowParams = window.getAttributes();
- windowParams.gravity = Gravity.TOP | Gravity.LEFT;
- windowParams.y = rect.top + height;
- windowParams.height = height;
- windowParams.x = rect.left;
- windowParams.width = width;
-
- window.setAttributes(windowParams);
- window.clearFlags(WindowManager.LayoutParams.FLAG_DIM_BEHIND);
- window.setBackgroundDrawableResource(android.R.color.transparent);
-
- mDialog.requestWindowFeature(Window.FEATURE_NO_TITLE);
- final ViewGroup.LayoutParams diagParams = new ViewGroup.LayoutParams(width, height);
- mDialog.setContentView(rootView, diagParams);
-
+ );
+ mShowing = false;
+ mBounds = new Rect(area.getBounds());
if (DEBUG) {
Log.d(TAG, "Created FillWindow: params= " + smartSuggestion + " view=" + rootView);
}
-
+ mDestroyed = false;
mProxy.setFillWindow(this);
return true;
}
@@ -194,36 +183,87 @@ public final class FillWindow implements AutoCloseable {
void show() {
// TODO(b/111330312): check if updated first / throw exception
if (DEBUG) Log.d(TAG, "show()");
-
synchronized (mLock) {
checkNotDestroyedLocked();
- if (mDialog == null) {
+ if (mWm == null || mFillView == null) {
throw new IllegalStateException("update() not called yet, or already destroyed()");
}
-
- mDialog.show();
if (mProxy != null) {
+ try {
+ mProxy.requestShowFillUi(mBounds.right - mBounds.left,
+ mBounds.bottom - mBounds.top,
+ /*anchorBounds=*/ null, mFillWindowPresenter);
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error requesting to show fill window", e);
+ }
mProxy.report(AutofillProxy.REPORT_EVENT_UI_SHOWN);
}
}
}
/**
- * Destroys the window.
+ * Hides the window.
*
- * <p>Once destroyed, this window cannot be used anymore
+ * <p>The window is not destroyed and can be shown again
*/
- public void destroy() {
- if (DEBUG) Log.d(TAG, "destroy(): mDestroyed=" + mDestroyed + " mDialog=" + mDialog);
+ private void hide() {
+ if (DEBUG) Log.d(TAG, "hide()");
+ synchronized (mLock) {
+ checkNotDestroyedLocked();
+ if (mWm == null || mFillView == null) {
+ throw new IllegalStateException("update() not called yet, or already destroyed()");
+ }
+ if (mProxy != null && mShowing) {
+ try {
+ mProxy.requestHideFillUi();
+ } catch (RemoteException e) {
+ Log.w(TAG, "Error requesting to hide fill window", e);
+ }
+ }
+ }
+ }
- synchronized (this) {
- if (mDestroyed || mDialog == null) return;
+ private void handleShow(WindowManager.LayoutParams p) {
+ if (DEBUG) Log.d(TAG, "handleShow()");
+ synchronized (mLock) {
+ if (mWm != null && mFillView != null) {
+ p.flags |= WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
+ if (!mShowing) {
+ mWm.addView(mFillView, p);
+ mShowing = true;
+ } else {
+ mWm.updateViewLayout(mFillView, p);
+ }
+ }
+ }
+ }
- mDialog.dismiss();
- mDialog = null;
- if (mProxy != null) {
- mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+ private void handleHide() {
+ if (DEBUG) Log.d(TAG, "handleHide()");
+ synchronized (mLock) {
+ if (mWm != null && mFillView != null && mShowing) {
+ mWm.removeView(mFillView);
+ mShowing = false;
}
+ }
+ }
+
+ /**
+ * Destroys the window.
+ *
+ * <p>Once destroyed, this window cannot be used anymore
+ */
+ public void destroy() {
+ if (DEBUG) {
+ Log.d(TAG,
+ "destroy(): mDestroyed=" + mDestroyed + " mShowing=" + mShowing + " mFillView="
+ + mFillView);
+ }
+ synchronized (mLock) {
+ if (mDestroyed) return;
+ hide();
+ mProxy.report(AutofillProxy.REPORT_EVENT_UI_DESTROYED);
+ mDestroyed = true;
mCloseGuard.close();
}
}
@@ -250,11 +290,15 @@ public final class FillWindow implements AutoCloseable {
public void dump(@NonNull String prefix, @NonNull PrintWriter pw) {
synchronized (this) {
pw.print(prefix); pw.print("destroyed: "); pw.println(mDestroyed);
- if (mDialog != null) {
- pw.print(prefix); pw.print("dialog: ");
- pw.println(mDialog.isShowing() ? "shown" : "hidden");
- pw.print(prefix); pw.print("window: ");
- pw.println(mDialog.getWindow().getAttributes());
+ if (mFillView != null) {
+ pw.print(prefix); pw.print("fill window: ");
+ pw.println(mShowing ? "shown" : "hidden");
+ pw.print(prefix); pw.print("fill view: ");
+ pw.println(mFillView);
+ pw.print(prefix); pw.print("mBounds: ");
+ pw.println(mBounds);
+ pw.print(prefix); pw.print("mWm: ");
+ pw.println(mWm);
}
}
}
@@ -264,4 +308,19 @@ public final class FillWindow implements AutoCloseable {
public void close() throws Exception {
destroy();
}
+
+ private final class FillWindowPresenter extends IAutofillWindowPresenter.Stub {
+ @Override
+ public void show(WindowManager.LayoutParams p, Rect transitionEpicenter,
+ boolean fitsSystemWindows, int layoutDirection) {
+ if (DEBUG) Log.d(TAG, "FillWindowPresenter.show()");
+ mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleShow, FillWindow.this, p));
+ }
+
+ @Override
+ public void hide(Rect transitionEpicenter) {
+ if (DEBUG) Log.d(TAG, "FillWindowPresenter.hide()");
+ mUiThreadHandler.sendMessage(obtainMessage(FillWindow::handleHide, FillWindow.this));
+ }
+ }
}
diff --git a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
index b3ac2da1c17e..fb6912ac6752 100644
--- a/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
+++ b/core/java/android/service/autofill/augmented/IAugmentedAutofillService.aidl
@@ -36,5 +36,5 @@ oneway interface IAugmentedAutofillService {
in ComponentName activityComponent, in AutofillId focusedId,
in AutofillValue focusedValue, long requestTime, in IFillCallback callback);
- void onDestroyFillWindowRequest(int sessionId);
+ void onDestroyAllFillWindowsRequest();
}
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index 93941d0d6edb..888a4c57751e 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -2997,5 +2997,23 @@ public final class AutofillManager {
afm.post(() -> afm.autofill(sessionId, ids, values));
}
}
+
+ @Override
+ public void requestShowFillUi(int sessionId, AutofillId id, int width, int height,
+ Rect anchorBounds, IAutofillWindowPresenter presenter) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.requestShowFillUi(sessionId, id, width, height, anchorBounds,
+ presenter));
+ }
+ }
+
+ @Override
+ public void requestHideFillUi(int sessionId, AutofillId id) {
+ final AutofillManager afm = mAfm.get();
+ if (afm != null) {
+ afm.post(() -> afm.requestHideFillUi(id, false));
+ }
+ }
}
}
diff --git a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
index 67cd0bf87b99..140507c80ed0 100644
--- a/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
+++ b/core/java/android/view/autofill/IAugmentedAutofillManagerClient.aidl
@@ -21,6 +21,7 @@ import java.util.List;
import android.graphics.Rect;
import android.view.autofill.AutofillId;
import android.view.autofill.AutofillValue;
+import android.view.autofill.IAutofillWindowPresenter;
/**
* Object running in the application process and responsible to provide the functionalities
@@ -29,6 +30,24 @@ import android.view.autofill.AutofillValue;
* @hide
*/
interface IAugmentedAutofillManagerClient {
- Rect getViewCoordinates(in AutofillId id);
- void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+ /**
+ * Gets the coordinates of the input field view.
+ */
+ Rect getViewCoordinates(in AutofillId id);
+
+ /**
+ * Autofills the activity with the contents of the values.
+ */
+ void autofill(int sessionId, in List<AutofillId> ids, in List<AutofillValue> values);
+
+ /**
+ * Requests showing the fill UI.
+ */
+ void requestShowFillUi(int sessionId, in AutofillId id, int width, int height,
+ in Rect anchorBounds, in IAutofillWindowPresenter presenter);
+
+ /**
+ * Requests hiding the fill UI.
+ */
+ void requestHideFillUi(int sessionId, in AutofillId id);
}
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
index 24fd7b9ae71d..ec6d20dd5c6a 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerService.java
@@ -701,6 +701,11 @@ public final class AutofillManagerService
public void onBackKeyPressed() {
if (sDebug) Slog.d(TAG, "onBackKeyPressed()");
mUi.hideAll(null);
+ synchronized (mLock) {
+ final AutofillManagerServiceImpl service =
+ getServiceForUserLocked(UserHandle.getCallingUserId());
+ service.onBackKeyPressed();
+ }
}
@Override
diff --git a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
index a6bb049602a0..d037b081cd4d 100644
--- a/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
+++ b/services/autofill/java/com/android/server/autofill/AutofillManagerServiceImpl.java
@@ -187,6 +187,15 @@ final class AutofillManagerServiceImpl
}
@GuardedBy("mLock")
+ void onBackKeyPressed() {
+ final RemoteAugmentedAutofillService remoteService =
+ getRemoteAugmentedAutofillServiceLocked();
+ if (remoteService != null) {
+ remoteService.onDestroyAutofillWindowsRequest();
+ }
+ }
+
+ @GuardedBy("mLock")
@Override // from PerUserSystemService
protected boolean updateLocked(boolean disabled) {
destroySessionsLocked();
diff --git a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
index a8ff9b0d5a3f..5d8d8fa46d3f 100644
--- a/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
+++ b/services/autofill/java/com/android/server/autofill/RemoteAugmentedAutofillService.java
@@ -109,8 +109,8 @@ final class RemoteAugmentedAutofillService
/**
* Called by {@link Session} when it's time to destroy all augmented autofill requests.
*/
- public void onDestroyAutofillWindowsRequest(int sessionId) {
- scheduleAsyncRequest((s) -> s.onDestroyFillWindowRequest(sessionId));
+ public void onDestroyAutofillWindowsRequest() {
+ scheduleAsyncRequest((s) -> s.onDestroyAllFillWindowsRequest());
}
// TODO(b/111330312): inline into PendingAutofillRequest if it doesn't have any other subclass
diff --git a/services/autofill/java/com/android/server/autofill/Session.java b/services/autofill/java/com/android/server/autofill/Session.java
index cf4963c1bebf..a5ef21afc23e 100644
--- a/services/autofill/java/com/android/server/autofill/Session.java
+++ b/services/autofill/java/com/android/server/autofill/Session.java
@@ -2619,7 +2619,7 @@ final class Session implements RemoteFillService.FillServiceCallbacks, ViewState
currentValue);
if (mAugmentedAutofillDestroyer == null) {
- mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest(id);
+ mAugmentedAutofillDestroyer = () -> remoteService.onDestroyAutofillWindowsRequest();
}
return mAugmentedAutofillDestroyer;
}