summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/view/autofill/AutofillManager.java8
-rw-r--r--core/java/com/android/internal/view/inline/InlineTooltipUi.java154
2 files changed, 149 insertions, 13 deletions
diff --git a/core/java/android/view/autofill/AutofillManager.java b/core/java/android/view/autofill/AutofillManager.java
index dcedb3083f76..7353bbccf77c 100644
--- a/core/java/android/view/autofill/AutofillManager.java
+++ b/core/java/android/view/autofill/AutofillManager.java
@@ -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 */
diff --git a/core/java/com/android/internal/view/inline/InlineTooltipUi.java b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
index 25fa678d0507..3eae89e350a0 100644
--- a/core/java/com/android/internal/view/inline/InlineTooltipUi.java
+++ b/core/java/com/android/internal/view/inline/InlineTooltipUi.java
@@ -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);
+ }
+ }
}