Merge "FloatingActionMode.setOutsideTouchable" into pi-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
8e7f8ad3ce
@@ -123,6 +123,7 @@ import com.android.internal.logging.nano.MetricsProto.MetricsEvent;
|
||||
import com.android.internal.util.ArrayUtils;
|
||||
import com.android.internal.util.GrowingArrayUtils;
|
||||
import com.android.internal.util.Preconditions;
|
||||
import com.android.internal.view.FloatingActionMode;
|
||||
import com.android.internal.widget.EditableInputConnection;
|
||||
|
||||
import java.lang.annotation.Retention;
|
||||
@@ -2215,6 +2216,15 @@ public class Editor {
|
||||
ActionMode.Callback actionModeCallback = new TextActionModeCallback(actionMode);
|
||||
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;
|
||||
if (selectionStarted
|
||||
&& mTextView.isTextEditable() && !mTextView.isTextSelectable()
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
package com.android.internal.view;
|
||||
|
||||
import android.annotation.NonNull;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.graphics.Point;
|
||||
import android.graphics.Rect;
|
||||
@@ -30,6 +31,7 @@ import android.view.ViewGroup;
|
||||
import android.view.ViewParent;
|
||||
import android.view.WindowManager;
|
||||
|
||||
import android.widget.PopupWindow;
|
||||
import com.android.internal.R;
|
||||
import com.android.internal.util.Preconditions;
|
||||
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
|
||||
public void onWindowFocusChanged(boolean hasWindowFocus) {
|
||||
mFloatingToolbarVisibilityHelper.setWindowFocused(hasWindowFocus);
|
||||
|
||||
@@ -21,6 +21,7 @@ import android.animation.AnimatorListenerAdapter;
|
||||
import android.animation.AnimatorSet;
|
||||
import android.animation.ObjectAnimator;
|
||||
import android.animation.ValueAnimator;
|
||||
import android.annotation.Nullable;
|
||||
import android.content.Context;
|
||||
import android.content.res.TypedArray;
|
||||
import android.graphics.Color;
|
||||
@@ -259,6 +260,22 @@ public final class FloatingToolbar {
|
||||
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() {
|
||||
List<MenuItem> menuItems = getVisibleAndEnabledMenuItems(mMenu);
|
||||
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.
|
||||
* Requires a subsequent call to {@link #show()} to show the items.
|
||||
|
||||
@@ -31,6 +31,8 @@
|
||||
<TextView
|
||||
android:id="@+id/nonselectable_textview"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
android:layout_height="wrap_content"
|
||||
android:focusable="false"
|
||||
android:focusableInTouchMode="false" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
@@ -318,40 +318,52 @@ public class TextViewActivityTest {
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testToolbarAppearsAfterLinkClickedNonselectable() throws Throwable {
|
||||
TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
|
||||
int position = (textLink.getStart() + textLink.getEnd()) / 2;
|
||||
final TextView textView = mActivity.findViewById(R.id.nonselectable_textview);
|
||||
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));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
assertTrue(textView.hasSelection());
|
||||
|
||||
// click outside
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(0));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFalse(textView.hasSelection());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void testSelectionRemovedWhenNonselectableTextLosesFocus() throws Throwable {
|
||||
// Add a link to both selectable and nonselectable TextViews:
|
||||
TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.textview);
|
||||
int selectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
|
||||
textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
|
||||
int nonselectablePosition = (textLink.getStart() + textLink.getEnd()) / 2;
|
||||
TextView selectableTextView = mActivity.findViewById(R.id.textview);
|
||||
TextView nonselectableTextView = mActivity.findViewById(R.id.nonselectable_textview);
|
||||
final TextLinks.TextLink textLink = addLinkifiedTextToTextView(R.id.nonselectable_textview);
|
||||
final int position = (textLink.getStart() + textLink.getEnd()) / 2;
|
||||
final TextView textView = mActivity.findViewById(R.id.nonselectable_textview);
|
||||
mActivityRule.runOnUiThread(() -> textView.setFocusableInTouchMode(true));
|
||||
|
||||
onView(withId(R.id.nonselectable_textview))
|
||||
.perform(clickOnTextAtIndex(nonselectablePosition));
|
||||
onView(withId(R.id.nonselectable_textview)).perform(clickOnTextAtIndex(position));
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
assertTrue(nonselectableTextView.hasSelection());
|
||||
assertTrue(textView.hasSelection());
|
||||
|
||||
onView(withId(R.id.textview)).perform(clickOnTextAtIndex(selectablePosition));
|
||||
mActivityRule.runOnUiThread(() -> textView.clearFocus());
|
||||
mInstrumentation.waitForIdleSync();
|
||||
sleepForFloatingToolbarPopup();
|
||||
assertFloatingToolbarIsDisplayed();
|
||||
|
||||
assertTrue(selectableTextView.hasSelection());
|
||||
assertFalse(nonselectableTextView.hasSelection());
|
||||
assertFalse(textView.hasSelection());
|
||||
}
|
||||
|
||||
@Test
|
||||
|
||||
Reference in New Issue
Block a user