Merge "Fix inline tooltip position is wrong" into tm-dev
This commit is contained in:
@@ -506,6 +506,14 @@ public final class AutofillManager {
|
||||
public static final String DEVICE_CONFIG_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 = ":";
|
||||
|
||||
/** @hide */
|
||||
|
||||
@@ -15,24 +15,30 @@
|
||||
*/
|
||||
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 android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.graphics.Rect;
|
||||
import android.graphics.drawable.Drawable;
|
||||
import android.provider.DeviceConfig;
|
||||
import android.provider.Settings;
|
||||
import android.transition.Transition;
|
||||
import android.util.Slog;
|
||||
import android.view.Gravity;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.WindowManager;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.PopupWindow;
|
||||
import android.widget.inline.InlineContentView;
|
||||
|
||||
import java.io.PrintWriter;
|
||||
import java.lang.ref.WeakReference;
|
||||
|
||||
/**
|
||||
* UI container for the inline suggestion tooltip.
|
||||
@@ -40,6 +46,8 @@ import java.io.PrintWriter;
|
||||
public final class InlineTooltipUi extends PopupWindow implements AutoCloseable {
|
||||
private static final String TAG = "InlineTooltipUi";
|
||||
|
||||
private static final int FIRST_TIME_SHOW_DEFAULT_DELAY_MS = 250;
|
||||
|
||||
private final WindowManager mWm;
|
||||
private final ViewGroup mContentContainer;
|
||||
|
||||
@@ -47,6 +55,16 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
|
||||
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 =
|
||||
new View.OnAttachStateChangeListener() {
|
||||
@Override
|
||||
@@ -56,6 +74,7 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
|
||||
@Override
|
||||
public void onViewDetachedFromWindow(View v) {
|
||||
mHasEverDetached = true;
|
||||
dismiss();
|
||||
}
|
||||
};
|
||||
@@ -66,6 +85,13 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
@Override
|
||||
public void onLayoutChange(View v, int left, int top, int right, int bottom,
|
||||
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) {
|
||||
mHeight = bottom - top;
|
||||
adjustPosition();
|
||||
@@ -77,6 +103,13 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
mContentContainer = new LinearLayout(new ContextWrapper(context));
|
||||
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);
|
||||
setOutsideTouchable(true);
|
||||
setInputMethodMode(INPUT_METHOD_NOT_NEEDED);
|
||||
@@ -95,7 +128,7 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
hide();
|
||||
dismiss();
|
||||
}
|
||||
|
||||
@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.
|
||||
*/
|
||||
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
|
||||
setWindowLayoutType(WindowManager.LayoutParams.TYPE_APPLICATION_ABOVE_SUB_PANEL);
|
||||
|
||||
// The first time to show up, the height of tooltip is zero,
|
||||
// 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;
|
||||
final int offsetY = -anchor.getHeight() - getPreferHeight(anchor);
|
||||
|
||||
if (!isShowing()) {
|
||||
setWidth(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
|
||||
protected void update(View anchor, WindowManager.LayoutParams params) {
|
||||
// update content view for the anchor is scrolling
|
||||
@@ -175,7 +279,9 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
final View anchor = getAnchor();
|
||||
if (anchor != null) {
|
||||
anchor.removeOnAttachStateChangeListener(mAnchorOnAttachStateChangeListener);
|
||||
removeDelayShowTooltip(anchor);
|
||||
}
|
||||
mHasEverDetached = true;
|
||||
super.detachFromAnchor();
|
||||
}
|
||||
|
||||
@@ -185,7 +291,6 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
return;
|
||||
}
|
||||
|
||||
setShowing(false);
|
||||
setTransitioningToDismiss(true);
|
||||
|
||||
hide();
|
||||
@@ -193,6 +298,7 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
if (getOnDismissListener() != null) {
|
||||
getOnDismissListener().onDismiss();
|
||||
}
|
||||
super.dismiss();
|
||||
}
|
||||
|
||||
private void adjustPosition() {
|
||||
@@ -202,15 +308,15 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
}
|
||||
|
||||
private void show(WindowManager.LayoutParams params) {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "show()");
|
||||
}
|
||||
mWindowLayoutParams = params;
|
||||
|
||||
try {
|
||||
params.packageName = "android";
|
||||
params.setTitle("Autofill Inline Tooltip"); // Title is set for debugging purposes
|
||||
if (!mShowing) {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "show()");
|
||||
}
|
||||
params.flags = WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
|
||||
| WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
|
||||
params.privateFlags |=
|
||||
@@ -232,11 +338,11 @@ public final class InlineTooltipUi extends PopupWindow implements AutoCloseable
|
||||
}
|
||||
|
||||
private void hide() {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "hide()");
|
||||
}
|
||||
try {
|
||||
if (mShowing) {
|
||||
if (sVerbose) {
|
||||
Slog.v(TAG, "hide()");
|
||||
}
|
||||
mContentContainer.removeOnLayoutChangeListener(mAnchoredOnLayoutChangeListener);
|
||||
mWm.removeView(mContentContainer);
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user