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

Commit 3ebb4719 authored by Abodunrinwa Toki's avatar Abodunrinwa Toki Committed by android-build-merger
Browse files

Merge "FloatingActionMode.setOutsideTouchable" into pi-dev

am: 8e7f8ad3

Change-Id: Ifb6a6eb13f7577ded8787fa5d1d6404c97bbf063
parents 453c1225 8e7f8ad3
Loading
Loading
Loading
Loading
+10 −0
Original line number Original line Diff line number Diff line
@@ -123,6 +123,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.ArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.GrowingArrayUtils;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
import com.android.internal.view.FloatingActionMode;
import com.android.internal.widget.EditableInputConnection;
import com.android.internal.widget.EditableInputConnection;


import java.lang.annotation.Retention;
import java.lang.annotation.Retention;
@@ -2215,6 +2216,15 @@ public class Editor {
        ActionMode.Callback actionModeCallback = new TextActionModeCallback(actionMode);
        ActionMode.Callback actionModeCallback = new TextActionModeCallback(actionMode);
        mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);
        mTextActionMode = mTextView.startActionMode(actionModeCallback, ActionMode.TYPE_FLOATING);


        final boolean selectableText = mTextView.isTextEditable() || mTextView.isTextSelectable();
        if (actionMode == TextActionMode.TEXT_LINK && !selectableText
                && mTextActionMode instanceof FloatingActionMode) {
            // Make the toolbar outside-touchable so that it can be dismissed when the user clicks
            // outside of it.
            ((FloatingActionMode) mTextActionMode).setOutsideTouchable(true,
                    () -> stopTextActionMode());
        }

        final boolean selectionStarted = mTextActionMode != null;
        final boolean selectionStarted = mTextActionMode != null;
        if (selectionStarted
        if (selectionStarted
                && mTextView.isTextEditable() && !mTextView.isTextSelectable()
                && mTextView.isTextEditable() && !mTextView.isTextSelectable()
+19 −0
Original line number Original line Diff line number Diff line
@@ -17,6 +17,7 @@
package com.android.internal.view;
package com.android.internal.view;


import android.annotation.NonNull;
import android.annotation.NonNull;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Context;
import android.graphics.Point;
import android.graphics.Point;
import android.graphics.Rect;
import android.graphics.Rect;
@@ -30,6 +31,7 @@ import android.view.ViewGroup;
import android.view.ViewParent;
import android.view.ViewParent;
import android.view.WindowManager;
import android.view.WindowManager;


import android.widget.PopupWindow;
import com.android.internal.R;
import com.android.internal.R;
import com.android.internal.util.Preconditions;
import com.android.internal.util.Preconditions;
import com.android.internal.view.menu.MenuBuilder;
import com.android.internal.view.menu.MenuBuilder;
@@ -241,6 +243,23 @@ public final class FloatingActionMode extends ActionMode {
        }
        }
    }
    }


    /**
     * If this is set to true, the action mode view will dismiss itself on touch events outside of
     * its window. This only makes sense if the action mode view is a PopupWindow that is touchable
     * but not focusable, which means touches outside of the window will be delivered to the window
     * behind. The default is false.
     *
     * This is for internal use only and the approach to this may change.
     * @hide
     *
     * @param outsideTouchable whether or not this action mode is "outside touchable"
     * @param onDismiss optional. Sets a callback for when this action mode popup dismisses itself
     */
    public void setOutsideTouchable(
            boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) {
        mFloatingToolbar.setOutsideTouchable(outsideTouchable, onDismiss);
    }

    @Override
    @Override
    public void onWindowFocusChanged(boolean hasWindowFocus) {
    public void onWindowFocusChanged(boolean hasWindowFocus) {
        mFloatingToolbarVisibilityHelper.setWindowFocused(hasWindowFocus);
        mFloatingToolbarVisibilityHelper.setWindowFocused(hasWindowFocus);
+43 −0
Original line number Original line Diff line number Diff line
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.animation.ObjectAnimator;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator;
import android.annotation.Nullable;
import android.content.Context;
import android.content.Context;
import android.content.res.TypedArray;
import android.content.res.TypedArray;
import android.graphics.Color;
import android.graphics.Color;
@@ -259,6 +260,22 @@ public final class FloatingToolbar {
        return mPopup.isHidden();
        return mPopup.isHidden();
    }
    }


    /**
     * If this is set to true, the action mode view will dismiss itself on touch events outside of
     * its window. If the toolbar is already showing, it will be re-shown so that this setting takes
     * effect immediately.
     *
     * @param outsideTouchable whether or not this action mode is "outside touchable"
     * @param onDismiss optional. Sets a callback for when this action mode popup dismisses itself
     */
    public void setOutsideTouchable(
            boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) {
        if (mPopup.setOutsideTouchable(outsideTouchable, onDismiss) && isShowing()) {
            dismiss();
            doShow();
        }
    }

    private void doShow() {
    private void doShow() {
        List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
        List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
        menuItems.sort(mMenuItemComparator);
        menuItems.sort(mMenuItemComparator);
@@ -512,6 +529,32 @@ public final class FloatingToolbar {
                    });
                    });
        }
        }


        /**
         * Makes this toolbar "outside touchable" and sets the onDismissListener.
         * This will take effect the next time the toolbar is re-shown.
         *
         * @param outsideTouchable if true, the popup will be made "outside touchable" and
         *      "non focusable". The reverse will happen if false.
         * @param onDismiss
         *
         * @return true if the "outsideTouchable" setting was modified. Otherwise returns false
         *
         * @see PopupWindow#setOutsideTouchable(boolean)
         * @see PopupWindow#setFocusable(boolean)
         * @see PopupWindow.OnDismissListener
         */
        public boolean setOutsideTouchable(
                boolean outsideTouchable, @Nullable PopupWindow.OnDismissListener onDismiss) {
            boolean ret = false;
            if (mPopupWindow.isOutsideTouchable() ^ outsideTouchable) {
                mPopupWindow.setOutsideTouchable(outsideTouchable);
                mPopupWindow.setFocusable(!outsideTouchable);
                ret = true;
            }
            mPopupWindow.setOnDismissListener(onDismiss);
            return ret;
        }

        /**
        /**
         * Lays out buttons for the specified menu items.
         * Lays out buttons for the specified menu items.
         * Requires a subsequent call to {@link #show()} to show the items.
         * Requires a subsequent call to {@link #show()} to show the items.
+3 −1
Original line number Original line Diff line number Diff line
@@ -31,6 +31,8 @@
    <TextView
    <TextView
        android:id="@+id/nonselectable_textview"
        android:id="@+id/nonselectable_textview"
        android:layout_width="match_parent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
        android:layout_height="wrap_content"
        android:focusable="false"
        android:focusableInTouchMode="false" />


</LinearLayout>
</LinearLayout>
+29 −17
Original line number Original line Diff line number Diff line
@@ -318,40 +318,52 @@ public class TextViewActivityTest {
        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(position));
        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(position));
        sleepForFloatingToolbarPopup();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarIsDisplayed();

    }
    }


    @Test
    @Test
    public void testToolbarAppearsAfterLinkClickedNonselectable() throws Throwable {
    public void testToolbarAppearsAfterLinkClickedNonselectable() throws Throwable {
        TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
        final TextView textView = mActivity.findViewById(R.id.nonselectable_textview);
        int position = (textLink.getStart() + textLink.getEnd()) / 2;
        final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
        final int position = (textLink.getStart() + textLink.getEnd()) / 2;

        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertTrue(textView.hasSelection());

        // toggle
        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
        sleepForFloatingToolbarPopup();
        assertFalse(textView.hasSelection());

        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
        sleepForFloatingToolbarPopup();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarIsDisplayed();
        assertTrue(textView.hasSelection());

        // click outside
        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(0));
        sleepForFloatingToolbarPopup();
        assertFalse(textView.hasSelection());
    }
    }


    @Test
    @Test
    public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
    public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
        // Add a link to both selectable and nonselectable TextViews:
        final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
        TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.textview);
        final int position = (textLink.getStart() + textLink.getEnd()) / 2;
        int selectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
        final TextView textView = mActivity.findViewById(R.id.nonselectable_textview);
        textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
        mActivityRule.runOnUiThread(() -> textView.setFocusableInTouchMode(true));
        int nonselectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
        TextView selectableTextView = mActivity.findViewById(R.id.textview);
        TextView nonselectableTextView = mActivity.findViewById(R.id.nonselectable_textview);


        onView(withId(R.id.nonselectable_textview))
        onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
                .perform(clickOnTextAtIndex(nonselectablePosition));
        sleepForFloatingToolbarPopup();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();
        assertFloatingToolbarIsDisplayed();
        assertTrue(nonselectableTextView.hasSelection());
        assertTrue(textView.hasSelection());


        onView(withId(R.id.textview)).perform(clickOnTextAtIndex(selectablePosition));
        mActivityRule.runOnUiThread(() -> textView.clearFocus());
        mInstrumentation.waitForIdleSync();
        sleepForFloatingToolbarPopup();
        sleepForFloatingToolbarPopup();
        assertFloatingToolbarIsDisplayed();


        assertTrue(selectableTextView.hasSelection());
        assertFalse(textView.hasSelection());
        assertFalse(nonselectableTextView.hasSelection());
    }
    }


    @Test
    @Test