diff options
| author | 2019-01-16 01:51:07 +0000 | |
|---|---|---|
| committer | 2019-01-16 01:51:07 +0000 | |
| commit | a5073ec65e42ff6cb75fbbff6e333339c2740f7d (patch) | |
| tree | 8a671fa9dac7bc361859e3567e69d7210a6554ca | |
| parent | 7dcdca64e8e08050fa282e6c4ae3341389fbf6fc (diff) | |
| parent | 158b65635ed01fa5eb9640a0eb1aef756ffb7ccf (diff) | |
Merge "Use the same UI classes for augmented autofill as the standard android autofill."
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; } |