Merge "Fix inline tooltip position is wrong" into tm-dev

This commit is contained in:
TYM Tsai
2022-05-25 01:05:17 +00:00
committed by Android (Google) Code Review
2 changed files with 149 additions and 13 deletions

View File

@@ -506,6 +506,14 @@ public final class AutofillManager {
public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS = public static final String DEVICE_CONFIG_AUTOFILL_DIALOG_HINTS =
"autofill_dialog_hints"; "autofill_dialog_hints";
/**
* Sets a value of delay time to show up the inline tooltip view.
*
* @hide
*/
public static final String DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY =
"autofill_inline_tooltip_first_show_delay";
private static final String DIALOG_HINTS_DELIMITER = ":"; private static final String DIALOG_HINTS_DELIMITER = ":";
/** @hide */ /** @hide */

View File

@@ -15,24 +15,30 @@
*/ */
package com.android.internal.view.inline; package com.android.internal.view.inline;
import static android.view.autofill.AutofillManager.DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY;
import static android.view.autofill.Helper.sVerbose; import static android.view.autofill.Helper.sVerbose;
import android.annotation.NonNull; import android.annotation.NonNull;
import android.annotation.Nullable; import android.annotation.Nullable;
import android.content.Context; import android.content.Context;
import android.content.ContextWrapper; import android.content.ContextWrapper;
import android.graphics.Rect;
import android.graphics.drawable.Drawable; import android.graphics.drawable.Drawable;
import android.provider.DeviceConfig;
import android.provider.Settings;
import android.transition.Transition; import android.transition.Transition;
import android.util.Slog; import android.util.Slog;
import android.view.Gravity; import android.view.Gravity;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.WindowManager; import android.view.WindowManager;
import android.widget.LinearLayout; import android.widget.LinearLayout;
import android.widget.PopupWindow; import android.widget.PopupWindow;
import android.widget.inline.InlineContentView; import android.widget.inline.InlineContentView;
import java.io.PrintWriter; import java.io.PrintWriter;
import java.lang.ref.WeakReference;
/** /**
* UI container for the inline suggestion tooltip. * UI container for the inline suggestion tooltip.
@@ -40,6 +46,8 @@ import java.io.PrintWriter;
public final class InlineTooltipUi extends PopupWindow implements AutoCloseable { public final class InlineTooltipUi extends PopupWindow implements AutoCloseable {
private static final String TAG = "InlineTooltipUi"; private static final String TAG = "InlineTooltipUi";
private static final int FIRST_TIME_SHOW_DEFAULT_DELAY_MS = 250;
private final WindowManager mWm; private final WindowManager mWm;
private final ViewGroup mContentContainer; private final ViewGroup mContentContainer;
@@ -47,6 +55,16 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
private WindowManager.LayoutParams mWindowLayoutParams; private WindowManager.LayoutParams mWindowLayoutParams;
private DelayShowRunnable mDelayShowTooltip;
private boolean mHasEverDetached;
private boolean mDelayShowAtStart = true;
private boolean mDelaying = false;
private int mShowDelayConfigMs;
private final Rect mTmpRect = new Rect();
private final View.OnAttachStateChangeListener mAnchorOnAttachStateChangeListener = private final View.OnAttachStateChangeListener mAnchorOnAttachStateChangeListener =
new View.OnAttachStateChangeListener() { new View.OnAttachStateChangeListener() {
@Override @Override
@@ -56,6 +74,7 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
@Override @Override
public void onViewDetachedFromWindow(View v) { public void onViewDetachedFromWindow(View v) {
mHasEverDetached = true;
dismiss(); dismiss();
} }
}; };
@@ -66,6 +85,13 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
@Override @Override
public void onLayoutChange(View v, int left, int top, int right, int bottom, public void onLayoutChange(View v, int left, int top, int right, int bottom,
int oldLeft, int oldTop, int oldRight, int oldBottom) { int oldLeft, int oldTop, int oldRight, int oldBottom) {
if (mHasEverDetached) {
// If the tooltip is ever detached, skip adjusting the position,
// because it only accepts to attach once and does not show again
// after detaching.
return;
}
if (mHeight != bottom - top) { if (mHeight != bottom - top) {
mHeight = bottom - top; mHeight = bottom - top;
adjustPosition(); adjustPosition();
@@ -77,6 +103,13 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
mContentContainer = new LinearLayout(new ContextWrapper(context)); mContentContainer = new LinearLayout(new ContextWrapper(context));
mWm = context.getSystemService(WindowManager.class); mWm = context.getSystemService(WindowManager.class);
// That's a default delay time, and it will scale via the value of
// Settings.Global.ANIMATOR_DURATION_SCALE
mShowDelayConfigMs = DeviceConfig.getInt(
DeviceConfig.NAMESPACE_AUTOFILL,
DEVICE_CONFIG_AUTOFILL_TOOLTIP_SHOW_UP_DELAY,
FIRST_TIME_SHOW_DEFAULT_DELAY_MS);
setTouchModal(false); setTouchModal(false);
setOutsideTouchable(true); setOutsideTouchable(true);
setInputMethodMode(INPUT_METHOD_NOT_NEEDED); setInputMethodMode(INPUT_METHOD_NOT_NEEDED);
@@ -95,7 +128,7 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
@Override @Override
public void close() { public void close() {
hide(); dismiss();
} }
@Override @Override
@@ -117,14 +150,57 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
* The effective {@code update} method that should be called by its clients. * The effective {@code update} method that should be called by its clients.
*/ */
public void update(View anchor) { public void update(View anchor) {
if (anchor == null) {
final View oldAnchor = getAnchor();
if (oldAnchor != null) {
removeDelayShowTooltip(oldAnchor);
}
return;
}
if (mDelayShowAtStart) {
// To avoid showing when the anchor is doing the fade in animation. That will
// cause the tooltip to show in the wrong position and jump at the start.
mDelayShowAtStart = false;
mDelaying = true;
if (mDelayShowTooltip == null) {
mDelayShowTooltip = new DelayShowRunnable(anchor);
}
int delayTimeMs = mShowDelayConfigMs;
try {
final float scale = Settings.Global.getFloat(
anchor.getContext().getContentResolver(),
Settings.Global.ANIMATOR_DURATION_SCALE);
delayTimeMs *= scale;
} catch (Settings.SettingNotFoundException e) {
// do nothing
}
anchor.postDelayed(mDelayShowTooltip, delayTimeMs);
} else if (!mDelaying) {
// Note: If we are going to reuse the tooltip, we need to take care the delay in
// the case that update for the new anchor.
updateInner(anchor);
}
}
private void removeDelayShowTooltip(View anchor) {
if (mDelayShowTooltip != null) {
anchor.removeCallbacks(mDelayShowTooltip);
mDelayShowTooltip = null;
}
}
private void updateInner(View anchor) {
if (mHasEverDetached) {
return;
}
// set to the application type with the highest z-order // set to the application type with the highest z-order
setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL); setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
// The first time to show up, the height of tooltip is zero, final int offsetY = -anchor.getHeight() - getPreferHeight(anchor);
// so set the offset Y to 2 * anchor height.
final int achoredHeight = mContentContainer.getHeight();
final int offsetY = (achoredHeight == 0)
? -anchor.getHeight() << 1 : -anchor.getHeight() - achoredHeight;
if (!isShowing()) { if (!isShowing()) {
setWidth(WindowManager.LayoutParams.WRAP_CONTENT); setWidth(WindowManager.LayoutParams.WRAP_CONTENT);
setHeight(WindowManager.LayoutParams.WRAP_CONTENT); setHeight(WindowManager.LayoutParams.WRAP_CONTENT);
@@ -135,6 +211,34 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
} }
} }
private int getPreferHeight(View anchor) {
// The first time to show up, the height of tooltip is zero, so make its height
// the same as anchor.
final int achoredHeight = mContentContainer.getHeight();
return (achoredHeight == 0) ? anchor.getHeight() : achoredHeight;
}
@Override
protected boolean findDropDownPosition(View anchor, WindowManager.LayoutParams outParams,
int xOffset, int yOffset, int width, int height, int gravity, boolean allowScroll) {
boolean isAbove = super.findDropDownPosition(anchor, outParams, xOffset, yOffset, width,
height, gravity, allowScroll);
// Make the tooltips y fo position is above or under the parent of the anchor,
// otherwise suggestions doesn't clickable.
ViewParent parent = anchor.getParent();
if (parent instanceof View) {
final Rect r = mTmpRect;
((View) parent).getGlobalVisibleRect(r);
if (isAbove) {
outParams.y = r.top - getPreferHeight(anchor);
} else {
outParams.y = r.bottom + 1;
}
}
return isAbove;
}
@Override @Override
protected void update(View anchor, WindowManager.LayoutParams params) { protected void update(View anchor, WindowManager.LayoutParams params) {
// update content view for the anchor is scrolling // update content view for the anchor is scrolling
@@ -175,7 +279,9 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
final View anchor = getAnchor(); final View anchor = getAnchor();
if (anchor != null) { if (anchor != null) {
anchor.removeOnAttachStateChangeListener(mAnchorOnAttachStateChangeListener); anchor.removeOnAttachStateChangeListener(mAnchorOnAttachStateChangeListener);
removeDelayShowTooltip(anchor);
} }
mHasEverDetached = true;
super.detachFromAnchor(); super.detachFromAnchor();
} }
@@ -185,7 +291,6 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
return; return;
} }
setShowing(false);
setTransitioningToDismiss(true); setTransitioningToDismiss(true);
hide(); hide();
@@ -193,6 +298,7 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
if (getOnDismissListener() != null) { if (getOnDismissListener() != null) {
getOnDismissListener().onDismiss(); getOnDismissListener().onDismiss();
} }
super.dismiss();
} }
private void adjustPosition() { private void adjustPosition() {
@@ -202,15 +308,15 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
} }
private void show(WindowManager.LayoutParams params) { private void show(WindowManager.LayoutParams params) {
if (sVerbose) {
Slog.v(TAG, "show()");
}
mWindowLayoutParams = params; mWindowLayoutParams = params;
try { try {
params.packageName = "android"; params.packageName = "android";
params.setTitle("Autofill Inline Tooltip"); // Title is set for debugging purposes params.setTitle("Autofill Inline Tooltip"); // Title is set for debugging purposes
if (!mShowing) { if (!mShowing) {
if (sVerbose) {
Slog.v(TAG, "show()");
}
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE; | WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
params.privateFlags |= params.privateFlags |=
@@ -232,11 +338,11 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
} }
private void hide() { private void hide() {
if (sVerbose) {
Slog.v(TAG, "hide()");
}
try { try {
if (mShowing) { if (mShowing) {
if (sVerbose) {
Slog.v(TAG, "hide()");
}
mContentContainer.removeOnLayoutChangeListener(mAnchoredOnLayoutChangeListener); mContentContainer.removeOnLayoutChangeListener(mAnchoredOnLayoutChangeListener);
mWm.removeView(mContentContainer); mWm.removeView(mContentContainer);
mShowing = false; mShowing = false;
@@ -336,4 +442,26 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
} }
} }
} }
private class DelayShowRunnable implements Runnable {
WeakReference<View> mAnchor;
DelayShowRunnable(View anchor) {
mAnchor = new WeakReference<>(anchor);
}
@Override
public void run() {
mDelaying = false;
final View anchor = mAnchor.get();
if (anchor != null) {
updateInner(anchor);
}
}
public void setAnchor(View anchor) {
mAnchor.clear();
mAnchor = new WeakReference<>(anchor);
}
}
} }