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

Commit edca30dc authored by TYM Tsai's avatar TYM Tsai Committed by Android (Google) Code Review
Browse files

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

parents ec3ee0a5 3392d187
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);
        }
    }
}