Loading core/res/res/values/dimens.xml +1 −2 Original line number Diff line number Diff line Loading @@ -520,7 +520,6 @@ <dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen> <!-- The elevation of AutoFill fill window--> <dimen name="autofill_fill_elevation">4dp</dimen> <dimen name="autofill_fill_elevation">2dp</dimen> <dimen name="autofill_fill_item_height">64dp</dimen> <dimen name="autofill_fill_min_margin">16dp</dimen> </resources> core/res/res/values/symbols.xml +0 −1 Original line number Diff line number Diff line Loading @@ -2834,7 +2834,6 @@ <!-- com.android.server.autofill --> <java-symbol type="dimen" name="autofill_fill_elevation" /> <java-symbol type="dimen" name="autofill_fill_item_height" /> <java-symbol type="dimen" name="autofill_fill_min_margin" /> <java-symbol type="layout" name="autofill_save"/> <java-symbol type="id" name="autofill_save_title" /> <java-symbol type="id" name="autofill_save_no" /> Loading services/autofill/java/com/android/server/autofill/AnchoredWindow.java +74 −217 Original line number Diff line number Diff line Loading @@ -17,277 +17,134 @@ package com.android.server.autofill; import static com.android.server.autofill.Helper.DEBUG; import android.annotation.Nullable; import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.IBinder; import android.util.Slog; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.FrameLayout; import java.io.PrintWriter; /** * A window above the application that is smartly anchored to a rectangular region. */ final class AnchoredWindow implements View.OnLayoutChangeListener, View.OnTouchListener { final class AnchoredWindow { private static final String TAG = "AutoFill"; private static final int NULL_HEIGHT = -1; private final WindowManager mWm; private final IBinder mAppToken; private final View mContentView; private final View mWindowSizeListenerView; private final int mMinMargin; private int mLastHeight = NULL_HEIGHT; @Nullable private Rect mLastBounds; @Nullable private Rect mLastDisplayBounds; private final View mRootView; private final View mView; private final int mWidth; private final int mHeight; private boolean mIsShowing = false; /** * Constructor. * * @param wm window manager that draws the content on a window * @param appToken token to pass to window manager * @param contentView content of the window * @param wm window manager that draws the view on a window * @param view singleton view in the window * @param width requested width of the view * @param height requested height of the view */ AnchoredWindow(WindowManager wm, IBinder appToken, View contentView) { AnchoredWindow(WindowManager wm, View view, int width, int height) { mWm = wm; mAppToken = appToken; mContentView = contentView; mContentView.addOnLayoutChangeListener(this); Context context = contentView.getContext(); mWindowSizeListenerView = new FrameLayout(context); mWindowSizeListenerView.addOnLayoutChangeListener(this); mMinMargin = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.autofill_fill_min_margin); mRootView = wrapView(view, width, height); mView = view; mWidth = width; mHeight = height; } /** * Shows the window. * * @param bounds the region the window should be anchored to * @param bounds the rectangular region this window should be anchored to */ void show(Rect bounds) { if (DEBUG) Slog.d(TAG, "show bounds=" + bounds); final LayoutParams params = createBaseLayoutParams(); params.x = bounds.left; params.y = bounds.bottom; if (!mWindowSizeListenerView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "adding mWindowSizeListenerView"); LayoutParams params = createWindowLayoutParams( mAppToken, LayoutParams.FLAG_NOT_TOUCHABLE); // not touchable params.gravity = Gravity.LEFT | Gravity.TOP; params.x = 0; params.y = 0; params.width = LayoutParams.MATCH_PARENT; params.height = LayoutParams.MATCH_PARENT; mWm.addView(mWindowSizeListenerView, params); if (!mIsShowing) { if (DEBUG) Slog.d(TAG, "adding view " + mView); mWm.addView(mRootView, params); } else { if (DEBUG) Slog.d(TAG, "updating view " + mView); mWm.updateViewLayout(mRootView, params); } updateBounds(bounds); mIsShowing = true; } /** * Hides the window. */ void hide() { if (DEBUG) Slog.d(TAG, "hide"); mLastHeight = NULL_HEIGHT; mLastBounds = null; mLastDisplayBounds = null; if (mWindowSizeListenerView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "removing mWindowSizeListenerView"); mWm.removeView(mWindowSizeListenerView); } if (mContentView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "removing mContentView"); mContentView.setOnTouchListener(null); mWm.removeView(mContentView); } } if (DEBUG) Slog.d(TAG, "removing view " + mView); @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { if (view == mWindowSizeListenerView) { if (DEBUG) Slog.d(TAG, "onLayoutChange() for mWindowSizeListenerView"); // mWindowSizeListenerView layout changed, get the size of the display bounds and update // the window. final Rect displayBounds = new Rect(); view.getBoundsOnScreen(displayBounds); updateDisplayBounds(displayBounds); } else if (view == mContentView) { // mContentView layout changed, update the window in case its height changed. if (DEBUG) Slog.d(TAG, "onLayoutChange() for mContentView"); updateHeight(); } } // When the window is touched outside, hide the window. @Override public boolean onTouch(View view, MotionEvent event) { if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) { hide(); return true; if (mIsShowing) { mWm.removeView(mRootView); } return false; mIsShowing = false; } private boolean updateHeight() { final Rect displayBounds = mLastDisplayBounds; if (displayBounds == null) { return false; } mContentView.measure( MeasureSpec.makeMeasureSpec(displayBounds.width(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(displayBounds.height(), MeasureSpec.AT_MOST)); int height = mContentView.getMeasuredHeight(); if (height != mLastHeight) { if (DEBUG) Slog.d(TAG, "update height=" + height); mLastHeight = height; update(height, mLastBounds, displayBounds); return true; } else { return false; } /** * Wraps a view with a SelfRemovingView and sets its requested width and height. */ private View wrapView(View view, int width, int height) { final ViewGroup viewGroup = new SelfRemovingView(view.getContext()); viewGroup.addView(view, new ViewGroup.LayoutParams(width, height)); return viewGroup; } private void updateBounds(Rect bounds) { if (!bounds.equals(mLastBounds)) { if (DEBUG) Slog.d(TAG, "update bounds=" + bounds); mLastBounds = bounds; update(mLastHeight, bounds, mLastDisplayBounds); } private static LayoutParams createBaseLayoutParams() { final LayoutParams params = new LayoutParams(); // TODO(b/33197203): LayoutParams.TYPE_AUTOFILL params.type = LayoutParams.TYPE_SYSTEM_ALERT; params.flags = LayoutParams.SOFT_INPUT_STATE_UNCHANGED | LayoutParams.FLAG_LAYOUT_IN_SCREEN | LayoutParams.FLAG_LAYOUT_NO_LIMITS | LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; params.gravity = Gravity.TOP | Gravity.LEFT; params.width = LayoutParams.WRAP_CONTENT; params.height = LayoutParams.WRAP_CONTENT; return params; } private void updateDisplayBounds(Rect displayBounds) { if (!displayBounds.equals(mLastDisplayBounds)) { if (DEBUG) Slog.d(TAG, "update displayBounds=" + displayBounds); mLastDisplayBounds = displayBounds; if (!updateHeight()) { update(mLastHeight, mLastBounds, displayBounds); } } } @Override public String toString() { if (!DEBUG) return super.toString(); // Updates the window if height, bounds, and displayBounds are not null. // Caller should ensure that something changed before calling. private void update(int height, @Nullable Rect bounds, @Nullable Rect displayBounds) { if (height == NULL_HEIGHT || bounds == null || displayBounds == null) { return; return "AnchoredWindow: [width=" + mWidth + ", height=" + mHeight + ", view=" + mView + "]"; } if (DEBUG) Slog.d(TAG, "update height=" + height + ", bounds=" + bounds + ", displayBounds=" + displayBounds); final LayoutParams params = createWindowLayoutParams(mAppToken, LayoutParams.FLAG_NOT_TOUCH_MODAL // outside touches go to windows behind us | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); // outside touches trigger MotionEvent params.setTitle("AutoFill Fill"); // used for debugging updatePosition(params, height, mMinMargin, bounds, displayBounds); if (!mContentView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "adding mContentView"); mWm.addView(mContentView, params); mContentView.setOnTouchListener(this); } else { if (DEBUG) Slog.d(TAG, "updating mContentView"); mWm.updateViewLayout(mContentView, params); } void dump(PrintWriter pw) { pw.println("Anchored Window"); final String prefix = " "; pw.print(prefix); pw.print("width: "); pw.println(mWidth); pw.print(prefix); pw.print("height: "); pw.println(mHeight); pw.print(prefix); pw.print("visible: "); pw.println(mIsShowing); } /** * Updates the position of the window by altering the {@link LayoutParams}. * * <p>The window can be anchored either above or below the bounds. Anchoring the window below * the bounds is preferred, if it fits. Otherwise, anchor the window on the side with more * space. * * @param params the params to update * @param height the requested height of the window * @param minMargin the minimum margin between the window and the display bounds * @param bounds the region the window should be anchored to * @param displayBounds the region in which the window may be displayed */ private static void updatePosition( LayoutParams params, int height, int minMargin, Rect bounds, Rect displayBounds) { boolean below; int verticalSpace; final int verticalSpaceBelow = displayBounds.bottom - bounds.bottom - minMargin; if (height <= verticalSpaceBelow) { // Fits below bounds. below = true; verticalSpace = height; } else { final int verticalSpaceAbove = bounds.top - displayBounds.top - minMargin; if (height <= verticalSpaceAbove) { // Fits above bounds. below = false; verticalSpace = height; } else { // Pick above/below based on which has the most space. if (verticalSpaceBelow >= verticalSpaceAbove) { below = true; verticalSpace = verticalSpaceBelow; } else { below = false; verticalSpace = verticalSpaceAbove; } } /** FrameLayout that listens for touch events removes itself if the touch event is outside. */ private final class SelfRemovingView extends FrameLayout { public SelfRemovingView(Context context) { super(context); } int gravity; int y; if (below) { if (DEBUG) Slog.d(TAG, "anchorBelow"); gravity = Gravity.TOP | Gravity.LEFT; y = bounds.bottom - displayBounds.top; @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { hide(); return true; } else { if (DEBUG) Slog.d(TAG, "anchorAbove"); gravity = Gravity.BOTTOM | Gravity.LEFT; y = displayBounds.bottom - bounds.top; return super.onTouchEvent(event); } final int x = bounds.left - displayBounds.left; params.gravity = gravity; params.x = x; params.y = y; params.width = bounds.width(); params.height = verticalSpace; } private static LayoutParams createWindowLayoutParams(IBinder appToken, int flags) { final LayoutParams params = new LayoutParams(); params.token = appToken; params.type = LayoutParams.TYPE_PHONE; params.flags = flags | LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events | LayoutParams.FLAG_ALT_FOCUSABLE_IM; // resize for soft input params.format = PixelFormat.TRANSLUCENT; return params; } } services/autofill/java/com/android/server/autofill/AutoFillUI.java +20 −5 Original line number Diff line number Diff line Loading @@ -69,6 +69,8 @@ final class AutoFillUI { private AnchoredWindow mFillWindow; private DatasetPicker mFillView; private ViewState mViewState; private Rect mBounds; private String mFilterText; /** * Custom snackbar UI used for saving autofill or other informational messages. Loading Loading @@ -112,6 +114,8 @@ final class AutoFillUI { } mViewState = null; mBounds = null; mFilterText = null; mFillView = null; mFillWindow = null; } Loading Loading @@ -139,14 +143,23 @@ final class AutoFillUI { mSession.autoFillApp(dataset); hideFillUi(); }); mFillWindow = new AnchoredWindow(mWm, mAppToken, mFillView); mFillWindow = new AnchoredWindow( mWm, mFillView, 800, ViewGroup.LayoutParams.WRAP_CONTENT); if (DEBUG) Slog.d(TAG, "showFillUi(): view changed"); if (DEBUG) Slog.d(TAG, "show FillUi"); } if (DEBUG) Slog.d(TAG, "showFillUi(): bounds=" + bounds + ", filterText=" + filterText); mFillView.update(filterText); mFillWindow.show(bounds); if (!bounds.equals(mBounds)) { if (DEBUG) Slog.d(TAG, "update FillUi bounds: " + mBounds); mBounds = bounds; mFillWindow.show(mBounds); } if (!filterText.equals(mFilterText)) { if (DEBUG) Slog.d(TAG, "update FillUi filter text: " + mFilterText); mFilterText = filterText; mFillView.update(mFilterText); } }, 0); } Loading Loading @@ -235,6 +248,8 @@ final class AutoFillUI { pw.print(prefix); pw.print("mSessionId: "); pw.println(mSession.mId); pw.print(prefix); pw.print("mSnackBar: "); pw.println(mSnackbar); pw.print(prefix); pw.print("mViewState: "); pw.println(mViewState); pw.print(prefix); pw.print("mBounds: "); pw.println(mBounds); pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText); } //similar to a snackbar, but can be a bit custom since it is more than just text. This will Loading Loading
core/res/res/values/dimens.xml +1 −2 Original line number Diff line number Diff line Loading @@ -520,7 +520,6 @@ <dimen name="item_touch_helper_swipe_escape_max_velocity">800dp</dimen> <!-- The elevation of AutoFill fill window--> <dimen name="autofill_fill_elevation">4dp</dimen> <dimen name="autofill_fill_elevation">2dp</dimen> <dimen name="autofill_fill_item_height">64dp</dimen> <dimen name="autofill_fill_min_margin">16dp</dimen> </resources>
core/res/res/values/symbols.xml +0 −1 Original line number Diff line number Diff line Loading @@ -2834,7 +2834,6 @@ <!-- com.android.server.autofill --> <java-symbol type="dimen" name="autofill_fill_elevation" /> <java-symbol type="dimen" name="autofill_fill_item_height" /> <java-symbol type="dimen" name="autofill_fill_min_margin" /> <java-symbol type="layout" name="autofill_save"/> <java-symbol type="id" name="autofill_save_title" /> <java-symbol type="id" name="autofill_save_no" /> Loading
services/autofill/java/com/android/server/autofill/AnchoredWindow.java +74 −217 Original line number Diff line number Diff line Loading @@ -17,277 +17,134 @@ package com.android.server.autofill; import static com.android.server.autofill.Helper.DEBUG; import android.annotation.Nullable; import android.content.Context; import android.graphics.Color; import android.graphics.PixelFormat; import android.graphics.Rect; import android.os.IBinder; import android.util.Slog; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; import android.view.View.MeasureSpec; import android.view.ViewGroup; import android.view.WindowManager; import android.view.WindowManager.LayoutParams; import android.widget.FrameLayout; import java.io.PrintWriter; /** * A window above the application that is smartly anchored to a rectangular region. */ final class AnchoredWindow implements View.OnLayoutChangeListener, View.OnTouchListener { final class AnchoredWindow { private static final String TAG = "AutoFill"; private static final int NULL_HEIGHT = -1; private final WindowManager mWm; private final IBinder mAppToken; private final View mContentView; private final View mWindowSizeListenerView; private final int mMinMargin; private int mLastHeight = NULL_HEIGHT; @Nullable private Rect mLastBounds; @Nullable private Rect mLastDisplayBounds; private final View mRootView; private final View mView; private final int mWidth; private final int mHeight; private boolean mIsShowing = false; /** * Constructor. * * @param wm window manager that draws the content on a window * @param appToken token to pass to window manager * @param contentView content of the window * @param wm window manager that draws the view on a window * @param view singleton view in the window * @param width requested width of the view * @param height requested height of the view */ AnchoredWindow(WindowManager wm, IBinder appToken, View contentView) { AnchoredWindow(WindowManager wm, View view, int width, int height) { mWm = wm; mAppToken = appToken; mContentView = contentView; mContentView.addOnLayoutChangeListener(this); Context context = contentView.getContext(); mWindowSizeListenerView = new FrameLayout(context); mWindowSizeListenerView.addOnLayoutChangeListener(this); mMinMargin = context.getResources().getDimensionPixelSize( com.android.internal.R.dimen.autofill_fill_min_margin); mRootView = wrapView(view, width, height); mView = view; mWidth = width; mHeight = height; } /** * Shows the window. * * @param bounds the region the window should be anchored to * @param bounds the rectangular region this window should be anchored to */ void show(Rect bounds) { if (DEBUG) Slog.d(TAG, "show bounds=" + bounds); final LayoutParams params = createBaseLayoutParams(); params.x = bounds.left; params.y = bounds.bottom; if (!mWindowSizeListenerView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "adding mWindowSizeListenerView"); LayoutParams params = createWindowLayoutParams( mAppToken, LayoutParams.FLAG_NOT_TOUCHABLE); // not touchable params.gravity = Gravity.LEFT | Gravity.TOP; params.x = 0; params.y = 0; params.width = LayoutParams.MATCH_PARENT; params.height = LayoutParams.MATCH_PARENT; mWm.addView(mWindowSizeListenerView, params); if (!mIsShowing) { if (DEBUG) Slog.d(TAG, "adding view " + mView); mWm.addView(mRootView, params); } else { if (DEBUG) Slog.d(TAG, "updating view " + mView); mWm.updateViewLayout(mRootView, params); } updateBounds(bounds); mIsShowing = true; } /** * Hides the window. */ void hide() { if (DEBUG) Slog.d(TAG, "hide"); mLastHeight = NULL_HEIGHT; mLastBounds = null; mLastDisplayBounds = null; if (mWindowSizeListenerView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "removing mWindowSizeListenerView"); mWm.removeView(mWindowSizeListenerView); } if (mContentView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "removing mContentView"); mContentView.setOnTouchListener(null); mWm.removeView(mContentView); } } if (DEBUG) Slog.d(TAG, "removing view " + mView); @Override public void onLayoutChange(View view, int left, int top, int right, int bottom, int oldLeft, int oldTop, int oldRight, int oldBottom) { if (view == mWindowSizeListenerView) { if (DEBUG) Slog.d(TAG, "onLayoutChange() for mWindowSizeListenerView"); // mWindowSizeListenerView layout changed, get the size of the display bounds and update // the window. final Rect displayBounds = new Rect(); view.getBoundsOnScreen(displayBounds); updateDisplayBounds(displayBounds); } else if (view == mContentView) { // mContentView layout changed, update the window in case its height changed. if (DEBUG) Slog.d(TAG, "onLayoutChange() for mContentView"); updateHeight(); } } // When the window is touched outside, hide the window. @Override public boolean onTouch(View view, MotionEvent event) { if (view == mContentView && event.getAction() == MotionEvent.ACTION_OUTSIDE) { hide(); return true; if (mIsShowing) { mWm.removeView(mRootView); } return false; mIsShowing = false; } private boolean updateHeight() { final Rect displayBounds = mLastDisplayBounds; if (displayBounds == null) { return false; } mContentView.measure( MeasureSpec.makeMeasureSpec(displayBounds.width(), MeasureSpec.AT_MOST), MeasureSpec.makeMeasureSpec(displayBounds.height(), MeasureSpec.AT_MOST)); int height = mContentView.getMeasuredHeight(); if (height != mLastHeight) { if (DEBUG) Slog.d(TAG, "update height=" + height); mLastHeight = height; update(height, mLastBounds, displayBounds); return true; } else { return false; } /** * Wraps a view with a SelfRemovingView and sets its requested width and height. */ private View wrapView(View view, int width, int height) { final ViewGroup viewGroup = new SelfRemovingView(view.getContext()); viewGroup.addView(view, new ViewGroup.LayoutParams(width, height)); return viewGroup; } private void updateBounds(Rect bounds) { if (!bounds.equals(mLastBounds)) { if (DEBUG) Slog.d(TAG, "update bounds=" + bounds); mLastBounds = bounds; update(mLastHeight, bounds, mLastDisplayBounds); } private static LayoutParams createBaseLayoutParams() { final LayoutParams params = new LayoutParams(); // TODO(b/33197203): LayoutParams.TYPE_AUTOFILL params.type = LayoutParams.TYPE_SYSTEM_ALERT; params.flags = LayoutParams.SOFT_INPUT_STATE_UNCHANGED | LayoutParams.FLAG_LAYOUT_IN_SCREEN | LayoutParams.FLAG_LAYOUT_NO_LIMITS | LayoutParams.FLAG_NOT_FOCUSABLE | LayoutParams.FLAG_NOT_TOUCH_MODAL | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH; params.gravity = Gravity.TOP | Gravity.LEFT; params.width = LayoutParams.WRAP_CONTENT; params.height = LayoutParams.WRAP_CONTENT; return params; } private void updateDisplayBounds(Rect displayBounds) { if (!displayBounds.equals(mLastDisplayBounds)) { if (DEBUG) Slog.d(TAG, "update displayBounds=" + displayBounds); mLastDisplayBounds = displayBounds; if (!updateHeight()) { update(mLastHeight, mLastBounds, displayBounds); } } } @Override public String toString() { if (!DEBUG) return super.toString(); // Updates the window if height, bounds, and displayBounds are not null. // Caller should ensure that something changed before calling. private void update(int height, @Nullable Rect bounds, @Nullable Rect displayBounds) { if (height == NULL_HEIGHT || bounds == null || displayBounds == null) { return; return "AnchoredWindow: [width=" + mWidth + ", height=" + mHeight + ", view=" + mView + "]"; } if (DEBUG) Slog.d(TAG, "update height=" + height + ", bounds=" + bounds + ", displayBounds=" + displayBounds); final LayoutParams params = createWindowLayoutParams(mAppToken, LayoutParams.FLAG_NOT_TOUCH_MODAL // outside touches go to windows behind us | LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH); // outside touches trigger MotionEvent params.setTitle("AutoFill Fill"); // used for debugging updatePosition(params, height, mMinMargin, bounds, displayBounds); if (!mContentView.isAttachedToWindow()) { if (DEBUG) Slog.d(TAG, "adding mContentView"); mWm.addView(mContentView, params); mContentView.setOnTouchListener(this); } else { if (DEBUG) Slog.d(TAG, "updating mContentView"); mWm.updateViewLayout(mContentView, params); } void dump(PrintWriter pw) { pw.println("Anchored Window"); final String prefix = " "; pw.print(prefix); pw.print("width: "); pw.println(mWidth); pw.print(prefix); pw.print("height: "); pw.println(mHeight); pw.print(prefix); pw.print("visible: "); pw.println(mIsShowing); } /** * Updates the position of the window by altering the {@link LayoutParams}. * * <p>The window can be anchored either above or below the bounds. Anchoring the window below * the bounds is preferred, if it fits. Otherwise, anchor the window on the side with more * space. * * @param params the params to update * @param height the requested height of the window * @param minMargin the minimum margin between the window and the display bounds * @param bounds the region the window should be anchored to * @param displayBounds the region in which the window may be displayed */ private static void updatePosition( LayoutParams params, int height, int minMargin, Rect bounds, Rect displayBounds) { boolean below; int verticalSpace; final int verticalSpaceBelow = displayBounds.bottom - bounds.bottom - minMargin; if (height <= verticalSpaceBelow) { // Fits below bounds. below = true; verticalSpace = height; } else { final int verticalSpaceAbove = bounds.top - displayBounds.top - minMargin; if (height <= verticalSpaceAbove) { // Fits above bounds. below = false; verticalSpace = height; } else { // Pick above/below based on which has the most space. if (verticalSpaceBelow >= verticalSpaceAbove) { below = true; verticalSpace = verticalSpaceBelow; } else { below = false; verticalSpace = verticalSpaceAbove; } } /** FrameLayout that listens for touch events removes itself if the touch event is outside. */ private final class SelfRemovingView extends FrameLayout { public SelfRemovingView(Context context) { super(context); } int gravity; int y; if (below) { if (DEBUG) Slog.d(TAG, "anchorBelow"); gravity = Gravity.TOP | Gravity.LEFT; y = bounds.bottom - displayBounds.top; @Override public boolean onTouchEvent(MotionEvent event) { if (event.getAction() == MotionEvent.ACTION_OUTSIDE) { hide(); return true; } else { if (DEBUG) Slog.d(TAG, "anchorAbove"); gravity = Gravity.BOTTOM | Gravity.LEFT; y = displayBounds.bottom - bounds.top; return super.onTouchEvent(event); } final int x = bounds.left - displayBounds.left; params.gravity = gravity; params.x = x; params.y = y; params.width = bounds.width(); params.height = verticalSpace; } private static LayoutParams createWindowLayoutParams(IBinder appToken, int flags) { final LayoutParams params = new LayoutParams(); params.token = appToken; params.type = LayoutParams.TYPE_PHONE; params.flags = flags | LayoutParams.FLAG_NOT_FOCUSABLE // don't receive input events | LayoutParams.FLAG_ALT_FOCUSABLE_IM; // resize for soft input params.format = PixelFormat.TRANSLUCENT; return params; } }
services/autofill/java/com/android/server/autofill/AutoFillUI.java +20 −5 Original line number Diff line number Diff line Loading @@ -69,6 +69,8 @@ final class AutoFillUI { private AnchoredWindow mFillWindow; private DatasetPicker mFillView; private ViewState mViewState; private Rect mBounds; private String mFilterText; /** * Custom snackbar UI used for saving autofill or other informational messages. Loading Loading @@ -112,6 +114,8 @@ final class AutoFillUI { } mViewState = null; mBounds = null; mFilterText = null; mFillView = null; mFillWindow = null; } Loading Loading @@ -139,14 +143,23 @@ final class AutoFillUI { mSession.autoFillApp(dataset); hideFillUi(); }); mFillWindow = new AnchoredWindow(mWm, mAppToken, mFillView); mFillWindow = new AnchoredWindow( mWm, mFillView, 800, ViewGroup.LayoutParams.WRAP_CONTENT); if (DEBUG) Slog.d(TAG, "showFillUi(): view changed"); if (DEBUG) Slog.d(TAG, "show FillUi"); } if (DEBUG) Slog.d(TAG, "showFillUi(): bounds=" + bounds + ", filterText=" + filterText); mFillView.update(filterText); mFillWindow.show(bounds); if (!bounds.equals(mBounds)) { if (DEBUG) Slog.d(TAG, "update FillUi bounds: " + mBounds); mBounds = bounds; mFillWindow.show(mBounds); } if (!filterText.equals(mFilterText)) { if (DEBUG) Slog.d(TAG, "update FillUi filter text: " + mFilterText); mFilterText = filterText; mFillView.update(mFilterText); } }, 0); } Loading Loading @@ -235,6 +248,8 @@ final class AutoFillUI { pw.print(prefix); pw.print("mSessionId: "); pw.println(mSession.mId); pw.print(prefix); pw.print("mSnackBar: "); pw.println(mSnackbar); pw.print(prefix); pw.print("mViewState: "); pw.println(mViewState); pw.print(prefix); pw.print("mBounds: "); pw.println(mBounds); pw.print(prefix); pw.print("mFilterText: "); pw.println(mFilterText); } //similar to a snackbar, but can be a bit custom since it is more than just text. This will Loading