Merge "Hide floating toolbar when user interacts with screen." into mnc-dev
This commit is contained in:
committed by
Android (Google) Code Review
commit
1f21d2a8b1
@ -34443,6 +34443,8 @@ package android.view {
|
||||
method public abstract void setTitle(int);
|
||||
method public void setTitleOptionalHint(boolean);
|
||||
method public void setType(int);
|
||||
method public void snooze(int);
|
||||
field public static final int SNOOZE_TIME_DEFAULT;
|
||||
field public static final int TYPE_FLOATING = 1; // 0x1
|
||||
field public static final int TYPE_PRIMARY = 0; // 0x0
|
||||
}
|
||||
@ -36507,6 +36509,7 @@ package android.view {
|
||||
public class ViewConfiguration {
|
||||
ctor public deprecated ViewConfiguration();
|
||||
method public static android.view.ViewConfiguration get(android.content.Context);
|
||||
method public static int getDefaultActionModeSnoozeTime();
|
||||
method public static int getDoubleTapTimeout();
|
||||
method public static deprecated int getEdgeSlop();
|
||||
method public static deprecated int getFadingEdgeLength();
|
||||
|
@ -36706,6 +36706,8 @@ package android.view {
|
||||
method public abstract void setTitle(int);
|
||||
method public void setTitleOptionalHint(boolean);
|
||||
method public void setType(int);
|
||||
method public void snooze(int);
|
||||
field public static final int SNOOZE_TIME_DEFAULT;
|
||||
field public static final int TYPE_FLOATING = 1; // 0x1
|
||||
field public static final int TYPE_PRIMARY = 0; // 0x0
|
||||
}
|
||||
@ -38770,6 +38772,7 @@ package android.view {
|
||||
public class ViewConfiguration {
|
||||
ctor public deprecated ViewConfiguration();
|
||||
method public static android.view.ViewConfiguration get(android.content.Context);
|
||||
method public static int getDefaultActionModeSnoozeTime();
|
||||
method public static int getDoubleTapTimeout();
|
||||
method public static deprecated int getEdgeSlop();
|
||||
method public static deprecated int getFadingEdgeLength();
|
||||
|
@ -44,6 +44,12 @@ public abstract class ActionMode {
|
||||
*/
|
||||
public static final int TYPE_FLOATING = 1;
|
||||
|
||||
/**
|
||||
* Default snooze time.
|
||||
*/
|
||||
public static final int SNOOZE_TIME_DEFAULT =
|
||||
ViewConfiguration.getDefaultActionModeSnoozeTime();
|
||||
|
||||
private Object mTag;
|
||||
private boolean mTitleOptionalHint;
|
||||
private int mType = TYPE_PRIMARY;
|
||||
@ -206,6 +212,19 @@ public abstract class ActionMode {
|
||||
*/
|
||||
public void invalidateContentRect() {}
|
||||
|
||||
/**
|
||||
* Hide the action mode view from obstructing the content below for a short period.
|
||||
* This only makes sense for action modes that support dynamic positioning on the screen.
|
||||
* If this method is called again before the snooze time expires, the later snooze will
|
||||
* cancel the former and then take effect.
|
||||
* NOTE that there is an internal limit to how long the mode can be snoozed for. It's typically
|
||||
* about a few seconds.
|
||||
*
|
||||
* @param snoozeTime The number of milliseconds to snooze for.
|
||||
* @see #SNOOZE_TIME_DEFAULT
|
||||
*/
|
||||
public void snooze(int snoozeTime) {}
|
||||
|
||||
/**
|
||||
* Finish and close this action mode. The action mode's {@link ActionMode.Callback} will
|
||||
* have its {@link Callback#onDestroyActionMode(ActionMode)} method called.
|
||||
|
@ -212,6 +212,11 @@ public class ViewConfiguration {
|
||||
*/
|
||||
private static final int OVERFLING_DISTANCE = 6;
|
||||
|
||||
/**
|
||||
* Default time to snooze an action mode for.
|
||||
*/
|
||||
private static final int ACTION_MODE_SNOOZE_TIME_DEFAULT = 2000;
|
||||
|
||||
/**
|
||||
* Configuration values for overriding {@link #hasPermanentMenuKey()} behavior.
|
||||
* These constants must match the definition in res/values/config.xml.
|
||||
@ -731,6 +736,13 @@ public class ViewConfiguration {
|
||||
return SCROLL_FRICTION;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return the default duration in milliseconds for {@link ActionMode#snooze(int)}.
|
||||
*/
|
||||
public static int getDefaultActionModeSnoozeTime() {
|
||||
return ACTION_MODE_SNOOZE_TIME_DEFAULT;
|
||||
}
|
||||
|
||||
/**
|
||||
* Report if the device has a permanent menu key available to the user.
|
||||
*
|
||||
|
@ -233,6 +233,24 @@ public class Editor {
|
||||
|
||||
final CursorAnchorInfoNotifier mCursorAnchorInfoNotifier = new CursorAnchorInfoNotifier();
|
||||
|
||||
private final Runnable mHideFloatingToolbar = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.snooze(ActionMode.SNOOZE_TIME_DEFAULT);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mShowFloatingToolbar = new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (mSelectionActionMode != null) {
|
||||
mSelectionActionMode.snooze(0); // snooze off.
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
Editor(TextView textView) {
|
||||
mTextView = textView;
|
||||
// Synchronize the filter list, which places the undo input filter at the end.
|
||||
@ -358,6 +376,9 @@ public class Editor {
|
||||
mTextView.removeCallbacks(mSelectionModeWithoutSelectionRunnable);
|
||||
}
|
||||
|
||||
mTextView.removeCallbacks(mHideFloatingToolbar);
|
||||
mTextView.removeCallbacks(mShowFloatingToolbar);
|
||||
|
||||
destroyDisplayListsData();
|
||||
|
||||
if (mSpellChecker != null) {
|
||||
@ -1169,6 +1190,8 @@ public class Editor {
|
||||
}
|
||||
|
||||
void onTouchEvent(MotionEvent event) {
|
||||
updateFloatingToolbarVisibility(event);
|
||||
|
||||
if (hasSelectionController()) {
|
||||
getSelectionController().onTouchEvent(event);
|
||||
}
|
||||
@ -1189,6 +1212,37 @@ public class Editor {
|
||||
}
|
||||
}
|
||||
|
||||
private void updateFloatingToolbarVisibility(MotionEvent event) {
|
||||
if (mSelectionActionMode != null) {
|
||||
switch (event.getActionMasked()) {
|
||||
case MotionEvent.ACTION_MOVE:
|
||||
hideFloatingToolbar();
|
||||
break;
|
||||
case MotionEvent.ACTION_UP: // fall through
|
||||
case MotionEvent.ACTION_CANCEL:
|
||||
showFloatingToolbar();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void hideFloatingToolbar() {
|
||||
if (mSelectionActionMode != null) {
|
||||
mTextView.removeCallbacks(mShowFloatingToolbar);
|
||||
// Delay the "hide" a little bit just in case a "show" will happen almost immediately.
|
||||
mTextView.postDelayed(mHideFloatingToolbar, 100);
|
||||
}
|
||||
}
|
||||
|
||||
private void showFloatingToolbar() {
|
||||
if (mSelectionActionMode != null) {
|
||||
mTextView.removeCallbacks(mHideFloatingToolbar);
|
||||
// Delay "show" so it doesn't interfere with click confirmations
|
||||
// or double-clicks that could "dismiss" the floating toolbar.
|
||||
int delay = ViewConfiguration.getDoubleTapTimeout();
|
||||
mTextView.postDelayed(mShowFloatingToolbar, delay);
|
||||
}
|
||||
}
|
||||
|
||||
public void beginBatchEdit() {
|
||||
mInBatchEditControllers = true;
|
||||
final InputMethodState ims = mInputMethodState;
|
||||
@ -3661,6 +3715,8 @@ public class Editor {
|
||||
|
||||
@Override
|
||||
public boolean onTouchEvent(MotionEvent ev) {
|
||||
updateFloatingToolbarVisibility(ev);
|
||||
|
||||
switch (ev.getActionMasked()) {
|
||||
case MotionEvent.ACTION_DOWN: {
|
||||
startTouchUpFilter(getCurrentCursorOffset());
|
||||
|
@ -30,6 +30,9 @@ import com.android.internal.widget.FloatingToolbar;
|
||||
|
||||
public class FloatingActionMode extends ActionMode {
|
||||
|
||||
private static final int MAX_SNOOZE_TIME = 3000;
|
||||
private static final int MOVING_HIDE_DELAY = 300;
|
||||
|
||||
private final Context mContext;
|
||||
private final ActionMode.Callback2 mCallback;
|
||||
private final MenuBuilder mMenu;
|
||||
@ -38,12 +41,26 @@ public class FloatingActionMode extends ActionMode {
|
||||
private final Rect mPreviousContentRectOnWindow;
|
||||
private final int[] mViewPosition;
|
||||
private final View mOriginatingView;
|
||||
|
||||
private final Runnable mMovingOff = new Runnable() {
|
||||
public void run() {
|
||||
mFloatingToolbarVisibilityHelper.setMoving(false);
|
||||
}
|
||||
};
|
||||
|
||||
private final Runnable mSnoozeOff = new Runnable() {
|
||||
public void run() {
|
||||
mFloatingToolbarVisibilityHelper.setSnoozed(false);
|
||||
}
|
||||
};
|
||||
|
||||
private FloatingToolbar mFloatingToolbar;
|
||||
private FloatingToolbarVisibilityHelper mFloatingToolbarVisibilityHelper;
|
||||
|
||||
public FloatingActionMode(
|
||||
Context context, ActionMode.Callback2 callback, View originatingView) {
|
||||
mContext = context;
|
||||
mCallback = callback;
|
||||
mContext = Preconditions.checkNotNull(context);
|
||||
mCallback = Preconditions.checkNotNull(callback);
|
||||
mMenu = new MenuBuilder(context).setDefaultShowAsAction(
|
||||
MenuItem.SHOW_AS_ACTION_IF_ROOM);
|
||||
setType(ActionMode.TYPE_FLOATING);
|
||||
@ -51,7 +68,8 @@ public class FloatingActionMode extends ActionMode {
|
||||
mContentRectOnWindow = new Rect();
|
||||
mPreviousContentRectOnWindow = new Rect();
|
||||
mViewPosition = new int[2];
|
||||
mOriginatingView = originatingView;
|
||||
mOriginatingView = Preconditions.checkNotNull(originatingView);
|
||||
mOriginatingView.getLocationInWindow(mViewPosition);
|
||||
}
|
||||
|
||||
public void setFloatingToolbar(FloatingToolbar floatingToolbar) {
|
||||
@ -63,6 +81,7 @@ public class FloatingActionMode extends ActionMode {
|
||||
return mCallback.onActionItemClicked(FloatingActionMode.this, item);
|
||||
}
|
||||
});
|
||||
mFloatingToolbarVisibilityHelper = new FloatingToolbarVisibilityHelper(mFloatingToolbar);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -82,7 +101,7 @@ public class FloatingActionMode extends ActionMode {
|
||||
|
||||
@Override
|
||||
public void invalidate() {
|
||||
Preconditions.checkNotNull(mFloatingToolbar);
|
||||
checkToolbarInitialized();
|
||||
mCallback.onPrepareActionMode(this, mMenu);
|
||||
mFloatingToolbar.updateLayout();
|
||||
invalidateContentRect();
|
||||
@ -90,32 +109,57 @@ public class FloatingActionMode extends ActionMode {
|
||||
|
||||
@Override
|
||||
public void invalidateContentRect() {
|
||||
Preconditions.checkNotNull(mFloatingToolbar);
|
||||
checkToolbarInitialized();
|
||||
mCallback.onGetContentRect(this, mOriginatingView, mContentRect);
|
||||
repositionToolbar();
|
||||
}
|
||||
|
||||
public void updateViewLocationInWindow() {
|
||||
Preconditions.checkNotNull(mFloatingToolbar);
|
||||
checkToolbarInitialized();
|
||||
mOriginatingView.getLocationInWindow(mViewPosition);
|
||||
repositionToolbar();
|
||||
}
|
||||
|
||||
private void repositionToolbar() {
|
||||
checkToolbarInitialized();
|
||||
mContentRectOnWindow.set(
|
||||
mContentRect.left + mViewPosition[0],
|
||||
mContentRect.top + mViewPosition[1],
|
||||
mContentRect.right + mViewPosition[0],
|
||||
mContentRect.bottom + mViewPosition[1]);
|
||||
if (!mContentRectOnWindow.equals(mPreviousContentRectOnWindow)) {
|
||||
if (!mPreviousContentRectOnWindow.isEmpty()) {
|
||||
notifyContentRectMoving();
|
||||
}
|
||||
mFloatingToolbar.setContentRect(mContentRectOnWindow);
|
||||
mFloatingToolbar.updateLayout();
|
||||
}
|
||||
mPreviousContentRectOnWindow.set(mContentRectOnWindow);
|
||||
}
|
||||
|
||||
private void notifyContentRectMoving() {
|
||||
mOriginatingView.removeCallbacks(mMovingOff);
|
||||
mFloatingToolbarVisibilityHelper.setMoving(true);
|
||||
mOriginatingView.postDelayed(mMovingOff, MOVING_HIDE_DELAY);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void snooze(int snoozeTime) {
|
||||
checkToolbarInitialized();
|
||||
snoozeTime = Math.min(MAX_SNOOZE_TIME, snoozeTime);
|
||||
mOriginatingView.removeCallbacks(mSnoozeOff);
|
||||
if (snoozeTime <= 0) {
|
||||
mSnoozeOff.run();
|
||||
} else {
|
||||
mFloatingToolbarVisibilityHelper.setSnoozed(true);
|
||||
mOriginatingView.postDelayed(mSnoozeOff, snoozeTime);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void finish() {
|
||||
checkToolbarInitialized();
|
||||
reset();
|
||||
mCallback.onDestroyActionMode(this);
|
||||
}
|
||||
|
||||
@ -144,4 +188,56 @@ public class FloatingActionMode extends ActionMode {
|
||||
return new MenuInflater(mContext);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws IlllegalStateException
|
||||
*/
|
||||
private void checkToolbarInitialized() {
|
||||
Preconditions.checkState(mFloatingToolbar != null);
|
||||
Preconditions.checkState(mFloatingToolbarVisibilityHelper != null);
|
||||
}
|
||||
|
||||
private void reset() {
|
||||
mOriginatingView.removeCallbacks(mMovingOff);
|
||||
mOriginatingView.removeCallbacks(mSnoozeOff);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* A helper that shows/hides the floating toolbar depending on certain states.
|
||||
*/
|
||||
private static final class FloatingToolbarVisibilityHelper {
|
||||
|
||||
private final FloatingToolbar mToolbar;
|
||||
|
||||
private boolean mSnoozed;
|
||||
private boolean mMoving;
|
||||
private boolean mOutOfBounds;
|
||||
|
||||
public FloatingToolbarVisibilityHelper(FloatingToolbar toolbar) {
|
||||
mToolbar = Preconditions.checkNotNull(toolbar);
|
||||
}
|
||||
|
||||
public void setSnoozed(boolean snoozed) {
|
||||
mSnoozed = snoozed;
|
||||
updateToolbarVisibility();
|
||||
}
|
||||
|
||||
public void setMoving(boolean moving) {
|
||||
mMoving = moving;
|
||||
updateToolbarVisibility();
|
||||
}
|
||||
|
||||
public void setOutOfBounds(boolean outOfBounds) {
|
||||
mOutOfBounds = outOfBounds;
|
||||
updateToolbarVisibility();
|
||||
}
|
||||
|
||||
private void updateToolbarVisibility() {
|
||||
if (mSnoozed || mMoving || mOutOfBounds) {
|
||||
mToolbar.hide();
|
||||
} else if (mToolbar.isHidden()) {
|
||||
mToolbar.show();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Reference in New Issue
Block a user