diff options
author | Sunny Goyal <sunnygoyal@google.com> | 2018-03-07 19:58:07 -0800 |
---|---|---|
committer | Sunny Goyal <sunnygoyal@google.com> | 2018-03-13 12:57:32 -0700 |
commit | 7c7be8c20a8b1e8740b734c7cfcebf4b88163773 (patch) | |
tree | 2598f31dd3f3694a80769f6d8465ebb8538d94da /src | |
parent | fad58c8159305923c6daaf28dee8c87d3c6b298f (diff) | |
download | packages_apps_Trebuchet-7c7be8c20a8b1e8740b734c7cfcebf4b88163773.tar.gz packages_apps_Trebuchet-7c7be8c20a8b1e8740b734c7cfcebf4b88163773.tar.bz2 packages_apps_Trebuchet-7c7be8c20a8b1e8740b734c7cfcebf4b88163773.zip |
Simplifying options popup and overview handling
> Removing support for page drag-n-drop from pagedView
> Removing Overview UI from Launcher3 without quickstep and using options popup instead
> Removing touch handlers from CellLayouts and showing options popup based on workspace long press
> Excluding touch outside inset when showing the popup
Bug: 74136505
Change-Id: I34c2a7ff58452db26f5d1a85d554be40fc75f2b8
Diffstat (limited to 'src')
-rw-r--r-- | src/com/android/launcher3/CellLayout.java | 2 | ||||
-rw-r--r-- | src/com/android/launcher3/DeviceProfile.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/Hotseat.java | 8 | ||||
-rw-r--r-- | src/com/android/launcher3/Launcher.java | 134 | ||||
-rw-r--r-- | src/com/android/launcher3/PagedView.java | 387 | ||||
-rw-r--r-- | src/com/android/launcher3/Workspace.java | 95 | ||||
-rw-r--r-- | src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java | 96 | ||||
-rw-r--r-- | src/com/android/launcher3/folder/Folder.java | 6 | ||||
-rw-r--r-- | src/com/android/launcher3/touch/WorkspaceTouchListener.java | 143 | ||||
-rw-r--r-- | src/com/android/launcher3/views/OptionsPopupView.java | 310 |
10 files changed, 478 insertions, 709 deletions
diff --git a/src/com/android/launcher3/CellLayout.java b/src/com/android/launcher3/CellLayout.java index 734aec302..797908261 100644 --- a/src/com/android/launcher3/CellLayout.java +++ b/src/com/android/launcher3/CellLayout.java @@ -292,7 +292,7 @@ public class CellLayout extends ViewGroup { ViewCompat.setAccessibilityDelegate(this, null); setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); getShortcutsAndWidgets().setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - setOnClickListener(mLauncher); + setOnClickListener(null); } else { if (dragType == WORKSPACE_ACCESSIBILITY_DRAG && !(mTouchHelper instanceof WorkspaceAccessibilityHelper)) { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index ea52324a5..13971ad95 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -515,12 +515,6 @@ public class DeviceProfile { } } - public boolean shouldIgnoreLongPressToOverview(float touchX) { - boolean touchedLhsEdge = mInsets.left == 0 && touchX < edgeMarginPx; - boolean touchedRhsEdge = mInsets.right == 0 && touchX > (widthPx - edgeMarginPx); - return !isMultiWindowMode && (touchedLhsEdge || touchedRhsEdge); - } - private static Context getContext(Context c, int orientation) { Configuration context = new Configuration(c.getResources().getConfiguration()); context.orientation = orientation; diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 03043f245..211a75656 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -63,14 +63,6 @@ public class Hotseat extends FrameLayout implements LogContainerProvider, Insett return mContent; } - /** - * Registers the specified listener on the cell layout of the hotseat. - */ - @Override - public void setOnLongClickListener(OnLongClickListener l) { - mContent.setOnLongClickListener(l); - } - /* Get the orientation invariant order of the item in the hotseat for persistence. */ int getOrderInHotseat(int x, int y) { return mHasVerticalHotseat ? (mContent.getCountY() - y - 1) : x; diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 375deb745..b4f9409d5 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -31,7 +31,6 @@ import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.animation.ValueAnimator; -import android.annotation.SuppressLint; import android.annotation.TargetApi; import android.app.ActivityOptions; import android.appwidget.AppWidgetHostView; @@ -49,7 +48,6 @@ import android.content.pm.PackageManager; import android.content.res.Configuration; import android.database.sqlite.SQLiteDatabase; import android.graphics.Point; -import android.graphics.PointF; import android.graphics.Rect; import android.os.AsyncTask; import android.os.Build; @@ -65,16 +63,12 @@ import android.util.Log; import android.util.SparseArray; import android.view.ActionMode; import android.view.Display; -import android.view.HapticFeedbackConstants; import android.view.KeyEvent; import android.view.KeyboardShortcutGroup; import android.view.KeyboardShortcutInfo; import android.view.LayoutInflater; import android.view.Menu; -import android.view.MotionEvent; import android.view.View; -import android.view.View.OnClickListener; -import android.view.View.OnLongClickListener; import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.animation.OvershootInterpolator; @@ -109,7 +103,6 @@ import com.android.launcher3.states.InternalStateHandler; import com.android.launcher3.states.RotationHelper; import com.android.launcher3.touch.ItemClickHandler; import com.android.launcher3.uioverrides.UiFactory; -import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; import com.android.launcher3.userevent.nano.LauncherLogProto.Target; @@ -126,6 +119,7 @@ import com.android.launcher3.util.Thunk; import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.UiThreadHelper; import com.android.launcher3.util.ViewOnDrawExecutor; +import com.android.launcher3.views.OptionsPopupView; import com.android.launcher3.widget.LauncherAppWidgetHostView; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; @@ -147,10 +141,8 @@ import java.util.Set; /** * Default launcher application. */ -public class Launcher extends BaseActivity - implements LauncherExterns, OnClickListener, OnLongClickListener, - LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener, - WallpaperColorInfo.OnThemeChangeListener { +public class Launcher extends BaseActivity implements LauncherExterns, LauncherModel.Callbacks, + LauncherProviderChangeListener, WallpaperColorInfo.OnThemeChangeListener { public static final String TAG = "Launcher"; static final boolean LOGD = false; @@ -228,7 +220,7 @@ public class Launcher extends BaseActivity AllAppsTransitionController mAllAppsController; // UI and state for the overview panel - private ViewGroup mOverviewPanel; + private View mOverviewPanel; @Thunk boolean mWorkspaceLoading = true; @@ -261,8 +253,6 @@ public class Launcher extends BaseActivity */ private PendingRequestArgs mPendingRequestArgs; - private final PointF mLastDispatchTouchEvent = new PointF(); - public ViewGroupFocusHelper mFocusHandler; private boolean mAppLaunchSuccess; @@ -952,6 +942,7 @@ public class Launcher extends BaseActivity mWorkspace = mDragLayer.findViewById(R.id.workspace); mWorkspace.initParentViews(mDragLayer); mOverviewPanel = findViewById(R.id.overview_panel); + mHotseat = findViewById(R.id.hotseat); mLauncherView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION @@ -960,15 +951,6 @@ public class Launcher extends BaseActivity // Setup the drag layer mDragLayer.setup(this, mDragController); - // Setup the hotseat - mHotseat = (Hotseat) findViewById(R.id.hotseat); - if (mHotseat != null) { - mHotseat.setOnLongClickListener(this); - } - - // Setup the workspace - mWorkspace.setHapticFeedbackEnabled(false); - mWorkspace.setOnLongClickListener(this); mWorkspace.setup(mDragController); // Until the workspace is bound, ensure that we keep the wallpaper offset locked to the // default state, otherwise we will update to the wrong offsets in RTL @@ -1222,7 +1204,7 @@ public class Launcher extends BaseActivity return mHotseat; } - public <T extends ViewGroup> T getOverviewPanel() { + public <T extends View> T getOverviewPanel() { return (T) mOverviewPanel; } @@ -1659,51 +1641,6 @@ public class Launcher extends BaseActivity } /** - * Launches the intent referred by the clicked shortcut. - * - * @param v The view representing the clicked shortcut. - */ - @Override - public void onClick(View v) { - // Make sure that rogue clicks don't get through while allapps is launching, or after the - // view has detached (it's possible for this to happen if the view is removed mid touch). - if (v.getWindowToken() == null) { - return; - } - - if (!mWorkspace.isFinishedSwitchingState()) { - return; - } - - if (v instanceof Workspace) { - if (isInState(OVERVIEW)) { - getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Touch.TAP, - LauncherLogProto.Action.Direction.NONE, - LauncherLogProto.ContainerType.OVERVIEW, mWorkspace.getCurrentPage()); - mStateManager.goToState(NORMAL); - } - return; - } - - if (v instanceof CellLayout) { - if (isInState(OVERVIEW)) { - int page = mWorkspace.indexOfChild(v); - getUserEventDispatcher().logActionOnContainer(LauncherLogProto.Action.Touch.TAP, - LauncherLogProto.Action.Direction.NONE, - LauncherLogProto.ContainerType.OVERVIEW, page); - mWorkspace.snapToPageFromOverView(page); - mStateManager.goToState(NORMAL); - } - return; - } - } - - @SuppressLint("ClickableViewAccessibility") - public boolean onTouch(View v, MotionEvent event) { - return false; - } - - /** * Event handler for the wallpaper picker button that appears after a long press * on the home screen. */ @@ -1860,62 +1797,6 @@ public class Launcher extends BaseActivity return mAppLaunchSuccess; } - @Override - public boolean dispatchTouchEvent(MotionEvent ev) { - mLastDispatchTouchEvent.set(ev.getX(), ev.getY()); - return super.dispatchTouchEvent(ev); - } - - @Override - public boolean onLongClick(View v) { - if (!isDraggingEnabled()) return false; - if (isWorkspaceLocked()) return false; - if (!isInState(NORMAL) && !isInState(OVERVIEW)) return false; - - boolean ignoreLongPressToOverview = - mDeviceProfile.shouldIgnoreLongPressToOverview(mLastDispatchTouchEvent.x); - - if (v instanceof Workspace) { - if (!isInState(OVERVIEW)) { - if (!mWorkspace.isTouchActive() && !ignoreLongPressToOverview) { - getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, - Action.Direction.NONE, ContainerType.WORKSPACE, - mWorkspace.getCurrentPage()); - UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent); - mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - return true; - } else { - return false; - } - } else { - return false; - } - } - - // The hotseat touch handling does not go through Workspace, and we always allow long press - // on hotseat items. - if (!mDragController.isDragging()) { - // User long pressed on empty space - if (mWorkspace.isPageRearrangeEnabled()) { - mWorkspace.startReordering(v); - getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, - Action.Direction.NONE, ContainerType.OVERVIEW); - } else { - if (ignoreLongPressToOverview) { - return false; - } - getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, - Action.Direction.NONE, ContainerType.WORKSPACE, - mWorkspace.getCurrentPage()); - UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent); - } - mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); - } - return true; - } - boolean isHotseatLayout(View layout) { // TODO: Remove this method return mHotseat != null && layout != null && @@ -2628,8 +2509,7 @@ public class Launcher extends BaseActivity // Setting the touch point to (-1, -1) will show the options popup in the center of // the screen. - mLastDispatchTouchEvent.set(-1, -1); - UiFactory.onWorkspaceLongPress(this, mLastDispatchTouchEvent); + OptionsPopupView.show(this, -1, -1); } return true; } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index d39ec3ee3..9abb9c1ad 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -19,10 +19,7 @@ package com.android.launcher3; import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled; import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType; -import android.animation.Animator; -import android.animation.AnimatorListenerAdapter; import android.animation.LayoutTransition; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.annotation.SuppressLint; import android.content.Context; @@ -30,8 +27,6 @@ import android.content.res.TypedArray; import android.graphics.Matrix; import android.graphics.Rect; import android.os.Bundle; -import android.os.Parcel; -import android.os.Parcelable; import android.util.AttributeSet; import android.util.Log; import android.view.InputDevice; @@ -48,7 +43,6 @@ import android.view.accessibility.AccessibilityNodeInfo; import android.view.animation.Interpolator; import com.android.launcher3.anim.Interpolators; -import com.android.launcher3.anim.PropertyListBuilder; import com.android.launcher3.pageindicators.PageIndicator; import com.android.launcher3.touch.OverScroll; import com.android.launcher3.util.Thunk; @@ -105,31 +99,21 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou private VelocityTracker mVelocityTracker; protected int mPageSpacing = 0; - private float mParentDownMotionX; - private float mParentDownMotionY; private float mDownMotionX; private float mDownMotionY; - private float mDownScrollX; - private float mDragViewBaselineLeft; private float mLastMotionX; private float mLastMotionXRemainder; - private float mLastMotionY; private float mTotalMotionX; - private boolean mCancelTap; - private int[] mPageScrolls; protected final static int TOUCH_STATE_REST = 0; protected final static int TOUCH_STATE_SCROLLING = 1; protected final static int TOUCH_STATE_PREV_PAGE = 2; protected final static int TOUCH_STATE_NEXT_PAGE = 3; - protected final static int TOUCH_STATE_REORDERING = 4; protected int mTouchState = TOUCH_STATE_REST; - protected OnLongClickListener mLongClickListener; - protected int mTouchSlop; private int mMaximumVelocity; protected boolean mAllowOverScroll = true; @@ -153,26 +137,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou @Thunk int mPageIndicatorViewId; protected T mPageIndicator; - // Reordering - // We use the min scale to determine how much to expand the actually PagedView measured - // dimensions such that when we are zoomed out, the view is not clipped - private static int REORDERING_DROP_REPOSITION_DURATION = 200; - @Thunk static int REORDERING_REORDER_REPOSITION_DURATION = 300; - private static int REORDERING_SIDE_PAGE_HOVER_TIMEOUT = 80; - - @Thunk View mDragView; - private Runnable mSidePageHoverRunnable; - @Thunk int mSidePageHoverIndex = -1; - // This variable's scope is only for the duration of startReordering() and endReordering() - private boolean mReorderingStarted = false; - // This variable's scope is for the duration of startReordering() and after the zoomIn() - // animation after endReordering() - private boolean mIsReordering; - // The runnable that settles the page after snapToPage and animateDragViewToOriginalPosition - private static final int NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT = 2; - private int mPostReorderingPreZoomInRemainingAnimationCount; - private Runnable mPostReorderingPreZoomInRunnable; - // Convenience/caching private static final Matrix sTmpInvMatrix = new Matrix(); private static final float[] sTmpPoint = new float[2]; @@ -237,47 +201,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou } } - // Convenience methods to map points from self to parent and vice versa - private float[] mapPointFromViewToParent(View v, float x, float y) { - sTmpPoint[0] = x; - sTmpPoint[1] = y; - v.getMatrix().mapPoints(sTmpPoint); - sTmpPoint[0] += v.getLeft(); - sTmpPoint[1] += v.getTop(); - return sTmpPoint; - } - private float[] mapPointFromParentToView(View v, float x, float y) { - sTmpPoint[0] = x - v.getLeft(); - sTmpPoint[1] = y - v.getTop(); - v.getMatrix().invert(sTmpInvMatrix); - sTmpInvMatrix.mapPoints(sTmpPoint); - return sTmpPoint; - } - - private void updateDragViewTranslationDuringDrag() { - if (mDragView != null) { - float x = (mLastMotionX - mDownMotionX) + (getScrollX() - mDownScrollX) + - (mDragViewBaselineLeft - mDragView.getLeft()); - float y = mLastMotionY - mDownMotionY; - mDragView.setTranslationX(x); - mDragView.setTranslationY(y); - - if (DEBUG) Log.d(TAG, "PagedView.updateDragViewTranslationDuringDrag(): " - + x + ", " + y); - } - } - - @Override - public void setScaleX(float scaleX) { - super.setScaleX(scaleX); - if (isReordering(true)) { - float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY); - mLastMotionX = p[0]; - mLastMotionY = p[1]; - updateDragViewTranslationDuringDrag(); - } - } - public T getPageIndicator() { return mPageIndicator; } @@ -383,9 +306,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou // Update the page indicator (when we aren't reordering) if (mPageIndicator != null) { mPageIndicator.setPageDescription(getPageIndicatorDescription()); - if (!isReordering(false)) { - mPageIndicator.setActiveMarker(getNextPage()); - } } } protected void pageBeginTransition() { @@ -421,21 +341,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou mWasInOverscroll = false; } - /** - * Registers the specified listener on each page contained in this workspace. - * - * @param l The listener used to respond to long clicks. - */ - @Override - public void setOnLongClickListener(OnLongClickListener l) { - mLongClickListener = l; - final int count = getPageCount(); - for (int i = 0; i < count; i++) { - getPageAt(i).setOnLongClickListener(l); - } - super.setOnLongClickListener(l); - } - protected int getUnboundedScrollX() { return mUnboundedScrollX; } @@ -490,14 +395,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou mOverScrollX = x; super.scrollTo(x, y); } - - // Update the last motion events when scrolling - if (isReordering(true)) { - float[] p = mapPointFromParentToView(this, mParentDownMotionX, mParentDownMotionY); - mLastMotionX = p[0]; - mLastMotionY = p[1]; - updateDragViewTranslationDuringDrag(); - } } private void sendScrollAccessibilityEvent() { @@ -549,7 +446,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou pageEndTransition(); } - onPostReorderingAnimationCompleted(); if (isAccessibilityEnabled(getContext())) { // Notify the user when the page changes announceForAccessibility(getCurrentPageDescription()); @@ -716,10 +612,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou setCurrentPage(getNextPage()); } mChildCountOnLastLayout = childCount; - - if (isReordering(true)) { - updateDragViewTranslationDuringDrag(); - } } protected int getChildGap() { @@ -937,12 +829,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou // Remember location of down touch mDownMotionX = x; mDownMotionY = y; - mDownScrollX = getScrollX(); mLastMotionX = x; - mLastMotionY = y; - float[] p = mapPointFromViewToParent(this, x, y); - mParentDownMotionX = p[0]; - mParentDownMotionY = p[1]; mLastMotionXRemainder = 0; mTotalMotionX = 0; mActivePointerId = ev.getPointerId(0); @@ -990,6 +877,10 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou return mTouchState != TOUCH_STATE_REST; } + public boolean isHandlingTouch() { + return mTouchState != TOUCH_STATE_REST; + } + protected void determineScrollingStart(MotionEvent ev) { determineScrollingStart(ev, 1.0f); } @@ -1101,22 +992,12 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou dampedOverScroll(amount); } - /** - * return true if freescroll has been enabled, false otherwise - */ - protected void enableFreeScroll() { - enableFreeScroll(false); - } protected void enableFreeScroll(boolean settleOnPageInFreeScroll) { setEnableFreeScroll(true); mSettleOnPageInFreeScroll = settleOnPageInFreeScroll; } - protected void disableFreeScroll() { - setEnableFreeScroll(false); - } - private void setEnableFreeScroll(boolean freeScroll) { boolean wasFreeScroll = mFreeScroll; mFreeScroll = freeScroll; @@ -1134,27 +1015,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou mAllowOverScroll = enable; } - private int getNearestHoverOverPageIndex() { - if (mDragView != null) { - int dragX = (int) (mDragView.getLeft() + (mDragView.getMeasuredWidth() / 2) - + mDragView.getTranslationX()); - int minDistance = Integer.MAX_VALUE; - int minIndex = indexOfChild(mDragView); - int maxPageNo = getChildCount() - 1; - for (int i = 0; i <= maxPageNo; i++) { - View page = getPageAt(i); - int pageX = (page.getLeft() + page.getMeasuredWidth() / 2); - int d = Math.abs(dragX - pageX); - if (d < minDistance) { - minIndex = i; - minDistance = d; - } - } - return minIndex; - } - return -1; - } - @Override public boolean onTouchEvent(MotionEvent ev) { super.onTouchEvent(ev); @@ -1178,11 +1038,7 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou // Remember where the motion event started mDownMotionX = mLastMotionX = ev.getX(); - mDownMotionY = mLastMotionY = ev.getY(); - mDownScrollX = getScrollX(); - float[] p = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); - mParentDownMotionX = p[0]; - mParentDownMotionY = p[1]; + mDownMotionY = ev.getY(); mLastMotionXRemainder = 0; mTotalMotionX = 0; mActivePointerId = ev.getPointerId(0); @@ -1215,82 +1071,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou } else { awakenScrollBars(); } - } else if (mTouchState == TOUCH_STATE_REORDERING) { - // Update the last motion position - mLastMotionX = ev.getX(); - mLastMotionY = ev.getY(); - - // Update the parent down so that our zoom animations take this new movement into - // account - float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); - mParentDownMotionX = pt[0]; - mParentDownMotionY = pt[1]; - updateDragViewTranslationDuringDrag(); - - // Find the closest page to the touch point - final int dragViewIndex = indexOfChild(mDragView); - - if (DEBUG) Log.d(TAG, "mLastMotionX: " + mLastMotionX); - if (DEBUG) Log.d(TAG, "mLastMotionY: " + mLastMotionY); - if (DEBUG) Log.d(TAG, "mParentDownMotionX: " + mParentDownMotionX); - if (DEBUG) Log.d(TAG, "mParentDownMotionY: " + mParentDownMotionY); - - final int pageUnderPointIndex = getNearestHoverOverPageIndex(); - // Do not allow any page to be moved to 0th position. - if (pageUnderPointIndex > 0 && pageUnderPointIndex != indexOfChild(mDragView)) { - if (0 <= pageUnderPointIndex && pageUnderPointIndex <= getPageCount() - 1 && - pageUnderPointIndex != mSidePageHoverIndex && mScroller.isFinished()) { - mSidePageHoverIndex = pageUnderPointIndex; - mSidePageHoverRunnable = new Runnable() { - @Override - public void run() { - // Setup the scroll to the correct page before we swap the views - snapToPage(pageUnderPointIndex); - - // For each of the pages between the paged view and the drag view, - // animate them from the previous position to the new position in - // the layout (as a result of the drag view moving in the layout) - int shiftDelta = (dragViewIndex < pageUnderPointIndex) ? -1 : 1; - int lowerIndex = (dragViewIndex < pageUnderPointIndex) ? - dragViewIndex + 1 : pageUnderPointIndex; - int upperIndex = (dragViewIndex > pageUnderPointIndex) ? - dragViewIndex - 1 : pageUnderPointIndex; - for (int i = lowerIndex; i <= upperIndex; ++i) { - View v = getChildAt(i); - // dragViewIndex < pageUnderPointIndex, so after we remove the - // drag view all subsequent views to pageUnderPointIndex will - // shift down. - int oldX = getChildOffset(i); - int newX = getChildOffset(i + shiftDelta); - - // Animate the view translation from its old position to its new - // position - ObjectAnimator anim = (ObjectAnimator) v.getTag(); - if (anim != null) { - anim.cancel(); - } - - v.setTranslationX(oldX - newX); - anim = LauncherAnimUtils.ofFloat(v, View.TRANSLATION_X, 0); - anim.setDuration(REORDERING_REORDER_REPOSITION_DURATION); - anim.start(); - v.setTag(anim); - } - - removeView(mDragView); - addView(mDragView, pageUnderPointIndex); - mSidePageHoverIndex = -1; - if (mPageIndicator != null) { - mPageIndicator.setActiveMarker(getNextPage()); - } - } - }; - postDelayed(mSidePageHoverRunnable, REORDERING_SIDE_PAGE_HOVER_TIMEOUT); - } - } else { - removeCallbacks(mSidePageHoverRunnable); - mSidePageHoverIndex = -1; - } } else { determineScrollingStart(ev); } @@ -1391,25 +1171,8 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou } else { snapToDestination(); } - } else if (mTouchState == TOUCH_STATE_REORDERING) { - // Update the last motion position - mLastMotionX = ev.getX(); - mLastMotionY = ev.getY(); - - // Update the parent down so that our zoom animations take this new movement into - // account - float[] pt = mapPointFromViewToParent(this, mLastMotionX, mLastMotionY); - mParentDownMotionX = pt[0]; - mParentDownMotionY = pt[1]; - updateDragViewTranslationDuringDrag(); - } else { - if (!mCancelTap) { - onUnhandledTap(ev); - } } - // Remove the callback to wait for the side page hover timeout - removeCallbacks(mSidePageHoverRunnable); // End any intermediate reordering states resetTouchState(); break; @@ -1437,8 +1200,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou private void resetTouchState() { releaseVelocityTracker(); - endReordering(); - mCancelTap = false; mTouchState = TOUCH_STATE_REST; mActivePointerId = INVALID_POINTER; } @@ -1452,10 +1213,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou protected void onScrollInteractionEnd() { } - protected void onUnhandledTap(MotionEvent ev) { - Launcher.getLauncher(getContext()).onClick(this); - } - @Override public boolean onGenericMotionEvent(MotionEvent event) { if ((event.getSource() & InputDevice.SOURCE_CLASS_POINTER) != 0) { @@ -1512,7 +1269,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou // TODO: Make this decision more intelligent. final int newPointerIndex = pointerIndex == 0 ? 1 : 0; mLastMotionX = mDownMotionX = ev.getX(newPointerIndex); - mLastMotionY = ev.getY(newPointerIndex); mLastMotionXRemainder = 0; mActivePointerId = ev.getPointerId(newPointerIndex); if (mVelocityTracker != null) { @@ -1689,139 +1445,6 @@ public abstract class PagedView<T extends View & PageIndicator> extends ViewGrou if (getNextPage() < getChildCount() -1) snapToPage(getNextPage() + 1); } - @Override - public boolean performLongClick() { - mCancelTap = true; - return super.performLongClick(); - } - - public static class SavedState extends BaseSavedState { - int currentPage = -1; - - SavedState(Parcelable superState) { - super(superState); - } - - @Thunk SavedState(Parcel in) { - super(in); - currentPage = in.readInt(); - } - - @Override - public void writeToParcel(Parcel out, int flags) { - super.writeToParcel(out, flags); - out.writeInt(currentPage); - } - - public static final Parcelable.Creator<SavedState> CREATOR = - new Parcelable.Creator<SavedState>() { - public SavedState createFromParcel(Parcel in) { - return new SavedState(in); - } - - public SavedState[] newArray(int size) { - return new SavedState[size]; - } - }; - } - - // Animate the drag view back to the original position - private void animateDragViewToOriginalPosition() { - if (mDragView != null) { - Animator anim = LauncherAnimUtils.ofPropertyValuesHolder(mDragView, - new PropertyListBuilder() - .scale(1) - .translationX(0) - .translationY(0) - .build()) - .setDuration(REORDERING_DROP_REPOSITION_DURATION); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - onPostReorderingAnimationCompleted(); - } - }); - anim.start(); - } - } - - public void onStartReordering() { - // Set the touch state to reordering (allows snapping to pages, dragging a child, etc.) - mTouchState = TOUCH_STATE_REORDERING; - mIsReordering = true; - - // We must invalidate to trigger a redraw to update the layers such that the drag view - // is always drawn on top - invalidate(); - } - - @Thunk void onPostReorderingAnimationCompleted() { - // Trigger the callback when reordering has settled - --mPostReorderingPreZoomInRemainingAnimationCount; - if (mPostReorderingPreZoomInRunnable != null && - mPostReorderingPreZoomInRemainingAnimationCount == 0) { - mPostReorderingPreZoomInRunnable.run(); - mPostReorderingPreZoomInRunnable = null; - } - } - - public void onEndReordering() { - mIsReordering = false; - } - - public boolean startReordering(View v) { - int dragViewIndex = indexOfChild(v); - - // Do not allow the first page to be moved around - if (mTouchState != TOUCH_STATE_REST || dragViewIndex <= 0) return false; - - // Check if we are within the reordering range - if (0 <= dragViewIndex && dragViewIndex <= getPageCount() - 1) { - // Find the drag view under the pointer - mDragView = getChildAt(dragViewIndex); - mDragView.animate().scaleX(1.15f).scaleY(1.15f).setDuration(100).start(); - mDragViewBaselineLeft = mDragView.getLeft(); - mReorderingStarted = true; - - snapToPage(getPageNearestToCenterOfScreen()); - disableFreeScroll(); - onStartReordering(); - return true; - } - return false; - } - - boolean isReordering(boolean testTouchState) { - boolean state = mIsReordering; - if (testTouchState) { - state &= (mTouchState == TOUCH_STATE_REORDERING); - } - return state; - } - void endReordering() { - // For simplicity, we call endReordering sometimes even if reordering was never started. - // In that case, we don't want to do anything. - if (!mReorderingStarted) return; - mReorderingStarted = false; - - mPostReorderingPreZoomInRunnable = new Runnable() { - public void run() { - // If we haven't flung-to-delete the current child, - // then we just animate the drag view back into position - onEndReordering(); - - enableFreeScroll(); - } - }; - - mPostReorderingPreZoomInRemainingAnimationCount = - NUM_ANIMATIONS_RUNNING_BEFORE_ZOOM_OUT; - // Snap to the current page - snapToPage(indexOfChild(mDragView), 0); - // Animate the drag view back to the front position - animateDragViewToOriginalPosition(); - } - /* Accessibility */ @SuppressWarnings("deprecation") @Override diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index f329f5ea8..996095392 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -59,7 +59,6 @@ import com.android.launcher3.Launcher.LauncherOverlay; import com.android.launcher3.LauncherAppWidgetHost.ProviderChangedListener; import com.android.launcher3.LauncherStateManager.AnimationConfig; import com.android.launcher3.accessibility.AccessibleDragListenerAdapter; -import com.android.launcher3.accessibility.OverviewScreenAccessibilityDelegate; import com.android.launcher3.accessibility.WorkspaceAccessibilityHelper; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.anim.Interpolators; @@ -82,6 +81,7 @@ import com.android.launcher3.pageindicators.WorkspacePageIndicator; import com.android.launcher3.popup.PopupContainerWithArrow; import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider; import com.android.launcher3.touch.ItemLongClickListener; +import com.android.launcher3.touch.WorkspaceTouchListener; import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.userevent.nano.LauncherLogProto.Action; import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; @@ -242,7 +242,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> private Runnable mOnOverlayHiddenCallback; private boolean mForceDrawAdjacentPages = false; - private boolean mPageRearrangeEnabled = false; // Total over scrollX in the overlay direction. private float mOverlayTranslation; @@ -250,8 +249,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> // Handles workspace state transitions private final WorkspaceStateTransitionAnimation mStateTransitionAnimation; - private AccessibilityDelegate mPagesAccessibilityDelegate; - /** * Used to inflate the Workspace from XML. * @@ -286,6 +283,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator> // Attach a scrim new WorkspaceAndHotseatScrim(this).attach(); + setOnTouchListener(new WorkspaceTouchListener(mLauncher, this)); } @Override @@ -475,7 +473,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> } CellLayout cl = ((CellLayout) child); cl.setOnInterceptTouchListener(this); - cl.setClickable(true); cl.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); super.onViewAdded(child); } @@ -555,10 +552,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> // created CellLayout. CellLayout newScreen = (CellLayout) LayoutInflater.from(getContext()).inflate( R.layout.workspace_screen, this, false /* attachToRoot */); - newScreen.setOnLongClickListener(mLongClickListener); - newScreen.setOnClickListener(mLauncher); - newScreen.setSoundEffectsEnabled(false); - int paddingLeftRight = mLauncher.getDeviceProfile().cellLayoutPaddingLeftRightPx; int paddingBottom = mLauncher.getDeviceProfile().cellLayoutBottomPaddingPx; newScreen.setPadding(paddingLeftRight, 0, paddingLeftRight, paddingBottom); @@ -938,7 +931,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> child.setHapticFeedbackEnabled(false); child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE); - if (child instanceof DropTarget) { mDragController.addDropTarget((DropTarget) child); } @@ -1378,8 +1370,7 @@ public class Workspace extends PagedView<WorkspacePageIndicator> } private void updateChildrenLayersEnabled() { - boolean enableChildrenLayers = - isPageRearrangeEnabled() || mIsSwitchingState || isPageInTransition(); + boolean enableChildrenLayers = mIsSwitchingState || isPageInTransition(); if (enableChildrenLayers != mChildrenLayersEnabled) { mChildrenLayersEnabled = enableChildrenLayers; @@ -1463,40 +1454,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> mOutlineProvider = outlineProvider; } - public void onStartReordering() { - super.onStartReordering(); - // Reordering handles its own animations, disable the automatic ones. - disableLayoutTransitions(); - } - - public void onEndReordering() { - super.onEndReordering(); - - if (mLauncher.isWorkspaceLoading()) { - // Invalid and dangerous operation if workspace is loading - return; - } - - ArrayList<Long> prevScreenOrder = (ArrayList<Long>) mScreenOrder.clone(); - mScreenOrder.clear(); - int count = getChildCount(); - for (int i = 0; i < count; i++) { - CellLayout cl = ((CellLayout) getChildAt(i)); - mScreenOrder.add(getIdForScreen(cl)); - } - - for (int i = 0; i < prevScreenOrder.size(); i++) { - if (mScreenOrder.get(i) != prevScreenOrder.get(i)) { - mLauncher.getUserEventDispatcher().logOverviewReorder(); - break; - } - } - LauncherModel.updateWorkspaceScreenOrder(mLauncher, mScreenOrder); - - // Re-enable auto layout transitions for page deletion. - enableLayoutTransitions(); - } - public void snapToPageFromOverView(int whichPage) { snapToPage(whichPage, OVERVIEW_TRANSITION_MS, Interpolators.ZOOM_IN); } @@ -1556,47 +1513,17 @@ public class Workspace extends PagedView<WorkspacePageIndicator> if (!mLauncher.getAccessibilityDelegate().isInAccessibleDrag()) { int total = getPageCount(); for (int i = 0; i < total; i++) { - updateAccessibilityFlags(accessibilityFlag, (CellLayout) getPageAt(i), i); + updateAccessibilityFlags(accessibilityFlag, (CellLayout) getPageAt(i)); } setImportantForAccessibility(accessibilityFlag); } } - private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page, int pageNo) { - if (isPageRearrangeEnabled()) { - page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_YES); - page.getShortcutsAndWidgets().setImportantForAccessibility( - IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS); - page.setContentDescription(getPageDescription(pageNo)); - - // No custom action for the first page. - if (!FeatureFlags.QSB_ON_FIRST_SCREEN || pageNo > 0) { - if (mPagesAccessibilityDelegate == null) { - mPagesAccessibilityDelegate = new OverviewScreenAccessibilityDelegate(this); - } - page.setAccessibilityDelegate(mPagesAccessibilityDelegate); - } - } else { - page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); - page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag); - page.setContentDescription(null); - page.setAccessibilityDelegate(null); - } - } - - public void setPageRearrangeEnabled(boolean isEnabled) { - if (mPageRearrangeEnabled != isEnabled) { - mPageRearrangeEnabled = isEnabled; - if (isEnabled) { - enableFreeScroll(); - } else { - disableFreeScroll(); - } - } - } - - public boolean isPageRearrangeEnabled() { - return mPageRearrangeEnabled; + private void updateAccessibilityFlags(int accessibilityFlag, CellLayout page) { + page.setImportantForAccessibility(IMPORTANT_FOR_ACCESSIBILITY_NO); + page.getShortcutsAndWidgets().setImportantForAccessibility(accessibilityFlag); + page.setContentDescription(null); + page.setAccessibilityDelegate(null); } public void startDrag(CellLayout.CellInfo cellInfo, DragOptions options) { @@ -1612,10 +1539,6 @@ public class Workspace extends PagedView<WorkspacePageIndicator> protected void enableAccessibleDrag(boolean enable) { super.enableAccessibleDrag(enable); setEnableForLayout(mLauncher.getHotseat().getLayout(),enable); - - // We need to allow our individual children to become click handlers in this - // case, so temporarily unset the click handlers. - setOnClickListener(enable ? null : mLauncher); } }); } diff --git a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java deleted file mode 100644 index f9eb2eda6..000000000 --- a/src/com/android/launcher3/accessibility/OverviewScreenAccessibilityDelegate.java +++ /dev/null @@ -1,96 +0,0 @@ -/* - * Copyright (C) 2015 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package com.android.launcher3.accessibility; - -import android.content.Context; -import android.os.Bundle; -import android.util.SparseArray; -import android.view.View; -import android.view.View.AccessibilityDelegate; -import android.view.accessibility.AccessibilityNodeInfo; -import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction; - -import com.android.launcher3.R; -import com.android.launcher3.Utilities; -import com.android.launcher3.Workspace; -import com.android.launcher3.config.FeatureFlags; - -public class OverviewScreenAccessibilityDelegate extends AccessibilityDelegate { - - private static final int MOVE_BACKWARD = R.id.action_move_screen_backwards; - private static final int MOVE_FORWARD = R.id.action_move_screen_forwards; - - private final SparseArray<AccessibilityAction> mActions = new SparseArray<>(); - private final Workspace mWorkspace; - - public OverviewScreenAccessibilityDelegate(Workspace workspace) { - mWorkspace = workspace; - - Context context = mWorkspace.getContext(); - boolean isRtl = Utilities.isRtl(context.getResources()); - mActions.put(MOVE_BACKWARD, new AccessibilityAction(MOVE_BACKWARD, - context.getText(isRtl ? R.string.action_move_screen_right : - R.string.action_move_screen_left))); - mActions.put(MOVE_FORWARD, new AccessibilityAction(MOVE_FORWARD, - context.getText(isRtl ? R.string.action_move_screen_left : - R.string.action_move_screen_right))); - } - - @Override - public boolean performAccessibilityAction(View host, int action, Bundle args) { - if (host != null) { - if (action == AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS ) { - int index = mWorkspace.indexOfChild(host); - mWorkspace.setCurrentPage(index); - } else if (action == MOVE_FORWARD) { - movePage(mWorkspace.indexOfChild(host) + 1, host); - return true; - } else if (action == MOVE_BACKWARD) { - movePage(mWorkspace.indexOfChild(host) - 1, host); - return true; - } - } - - return super.performAccessibilityAction(host, action, args); - } - - private void movePage(int finalIndex, View view) { - mWorkspace.onStartReordering(); - mWorkspace.removeView(view); - mWorkspace.addView(view, finalIndex); - mWorkspace.onEndReordering(); - mWorkspace.announceForAccessibility(mWorkspace.getContext().getText(R.string.screen_moved)); - - mWorkspace.updateAccessibilityFlags(); - view.performAccessibilityAction(AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS, null); - } - - @Override - public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) { - super.onInitializeAccessibilityNodeInfo(host, info); - - int index = mWorkspace.indexOfChild(host); - if (index < mWorkspace.getChildCount() - 1) { - info.addAction(mActions.get(MOVE_FORWARD)); - } - - int startIndex = FeatureFlags.QSB_ON_FIRST_SCREEN ? 1 : 0; - if (index > startIndex) { - info.addAction(mActions.get(MOVE_BACKWARD)); - } - } -} diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java index 2b4242959..1bdd554b1 100644 --- a/src/com/android/launcher3/folder/Folder.java +++ b/src/com/android/launcher3/folder/Folder.java @@ -207,11 +207,11 @@ public class Folder extends AbstractFloatingView implements DragSource, @Override protected void onFinishInflate() { super.onFinishInflate(); - mContent = (FolderPagedView) findViewById(R.id.folder_content); + mContent = findViewById(R.id.folder_content); mContent.setFolder(this); - mPageIndicator = (PageIndicatorDots) findViewById(R.id.folder_page_indicator); - mFolderName = (ExtendedEditText) findViewById(R.id.folder_name); + mPageIndicator = findViewById(R.id.folder_page_indicator); + mFolderName = findViewById(R.id.folder_name); mFolderName.setOnBackKeyListener(this); mFolderName.setOnFocusChangeListener(this); diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java new file mode 100644 index 000000000..df11686b2 --- /dev/null +++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.touch; + +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_DOWN; +import static android.view.MotionEvent.ACTION_UP; +import static android.view.ViewConfiguration.getLongPressTimeout; + +import static com.android.launcher3.LauncherState.NORMAL; + +import android.graphics.PointF; +import android.graphics.Rect; +import android.view.HapticFeedbackConstants; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnTouchListener; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.Workspace; +import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.views.OptionsPopupView; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; + +/** + * Helper class to handle touch on empty space in workspace and show options popup on long press + */ +public class WorkspaceTouchListener implements OnTouchListener, Runnable { + + /** + * STATE_PENDING_PARENT_INFORM is the state between longPress performed & the next motionEvent. + * This next event is used to send an ACTION_CANCEL to Workspace, to that it clears any + * temporary scroll state. After that, the state is set to COMPLETED, and we just eat up all + * subsequent motion events. + */ + private static final int STATE_CANCELLED = 0; + private static final int STATE_REQUESTED = 1; + private static final int STATE_PENDING_PARENT_INFORM = 2; + private static final int STATE_COMPLETED = 3; + + private final Rect mTempRect = new Rect(); + private final Launcher mLauncher; + private final Workspace mWorkspace; + private final PointF mTouchDownPoint = new PointF(); + + private int mLongPressState = STATE_CANCELLED; + + public WorkspaceTouchListener(Launcher launcher, Workspace workspace) { + mLauncher = launcher; + mWorkspace = workspace; + } + + @Override + public boolean onTouch(View view, MotionEvent ev) { + int action = ev.getActionMasked(); + if (action == ACTION_DOWN) { + // Check if we can handle long press. + boolean handleLongPress = AbstractFloatingView.getTopOpenView(mLauncher) == null + && mLauncher.isInState(NORMAL); + + if (handleLongPress) { + // Check if the event is not near the edges + DeviceProfile dp = mLauncher.getDeviceProfile(); + DragLayer dl = mLauncher.getDragLayer(); + Rect insets = dp.getInsets(); + + mTempRect.set(insets.left, insets.top, dl.getWidth() - insets.right, + dl.getHeight() - insets.bottom); + mTempRect.inset(dp.edgeMarginPx, dp.edgeMarginPx); + handleLongPress = mTempRect.contains((int) ev.getX(), (int) ev.getY()); + } + + cancelLongPress(); + if (handleLongPress) { + mLongPressState = STATE_REQUESTED; + mTouchDownPoint.set(ev.getX(), ev.getY()); + mWorkspace.postDelayed(this, getLongPressTimeout()); + } + + mWorkspace.onTouchEvent(ev); + // Return true to keep receiving touch events + return true; + } + + if (mLongPressState == STATE_PENDING_PARENT_INFORM) { + // Inform the workspace to cancel touch handling + ev.setAction(ACTION_CANCEL); + mWorkspace.onTouchEvent(ev); + ev.setAction(action); + mLongPressState = STATE_COMPLETED; + } + + if (mLongPressState == STATE_COMPLETED) { + // We have handled the touch, so workspace does not need to know anything anymore. + return true; + } else if (mLongPressState == STATE_REQUESTED) { + mWorkspace.onTouchEvent(ev); + if (action == ACTION_UP || action == ACTION_CANCEL || mWorkspace.isHandlingTouch()) { + cancelLongPress(); + } + return true; + } else { + // We don't want to handle touch, let workspace handle it as usual. + return false; + } + } + + private void cancelLongPress() { + mWorkspace.removeCallbacks(this); + mLongPressState = STATE_CANCELLED; + } + + @Override + public void run() { + if (mLongPressState == STATE_REQUESTED) { + mLongPressState = STATE_PENDING_PARENT_INFORM; + mWorkspace.getParent().requestDisallowInterceptTouchEvent(true); + + mWorkspace.performHapticFeedback(HapticFeedbackConstants.LONG_PRESS, + HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + mLauncher.getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS, + Action.Direction.NONE, ContainerType.WORKSPACE, + mWorkspace.getCurrentPage()); + OptionsPopupView.show(mLauncher, mTouchDownPoint.x, mTouchDownPoint.y); + } + } +} diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java new file mode 100644 index 000000000..21b677355 --- /dev/null +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -0,0 +1,310 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.views; + +import android.animation.Animator; +import android.animation.AnimatorListenerAdapter; +import android.animation.AnimatorSet; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.content.Context; +import android.content.Intent; +import android.graphics.Outline; +import android.graphics.PointF; +import android.graphics.Rect; +import android.util.AttributeSet; +import android.view.MotionEvent; +import android.view.View; +import android.view.View.OnClickListener; +import android.view.View.OnLongClickListener; +import android.view.ViewGroup; +import android.view.ViewOutlineProvider; +import android.widget.Toast; + +import com.android.launcher3.AbstractFloatingView; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAnimUtils; +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.launcher3.anim.Interpolators; +import com.android.launcher3.anim.RevealOutlineAnimation; +import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; +import com.android.launcher3.dragndrop.DragLayer; +import com.android.launcher3.graphics.ColorScrim; +import com.android.launcher3.userevent.nano.LauncherLogProto.Action; +import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; +import com.android.launcher3.widget.WidgetsFullSheet; + +/** + * Popup shown on long pressing an empty space in launcher + */ +public class OptionsPopupView extends AbstractFloatingView + implements OnClickListener, OnLongClickListener { + + private final float mOutlineRadius; + private final Launcher mLauncher; + private final PointF mTouchPoint = new PointF(); + + private final ColorScrim mScrim; + + protected Animator mOpenCloseAnimator; + + public OptionsPopupView(Context context, AttributeSet attrs) { + this(context, attrs, 0); + } + + public OptionsPopupView(Context context, AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + + mOutlineRadius = getResources().getDimension(R.dimen.bg_round_rect_radius); + setClipToOutline(true); + setOutlineProvider(new ViewOutlineProvider() { + @Override + public void getOutline(View view, Outline outline) { + outline.setRoundRect(0, 0, view.getWidth(), view.getHeight(), mOutlineRadius); + } + }); + + mLauncher = Launcher.getLauncher(context); + mScrim = ColorScrim.createExtractedColorScrim(this); + } + + @Override + protected void onFinishInflate() { + super.onFinishInflate(); + attachListeners(findViewById(R.id.wallpaper_button)); + attachListeners(findViewById(R.id.widget_button)); + attachListeners(findViewById(R.id.settings_button)); + } + + private void attachListeners(View view) { + view.setOnClickListener(this); + view.setOnLongClickListener(this); + } + + @Override + public void onClick(View view) { + handleViewClick(view, Action.Touch.TAP); + } + + @Override + public boolean onLongClick(View view) { + return handleViewClick(view, Action.Touch.LONGPRESS); + } + + private boolean handleViewClick(View view, int action) { + if (view.getId() == R.id.wallpaper_button) { + mLauncher.onClickWallpaperPicker(null); + logTap(action, ControlType.WALLPAPER_BUTTON); + close(true); + return true; + } else if (view.getId() == R.id.widget_button) { + logTap(action, ControlType.WIDGETS_BUTTON); + if (onWidgetsClicked(mLauncher)) { + close(true); + return true; + } + } else if (view.getId() == R.id.settings_button) { + startSettings(mLauncher); + logTap(action, ControlType.SETTINGS_BUTTON); + close(true); + return true; + } + return false; + } + + private void logTap(int action, int controlType) { + mLauncher.getUserEventDispatcher().logActionOnControl(action, controlType); + } + + @Override + public boolean onControllerInterceptTouchEvent(MotionEvent ev) { + if (ev.getAction() != MotionEvent.ACTION_DOWN) { + return false; + } + if (mLauncher.getDragLayer().isEventOverView(this, ev)) { + return false; + } + close(true); + return true; + } + + @Override + protected void handleClose(boolean animate) { + if (animate) { + animateClose(); + } else { + closeComplete(); + } + } + + protected void animateClose() { + if (!mIsOpen) { + return; + } + mIsOpen = false; + + final AnimatorSet closeAnim = LauncherAnimUtils.createAnimatorSet(); + closeAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration)); + + // Rectangular reveal (reversed). + final ValueAnimator revealAnim = createOpenCloseOutlineProvider() + .createRevealAnimator(this, true); + closeAnim.play(revealAnim); + + Animator fadeOut = ObjectAnimator.ofFloat(this, ALPHA, 0); + fadeOut.setInterpolator(Interpolators.DEACCEL); + closeAnim.play(fadeOut); + + Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 0); + gradientAlpha.setInterpolator(Interpolators.DEACCEL); + closeAnim.play(gradientAlpha); + + closeAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mOpenCloseAnimator = null; + closeComplete(); + } + }); + if (mOpenCloseAnimator != null) { + mOpenCloseAnimator.cancel(); + } + mOpenCloseAnimator = closeAnim; + closeAnim.start(); + } + + /** + * Closes the popup without animation. + */ + private void closeComplete() { + if (mOpenCloseAnimator != null) { + mOpenCloseAnimator.cancel(); + mOpenCloseAnimator = null; + } + mIsOpen = false; + mLauncher.getDragLayer().removeView(this); + } + + @Override + public void logActionCommand(int command) { + // TODO: + } + + @Override + protected boolean isOfType(int type) { + return (type & TYPE_OPTIONS_POPUP) != 0; + } + + private RoundedRectRevealOutlineProvider createOpenCloseOutlineProvider() { + DragLayer.LayoutParams lp = (DragLayer.LayoutParams) getLayoutParams(); + Rect startRect = new Rect(); + startRect.offset((int) (mTouchPoint.x - lp.x), (int) (mTouchPoint.y - lp.y)); + + Rect endRect = new Rect(0, 0, lp.width, lp.height); + if (getOutlineProvider() instanceof RevealOutlineAnimation) { + ((RevealOutlineAnimation) getOutlineProvider()).getOutline(endRect); + } + + return new RoundedRectRevealOutlineProvider + (mOutlineRadius, mOutlineRadius, startRect, endRect); + } + + private void animateOpen() { + mIsOpen = true; + final AnimatorSet openAnim = LauncherAnimUtils.createAnimatorSet(); + openAnim.setDuration(getResources().getInteger(R.integer.config_popupOpenCloseDuration)); + + final ValueAnimator revealAnim = createOpenCloseOutlineProvider() + .createRevealAnimator(this, false); + openAnim.play(revealAnim); + + Animator gradientAlpha = ObjectAnimator.ofFloat(mScrim, ColorScrim.PROGRESS, 1); + gradientAlpha.setInterpolator(Interpolators.ACCEL); + openAnim.play(gradientAlpha); + + mOpenCloseAnimator = openAnim; + + openAnim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + mOpenCloseAnimator = null; + } + }); + openAnim.start(); + } + + public static void show(Launcher launcher, float x, float y) { + DragLayer dl = launcher.getDragLayer(); + OptionsPopupView view = (OptionsPopupView) launcher.getLayoutInflater() + .inflate(R.layout.longpress_options_menu, dl, false); + DragLayer.LayoutParams lp = (DragLayer.LayoutParams) view.getLayoutParams(); + + int maxWidth = dl.getWidth(); + int maxHeight = dl.getHeight(); + if (x <= 0 || y <= 0 || x >= maxWidth || y >= maxHeight) { + x = maxWidth / 2; + y = maxHeight / 2; + } + view.mTouchPoint.set(x, y); + + int height = lp.height; + + // Find a good width; + int childCount = view.getChildCount(); + int heightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.AT_MOST); + int widthSpec = MeasureSpec.makeMeasureSpec(maxWidth / childCount, MeasureSpec.AT_MOST); + int maxChildWidth = 0; + + for (int i = 0; i < childCount; i ++) { + View child = ((ViewGroup) view.getChildAt(i)).getChildAt(0); + child.measure(widthSpec, heightSpec); + maxChildWidth = Math.max(maxChildWidth, child.getMeasuredWidth()); + } + Rect insets = dl.getInsets(); + int margin = (int) (2 * view.getElevation()); + + int width = Math.min(maxWidth - insets.left - insets.right - 2 * margin, + maxChildWidth * childCount); + lp.width = width; + + // Position is towards the finger + lp.customPosition = true; + lp.x = Utilities.boundToRange((int) (x - width / 2), insets.left + margin, + maxWidth - insets.right - width - margin); + lp.y = Utilities.boundToRange((int) (y - height / 2), insets.top + margin, + maxHeight - insets.bottom - height - margin); + + launcher.getDragLayer().addView(view); + view.animateOpen(); + } + + public static boolean onWidgetsClicked(Launcher launcher) { + if (launcher.getPackageManager().isSafeMode()) { + Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show(); + return false; + } else { + WidgetsFullSheet.show(launcher, true /* animated */); + return true; + } + } + + public static void startSettings(Launcher launcher) { + launcher.startActivity(new Intent(Intent.ACTION_APPLICATION_PREFERENCES) + .setPackage(launcher.getPackageName()) + .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); + } +} |