Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit eedfddb0 authored by TYM Tsai's avatar TYM Tsai Committed by Automerger Merge Worker
Browse files

Merge "Fix inline tooltip position is wrong" into tm-dev am: edca30dc am:...

Merge "Fix inline tooltip position is wrong" into tm-dev am: edca30dc am: 34fe9578 am: 8a29813f

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/18350147



Change-Id: I9296fbcb8b115d0a3a43fa6cafefc1606dd3b916
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents 1783dc56 8a29813f
Loading
Loading
Loading
Loading
+8 −0
Original line number Diff line number Diff line
@@ -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 */
+141 −13
Original line number Diff line number Diff line
@@ -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() {
        try {
            if (mShowing) {
                if (sVerbose) {
                    Slog.v(TAG, "hide()");
                }
        try {
            if (mShowing) {
                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);
        }
    }
}