Merge "Adding implementation of InstantAppResolver for quickstep" into ub-launcher3-master
diff --git a/quickstep/libs/sysui_shared.jar b/quickstep/libs/sysui_shared.jar
index d76cd25..dbc2763 100644
--- a/quickstep/libs/sysui_shared.jar
+++ b/quickstep/libs/sysui_shared.jar
Binary files differ
diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml
index 9f4f8a1..54190ec 100644
--- a/quickstep/res/layout/overview_panel.xml
+++ b/quickstep/res/layout/overview_panel.xml
@@ -24,8 +24,4 @@
android:alpha="0.0"
android:visibility="invisible" >
- <com.android.launcher3.uioverrides.WorkspaceCard
- android:layout_width="match_parent"
- android:layout_height="match_parent" />
-
</com.android.quickstep.RecentsView>
\ No newline at end of file
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index cf86176..6a76b45 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -33,8 +33,6 @@
<dimen name="quickstep_fling_threshold_velocity">500dp</dimen>
<dimen name="quickstep_fling_min_velocity">250dp</dimen>
- <dimen name="workspace_overview_offset_x">-24dp</dimen>
-
<!-- Launcher app transition -->
<dimen name="content_trans_y">25dp</dimen>
<dimen name="workspace_trans_y">80dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
index b97669b..27b7f52 100644
--- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
+++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java
@@ -295,7 +295,7 @@
boolean launchingCenterTask = launchedTaskIndex == centerTaskIndex;
boolean isRtl = recentsView.isRtl();
if (launchingCenterTask) {
- if (launchedTaskIndex - 1 >= recentsView.getFirstTaskIndex()) {
+ if (launchedTaskIndex - 1 >= 0) {
TaskView adjacentPage1 = (TaskView) recentsView.getPageAt(launchedTaskIndex - 1);
ObjectAnimator adjacentTask1ScaleAndTranslate =
LauncherAnimUtils.ofPropertyValuesHolder(adjacentPage1,
@@ -317,7 +317,7 @@
.build());
launcherAnimator.play(adjacentTask2ScaleAndTranslate);
}
- } else if (centerTaskIndex >= recentsView.getFirstTaskIndex()) {
+ } else {
// We are launching an adjacent task, so parallax the center and other adjacent task.
TaskView centerTask = (TaskView) recentsView.getPageAt(centerTaskIndex);
float translationX = Math.abs(v.getTranslationX());
@@ -329,7 +329,7 @@
.build());
launcherAnimator.play(centerTaskParallaxToRight);
int otherAdjacentTaskIndex = centerTaskIndex + (centerTaskIndex - launchedTaskIndex);
- if (otherAdjacentTaskIndex >= recentsView.getFirstTaskIndex()
+ if (otherAdjacentTaskIndex >= 0
&& otherAdjacentTaskIndex < recentsView.getPageCount()) {
TaskView otherAdjacentTask = (TaskView) recentsView.getPageAt(
otherAdjacentTaskIndex);
diff --git a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
index 541c6bb..a55edfe 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/EdgeSwipeController.java
@@ -31,7 +31,6 @@
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -143,11 +142,6 @@
}
@Override
- protected void initSprings() {
- mSpringHandlers = new SpringAnimationHandler[0];
- }
-
- @Override
protected float getShiftRange() {
return getShiftRange(mLauncher);
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
index acd4fc1..c86c5af 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java
@@ -23,7 +23,7 @@
public class FastOverviewState extends OverviewState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_DISABLE_RESTORE
- | FLAG_PAGE_BACKGROUNDS | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
+ | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI;
private static final boolean DEBUG_DIFFERENT_UI = false;
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 854fb4f..4dfbf8d 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
-import static com.android.launcher3.anim.Interpolators.ACCEL_2;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_2;
import static com.android.launcher3.states.RotationHelper.REQUEST_ROTATE;
import android.graphics.Rect;
@@ -24,7 +24,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
-import com.android.launcher3.R;
import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsView;
@@ -35,7 +34,7 @@
public class OverviewState extends LauncherState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED
- | FLAG_DISABLE_RESTORE | FLAG_PAGE_BACKGROUNDS | FLAG_OVERVIEW_UI;
+ | FLAG_DISABLE_RESTORE | FLAG_OVERVIEW_UI;
public OverviewState(int id) {
this(id, STATE_FLAGS);
@@ -48,18 +47,13 @@
@Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
Rect pageRect = new Rect();
- RecentsView.getScaledDownPageRect(launcher.getDeviceProfile(), launcher, pageRect);
- RecentsView rv = launcher.getOverviewPanel();
+ RecentsView.getPageRect(launcher.getDeviceProfile(), launcher, pageRect);
if (launcher.getWorkspace().getNormalChildWidth() <= 0 || pageRect.isEmpty()) {
return super.getWorkspaceScaleAndTranslation(launcher);
}
- float overlap = 0;
- if (rv.getCurrentPage() >= rv.getFirstTaskIndex()) {
- overlap = launcher.getResources().getDimension(R.dimen.workspace_overview_offset_x);
- }
- return getScaleAndTranslationForPageRect(launcher, overlap, pageRect);
+ return getScaleAndTranslationForPageRect(launcher, pageRect);
}
@Override
@@ -85,40 +79,25 @@
}
public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
- final int centerPage = launcher.getWorkspace().getNextPage();
- return new PageAlphaProvider(ACCEL_2) {
+ return new PageAlphaProvider(DEACCEL_2) {
@Override
public float getPageAlpha(int pageIndex) {
- return pageIndex != centerPage ? 0 : 1f;
+ return 0;
}
};
}
- public static float[] getScaleAndTranslationForPageRect(Launcher launcher, float offsetX,
- Rect pageRect) {
+ public static float[] getScaleAndTranslationForPageRect(Launcher launcher, Rect pageRect) {
Workspace ws = launcher.getWorkspace();
float childWidth = ws.getNormalChildWidth();
- float childHeight = ws.getNormalChildHeight();
- float scale = pageRect.height() / childHeight;
+ float scale = pageRect.width() / childWidth;
Rect insets = launcher.getDragLayer().getInsets();
float halfHeight = ws.getExpectedHeight() / 2;
float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
float translationY = pageRect.top - childTop;
- // Align the workspace horizontally centered with the task rect
- float halfWidth = ws.getExpectedWidth() / 2;
- float childCenter = halfWidth -
- scale * (halfWidth - ws.getPaddingLeft() - insets.left - childWidth / 2);
- float translationX = pageRect.centerX() - childCenter;
-
- if (launcher.<RecentsView>getOverviewPanel().isRtl()) {
- translationX -= offsetX / scale;
- } else {
- translationX += offsetX / scale;
- }
-
- return new float[] {scale, translationX, translationY};
+ return new float[] {scale, 0, translationY};
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
index 468a561..958091b 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewSwipeController.java
@@ -15,6 +15,13 @@
*/
package com.android.launcher3.uioverrides;
+import static com.android.launcher3.LauncherState.ALL_APPS;
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
+import static com.android.launcher3.anim.Interpolators.LINEAR;
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
@@ -32,20 +39,13 @@
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.util.TouchController;
import com.android.quickstep.RecentsView;
import com.android.quickstep.TaskView;
-import static com.android.launcher3.LauncherState.ALL_APPS;
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.launcher3.anim.Interpolators.DEACCEL_1_5;
-import static com.android.launcher3.anim.Interpolators.LINEAR;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-
/**
* Touch controller for swipe interaction in Overview state
*/
@@ -132,28 +132,22 @@
mTaskBeingDragged = null;
mSwipeDownEnabled = true;
- int currentPage = mRecentsView.getCurrentPage();
- if (currentPage == 0) {
- // User is on home tile
+ View view = mRecentsView.getChildAt(mRecentsView.getCurrentPage());
+ if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
+ view instanceof TaskView) {
+ // The tile can be dragged down to open the task.
+ mTaskBeingDragged = (TaskView) view;
directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
+ mStartingTarget = LauncherLogProto.ItemType.TASK;
+ } else if (isEventOverHotseat(ev)) {
+ // The hotseat is being dragged
+ directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
+ mSwipeDownEnabled = false;
+ mStartingTarget = ContainerType.HOTSEAT;
} else {
- View view = mRecentsView.getChildAt(currentPage);
- if (mLauncher.getDragLayer().isEventOverView(view, ev) &&
- view instanceof TaskView) {
- // The tile can be dragged down to open the task.
- mTaskBeingDragged = (TaskView) view;
- directionsToDetectScroll = SwipeDetector.DIRECTION_BOTH;
- mStartingTarget = LauncherLogProto.ItemType.TASK;
- } else if (isEventOverHotseat(ev)) {
- // The hotseat is being dragged
- directionsToDetectScroll = SwipeDetector.DIRECTION_POSITIVE;
- mSwipeDownEnabled = false;
- mStartingTarget = ContainerType.HOTSEAT;
- } else {
- mNoIntercept = true;
- mStartingTarget = ContainerType.WORKSPACE;
- return false;
- }
+ mNoIntercept = true;
+ mStartingTarget = ContainerType.WORKSPACE;
+ return false;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index 92d071a..2a2e9c5 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -16,7 +16,7 @@
package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
+import static com.android.launcher3.anim.Interpolators.ACCEL;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -28,7 +28,6 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.PagedView;
-import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorSetBuilder;
import com.android.launcher3.anim.Interpolators;
@@ -40,31 +39,26 @@
private final Launcher mLauncher;
private final RecentsView mRecentsView;
- private final WorkspaceCard mWorkspaceCard;
private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::onTransitionProgress);
// The fraction representing the visibility of the RecentsView. This allows delaying the
// overall transition while the RecentsView is being shown or hidden.
private final AnimatedFloat mVisibilityMultiplier = new AnimatedFloat(this::onVisibilityProgress);
- private boolean mIsRecentsScrollingToFirstTask;
+ private boolean mIsRecentsSlidingInOrOut;
public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher;
mRecentsView = launcher.getOverviewPanel();
mRecentsView.setStateController(this);
-
- mWorkspaceCard = (WorkspaceCard) mRecentsView.getChildAt(0);
- mWorkspaceCard.setup(launcher);
}
@Override
public void setState(LauncherState state) {
- mWorkspaceCard.setWorkspaceScrollingEnabled(state.overviewUi);
setVisibility(state.overviewUi);
setTransitionProgress(state.overviewUi ? 1 : 0);
if (state.overviewUi) {
- for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+ for (int i = 0; i < mRecentsView.getPageCount(); i++) {
((TaskView) mRecentsView.getPageAt(i)).resetVisualProperties();
}
mRecentsView.updateCurveProperties();
@@ -74,22 +68,19 @@
@Override
public void setStateWithAnimation(final LauncherState toState,
AnimatorSetBuilder builder, AnimationConfig config) {
- boolean settingEnabled = Utilities.getPrefs(mLauncher)
- .getBoolean("pref_scroll_to_first_task_default_true", true);
- mIsRecentsScrollingToFirstTask = mLauncher.isInState(NORMAL) && toState == OVERVIEW
- && settingEnabled;
- // TODO: Instead of animating the workspace translationX, move the contents
- mWorkspaceCard.setWorkspaceScrollingEnabled(mIsRecentsScrollingToFirstTask);
+ LauncherState fromState = mLauncher.getStateManager().getState();
+ mIsRecentsSlidingInOrOut = fromState == NORMAL && toState.overviewUi
+ || fromState.overviewUi && toState == NORMAL;
// Scroll to the workspace card before changing to the NORMAL state.
int currPage = mRecentsView.getCurrentPage();
- LauncherState fromState = mLauncher.getStateManager().getState();
if (fromState.overviewUi && toState == NORMAL && currPage != 0 && !config.userControlled) {
int maxSnapDuration = PagedView.SLOW_PAGE_SNAP_ANIMATION_DURATION;
int durationPerPage = maxSnapDuration / 10;
int snapDuration = Math.min(maxSnapDuration, durationPerPage * currPage);
mRecentsView.snapToPage(0, snapDuration);
- builder.setStartDelay(snapDuration);
+ // Let the snapping animation play for a bit before we translate off screen.
+ builder.setStartDelay(snapDuration / 4);
}
ObjectAnimator progressAnim =
@@ -100,7 +91,6 @@
@Override
public void onAnimationSuccess(Animator animator) {
- mWorkspaceCard.setWorkspaceScrollingEnabled(toState.overviewUi);
mRecentsView.setCurrentPage(mRecentsView.getPageNearestToCenterOfScreen());
}
});
@@ -145,11 +135,14 @@
private void onTransitionProgress() {
applyProgress();
- if (mIsRecentsScrollingToFirstTask) {
- int scrollForFirstTask = mRecentsView.getScrollForPage(mRecentsView.getFirstTaskIndex());
- int scrollForPage0 = mRecentsView.getScrollForPage(0);
- mRecentsView.setScrollX((int) (mTransitionProgress.value * scrollForFirstTask
- + (1 - mTransitionProgress.value) * scrollForPage0));
+ if (mIsRecentsSlidingInOrOut) {
+ float interpolatedProgress = ACCEL.getInterpolation(mTransitionProgress.value);
+ // Slide in from the side as we swipe.
+ int translation = mRecentsView.getWidth();
+ if (mRecentsView.isRtl()) {
+ translation = -translation;
+ }
+ mRecentsView.setTranslationX(translation * (1 - interpolatedProgress));
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
index 2695054..c8d75dc 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/TwoStepSwipeController.java
@@ -19,7 +19,6 @@
import static com.android.launcher3.LauncherState.NORMAL;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
import static com.android.quickstep.TouchInteractionService.EDGE_NAV_BAR;
import android.animation.Animator;
@@ -27,7 +26,6 @@
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
import android.animation.ValueAnimator.AnimatorUpdateListener;
-import android.support.animation.SpringAnimation;
import android.util.Log;
import android.view.MotionEvent;
@@ -38,11 +36,9 @@
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.AnimationSuccessListener;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.anim.AnimatorSetBuilder;
-import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction;
@@ -52,8 +48,6 @@
import com.android.launcher3.util.TouchController;
import com.android.quickstep.TouchInteractionService;
-import java.util.ArrayList;
-
/**
* Handles vertical touch gesture on the DragLayer
*/
@@ -112,8 +106,6 @@
// Ratio of transition process [0, 1] to drag displacement (px)
private float mProgressMultiplier;
- private SpringAnimationHandler[] mSpringHandlers;
-
public TwoStepSwipeController(Launcher l) {
mLauncher = l;
mDetector = new SwipeDetector(l, this, SwipeDetector.VERTICAL);
@@ -156,29 +148,6 @@
}
}
- private void initSprings() {
- AllAppsContainerView appsView = mLauncher.getAppsView();
-
- SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
- if (handler == null) {
- mSpringHandlers = new SpringAnimationHandler[0];
- return;
- }
-
- ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
- handlers.add(handler);
-
- SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
- if (searchSpring != null) {
- SpringAnimationHandler searchHandler =
- new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
- searchHandler.add(searchSpring, true /* setDefaultValues */);
- handlers.add(searchHandler);
- }
-
- mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
- }
-
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -214,10 +183,6 @@
mDetector.setDetectableScrollConditions(
directionsToDetectScroll, ignoreSlopWhenSettling);
-
- if (mSpringHandlers == null) {
- initSprings();
- }
}
if (mNoIntercept) {
@@ -230,9 +195,6 @@
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
- for (SpringAnimationHandler h : mSpringHandlers) {
- h.addMovement(ev);
- }
return mDetector.onTouchEvent(ev);
}
@@ -283,10 +245,6 @@
mDragPauseDetector.clearDisabledFlags(FLAG_OVERVIEW_DISABLED_FLING);
updatePauseDetectorRangeFlag();
}
-
- for (SpringAnimationHandler h : mSpringHandlers) {
- h.skipToEnd();
- }
}
private float getShiftRange() {
@@ -329,13 +287,6 @@
targetState = (progress > SUCCESS_TRANSITION_PROGRESS) ? mToState : mFromState;
}
- if (fling && targetState == ALL_APPS) {
- for (SpringAnimationHandler h : mSpringHandlers) {
- // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
- h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
- }
- }
-
float endProgress;
if (mDragPauseDetector.isTriggered() && targetState == NORMAL) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java b/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
deleted file mode 100644
index 8533502..0000000
--- a/quickstep/src/com/android/launcher3/uioverrides/WorkspaceCard.java
+++ /dev/null
@@ -1,127 +0,0 @@
-/*
- * Copyright (C) 2017 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.uioverrides;
-
-import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
-import android.content.Context;
-import android.graphics.Canvas;
-import android.graphics.Rect;
-import android.util.AttributeSet;
-import android.view.View;
-import android.view.View.OnClickListener;
-
-import com.android.launcher3.Launcher;
-import com.android.launcher3.R;
-import com.android.launcher3.Workspace;
-import com.android.quickstep.RecentsView;
-import com.android.quickstep.RecentsView.PageCallbacks;
-import com.android.quickstep.RecentsView.ScrollState;
-
-public class WorkspaceCard extends View implements PageCallbacks, OnClickListener {
-
- private final Rect mTempRect = new Rect();
-
- private Launcher mLauncher;
- private Workspace mWorkspace;
-
- private float mLinearInterpolationForPage2 = 1;
- private float mTranslateXPage0, mTranslateXPage1;
- private float mExtraScrollShift;
-
- private boolean mIsWorkspaceScrollingEnabled;
-
- public WorkspaceCard(Context context) {
- this(context, null);
- }
-
- public WorkspaceCard(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
-
- public WorkspaceCard(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- setOnClickListener(this);
- }
-
- /**
- * Draw nothing.
- */
- @Override
- public void draw(Canvas canvas) { }
-
- @Override
- protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
- super.onLayout(changed, left, top, right, bottom);
-
- // Initiate data
- mLinearInterpolationForPage2 = RecentsView.getScaledDownPageRect(
- mLauncher.getDeviceProfile(), mLauncher, mTempRect);
-
- float[] scale = OverviewState.getScaleAndTranslationForPageRect(mLauncher, 0, mTempRect);
- mTranslateXPage0 = scale[1];
- mTranslateXPage1 = OverviewState
- .getScaleAndTranslationForPageRect(mLauncher,
- getResources().getDimension(R.dimen.workspace_overview_offset_x) / scale[0],
- mTempRect)[1];
-
- mExtraScrollShift = 0;
- if (mWorkspace != null && getWidth() > 0) {
- float workspaceWidth = mWorkspace.getNormalChildWidth() * scale[0];
- mExtraScrollShift = (workspaceWidth - getWidth()) / 2;
- setScaleX(workspaceWidth / getWidth());
- }
- }
-
- @Override
- public void onClick(View view) {
- mLauncher.getStateManager().goToState(NORMAL);
- }
-
- public void setup(Launcher launcher) {
- mLauncher = launcher;
- mWorkspace = mLauncher.getWorkspace();
- }
-
- public void setWorkspaceScrollingEnabled(boolean isEnabled) {
- mIsWorkspaceScrollingEnabled = isEnabled;
- }
-
- @Override
- public int onPageScroll(ScrollState scrollState) {
- float factor = scrollState.linearInterpolation;
- float translateX = scrollState.distanceFromScreenCenter;
- if (mIsWorkspaceScrollingEnabled) {
- float shift = factor * (mTranslateXPage1 - mTranslateXPage0);
- mWorkspace.setTranslationX(shift + mTranslateXPage0);
- translateX += shift;
- }
-
- setTranslationX(translateX);
-
- // If the workspace card is still the first page, shift all the other pages.
- if (scrollState.linearInterpolation > mLinearInterpolationForPage2) {
- scrollState.prevPageExtraWidth = 0;
- } else if (mLinearInterpolationForPage2 > 0) {
- scrollState.prevPageExtraWidth = mExtraScrollShift *
- (1 - scrollState.linearInterpolation / mLinearInterpolationForPage2);
- } else {
- scrollState.prevPageExtraWidth = mExtraScrollShift;
- }
- return SCROLL_TYPE_WORKSPACE;
- }
-}
diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
index 73cd503..9b2e822 100644
--- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
+++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java
@@ -23,8 +23,10 @@
import static android.view.MotionEvent.INVALID_POINTER_ID;
import static com.android.quickstep.RemoteRunnable.executeSafely;
+import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_BACK;
import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_NONE;
+import static com.android.systemui.shared.system.NavigationBarCompat.HIT_TARGET_OVERVIEW;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
@@ -61,6 +63,7 @@
import com.android.systemui.shared.system.RemoteAnimationTargetCompat;
import com.android.systemui.shared.system.WindowManagerWrapper;
+import java.util.Arrays;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
@@ -71,6 +74,8 @@
private static final String TAG = "ActivityTouchConsumer";
private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150;
+ private static final int[] DEFERRED_HIT_TARGETS = DEBUG_SHOW_OVERVIEW_BUTTON
+ ? new int[] {HIT_TARGET_BACK, HIT_TARGET_OVERVIEW} : new int[] {HIT_TARGET_BACK};
private final RunningTaskInfo mRunningTask;
private final RecentsModel mRecentsModel;
@@ -79,6 +84,7 @@
private final MainThreadExecutor mMainThreadExecutor;
private final Choreographer mBackgroundThreadChoreographer;
+ private final boolean mIsDeferredDownTarget;
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
@@ -88,7 +94,6 @@
private BaseSwipeInteractionHandler mInteractionHandler;
private int mDisplayRotation;
private Rect mStableInsets = new Rect();
- private @HitTarget int mDownHitTarget = HIT_TARGET_NONE;
private VelocityTracker mVelocityTracker;
private MotionEventQueue mEventQueue;
@@ -105,7 +110,7 @@
mISystemUiProxy = systemUiProxy;
mMainThreadExecutor = mainThreadExecutor;
mBackgroundThreadChoreographer = backgroundThreadChoreographer;
- mDownHitTarget = downHitTarget;
+ mIsDeferredDownTarget = Arrays.binarySearch(DEFERRED_HIT_TARGETS, downHitTarget) >= 0;
}
@Override
@@ -124,7 +129,7 @@
// Start the window animation on down to give more time for launcher to draw if the
// user didn't start the gesture over the back button
- if (!isUsingScreenShot() && mDownHitTarget != HIT_TARGET_BACK) {
+ if (!isUsingScreenShot() && !mIsDeferredDownTarget) {
startTouchTrackingForWindowAnimation(ev.getEventTime());
}
@@ -166,7 +171,7 @@
if (isUsingScreenShot()) {
startTouchTrackingForScreenshotAnimation();
- } else if (mDownHitTarget == HIT_TARGET_BACK) {
+ } else if (mIsDeferredDownTarget) {
// If we deferred starting the window animation on touch down, then
// start tracking now
startTouchTrackingForWindowAnimation(ev.getEventTime());
diff --git a/quickstep/src/com/android/quickstep/OverviewCommandHelper.java b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
new file mode 100644
index 0000000..b60d1e2
--- /dev/null
+++ b/quickstep/src/com/android/quickstep/OverviewCommandHelper.java
@@ -0,0 +1,111 @@
+/*
+ * 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.quickstep;
+
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.annotation.TargetApi;
+import android.app.ActivityManager.RecentTaskInfo;
+import android.content.ComponentName;
+import android.content.Context;
+import android.content.Intent;
+import android.content.pm.ResolveInfo;
+import android.os.Build;
+import android.os.SystemClock;
+import android.os.UserHandle;
+import android.view.ViewConfiguration;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.states.InternalStateHandler;
+import com.android.systemui.shared.system.ActivityManagerWrapper;
+
+/**
+ * Helper class to handle various atomic commands for switching between Overview.
+ */
+@TargetApi(Build.VERSION_CODES.P)
+public class OverviewCommandHelper extends InternalStateHandler {
+
+ private final Context mContext;
+ private final ActivityManagerWrapper mAM;
+
+ public final Intent homeIntent;
+ public final ComponentName launcher;
+
+ private long mLastToggleTime;
+
+ public OverviewCommandHelper(Context context) {
+ mContext = context;
+ mAM = ActivityManagerWrapper.getInstance();
+
+ homeIntent = new Intent(Intent.ACTION_MAIN)
+ .addCategory(Intent.CATEGORY_HOME)
+ .setPackage(context.getPackageName())
+ .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ ResolveInfo info = context.getPackageManager().resolveActivity(homeIntent, 0);
+ launcher = new ComponentName(context.getPackageName(), info.activityInfo.name);
+ // Clear the packageName as system can fail to dedupe it b/64108432
+ homeIntent.setComponent(launcher).setPackage(null);
+ }
+
+ public void onOverviewToggle() {
+ long elapsedTime = SystemClock.elapsedRealtime() - mLastToggleTime;
+ mLastToggleTime = SystemClock.elapsedRealtime();
+
+ if (isOverviewAlmostVisible()) {
+ boolean isQuickTap = elapsedTime < ViewConfiguration.getDoubleTapTimeout();
+ startNonLauncherTask(isQuickTap ? 2 : 1);
+ } else {
+ Intent intent = addToIntent(new Intent(homeIntent));
+ mContext.startActivity(intent);
+ initWhenReady();
+ }
+ }
+
+ private void startNonLauncherTask(int backStackCount) {
+ for (RecentTaskInfo rti : mAM.getRecentTasks(backStackCount, UserHandle.myUserId())) {
+ backStackCount--;
+ if (backStackCount == 0) {
+ mAM.startActivityFromRecents(rti.id, null);
+ }
+ }
+ }
+
+ private boolean isOverviewAlmostVisible() {
+ if (clearReference()) {
+ return true;
+ }
+ if (!mAM.getRunningTask().topActivity.equals(launcher)) {
+ return false;
+ }
+ Launcher launcher = getLauncher();
+ return launcher != null && launcher.isStarted() && launcher.isInState(OVERVIEW);
+ }
+
+ private Launcher getLauncher() {
+ return (Launcher) LauncherAppState.getInstance(mContext).getModel().getCallback();
+ }
+
+ @Override
+ protected boolean init(Launcher launcher, boolean alreadyOnHome) {
+ AbstractFloatingView.closeAllOpenViews(launcher, alreadyOnHome);
+ launcher.getStateManager().goToState(OVERVIEW, alreadyOnHome);
+ clearReference();
+ return false;
+ }
+
+}
diff --git a/quickstep/src/com/android/quickstep/OverviewInteractionState.java b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
index 3c68281..4af89bf 100644
--- a/quickstep/src/com/android/quickstep/OverviewInteractionState.java
+++ b/quickstep/src/com/android/quickstep/OverviewInteractionState.java
@@ -15,7 +15,9 @@
*/
package com.android.quickstep;
+import static com.android.quickstep.TouchInteractionService.DEBUG_SHOW_OVERVIEW_BUTTON;
import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_HIDE_BACK_BUTTON;
+import static com.android.systemui.shared.system.NavigationBarCompat.FLAG_SHOW_OVERVIEW_BUTTON;
import android.content.Context;
import android.os.Handler;
@@ -60,7 +62,7 @@
}
};
- private static int sFlags;
+ private static int sFlags = DEBUG_SHOW_OVERVIEW_BUTTON ? FLAG_SHOW_OVERVIEW_BUTTON : 0;
public static void setBackButtonVisible(Context context, boolean visible) {
updateFlagOnUi(context, FLAG_HIDE_BACK_BUTTON, !visible);
diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java
index f28d51c..dc1c0d2 100644
--- a/quickstep/src/com/android/quickstep/QuickScrubController.java
+++ b/quickstep/src/com/android/quickstep/QuickScrubController.java
@@ -22,10 +22,9 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.OnAlarmListener;
import com.android.launcher3.Utilities;
-import com.android.launcher3.userevent.nano.LauncherLogProto;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch;
-import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
+import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType;
/**
* Responds to quick scrub callbacks to page through and launch recent tasks.
@@ -52,6 +51,7 @@
private boolean mInQuickScrub;
private int mQuickScrubSection;
private int mStartPage;
+ private boolean mStartedFromHome;
private boolean mHasAlarmRun;
public QuickScrubController(Launcher launcher, RecentsView recentsView) {
@@ -65,7 +65,8 @@
public void onQuickScrubStart(boolean startingFromHome) {
mInQuickScrub = true;
- mStartPage = startingFromHome ? 0 : mRecentsView.getFirstTaskIndex();
+ mStartPage = 0;
+ mStartedFromHome = startingFromHome;
mQuickScrubSection = 0;
mHasAlarmRun = false;
mLauncher.getUserEventDispatcher().resetActionDurationMillis();
@@ -78,11 +79,7 @@
}
int page = mRecentsView.getNextPage();
Runnable launchTaskRunnable = () -> {
- if (page < mRecentsView.getFirstTaskIndex()) {
- mRecentsView.getPageAt(page).performClick();
- } else {
- ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
- }
+ ((TaskView) mRecentsView.getPageAt(page)).launchTask(true);
};
int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen())
* QUICKSCRUB_END_SNAP_DURATION_PER_PAGE;
@@ -94,7 +91,7 @@
launchTaskRunnable.run();
}
mLauncher.getUserEventDispatcher().logActionOnControl(Touch.DRAGDROP,
- ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
+ ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
ContainerType.WORKSPACE : ContainerType.APP);
}
@@ -116,7 +113,7 @@
}
public void onQuickSwitch() {
- for (int i = mRecentsView.getFirstTaskIndex(); i < mRecentsView.getPageCount(); i++) {
+ for (int i = 0; i < mRecentsView.getPageCount(); i++) {
TaskView taskView = (TaskView) mRecentsView.getPageAt(i);
if (taskView.getTask().key.id != mRecentsView.getRunningTaskId()) {
Runnable launchTaskRunnable = () -> taskView.launchTask(true);
@@ -131,13 +128,13 @@
}
}
mLauncher.getUserEventDispatcher().logActionOnControl(Touch.FLING,
- ControlType.QUICK_SCRUB_BUTTON, null, mStartPage == 0 ?
+ ControlType.QUICK_SCRUB_BUTTON, null, mStartedFromHome ?
ContainerType.WORKSPACE : ContainerType.APP);
}
public void snapToPageForCurrentQuickScrubSection() {
if (mInQuickScrub) {
- goToPageWithHaptic(mRecentsView.getFirstTaskIndex() + mQuickScrubSection);
+ goToPageWithHaptic(mQuickScrubSection);
}
}
diff --git a/quickstep/src/com/android/quickstep/RecentsModel.java b/quickstep/src/com/android/quickstep/RecentsModel.java
index 3e3b3b2..b4ce646 100644
--- a/quickstep/src/com/android/quickstep/RecentsModel.java
+++ b/quickstep/src/com/android/quickstep/RecentsModel.java
@@ -31,7 +31,6 @@
import android.util.LruCache;
import android.util.SparseArray;
-import com.android.launcher3.Launcher;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.Preconditions;
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index 9ae41eb..fdfca84 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -17,9 +17,6 @@
package com.android.quickstep;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
-import static com.android.quickstep.TaskView.CURVE_FACTOR;
-import static com.android.quickstep.TaskView.CURVE_INTERPOLATOR;
import android.animation.LayoutTransition;
import android.animation.LayoutTransition.TransitionListener;
@@ -52,7 +49,6 @@
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
@@ -72,10 +68,6 @@
private static final Rect sTempStableInsets = new Rect();
- public static final int SCROLL_TYPE_NONE = 0;
- public static final int SCROLL_TYPE_TASK = 1;
- public static final int SCROLL_TYPE_WORKSPACE = 2;
-
private static final String PREF_FLIP_RECENTS = "pref_flip_recents";
private final Launcher mLauncher;
@@ -152,7 +144,6 @@
mIsRtl = !mIsRtl;
}
setLayoutDirection(mIsRtl ? View.LAYOUT_DIRECTION_RTL : View.LAYOUT_DIRECTION_LTR);
- mScrollState.isRtl = mIsRtl;
}
}
@@ -274,7 +265,7 @@
}
public TaskView getTaskView(int taskId) {
- for (int i = getFirstTaskIndex(); i < getChildCount(); i++) {
+ for (int i = 0; i < getChildCount(); i++) {
TaskView tv = (TaskView) getChildAt(i);
if (tv.getTask().key.id == taskId) {
return tv;
@@ -407,33 +398,6 @@
return padding;
}
- /**
- * Sets the {@param outRect} to match the position of the first tile such that it is scaled
- * down to match the 2nd taskView.
- * @return returns the factor which determines the scaling factor for the second task.
- */
- public static float getScaledDownPageRect(DeviceProfile dp, Context context, Rect outRect) {
- getPageRect(dp, context, outRect);
-
- int pageSpacing = context.getResources()
- .getDimensionPixelSize(R.dimen.recents_page_spacing);
- float halfScreenWidth = dp.widthPx * 0.5f;
- float halfPageWidth = outRect.width() * 0.5f;
- float pageCenter = outRect.right + pageSpacing + halfPageWidth;
- float distanceFromCenter = Math.abs(halfScreenWidth - pageCenter);
- float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
- float linearInterpolation = Math.min(1, distanceFromCenter / distanceToReachEdge);
-
- float scale = 1 - CURVE_INTERPOLATOR.getInterpolation(linearInterpolation) * CURVE_FACTOR;
-
- int topMargin = context.getResources()
- .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
- outRect.top -= topMargin;
- Utilities.scaleRectAboutCenter(outRect, scale);
- outRect.top += (int) (scale * topMargin);
- return linearInterpolation;
- }
-
public static void getPageRect(DeviceProfile grid, Context context, Rect outRect) {
Rect targetPadding = getPadding(grid, context);
Rect insets = grid.getInsets();
@@ -474,8 +438,7 @@
if (getPageCount() == 0 || getPageAt(0).getMeasuredWidth() == 0) {
return;
}
- final int halfPageWidth = mScrollState.halfPageWidth = getNormalChildWidth() / 2;
- mScrollState.lastScrollType = SCROLL_TYPE_NONE;
+ final int halfPageWidth = getNormalChildWidth() / 2;
final int screenCenter = mInsets.left + getPaddingLeft() + getScrollX() + halfPageWidth;
final int halfScreenWidth = getMeasuredWidth() / 2;
final int pageSpacing = mPageSpacing;
@@ -484,11 +447,11 @@
for (int i = 0; i < pageCount; i++) {
View page = getPageAt(i);
int pageCenter = page.getLeft() + halfPageWidth;
- mScrollState.distanceFromScreenCenter = screenCenter - pageCenter;
+ float distanceFromScreenCenter = screenCenter - pageCenter;
float distanceToReachEdge = halfScreenWidth + halfPageWidth + pageSpacing;
mScrollState.linearInterpolation = Math.min(1,
- Math.abs(mScrollState.distanceFromScreenCenter) / distanceToReachEdge);
- mScrollState.lastScrollType = ((PageCallbacks) page).onPageScroll(mScrollState);
+ Math.abs(distanceFromScreenCenter) / distanceToReachEdge);
+ ((PageCallbacks) page).onPageScroll(mScrollState);
}
}
@@ -640,25 +603,17 @@
public interface PageCallbacks {
/**
- * Updates the page UI based on scroll params and returns the type of scroll
- * effect performed.
- *
- * @see #SCROLL_TYPE_NONE
- * @see #SCROLL_TYPE_TASK
- * @see #SCROLL_TYPE_WORKSPACE
+ * Updates the page UI based on scroll params.
*/
- int onPageScroll(ScrollState scrollState);
+ default void onPageScroll(ScrollState scrollState) {};
}
public static class ScrollState {
- public boolean isRtl;
- public int lastScrollType;
-
- public int halfPageWidth;
- public float distanceFromScreenCenter;
+ /**
+ * The progress from 0 to 1, where 0 is the center
+ * of the screen and 1 is the edge of the screen.
+ */
public float linearInterpolation;
-
- public float prevPageExtraWidth;
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
index 9b9c6f2..2cdd4e9 100644
--- a/quickstep/src/com/android/quickstep/TaskThumbnailView.java
+++ b/quickstep/src/com/android/quickstep/TaskThumbnailView.java
@@ -74,6 +74,7 @@
mCornerRadius = getResources().getDimension(R.dimen.task_corner_radius);
mFadeLength = getResources().getDimension(R.dimen.task_fade_length);
mOverlay = TaskOverlayFactory.get(context).createOverlay(this);
+ mPaint.setFilterBitmap(true);
}
public void bind() {
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index b407f75..e0b03b8 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -16,9 +16,6 @@
package com.android.quickstep;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_TASK;
-import static com.android.quickstep.RecentsView.SCROLL_TYPE_WORKSPACE;
-
import android.animation.TimeInterpolator;
import android.app.ActivityOptions;
import android.content.Context;
@@ -47,17 +44,15 @@
*/
public class TaskView extends FrameLayout implements TaskCallbacks, PageCallbacks {
- /** Designates how "curvy" the carousel is from 0 to 1, where 0 is a straight line. */
- public static final float CURVE_FACTOR = 0.25f;
- /** A circular curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
- public static final TimeInterpolator CURVE_INTERPOLATOR
- = x -> (float) (1 - Math.sqrt(1 - Math.pow(x, 2)));
+ /** A curve of x from 0 to 1, where 0 is the center of the screen and 1 is the edge. */
+ private static final TimeInterpolator CURVE_INTERPOLATOR
+ = x -> (float) -Math.cos(x * Math.PI) / 2f + .5f;
/**
* The alpha of a black scrim on a page in the carousel as it leaves the screen.
* In the resting position of the carousel, the adjacent pages have about half this scrim.
*/
- private static final float MAX_PAGE_SCRIM_ALPHA = 0.8f;
+ private static final float MAX_PAGE_SCRIM_ALPHA = 0.4f;
private static final long SCALE_ICON_DURATION = 120;
@@ -163,34 +158,11 @@
}
@Override
- public int onPageScroll(ScrollState scrollState) {
+ public void onPageScroll(ScrollState scrollState) {
float curveInterpolation =
CURVE_INTERPOLATOR.getInterpolation(scrollState.linearInterpolation);
- float scale = 1 - curveInterpolation * CURVE_FACTOR;
- setScaleX(scale);
- setScaleY(scale);
-
- // Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
- setTranslationZ(scale);
mSnapshotView.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
-
- float translation =
- scrollState.distanceFromScreenCenter * curveInterpolation * CURVE_FACTOR;
-
- if (scrollState.lastScrollType == SCROLL_TYPE_WORKSPACE) {
- // Make sure that the task cards do not overlap with the workspace card
- float min = scrollState.halfPageWidth * (1 - scale);
- if (scrollState.isRtl) {
- setTranslationX(Math.min(translation, min) - scrollState.prevPageExtraWidth);
- } else {
- setTranslationX(Math.max(translation, -min) + scrollState.prevPageExtraWidth);
- }
- } else {
- setTranslationX(translation);
- }
- scrollState.prevPageExtraWidth = 0;
- return SCROLL_TYPE_TASK;
}
private static final class TaskOutlineProvider extends ViewOutlineProvider {
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index e5af3e5..12c2170 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -23,15 +23,12 @@
import static android.view.MotionEvent.ACTION_UP;
import static com.android.launcher3.LauncherState.FAST_OVERVIEW;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.quickstep.QuickScrubController.QUICK_SWITCH_START_DURATION;
import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.Service;
-import android.content.ComponentName;
import android.content.Intent;
-import android.content.pm.ResolveInfo;
import android.graphics.PointF;
import android.os.Build;
import android.os.Handler;
@@ -62,6 +59,8 @@
@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
+ public static final boolean DEBUG_SHOW_OVERVIEW_BUTTON = false;
+
private static final SparseArray<String> sMotionEventNames;
static {
@@ -132,6 +131,17 @@
mEventQueue.onQuickScrubEnd();
TraceHelper.endSection("SysUiBinder", "onQuickScrubEnd");
}
+
+ @Override
+ public void onOverviewToggle() {
+ mOverviewCommandHelper.onOverviewToggle();
+ }
+
+ @Override
+ public void onOverviewShown(boolean triggeredFromAltTab) { }
+
+ @Override
+ public void onOverviewHidden(boolean triggeredFromAltTab, boolean triggeredFromHomeKey) { }
};
private final TouchConsumer mNoOpTouchConsumer = (ev) -> {};
@@ -143,13 +153,11 @@
}
private ActivityManagerWrapper mAM;
- private RunningTaskInfo mRunningTask;
private RecentsModel mRecentsModel;
- private Intent mHomeIntent;
- private ComponentName mLauncher;
private MotionEventQueue mEventQueue;
private MainThreadExecutor mMainThreadExecutor;
private ISystemUiProxy mISystemUiProxy;
+ private OverviewCommandHelper mOverviewCommandHelper;
private Choreographer mMainThreadChoreographer;
private Choreographer mBackgroundThreadChoreographer;
@@ -161,16 +169,7 @@
mAM = ActivityManagerWrapper.getInstance();
mRecentsModel = RecentsModel.getInstance(this);
mMainThreadExecutor = new MainThreadExecutor();
-
- mHomeIntent = new Intent(Intent.ACTION_MAIN)
- .addCategory(Intent.CATEGORY_HOME)
- .setPackage(getPackageName())
- .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ResolveInfo info = getPackageManager().resolveActivity(mHomeIntent, 0);
- mLauncher = new ComponentName(getPackageName(), info.activityInfo.name);
- // Clear the packageName as system can fail to dedupe it b/64108432
- mHomeIntent.setComponent(mLauncher).setPackage(null);
-
+ mOverviewCommandHelper = new OverviewCommandHelper(this);
mMainThreadChoreographer = Choreographer.getInstance();
mNoOpEventQueue = new MotionEventQueue(mMainThreadChoreographer, mNoOpTouchConsumer);
mEventQueue = mNoOpEventQueue;
@@ -195,19 +194,19 @@
}
private void onBinderPreMotionEvent(@HitTarget int downHitTarget) {
- mRunningTask = mAM.getRunningTask();
+ RunningTaskInfo runningTaskInfo = mAM.getRunningTask();
mEventQueue.reset();
- if (mRunningTask == null) {
+ if (runningTaskInfo == null) {
mEventQueue = mNoOpEventQueue;
- } else if (mRunningTask.topActivity.equals(mLauncher)) {
+ } else if (runningTaskInfo.topActivity.equals(mOverviewCommandHelper.launcher)) {
mEventQueue = getLauncherEventQueue();
} else {
mEventQueue = new MotionEventQueue(mMainThreadChoreographer,
- new OtherActivityTouchConsumer(this, mRunningTask, mRecentsModel,
- mHomeIntent, mISystemUiProxy, mMainThreadExecutor,
- mBackgroundThreadChoreographer, downHitTarget));
+ new OtherActivityTouchConsumer(this, runningTaskInfo, mRecentsModel,
+ mOverviewCommandHelper.homeIntent, mISystemUiProxy, mMainThreadExecutor,
+ mBackgroundThreadChoreographer, downHitTarget));
}
}
diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
index f49106e..bab8ef1 100644
--- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
+++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java
@@ -235,7 +235,9 @@
mContext = context;
mRunningTaskId = runningTaskInfo.id;
mTouchTimeMs = touchTimeMs;
- mInputConsumer.registerInputConsumer();
+ // Register the input consumer on the UI thread, to ensure that it runs after any pending
+ // unregister calls
+ mMainExecutor.execute(mInputConsumer::registerInputConsumer);
initStateCallbacks();
}
@@ -565,8 +567,13 @@
for (RemoteAnimationTargetCompat app : mRecentsAnimationWrapper.targets) {
if (app.mode == MODE_CLOSING) {
transaction.setMatrix(app.leash, mTmpMatrix)
- .setWindowCrop(app.leash, mClipRect)
- .show(app.leash);
+ .setWindowCrop(app.leash, mClipRect);
+
+ if (app.isNotInRecents) {
+ transaction.setAlpha(app.leash, 1 - shift);
+ }
+
+ transaction.show(app.leash);
}
}
transaction.apply();
@@ -581,9 +588,8 @@
mLauncherTransitionController.setPlayFraction(shift);
// Make sure the window follows the first task if it moves, e.g. during quick scrub.
- int firstTaskIndex = mRecentsView.getFirstTaskIndex();
- View firstTask = mRecentsView.getPageAt(firstTaskIndex);
- int scrollForFirstTask = mRecentsView.getScrollForPage(firstTaskIndex);
+ View firstTask = mRecentsView.getPageAt(0);
+ int scrollForFirstTask = mRecentsView.getScrollForPage(0);
int offsetFromFirstTask = (scrollForFirstTask - mRecentsView.getScrollX());
if (offsetFromFirstTask != 0) {
synchronized (mTargetRect) {
diff --git a/res/layout/all_apps_rv_layout.xml b/res/layout/all_apps_rv_layout.xml
index 3c19f8c..c353b36 100644
--- a/res/layout/all_apps_rv_layout.xml
+++ b/res/layout/all_apps_rv_layout.xml
@@ -22,5 +22,4 @@
android:layout_below="@id/search_container_all_apps"
android:clipToPadding="false"
android:descendantFocusability="afterDescendants"
- android:focusable="true"
- android:overScrollMode="never" />
+ android:focusable="true" />
diff --git a/res/layout/widgets_full_sheet.xml b/res/layout/widgets_full_sheet.xml
index 978b5a1..f507a88 100644
--- a/res/layout/widgets_full_sheet.xml
+++ b/res/layout/widgets_full_sheet.xml
@@ -31,21 +31,22 @@
android:id="@+id/widgets_list_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:clipToPadding="false"
- />
+ android:clipToPadding="false" />
<!-- Fast scroller popup -->
<TextView
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
- android:layout_gravity="top|end"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
android:id="@+id/fast_scroller"
android:layout_width="@dimen/fastscroll_width"
android:layout_height="match_parent"
- android:layout_gravity="end"
+ android:layout_alignParentEnd="true"
+ android:layout_alignParentTop="true"
android:layout_marginEnd="@dimen/fastscroll_end_margin" />
</com.android.launcher3.views.TopRoundedCornerView>
</com.android.launcher3.widget.WidgetsFullSheet>
\ No newline at end of file
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index fdf468c..375deb7 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -19,11 +19,6 @@
import static android.content.pm.ActivityInfo.CONFIG_ORIENTATION;
import static android.content.pm.ActivityInfo.CONFIG_SCREEN_SIZE;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
-import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.LauncherState.NORMAL;
@@ -39,7 +34,6 @@
import android.annotation.SuppressLint;
import android.annotation.TargetApi;
import android.app.ActivityOptions;
-import android.app.AlertDialog;
import android.appwidget.AppWidgetHostView;
import android.appwidget.AppWidgetManager;
import android.content.ActivityNotFoundException;
@@ -47,7 +41,6 @@
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.ContextWrapper;
-import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentSender;
@@ -80,6 +73,7 @@
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;
@@ -99,10 +93,8 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
-import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dynamicui.WallpaperColorInfo;
-import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.keyboard.CustomActionsPopup;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
@@ -115,6 +107,7 @@
import com.android.launcher3.shortcuts.DeepShortcutManager;
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;
@@ -155,7 +148,7 @@
* Default launcher application.
*/
public class Launcher extends BaseActivity
- implements LauncherExterns, View.OnClickListener, OnLongClickListener,
+ implements LauncherExterns, OnClickListener, OnLongClickListener,
LauncherModel.Callbacks, View.OnTouchListener, LauncherProviderChangeListener,
WallpaperColorInfo.OnThemeChangeListener {
public static final String TAG = "Launcher";
@@ -170,8 +163,8 @@
private static final int REQUEST_PICK_WALLPAPER = 10;
private static final int REQUEST_BIND_APPWIDGET = 11;
- private static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
- private static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
+ public static final int REQUEST_BIND_PENDING_APPWIDGET = 12;
+ public static final int REQUEST_RECONFIGURE_APPWIDGET = 13;
private static final int REQUEST_PERMISSION_CALL_PHONE = 14;
@@ -1017,7 +1010,7 @@
BubbleTextView favorite = (BubbleTextView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.app_icon, parent, false);
favorite.applyFromShortcutInfo(info);
- favorite.setOnClickListener(this);
+ favorite.setOnClickListener(ItemClickHandler.INSTANCE);
favorite.setOnFocusChangeListener(mFocusHandler);
return favorite;
}
@@ -1670,6 +1663,7 @@
*
* @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).
@@ -1702,21 +1696,6 @@
}
return;
}
-
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- onClickAppShortcut(v);
- } else if (tag instanceof FolderInfo) {
- if (v instanceof FolderIcon) {
- onClickFolderIcon(v);
- }
- } else if (tag instanceof AppInfo) {
- startAppShortcutOrInfoActivity(v);
- } else if (tag instanceof LauncherAppWidgetInfo) {
- if (v instanceof PendingAppWidgetHostView) {
- onClickPendingWidget((PendingAppWidgetHostView) v);
- }
- }
}
@SuppressLint("ClickableViewAccessibility")
@@ -1725,173 +1704,6 @@
}
/**
- * Event handler for the app widget view which has not fully restored.
- */
- public void onClickPendingWidget(final PendingAppWidgetHostView v) {
- if (mIsSafeModeEnabled) {
- Toast.makeText(this, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
- return;
- }
-
- final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
- if (v.isReadyForClickSetup()) {
- LauncherAppWidgetProviderInfo appWidgetInfo =
- mAppWidgetManager.findProvider(info.providerName, info.user);
- if (appWidgetInfo == null) {
- return;
- }
- WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
-
- if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
- if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
- // This should not happen, as we make sure that an Id is allocated during bind.
- return;
- }
- addFlowHandler.startBindFlow(this, info.appWidgetId, info,
- REQUEST_BIND_PENDING_APPWIDGET);
- } else {
- addFlowHandler.startConfigActivity(this, info, REQUEST_RECONFIGURE_APPWIDGET);
- }
- } else {
- final String packageName = info.providerName.getPackageName();
- onClickPendingAppItem(v, packageName, info.installProgress >= 0);
- }
- }
-
- private void onClickPendingAppItem(final View v, final String packageName,
- boolean downloadStarted) {
- if (downloadStarted) {
- // If the download has started, simply direct to the market app.
- startMarketIntentForPackage(v, packageName);
- return;
- }
- new AlertDialog.Builder(this)
- .setTitle(R.string.abandoned_promises_title)
- .setMessage(R.string.abandoned_promise_explanation)
- .setPositiveButton(R.string.abandoned_search, new DialogInterface.OnClickListener() {
- @Override
- public void onClick(DialogInterface dialogInterface, int i) {
- startMarketIntentForPackage(v, packageName);
- }
- })
- .setNeutralButton(R.string.abandoned_clean_this,
- new DialogInterface.OnClickListener() {
- public void onClick(DialogInterface dialog, int id) {
- final UserHandle user = Process.myUserHandle();
- mWorkspace.removeAbandonedPromise(packageName, user);
- }
- })
- .create().show();
- }
-
- private void startMarketIntentForPackage(View v, String packageName) {
- ItemInfo item = (ItemInfo) v.getTag();
- Intent intent = new PackageManagerHelper(v.getContext()).getMarketIntent(packageName);
- startActivitySafely(v, intent, item);
- }
-
- /**
- * Event handler for an app shortcut click.
- *
- * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
- */
- protected void onClickAppShortcut(final View v) {
- if (LOGD) Log.d(TAG, "onClickAppShortcut");
- Object tag = v.getTag();
- if (!(tag instanceof ShortcutInfo)) {
- throw new IllegalArgumentException("Input must be a Shortcut");
- }
-
- // Open shortcut
- final ShortcutInfo shortcut = (ShortcutInfo) tag;
-
- if (shortcut.isDisabled()) {
- final int disabledFlags = shortcut.runtimeStatusFlags & ShortcutInfo.FLAG_DISABLED_MASK;
- if ((disabledFlags &
- ~FLAG_DISABLED_SUSPENDED &
- ~FLAG_DISABLED_QUIET_USER) == 0) {
- // If the app is only disabled because of the above flags, launch activity anyway.
- // Framework will tell the user why the app is suspended.
- } else {
- if (!TextUtils.isEmpty(shortcut.disabledMessage)) {
- // Use a message specific to this shortcut, if it has one.
- Toast.makeText(this, shortcut.disabledMessage, Toast.LENGTH_SHORT).show();
- return;
- }
- // Otherwise just use a generic error message.
- int error = R.string.activity_not_available;
- if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) {
- error = R.string.safemode_shortcut_error;
- } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 ||
- (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) {
- error = R.string.shortcut_not_available;
- }
- Toast.makeText(this, error, Toast.LENGTH_SHORT).show();
- return;
- }
- }
-
- // Check for abandoned promise
- if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
- String packageName = shortcut.intent.getComponent() != null ?
- shortcut.intent.getComponent().getPackageName() : shortcut.intent.getPackage();
- if (!TextUtils.isEmpty(packageName)) {
- onClickPendingAppItem(v, packageName,
- shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE));
- return;
- }
- }
-
- // Start activities
- startAppShortcutOrInfoActivity(v);
- }
-
- private void startAppShortcutOrInfoActivity(View v) {
- ItemInfo item = (ItemInfo) v.getTag();
- Intent intent;
- if (item instanceof PromiseAppInfo) {
- PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
- intent = promiseAppInfo.getMarketIntent(this);
- } else {
- intent = item.getIntent();
- }
- if (intent == null) {
- throw new IllegalArgumentException("Input must have a valid intent");
- }
- if (item instanceof ShortcutInfo) {
- ShortcutInfo si = (ShortcutInfo) item;
- if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
- && intent.getAction() == Intent.ACTION_VIEW) {
- // make a copy of the intent that has the package set to null
- // we do this because the platform sometimes disables instant
- // apps temporarily (triggered by the user) and fallbacks to the
- // web ui. This only works though if the package isn't set
- intent = new Intent(intent);
- intent.setPackage(null);
- }
- }
- startActivitySafely(v, intent, item);
- }
-
- /**
- * Event handler for a folder icon click.
- *
- * @param v The view that was clicked. Must be an instance of {@link FolderIcon}.
- */
- protected void onClickFolderIcon(View v) {
- if (LOGD) Log.d(TAG, "onClickFolder");
- if (!(v instanceof FolderIcon)){
- throw new IllegalArgumentException("Input must be a FolderIcon");
- }
-
- Folder folder = ((FolderIcon) v).getFolder();
- if (!folder.isOpen() && !folder.isDestroyed()) {
- // Open the requested folder
- folder.animateOpen();
- }
- }
-
- /**
* Event handler for the wallpaper picker button that appears after a long press
* on the home screen.
*/
@@ -2081,45 +1893,25 @@
}
}
- CellLayout.CellInfo longClickCellInfo = null;
- View itemUnderLongClick = null;
- if (v.getTag() instanceof ItemInfo) {
- ItemInfo info = (ItemInfo) v.getTag();
- longClickCellInfo = new CellLayout.CellInfo(v, info);
- itemUnderLongClick = longClickCellInfo.cell;
- mPendingRequestArgs = null;
- }
-
// The hotseat touch handling does not go through Workspace, and we always allow long press
// on hotseat items.
if (!mDragController.isDragging()) {
- if (itemUnderLongClick == null) {
- // 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);
+ // User long pressed on empty space
+ if (mWorkspace.isPageRearrangeEnabled()) {
+ mWorkspace.startReordering(v);
+ getUserEventDispatcher().logActionOnContainer(Action.Touch.LONGPRESS,
+ Action.Direction.NONE, ContainerType.OVERVIEW);
} else {
- final boolean isAllAppsButton =
- !FeatureFlags.NO_ALL_APPS_ICON && isHotseatLayout(v) &&
- mDeviceProfile.inv.isAllAppsButtonRank(mHotseat.getOrderInHotseat(
- longClickCellInfo.cellX, longClickCellInfo.cellY));
- if (!(itemUnderLongClick instanceof Folder || isAllAppsButton)) {
- // User long pressed on an item
- mWorkspace.startDrag(longClickCellInfo, new DragOptions());
+ 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;
}
diff --git a/src/com/android/launcher3/ShortcutInfo.java b/src/com/android/launcher3/ShortcutInfo.java
index ec608ca..8588c7a 100644
--- a/src/com/android/launcher3/ShortcutInfo.java
+++ b/src/com/android/launcher3/ShortcutInfo.java
@@ -79,7 +79,7 @@
* A message to display when the user tries to start a disabled shortcut.
* This is currently only used for deep shortcuts.
*/
- CharSequence disabledMessage;
+ public CharSequence disabledMessage;
public int status;
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 7c42b48..f329f5e 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -81,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.uioverrides.UiFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto.Action;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -935,10 +936,9 @@
Log.e(TAG, "Failed to add to item at (" + lp.cellX + "," + lp.cellY + ") to CellLayout");
}
- if (!(child instanceof Folder)) {
- child.setHapticFeedbackEnabled(false);
- child.setOnLongClickListener(mLongClickListener);
- }
+ child.setHapticFeedbackEnabled(false);
+ child.setOnLongClickListener(ItemLongClickListener.INSTANCE_WORKSPACE);
+
if (child instanceof DropTarget) {
mDragController.addDropTarget((DropTarget) child);
}
@@ -1635,7 +1635,6 @@
new DragPreviewProvider(child), options);
}
-
public DragView beginDragShared(View child, DragSource source, ItemInfo dragObject,
DragPreviewProvider previewProvider, DragOptions dragOptions) {
child.clearFocus();
@@ -2970,8 +2969,9 @@
+ "Workspace#onDropCompleted. Please file a bug. ");
}
}
- if (d.cancelled && mDragInfo != null && mDragInfo.cell != null) {
- mDragInfo.cell.setVisibility(VISIBLE);
+ View cell = getHomescreenIconByItemId(d.originalDragInfo.id);
+ if (d.cancelled && cell != null) {
+ cell.setVisibility(VISIBLE);
}
mDragInfo = null;
}
diff --git a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
index 2cd8b1d..4398f6e 100644
--- a/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
+++ b/src/com/android/launcher3/accessibility/LauncherAccessibilityDelegate.java
@@ -25,6 +25,7 @@
import com.android.launcher3.FolderInfo;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
import com.android.launcher3.LauncherAppWidgetInfo;
import com.android.launcher3.LauncherSettings;
@@ -358,29 +359,14 @@
mDragInfo.dragType = DragType.WIDGET;
}
- CellLayout.CellInfo cellInfo = new CellLayout.CellInfo(item, info);
-
Rect pos = new Rect();
mLauncher.getDragLayer().getDescendantRectRelativeToSelf(item, pos);
mLauncher.getDragController().prepareAccessibleDrag(pos.centerX(), pos.centerY());
-
- Folder folder = Folder.getOpen(mLauncher);
- if (folder != null) {
- if (!folder.getItemsInReadingOrder().contains(item)) {
- folder.close(true);
- folder = null;
- }
- }
-
mLauncher.getDragController().addDragListener(this);
DragOptions options = new DragOptions();
options.isAccessibleDrag = true;
- if (folder != null) {
- folder.startDrag(cellInfo.cell, options);
- } else {
- mLauncher.getWorkspace().startDrag(cellInfo, options);
- }
+ ItemLongClickListener.beginDrag(item, mLauncher, info, options);
}
@Override
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index 26922ad..3fe5d7a 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -34,26 +34,19 @@
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
-import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
-import android.widget.RelativeLayout;
import com.android.launcher3.AppInfo;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.DeviceProfile.OnDeviceProfileChangeListener;
import com.android.launcher3.DragSource;
-import com.android.launcher3.DropTarget;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.Insettable;
import com.android.launcher3.InsettableFrameLayout;
import com.android.launcher3.ItemInfo;
import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
-import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dragndrop.DragController;
-import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.ColorScrim;
import com.android.launcher3.keyboard.FocusedItemDecorator;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
@@ -61,12 +54,13 @@
import com.android.launcher3.util.Themes;
import com.android.launcher3.views.BottomUserEducationView;
import com.android.launcher3.views.RecyclerViewFastScroller;
+import com.android.launcher3.views.SpringRelativeLayout;
/**
* The all apps view container.
*/
-public class AllAppsContainerView extends RelativeLayout implements DragSource,
- OnLongClickListener, Insettable, OnDeviceProfileChangeListener {
+public class AllAppsContainerView extends SpringRelativeLayout implements DragSource,
+ Insettable, OnDeviceProfileChangeListener {
private final Launcher mLauncher;
private final AdapterHolder[] mAH;
@@ -119,6 +113,10 @@
// Attach a scrim to be drawn behind all-apps and hotseat
new ColorScrim(this, Themes.getAttrColor(context, R.attr.allAppsScrimColor), DEACCEL_2)
.attach();
+
+ addSpringView(R.id.all_apps_header);
+ addSpringView(R.id.apps_list_view);
+ addSpringView(R.id.all_apps_tabs_view_pager);
}
public AllAppsStore getAppsStore() {
@@ -249,37 +247,6 @@
}
@Override
- public boolean onLongClick(final View v) {
- // When we have exited all apps or are in transition, disregard long clicks
- if (!mLauncher.isInState(LauncherState.ALL_APPS) ||
- mLauncher.getWorkspace().isSwitchingState()) return false;
- // Return if global dragging is not enabled or we are already dragging
- if (!mLauncher.isDraggingEnabled()) return false;
- if (mLauncher.getDragController().isDragging()) return false;
-
- // Start the drag
- final DragController dragController = mLauncher.getDragController();
- dragController.addDragListener(new DragController.DragListener() {
- @Override
- public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
- v.setVisibility(INVISIBLE);
- }
-
- @Override
- public void onDragEnd() {
- v.setVisibility(VISIBLE);
- dragController.removeDragListener(this);
- }
- });
-
- DeviceProfile grid = mLauncher.getDeviceProfile();
- DragOptions options = new DragOptions();
- options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
- mLauncher.getWorkspace().beginDragShared(v, this, options);
- return false;
- }
-
- @Override
public void onDropCompleted(View target, DragObject d, boolean success) { }
@Override
@@ -324,10 +291,6 @@
}
}
- public SpringAnimationHandler getSpringAnimationHandler() {
- return mUsingTabs ? null : mAH[AdapterHolder.MAIN].animationHandler;
- }
-
private void rebindAdapters(boolean showTabs) {
rebindAdapters(showTabs, false /* force */);
}
@@ -470,7 +433,6 @@
public final AllAppsGridAdapter adapter;
final LinearLayoutManager layoutManager;
- final SpringAnimationHandler animationHandler;
final AlphabeticalAppsList appsList;
final Rect padding = new Rect();
AllAppsRecyclerView recyclerView;
@@ -478,25 +440,21 @@
AdapterHolder(boolean isWork) {
appsList = new AlphabeticalAppsList(mLauncher, mAllAppsStore, isWork);
- adapter = new AllAppsGridAdapter(mLauncher, appsList, mLauncher,
- AllAppsContainerView.this, true);
+ adapter = new AllAppsGridAdapter(mLauncher, appsList);
appsList.setAdapter(adapter);
- animationHandler = adapter.getSpringAnimationHandler();
layoutManager = adapter.getLayoutManager();
}
void setup(@NonNull View rv, @Nullable ItemInfoMatcher matcher) {
appsList.updateItemFilter(matcher);
recyclerView = (AllAppsRecyclerView) rv;
+ recyclerView.setEdgeEffectFactory(createEdgeEffectFactory());
recyclerView.setApps(appsList, mUsingTabs);
recyclerView.setLayoutManager(layoutManager);
recyclerView.setAdapter(adapter);
recyclerView.setHasFixedSize(true);
// No animations will occur when changes occur to the items in this RecyclerView.
recyclerView.setItemAnimator(null);
- if (FeatureFlags.LAUNCHER3_PHYSICS && animationHandler != null) {
- recyclerView.setSpringAnimationHandler(animationHandler);
- }
FocusedItemDecorator focusedItemDecorator = new FocusedItemDecorator(recyclerView);
recyclerView.addItemDecoration(focusedItemDecorator);
adapter.setIconFocusListener(focusedItemDecorator.getFocusListener());
diff --git a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
index a61521c..27fc53a 100644
--- a/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
+++ b/src/com/android/launcher3/allapps/AllAppsGridAdapter.java
@@ -18,8 +18,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.res.Resources;
-import android.support.animation.DynamicAnimation;
-import android.support.animation.SpringAnimation;
import android.support.v4.view.accessibility.AccessibilityEventCompat;
import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat;
import android.support.v4.view.accessibility.AccessibilityRecordCompat;
@@ -38,11 +36,10 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.Launcher;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.allapps.AlphabeticalAppsList.AdapterItem;
-import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.compat.UserManagerCompat;
-import com.android.launcher3.config.FeatureFlags;
+import com.android.launcher3.touch.ItemClickHandler;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageManagerHelper;
import java.util.List;
@@ -71,7 +68,6 @@
// Common view type masks
public static final int VIEW_TYPE_MASK_DIVIDER = VIEW_TYPE_ALL_APPS_DIVIDER;
public static final int VIEW_TYPE_MASK_ICON = VIEW_TYPE_ICON;
- public static final int VIEW_TYPE_MASK_HAS_SPRINGS = VIEW_TYPE_MASK_ICON;
public interface BindViewCallback {
@@ -182,8 +178,6 @@
private final AlphabeticalAppsList mApps;
private final GridLayoutManager mGridLayoutMgr;
private final GridSpanSizer mGridSizer;
- private final View.OnClickListener mIconClickListener;
- private final View.OnLongClickListener mIconLongClickListener;
private final int mAppsPerRow;
@@ -195,10 +189,7 @@
// The intent to send off to the market app, updated each time the search query changes.
private Intent mMarketSearchIntent;
- private final SpringAnimationHandler<ViewHolder> mSpringAnimationHandler;
-
- public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps, View.OnClickListener
- iconClickListener, View.OnLongClickListener iconLongClickListener, boolean springAnim) {
+ public AllAppsGridAdapter(Launcher launcher, AlphabeticalAppsList apps) {
Resources res = launcher.getResources();
mLauncher = launcher;
mApps = apps;
@@ -207,23 +198,11 @@
mGridLayoutMgr = new AppsGridLayoutManager(launcher);
mGridLayoutMgr.setSpanSizeLookup(mGridSizer);
mLayoutInflater = LayoutInflater.from(launcher);
- mIconClickListener = iconClickListener;
- mIconLongClickListener = iconLongClickListener;
- if (FeatureFlags.LAUNCHER3_PHYSICS && springAnim) {
- mSpringAnimationHandler = new SpringAnimationHandler<>(
- SpringAnimationHandler.Y_DIRECTION, new AllAppsSpringAnimationFactory());
- } else {
- mSpringAnimationHandler = null;
- }
mAppsPerRow = mLauncher.getDeviceProfile().inv.numColumns;
mGridLayoutMgr.setSpanCount(mAppsPerRow);
}
- public SpringAnimationHandler getSpringAnimationHandler() {
- return mSpringAnimationHandler;
- }
-
public static boolean isDividerViewType(int viewType) {
return isViewType(viewType, VIEW_TYPE_MASK_DIVIDER);
}
@@ -270,8 +249,8 @@
case VIEW_TYPE_ICON:
BubbleTextView icon = (BubbleTextView) mLayoutInflater.inflate(
R.layout.all_apps_icon, parent, false);
- icon.setOnClickListener(mIconClickListener);
- icon.setOnLongClickListener(mIconLongClickListener);
+ icon.setOnClickListener(ItemClickHandler.INSTANCE);
+ icon.setOnLongClickListener(ItemLongClickListener.INSTANCE_ALL_APPS);
icon.setLongPressTimeout(ViewConfiguration.getLongPressTimeout());
icon.setOnFocusChangeListener(mIconFocusListener);
@@ -344,22 +323,6 @@
}
@Override
- public void onViewAttachedToWindow(ViewHolder holder) {
- int type = holder.getItemViewType();
- if (mSpringAnimationHandler != null && isViewType(type, VIEW_TYPE_MASK_HAS_SPRINGS)) {
- mSpringAnimationHandler.add(holder.itemView, holder);
- }
- }
-
- @Override
- public void onViewDetachedFromWindow(ViewHolder holder) {
- int type = holder.getItemViewType();
- if (mSpringAnimationHandler != null && isViewType(type, VIEW_TYPE_MASK_HAS_SPRINGS)) {
- mSpringAnimationHandler.remove(holder.itemView);
- }
- }
-
- @Override
public boolean onFailedToRecycleView(ViewHolder holder) {
// Always recycle and we will reset the view when it is bound
return true;
@@ -376,104 +339,4 @@
return item.viewType;
}
- /**
- * Helper class to set the SpringAnimation values for an item in the adapter.
- */
- private class AllAppsSpringAnimationFactory
- implements SpringAnimationHandler.AnimationFactory<ViewHolder> {
- private static final float DEFAULT_MAX_VALUE_PX = 100;
- private static final float DEFAULT_MIN_VALUE_PX = -DEFAULT_MAX_VALUE_PX;
-
- // Damping ratio range is [0, 1]
- private static final float SPRING_DAMPING_RATIO = 0.55f;
-
- // Stiffness is a non-negative number.
- private static final float MIN_SPRING_STIFFNESS = 580f;
- private static final float MAX_SPRING_STIFFNESS = 900f;
-
- // The amount by which each adjacent rows' stiffness will differ.
- private static final float ROW_STIFFNESS_COEFFICIENT = 50f;
-
- // The percentage by which we multiply each row to create the row factor.
- private static final float ROW_PERCENTAGE = 0.3f;
-
- @Override
- public SpringAnimation initialize(ViewHolder vh) {
- return SpringAnimationHandler.forView(vh.itemView, DynamicAnimation.TRANSLATION_Y, 0);
- }
-
- /**
- * @param spring A new or recycled SpringAnimation.
- * @param vh The ViewHolder that {@param spring} is related to.
- */
- @Override
- public void update(SpringAnimation spring, ViewHolder vh) {
- int appPosition = vh.getAdapterPosition();
- int col = appPosition % mAppsPerRow;
- int row = appPosition / mAppsPerRow;
-
- int numTotalRows = mApps.getNumAppRows() - 1; // zero-based count
- if (row > (numTotalRows / 2)) {
- // Mirror the rows so that the top row acts the same as the bottom row.
- row = Math.abs(numTotalRows - row);
- }
-
- calculateSpringValues(spring, row, col);
- }
-
- @Override
- public void setDefaultValues(SpringAnimation spring) {
- calculateSpringValues(spring, 0, mAppsPerRow / 2);
- }
-
- /**
- * We manipulate the stiffness, min, and max values based on the items distance to the
- * first row and the items distance to the center column to create the ^-shaped motion
- * effect.
- */
- private void calculateSpringValues(SpringAnimation spring, int row, int col) {
- float rowFactor = (1 + row) * ROW_PERCENTAGE;
- float colFactor = getColumnFactor(col, mAppsPerRow);
-
- float minValue = DEFAULT_MIN_VALUE_PX * (rowFactor + colFactor);
- float maxValue = DEFAULT_MAX_VALUE_PX * (rowFactor + colFactor);
-
- float stiffness = Utilities.boundToRange(
- MAX_SPRING_STIFFNESS - (row * ROW_STIFFNESS_COEFFICIENT),
- MIN_SPRING_STIFFNESS,
- MAX_SPRING_STIFFNESS);
-
- spring.setMinValue(minValue)
- .setMaxValue(maxValue)
- .getSpring()
- .setStiffness(stiffness)
- .setDampingRatio(SPRING_DAMPING_RATIO);
- }
-
- /**
- * Increase the column factor as the distance increases between the column and the center
- * column(s).
- */
- private float getColumnFactor(int col, int numCols) {
- float centerColumn = numCols / 2;
- int distanceToCenter = (int) Math.abs(col - centerColumn);
-
- boolean evenNumberOfColumns = numCols % 2 == 0;
- if (evenNumberOfColumns && col < centerColumn) {
- distanceToCenter -= 1;
- }
-
- float factor = 0;
- while (distanceToCenter > 0) {
- if (distanceToCenter == 1) {
- factor += 0.2f;
- } else {
- factor += 0.1f;
- }
- --distanceToCenter;
- }
-
- return factor;
- }
- }
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 4a393c9..a7447b7 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -17,14 +17,12 @@
import static android.view.View.MeasureSpec.UNSPECIFIED;
-import android.animation.ObjectAnimator;
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
-import android.util.Property;
import android.util.SparseIntArray;
import android.view.MotionEvent;
import android.view.View;
@@ -35,12 +33,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
-import com.android.launcher3.anim.SpringAnimationHandler;
-import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.logging.UserEventDispatcher.LogContainerProvider;
-import com.android.launcher3.touch.OverScroll;
-import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -64,23 +58,6 @@
private AllAppsBackgroundDrawable mEmptySearchBackground;
private int mEmptySearchBackgroundTopOffset;
- private SpringAnimationHandler mSpringAnimationHandler;
- private OverScrollHelper mOverScrollHelper;
- private SwipeDetector mPullDetector;
- private float mContentTranslationY = 0;
- public static final Property<AllAppsRecyclerView, Float> CONTENT_TRANS_Y =
- new Property<AllAppsRecyclerView, Float>(Float.class, "appsRecyclerViewContentTransY") {
- @Override
- public Float get(AllAppsRecyclerView allAppsRecyclerView) {
- return allAppsRecyclerView.getContentTranslationY();
- }
-
- @Override
- public void set(AllAppsRecyclerView allAppsRecyclerView, Float y) {
- allAppsRecyclerView.setContentTranslationY(y);
- }
- };
-
public AllAppsRecyclerView(Context context) {
this(context, null);
}
@@ -99,30 +76,9 @@
Resources res = getResources();
mEmptySearchBackgroundTopOffset = res.getDimensionPixelSize(
R.dimen.all_apps_empty_search_bg_top_offset);
-
- mOverScrollHelper = new OverScrollHelper();
- mPullDetector = new SwipeDetector(getContext(), mOverScrollHelper, SwipeDetector.VERTICAL);
- mPullDetector.setDetectableScrollConditions(SwipeDetector.DIRECTION_BOTH, true);
-
mNumAppsPerRow = LauncherAppState.getIDP(context).numColumns;
}
- public void setSpringAnimationHandler(SpringAnimationHandler springAnimationHandler) {
- if (FeatureFlags.LAUNCHER3_PHYSICS) {
- mSpringAnimationHandler = springAnimationHandler;
- addOnScrollListener(new SpringMotionOnScrollListener());
- }
- }
-
- @Override
- public boolean onTouchEvent(MotionEvent e) {
- mPullDetector.onTouchEvent(e);
- if (FeatureFlags.LAUNCHER3_PHYSICS && mSpringAnimationHandler != null) {
- mSpringAnimationHandler.addMovement(e);
- }
- return super.onTouchEvent(e);
- }
-
/**
* Sets the list of apps in this view, used to determine the fastscroll position.
*/
@@ -170,26 +126,6 @@
}
@Override
- protected void dispatchDraw(Canvas canvas) {
- canvas.translate(0, mContentTranslationY);
- super.dispatchDraw(canvas);
- canvas.translate(0, -mContentTranslationY);
- }
-
- public float getContentTranslationY() {
- return mContentTranslationY;
- }
-
- /**
- * Use this method instead of calling {@link #setTranslationY(float)}} directly to avoid drawing
- * on top of other Views.
- */
- public void setContentTranslationY(float y) {
- mContentTranslationY = y;
- invalidate();
- }
-
- @Override
protected boolean verifyDrawable(Drawable who) {
return who == mEmptySearchBackground || super.verifyDrawable(who);
}
@@ -231,8 +167,7 @@
@Override
public boolean onInterceptTouchEvent(MotionEvent e) {
- mPullDetector.onTouchEvent(e);
- boolean result = super.onInterceptTouchEvent(e) || mOverScrollHelper.isInOverScroll();
+ boolean result = super.onInterceptTouchEvent(e);
if (!result && e.getAction() == MotionEvent.ACTION_DOWN
&& mEmptySearchBackground != null && mEmptySearchBackground.getAlpha() > 0) {
mEmptySearchBackground.setHotspot(e.getX(), e.getY());
@@ -480,114 +415,4 @@
y + mEmptySearchBackground.getIntrinsicHeight());
}
- private class SpringMotionOnScrollListener extends RecyclerView.OnScrollListener {
-
- @Override
- public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
- if (mOverScrollHelper.isInOverScroll()) {
- // OverScroll will handle animating the springs.
- return;
- }
-
- // We only start the spring animation when we hit the top/bottom, to ensure
- // that all of the animations start at the same time.
- if (dy < 0 && !canScrollVertically(-1)) {
- mSpringAnimationHandler.animateToFinalPosition(0, 1);
- } else if (dy > 0 && !canScrollVertically(1)) {
- mSpringAnimationHandler.animateToFinalPosition(0, -1);
- }
- }
- }
-
- private class OverScrollHelper implements SwipeDetector.Listener {
-
- private static final float MAX_RELEASE_VELOCITY = 5000; // px / s
- private static final float MAX_OVERSCROLL_PERCENTAGE = 0.07f;
-
- private boolean mIsInOverScroll;
-
- // We use this value to calculate the actual amount the user has overscrolled.
- private float mFirstDisplacement = 0;
-
- private boolean mAlreadyScrollingUp;
- private int mFirstScrollYOnScrollUp;
-
- @Override
- public void onDragStart(boolean start) {
- }
-
- @Override
- public boolean onDrag(float displacement, float velocity) {
- boolean isScrollingUp = displacement > 0;
- if (isScrollingUp) {
- if (!mAlreadyScrollingUp) {
- mFirstScrollYOnScrollUp = getCurrentScrollY();
- mAlreadyScrollingUp = true;
- }
- } else {
- mAlreadyScrollingUp = false;
- }
-
- // Only enter overscroll if the user is interacting with the RecyclerView directly
- // and if one of the following criteria are met:
- // - User scrolls down when they're already at the bottom.
- // - User starts scrolling up, hits the top, and continues scrolling up.
- boolean wasInOverScroll = mIsInOverScroll;
- mIsInOverScroll = !mScrollbar.isDraggingThumb() &&
- ((!canScrollVertically(1) && displacement < 0) ||
- (!canScrollVertically(-1) && isScrollingUp && mFirstScrollYOnScrollUp != 0));
-
- if (wasInOverScroll && !mIsInOverScroll) {
- // Exit overscroll. This can happen when the user is in overscroll and then
- // scrolls the opposite way.
- reset(false /* shouldSpring */);
- } else if (mIsInOverScroll) {
- if (Float.compare(mFirstDisplacement, 0) == 0) {
- // Because users can scroll before entering overscroll, we need to
- // subtract the amount where the user was not in overscroll.
- mFirstDisplacement = displacement;
- }
- float overscrollY = displacement - mFirstDisplacement;
- setContentTranslationY(getDampedOverScroll(overscrollY));
- }
-
- return mIsInOverScroll;
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- reset(mIsInOverScroll /* shouldSpring */);
- }
-
- private void reset(boolean shouldSpring) {
- float y = getContentTranslationY();
- if (Float.compare(y, 0) != 0) {
- if (mSpringAnimationHandler != null && shouldSpring) {
- // We calculate our own velocity to give the springs the desired effect.
- float velocity = y / getDampedOverScroll(getHeight()) * MAX_RELEASE_VELOCITY;
- // We want to negate the velocity because we are moving to 0 from -1 due to the
- // downward motion. (y-axis -1 is above 0).
- mSpringAnimationHandler.animateToPositionWithVelocity(0, -1, -velocity);
- }
-
- ObjectAnimator.ofFloat(AllAppsRecyclerView.this,
- AllAppsRecyclerView.CONTENT_TRANS_Y, 0)
- .setDuration(100)
- .start();
- }
- mIsInOverScroll = false;
- mFirstDisplacement = 0;
- mFirstScrollYOnScrollUp = 0;
- mAlreadyScrollingUp = false;
- }
-
- public boolean isInOverScroll() {
- return mIsInOverScroll;
- }
-
- private float getDampedOverScroll(float y) {
- return OverScroll.dampedScroll(y, getHeight());
- }
- }
-
}
diff --git a/src/com/android/launcher3/anim/SpringAnimationHandler.java b/src/com/android/launcher3/anim/SpringAnimationHandler.java
deleted file mode 100644
index 29a2430..0000000
--- a/src/com/android/launcher3/anim/SpringAnimationHandler.java
+++ /dev/null
@@ -1,265 +0,0 @@
-/*
- * Copyright (C) 2017 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.anim;
-
-import android.support.animation.FloatPropertyCompat;
-import android.support.animation.SpringAnimation;
-import android.support.animation.SpringForce;
-import android.support.annotation.IntDef;
-import android.util.Log;
-import android.view.MotionEvent;
-import android.view.VelocityTracker;
-import android.view.View;
-
-import com.android.launcher3.R;
-
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.util.ArrayList;
-
-/**
- * Handler class that manages springs for a set of views that should all move based on the same
- * {@link MotionEvent}s.
- *
- * Supports setting either X or Y velocity on the list of springs added to this handler.
- */
-public class SpringAnimationHandler<T> {
-
- private static final String TAG = "SpringAnimationHandler";
- private static final boolean DEBUG = false;
-
- private static final float VELOCITY_DAMPING_FACTOR = 0.175f;
-
- @Retention(RetentionPolicy.SOURCE)
- @IntDef({Y_DIRECTION, X_DIRECTION})
- public @interface Direction {}
- public static final int Y_DIRECTION = 0;
- public static final int X_DIRECTION = 1;
- private int mVelocityDirection;
-
- private VelocityTracker mVelocityTracker;
- private float mCurrentVelocity = 0;
- private boolean mShouldComputeVelocity = false;
-
- private AnimationFactory<T> mAnimationFactory;
-
- private ArrayList<SpringAnimation> mAnimations = new ArrayList<>();
-
- /**
- * @param direction Either {@link #X_DIRECTION} or {@link #Y_DIRECTION}.
- * Determines which direction we use to calculate and set the velocity.
- * @param factory The AnimationFactory is responsible for initializing and updating the
- * SpringAnimations added to this class.
- */
- public SpringAnimationHandler(@Direction int direction, AnimationFactory<T> factory) {
- mVelocityDirection = direction;
- mAnimationFactory = factory;
- }
-
- /**
- * Adds a spring to the list of springs handled by this class.
- * @param spring The new spring to be added.
- * @param setDefaultValues If True, sets the spring to the default
- * {@link AnimationFactory} values.
- */
- public void add(SpringAnimation spring, boolean setDefaultValues) {
- if (setDefaultValues) {
- mAnimationFactory.setDefaultValues(spring);
- }
- spring.setStartVelocity(mCurrentVelocity);
- mAnimations.add(spring);
- }
-
- public AnimationFactory<T> getFactory() {
- return mAnimationFactory;
- }
-
- /**
- * Adds a new or recycled animation to the list of springs handled by this class.
- *
- * @param view The view the spring is attached to.
- * @param object Used to initialize and update the spring.
- */
- public void add(View view, T object) {
- SpringAnimation spring = (SpringAnimation) view.getTag(R.id.spring_animation_tag);
- if (spring == null) {
- spring = mAnimationFactory.initialize(object);
- view.setTag(R.id.spring_animation_tag, spring);
- }
- mAnimationFactory.update(spring, object);
- add(spring, false /* setDefaultValues */);
- }
-
- /**
- * Stops and removes the spring attached to {@param view}.
- */
- public void remove(View view) {
- remove((SpringAnimation) view.getTag(R.id.spring_animation_tag));
- }
-
- public void remove(SpringAnimation animation) {
- if (animation.canSkipToEnd()) {
- animation.skipToEnd();
- }
- mAnimations.remove(animation);
- }
-
- public void addMovement(MotionEvent event) {
- int action = event.getActionMasked();
- if (DEBUG) Log.d(TAG, "addMovement#action=" + action);
- switch (action) {
- case MotionEvent.ACTION_CANCEL:
- case MotionEvent.ACTION_DOWN:
- reset();
- break;
- }
-
- getVelocityTracker().addMovement(event);
- mShouldComputeVelocity = true;
- }
-
- public void animateToFinalPosition(float position, int startValue) {
- animateToFinalPosition(position, startValue, mShouldComputeVelocity);
- }
-
- /**
- * @param position The final animation position.
- * @param startValue < 0 if scrolling from start to end; > 0 if scrolling from end to start
- * The magnitude of the number changes how the spring will move.
- * @param setVelocity If true, we set the velocity to {@link #mCurrentVelocity} before
- * starting the animation.
- */
- private void animateToFinalPosition(float position, int startValue, boolean setVelocity) {
- if (DEBUG) {
- Log.d(TAG, "animateToFinalPosition#position=" + position + ", startValue=" + startValue);
- }
-
- if (mShouldComputeVelocity) {
- mCurrentVelocity = computeVelocity();
- }
-
- int size = mAnimations.size();
- for (int i = 0; i < size; ++i) {
- mAnimations.get(i).setStartValue(startValue);
- if (setVelocity) {
- mAnimations.get(i).setStartVelocity(mCurrentVelocity);
- }
- mAnimations.get(i).animateToFinalPosition(position);
- }
-
- reset();
- }
-
- /**
- * Similar to {@link #animateToFinalPosition(float, int)}, but used in cases where we want to
- * manually set the velocity.
- */
- public void animateToPositionWithVelocity(float position, int startValue, float velocity) {
- if (DEBUG) {
- Log.d(TAG, "animateToPosition#pos=" + position + ", start=" + startValue
- + ", velocity=" + velocity);
- }
-
- mCurrentVelocity = velocity;
- mShouldComputeVelocity = false;
- animateToFinalPosition(position, startValue, true);
- }
-
-
- public boolean isRunning() {
- // All the animations run at the same time so we can just check the first one.
- return !mAnimations.isEmpty() && mAnimations.get(0).isRunning();
- }
-
- public void skipToEnd() {
- if (DEBUG) Log.d(TAG, "setStartVelocity#skipToEnd");
- if (DEBUG) Log.v(TAG, "setStartVelocity#skipToEnd", new Exception());
-
- int size = mAnimations.size();
- for (int i = 0; i < size; ++i) {
- if (mAnimations.get(i).canSkipToEnd()) {
- mAnimations.get(i).skipToEnd();
- }
- }
- }
-
- public void reset() {
- if (mVelocityTracker != null) {
- mVelocityTracker.recycle();
- mVelocityTracker = null;
- }
- mCurrentVelocity = 0;
- mShouldComputeVelocity = false;
- }
-
-
- private float computeVelocity() {
- getVelocityTracker().computeCurrentVelocity(1000 /* millis */);
-
- float velocity = isVerticalDirection()
- ? getVelocityTracker().getYVelocity()
- : getVelocityTracker().getXVelocity();
- velocity *= VELOCITY_DAMPING_FACTOR;
-
- if (DEBUG) Log.d(TAG, "computeVelocity=" + velocity);
- return velocity;
- }
-
- private boolean isVerticalDirection() {
- return mVelocityDirection == Y_DIRECTION;
- }
-
- private VelocityTracker getVelocityTracker() {
- if (mVelocityTracker == null) {
- mVelocityTracker = VelocityTracker.obtain();
- }
- return mVelocityTracker;
- }
-
- /**
- * This interface is used to initialize and update the SpringAnimations added to the
- * {@link SpringAnimationHandler}.
- *
- * @param <T> The object that each SpringAnimation is attached to.
- */
- public interface AnimationFactory<T> {
-
- /**
- * Initializes a new Spring for {@param object}.
- */
- SpringAnimation initialize(T object);
-
- /**
- * Updates the value of {@param spring} based on {@param object}.
- */
- void update(SpringAnimation spring, T object);
-
- /**
- * Sets the factory default values for the given {@param spring}.
- */
- void setDefaultValues(SpringAnimation spring);
- }
-
- /**
- * Helper method to create a new SpringAnimation for {@param view}.
- */
- public static SpringAnimation forView(View view, FloatPropertyCompat property, float finalPos) {
- SpringAnimation spring = new SpringAnimation(view, property, finalPos);
- spring.setSpring(new SpringForce(finalPos));
- return spring;
- }
-
-}
diff --git a/src/com/android/launcher3/config/BaseFlags.java b/src/com/android/launcher3/config/BaseFlags.java
index e494bea..28645dc 100644
--- a/src/com/android/launcher3/config/BaseFlags.java
+++ b/src/com/android/launcher3/config/BaseFlags.java
@@ -35,8 +35,6 @@
public static final boolean LAUNCHER3_DIRECT_SCROLL = true;
// When enabled the promise icon is visible in all apps while installation an app.
public static final boolean LAUNCHER3_PROMISE_APPS_IN_ALL_APPS = false;
- // When enabled allows use of physics based motions in the Launcher.
- public static final boolean LAUNCHER3_PHYSICS = true;
// When enabled allows use of spring motions on the icons.
public static final boolean LAUNCHER3_SPRING_ICONS = true;
diff --git a/src/com/android/launcher3/folder/Folder.java b/src/com/android/launcher3/folder/Folder.java
index b3310c7..2b42429 100644
--- a/src/com/android/launcher3/folder/Folder.java
+++ b/src/com/android/launcher3/folder/Folder.java
@@ -18,7 +18,6 @@
import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY;
import static com.android.launcher3.LauncherState.NORMAL;
-import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import android.animation.Animator;
@@ -86,7 +85,7 @@
/**
* Represents a set of icons chosen by the user or generated by the system.
*/
-public class Folder extends AbstractFloatingView implements DragSource, View.OnClickListener,
+public class Folder extends AbstractFloatingView implements DragSource,
View.OnLongClickListener, DropTarget, FolderListener, TextView.OnEditorActionListener,
View.OnFocusChangeListener, DragListener, ExtendedEditText.OnBackKeyListener {
private static final String TAG = "Launcher.Folder";
@@ -253,13 +252,6 @@
mFooterHeight = mFooter.getMeasuredHeight();
}
- public void onClick(View v) {
- Object tag = v.getTag();
- if (tag instanceof ShortcutInfo) {
- mLauncher.onClick(v);
- }
- }
-
public boolean onLongClick(View v) {
// Return if global dragging is not enabled
if (!mLauncher.isDraggingEnabled()) return true;
diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java
index 13926db..6c94273 100644
--- a/src/com/android/launcher3/folder/FolderIcon.java
+++ b/src/com/android/launcher3/folder/FolderIcon.java
@@ -63,6 +63,7 @@
import com.android.launcher3.dragndrop.BaseItemDragListener;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.dragndrop.DragView;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Thunk;
import com.android.launcher3.widget.PendingAddShortcutInfo;
@@ -159,14 +160,14 @@
.inflate(resId, group, false);
icon.setClipToPadding(false);
- icon.mFolderName = (BubbleTextView) icon.findViewById(R.id.folder_icon_name);
+ icon.mFolderName = icon.findViewById(R.id.folder_icon_name);
icon.mFolderName.setText(folderInfo.title);
icon.mFolderName.setCompoundDrawablePadding(0);
FrameLayout.LayoutParams lp = (FrameLayout.LayoutParams) icon.mFolderName.getLayoutParams();
lp.topMargin = grid.iconSizePx + grid.iconDrawablePaddingPx;
icon.setTag(folderInfo);
- icon.setOnClickListener(launcher);
+ icon.setOnClickListener(ItemClickHandler.INSTANCE);
icon.mInfo = folderInfo;
icon.mLauncher = launcher;
icon.mBadgeRenderer = launcher.getDeviceProfile().mBadgeRenderer;
diff --git a/src/com/android/launcher3/folder/FolderPagedView.java b/src/com/android/launcher3/folder/FolderPagedView.java
index a468cb5..fa7565a 100644
--- a/src/com/android/launcher3/folder/FolderPagedView.java
+++ b/src/com/android/launcher3/folder/FolderPagedView.java
@@ -45,6 +45,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.keyboard.ViewGroupFocusHelper;
import com.android.launcher3.pageindicators.PageIndicatorDots;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Thunk;
import java.util.ArrayList;
@@ -237,7 +238,7 @@
R.layout.folder_application, null, false);
textView.applyFromShortcutInfo(item);
textView.setHapticFeedbackEnabled(false);
- textView.setOnClickListener(mFolder);
+ textView.setOnClickListener(ItemClickHandler.INSTANCE);
textView.setOnLongClickListener(mFolder);
textView.setOnFocusChangeListener(mFocusIndicatorHelper);
textView.setOnKeyListener(mKeyListener);
diff --git a/src/com/android/launcher3/graphics/PreloadIconDrawable.java b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
index bc75268..42ba191 100644
--- a/src/com/android/launcher3/graphics/PreloadIconDrawable.java
+++ b/src/com/android/launcher3/graphics/PreloadIconDrawable.java
@@ -164,7 +164,7 @@
@Override
public void drawInternal(Canvas canvas, Rect bounds) {
if (mRanFinishAnimation) {
- super.draw(canvas);
+ super.drawInternal(canvas, bounds);
return;
}
@@ -178,7 +178,7 @@
int saveCount = canvas.save();
canvas.scale(mIconScale, mIconScale, bounds.exactCenterX(), bounds.exactCenterY());
- super.draw(canvas);
+ super.drawInternal(canvas, bounds);
canvas.restoreToCount(saveCount);
}
diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
index b3ef7bb..e427a81 100644
--- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java
+++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java
@@ -77,6 +77,7 @@
import com.android.launcher3.shortcuts.DeepShortcutManager;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.Themes;
@@ -907,12 +908,9 @@
@Override
public boolean onLongClick(View v) {
+ if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
// Return early if not the correct view
if (!(v.getParent() instanceof DeepShortcutView)) return false;
- // Return early if global dragging is not enabled
- if (!mLauncher.isDraggingEnabled()) return false;
- // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
- if (mLauncher.getDragController().isDragging()) return false;
// Long clicked on a shortcut.
DeepShortcutView sv = (DeepShortcutView) v.getParent();
diff --git a/src/com/android/launcher3/shortcuts/DeepShortcutView.java b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
index 450a690..9ad266b 100644
--- a/src/com/android/launcher3/shortcuts/DeepShortcutView.java
+++ b/src/com/android/launcher3/shortcuts/DeepShortcutView.java
@@ -30,6 +30,7 @@
import com.android.launcher3.ShortcutInfo;
import com.android.launcher3.Utilities;
import com.android.launcher3.popup.PopupContainerWithArrow;
+import com.android.launcher3.touch.ItemClickHandler;
/**
* A {@link android.widget.FrameLayout} that contains a {@link DeepShortcutView}.
@@ -120,7 +121,7 @@
mBubbleText.setText(usingLongLabel ? longLabel : mDetail.getShortLabel());
// TODO: Add the click handler to this view directly and not the child view.
- mBubbleText.setOnClickListener(Launcher.getLauncher(getContext()));
+ mBubbleText.setOnClickListener(ItemClickHandler.INSTANCE);
mBubbleText.setOnLongClickListener(container);
mBubbleText.setOnTouchListener(container);
}
diff --git a/src/com/android/launcher3/states/InternalStateHandler.java b/src/com/android/launcher3/states/InternalStateHandler.java
index d3c0fef..0a2c3e4 100644
--- a/src/com/android/launcher3/states/InternalStateHandler.java
+++ b/src/com/android/launcher3/states/InternalStateHandler.java
@@ -56,8 +56,8 @@
sScheduler.schedule(this);
}
- public void clearReference() {
- sScheduler.clearReference(this);
+ public boolean clearReference() {
+ return sScheduler.clearReference(this);
}
public static boolean handleCreate(Launcher launcher, Intent intent) {
@@ -125,10 +125,12 @@
return false;
}
- public synchronized void clearReference(InternalStateHandler handler) {
+ public synchronized boolean clearReference(InternalStateHandler handler) {
if (mPendingHandler.get() == handler) {
mPendingHandler.clear();
+ return true;
}
+ return false;
}
}
}
\ No newline at end of file
diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java
new file mode 100644
index 0000000..f2f5592
--- /dev/null
+++ b/src/com/android/launcher3/touch/ItemClickHandler.java
@@ -0,0 +1,232 @@
+/*
+ * 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 com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_BY_PUBLISHER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_LOCKED_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_QUIET_USER;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SAFEMODE;
+import static com.android.launcher3.ItemInfoWithIcon.FLAG_DISABLED_SUSPENDED;
+import static com.android.launcher3.Launcher.REQUEST_BIND_PENDING_APPWIDGET;
+import static com.android.launcher3.Launcher.REQUEST_RECONFIGURE_APPWIDGET;
+
+import android.app.AlertDialog;
+import android.content.Intent;
+import android.os.Process;
+import android.text.TextUtils;
+import android.view.View;
+import android.view.View.OnClickListener;
+import android.widget.Toast;
+
+import com.android.launcher3.AppInfo;
+import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.FolderInfo;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppWidgetInfo;
+import com.android.launcher3.LauncherAppWidgetProviderInfo;
+import com.android.launcher3.PromiseAppInfo;
+import com.android.launcher3.R;
+import com.android.launcher3.ShortcutInfo;
+import com.android.launcher3.compat.AppWidgetManagerCompat;
+import com.android.launcher3.folder.Folder;
+import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.util.PackageManagerHelper;
+import com.android.launcher3.widget.PendingAppWidgetHostView;
+import com.android.launcher3.widget.WidgetAddFlowHandler;
+
+/**
+ * Class for handling clicks on workspace and all-apps items
+ */
+public class ItemClickHandler {
+
+ /**
+ * Instance used for click handling on items
+ */
+ public static final OnClickListener INSTANCE = ItemClickHandler::onClick;
+
+ private static 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;
+ }
+
+ Launcher launcher = Launcher.getLauncher(v.getContext());
+ if (!launcher.getWorkspace().isFinishedSwitchingState()) {
+ return;
+ }
+
+ Object tag = v.getTag();
+ if (tag instanceof ShortcutInfo) {
+ onClickAppShortcut(v, (ShortcutInfo) tag, launcher);
+ } else if (tag instanceof FolderInfo) {
+ if (v instanceof FolderIcon) {
+ onClickFolderIcon(v);
+ }
+ } else if (tag instanceof AppInfo) {
+ startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher);
+ } else if (tag instanceof LauncherAppWidgetInfo) {
+ if (v instanceof PendingAppWidgetHostView) {
+ onClickPendingWidget((PendingAppWidgetHostView) v, launcher);
+ }
+ }
+ }
+
+ /**
+ * Event handler for a folder icon click.
+ *
+ * @param v The view that was clicked. Must be an instance of {@link FolderIcon}.
+ */
+ private static void onClickFolderIcon(View v) {
+ Folder folder = ((FolderIcon) v).getFolder();
+ if (!folder.isOpen() && !folder.isDestroyed()) {
+ // Open the requested folder
+ folder.animateOpen();
+ }
+ }
+
+ /**
+ * Event handler for the app widget view which has not fully restored.
+ */
+ private static void onClickPendingWidget(PendingAppWidgetHostView v, Launcher launcher) {
+ if (launcher.getPackageManager().isSafeMode()) {
+ Toast.makeText(launcher, R.string.safemode_widget_error, Toast.LENGTH_SHORT).show();
+ return;
+ }
+
+ final LauncherAppWidgetInfo info = (LauncherAppWidgetInfo) v.getTag();
+ if (v.isReadyForClickSetup()) {
+ LauncherAppWidgetProviderInfo appWidgetInfo = AppWidgetManagerCompat
+ .getInstance(launcher).findProvider(info.providerName, info.user);
+ if (appWidgetInfo == null) {
+ return;
+ }
+ WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo);
+
+ if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) {
+ if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) {
+ // This should not happen, as we make sure that an Id is allocated during bind.
+ return;
+ }
+ addFlowHandler.startBindFlow(launcher, info.appWidgetId, info,
+ REQUEST_BIND_PENDING_APPWIDGET);
+ } else {
+ addFlowHandler.startConfigActivity(launcher, info, REQUEST_RECONFIGURE_APPWIDGET);
+ }
+ } else {
+ final String packageName = info.providerName.getPackageName();
+ onClickPendingAppItem(v, launcher, packageName, info.installProgress >= 0);
+ }
+ }
+
+ private static void onClickPendingAppItem(View v, Launcher launcher, String packageName,
+ boolean downloadStarted) {
+ if (downloadStarted) {
+ // If the download has started, simply direct to the market app.
+ startMarketIntentForPackage(v, launcher, packageName);
+ return;
+ }
+ new AlertDialog.Builder(launcher)
+ .setTitle(R.string.abandoned_promises_title)
+ .setMessage(R.string.abandoned_promise_explanation)
+ .setPositiveButton(R.string.abandoned_search,
+ (d, i) -> startMarketIntentForPackage(v, launcher, packageName))
+ .setNeutralButton(R.string.abandoned_clean_this,
+ (d, i) -> launcher.getWorkspace()
+ .removeAbandonedPromise(packageName, Process.myUserHandle()))
+ .create().show();
+ }
+
+ private static void startMarketIntentForPackage(View v, Launcher launcher, String packageName) {
+ ItemInfo item = (ItemInfo) v.getTag();
+ Intent intent = new PackageManagerHelper(launcher).getMarketIntent(packageName);
+ launcher.startActivitySafely(v, intent, item);
+ }
+
+ /**
+ * Event handler for an app shortcut click.
+ *
+ * @param v The view that was clicked. Must be a tagged with a {@link ShortcutInfo}.
+ */
+ private static void onClickAppShortcut(View v, ShortcutInfo shortcut, Launcher launcher) {
+ if (shortcut.isDisabled()) {
+ final int disabledFlags = shortcut.runtimeStatusFlags & ShortcutInfo.FLAG_DISABLED_MASK;
+ if ((disabledFlags &
+ ~FLAG_DISABLED_SUSPENDED &
+ ~FLAG_DISABLED_QUIET_USER) == 0) {
+ // If the app is only disabled because of the above flags, launch activity anyway.
+ // Framework will tell the user why the app is suspended.
+ } else {
+ if (!TextUtils.isEmpty(shortcut.disabledMessage)) {
+ // Use a message specific to this shortcut, if it has one.
+ Toast.makeText(launcher, shortcut.disabledMessage, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ // Otherwise just use a generic error message.
+ int error = R.string.activity_not_available;
+ if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_SAFEMODE) != 0) {
+ error = R.string.safemode_shortcut_error;
+ } else if ((shortcut.runtimeStatusFlags & FLAG_DISABLED_BY_PUBLISHER) != 0 ||
+ (shortcut.runtimeStatusFlags & FLAG_DISABLED_LOCKED_USER) != 0) {
+ error = R.string.shortcut_not_available;
+ }
+ Toast.makeText(launcher, error, Toast.LENGTH_SHORT).show();
+ return;
+ }
+ }
+
+ // Check for abandoned promise
+ if ((v instanceof BubbleTextView) && shortcut.hasPromiseIconUi()) {
+ String packageName = shortcut.intent.getComponent() != null ?
+ shortcut.intent.getComponent().getPackageName() : shortcut.intent.getPackage();
+ if (!TextUtils.isEmpty(packageName)) {
+ onClickPendingAppItem(v, launcher, packageName,
+ shortcut.hasStatusFlag(ShortcutInfo.FLAG_INSTALL_SESSION_ACTIVE));
+ return;
+ }
+ }
+
+ // Start activities
+ startAppShortcutOrInfoActivity(v, shortcut, launcher);
+ }
+
+ private static void startAppShortcutOrInfoActivity(View v, ItemInfo item, Launcher launcher) {
+ Intent intent;
+ if (item instanceof PromiseAppInfo) {
+ PromiseAppInfo promiseAppInfo = (PromiseAppInfo) item;
+ intent = promiseAppInfo.getMarketIntent(launcher);
+ } else {
+ intent = item.getIntent();
+ }
+ if (intent == null) {
+ throw new IllegalArgumentException("Input must have a valid intent");
+ }
+ if (item instanceof ShortcutInfo) {
+ ShortcutInfo si = (ShortcutInfo) item;
+ if (si.hasStatusFlag(ShortcutInfo.FLAG_SUPPORTS_WEB_UI)
+ && intent.getAction() == Intent.ACTION_VIEW) {
+ // make a copy of the intent that has the package set to null
+ // we do this because the platform sometimes disables instant
+ // apps temporarily (triggered by the user) and fallbacks to the
+ // web ui. This only works though if the package isn't set
+ intent = new Intent(intent);
+ intent.setPackage(null);
+ }
+ }
+ launcher.startActivitySafely(v, intent, item);
+ }
+}
diff --git a/src/com/android/launcher3/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
new file mode 100644
index 0000000..f10a695
--- /dev/null
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -0,0 +1,118 @@
+/*
+ * 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.View.INVISIBLE;
+import static android.view.View.VISIBLE;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+import static com.android.launcher3.LauncherState.OVERVIEW;
+
+import android.view.View;
+import android.view.View.OnLongClickListener;
+
+import com.android.launcher3.CellLayout;
+import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.DropTarget;
+import com.android.launcher3.ItemInfo;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherState;
+import com.android.launcher3.dragndrop.DragController;
+import com.android.launcher3.dragndrop.DragOptions;
+import com.android.launcher3.folder.Folder;
+
+/**
+ * Class to handle long-clicks on workspace items and start drag as a result.
+ */
+public class ItemLongClickListener {
+
+ public static OnLongClickListener INSTANCE_WORKSPACE =
+ ItemLongClickListener::onWorkspaceItemLongClick;
+
+ public static OnLongClickListener INSTANCE_ALL_APPS =
+ ItemLongClickListener::onAllAppsItemLongClick;
+
+ private static boolean onWorkspaceItemLongClick(View v) {
+ Launcher launcher = Launcher.getLauncher(v.getContext());
+ if (!canStartDrag(launcher)) return false;
+ if (!launcher.isInState(NORMAL) && !launcher.isInState(OVERVIEW)) return false;
+ if (!(v.getTag() instanceof ItemInfo)) return false;
+
+ launcher.setWaitingForResult(null);
+ beginDrag(v, launcher, (ItemInfo) v.getTag(), new DragOptions());
+ return true;
+ }
+
+ public static void beginDrag(View v, Launcher launcher, ItemInfo info,
+ DragOptions dragOptions) {
+ if (info.container >= 0) {
+ Folder folder = Folder.getOpen(launcher);
+ if (folder != null) {
+ if (!folder.getItemsInReadingOrder().contains(v)) {
+ folder.close(true);
+ } else {
+ folder.startDrag(v, dragOptions);
+ return;
+ }
+ }
+ }
+
+ CellLayout.CellInfo longClickCellInfo = new CellLayout.CellInfo(v, info);
+ launcher.getWorkspace().startDrag(longClickCellInfo, dragOptions);
+ }
+
+ private static boolean onAllAppsItemLongClick(View v) {
+ Launcher launcher = Launcher.getLauncher(v.getContext());
+ if (!canStartDrag(launcher)) return false;
+ // When we have exited all apps or are in transition, disregard long clicks
+ if (!launcher.isInState(LauncherState.ALL_APPS) ||
+ launcher.getWorkspace().isSwitchingState()) return false;
+
+ // Start the drag
+ final DragController dragController = launcher.getDragController();
+ dragController.addDragListener(new DragController.DragListener() {
+ @Override
+ public void onDragStart(DropTarget.DragObject dragObject, DragOptions options) {
+ v.setVisibility(INVISIBLE);
+ }
+
+ @Override
+ public void onDragEnd() {
+ v.setVisibility(VISIBLE);
+ dragController.removeDragListener(this);
+ }
+ });
+
+ DeviceProfile grid = launcher.getDeviceProfile();
+ DragOptions options = new DragOptions();
+ options.intrinsicIconScaleFactor = (float) grid.allAppsIconSizePx / grid.iconSizePx;
+ launcher.getWorkspace().beginDragShared(v, launcher.getAppsView(), options);
+ return false;
+ }
+
+ public static boolean canStartDrag(Launcher launcher) {
+ if (launcher == null) {
+ return false;
+ }
+ // We prevent dragging when we are loading the workspace as it is possible to pick up a view
+ // that is subsequently removed from the workspace in startBinding().
+ if (launcher.isWorkspaceLocked()) return false;
+ // Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
+ if (launcher.getDragController().isDragging()) return false;
+
+ return true;
+ }
+}
diff --git a/src/com/android/launcher3/util/VerticalSwipeController.java b/src/com/android/launcher3/util/VerticalSwipeController.java
index a647378..ae5bfd5 100644
--- a/src/com/android/launcher3/util/VerticalSwipeController.java
+++ b/src/com/android/launcher3/util/VerticalSwipeController.java
@@ -18,12 +18,10 @@
import static com.android.launcher3.LauncherState.ALL_APPS;
import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
-import static com.android.launcher3.anim.SpringAnimationHandler.Y_DIRECTION;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
-import android.support.animation.SpringAnimation;
import android.util.Log;
import android.view.MotionEvent;
@@ -31,13 +29,10 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.anim.AnimatorPlaybackController;
-import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.touch.SwipeDetector;
import com.android.launcher3.touch.SwipeDetector.Direction;
-import java.util.ArrayList;
/**
* Handles vertical touch gesture on the DragLayer allowing transitioning from
@@ -68,8 +63,6 @@
// Ratio of transition process [0, 1] to drag displacement (px)
private float mProgressMultiplier;
- protected SpringAnimationHandler[] mSpringHandlers;
-
public VerticalSwipeController(Launcher l, LauncherState baseState) {
this(l, baseState, ALL_APPS, SwipeDetector.VERTICAL);
}
@@ -104,29 +97,6 @@
}
}
- protected void initSprings() {
- AllAppsContainerView appsView = mLauncher.getAppsView();
-
- SpringAnimationHandler handler = appsView.getSpringAnimationHandler();
- if (handler == null) {
- mSpringHandlers = new SpringAnimationHandler[0];
- return;
- }
-
- ArrayList<SpringAnimationHandler> handlers = new ArrayList<>();
- handlers.add(handler);
-
- SpringAnimation searchSpring = appsView.getSearchUiManager().getSpringForFling();
- if (searchSpring != null) {
- SpringAnimationHandler searchHandler =
- new SpringAnimationHandler(Y_DIRECTION, handler.getFactory());
- searchHandler.add(searchSpring, true /* setDefaultValues */);
- handlers.add(searchHandler);
- }
-
- mSpringHandlers = handlers.toArray(new SpringAnimationHandler[handlers.size()]);
- }
-
@Override
public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
if (ev.getAction() == MotionEvent.ACTION_DOWN) {
@@ -155,10 +125,6 @@
mDetector.setDetectableScrollConditions(
directionsToDetectScroll, ignoreSlopWhenSettling);
-
- if (mSpringHandlers == null) {
- initSprings();
- }
}
if (mNoIntercept) {
@@ -173,9 +139,6 @@
@Override
public boolean onControllerTouchEvent(MotionEvent ev) {
- for (SpringAnimationHandler h : mSpringHandlers) {
- h.addMovement(ev);
- }
return mDetector.onTouchEvent(ev);
}
@@ -198,10 +161,6 @@
mCurrentAnimation.pause();
mStartProgress = mCurrentAnimation.getProgressFraction();
}
-
- for (SpringAnimationHandler h : mSpringHandlers) {
- h.skipToEnd();
- }
}
protected boolean isTransitionFlipped() {
@@ -244,13 +203,6 @@
}
}
- if (fling && targetState == mTargetState) {
- for (SpringAnimationHandler h : mSpringHandlers) {
- // The icons are moving upwards, so we go to 0 from 1. (y-axis 1 is below 0.)
- h.animateToFinalPosition(0 /* pos */, 1 /* startValue */);
- }
- }
-
mCurrentAnimation.setEndAction(() -> {
mLauncher.getStateManager().goToState(targetState, false);
onTransitionComplete(fling, targetState == mToState);
diff --git a/src/com/android/launcher3/views/SpringRelativeLayout.java b/src/com/android/launcher3/views/SpringRelativeLayout.java
new file mode 100644
index 0000000..090b3e6
--- /dev/null
+++ b/src/com/android/launcher3/views/SpringRelativeLayout.java
@@ -0,0 +1,157 @@
+/*
+ * 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.content.Context;
+import android.graphics.Canvas;
+import android.support.animation.FloatPropertyCompat;
+import android.support.animation.SpringAnimation;
+import android.support.animation.SpringForce;
+import android.support.annotation.NonNull;
+import android.support.v7.widget.RecyclerView;
+import android.support.v7.widget.RecyclerView.EdgeEffectFactory;
+import android.util.AttributeSet;
+import android.util.Log;
+import android.util.SparseBooleanArray;
+import android.view.View;
+import android.widget.EdgeEffect;
+import android.widget.RelativeLayout;
+
+import static android.support.animation.SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY;
+import static android.support.animation.SpringForce.STIFFNESS_LOW;
+import static android.support.animation.SpringForce.STIFFNESS_MEDIUM;
+
+public class SpringRelativeLayout extends RelativeLayout {
+
+ private static final float STIFFNESS = (STIFFNESS_MEDIUM + STIFFNESS_LOW) / 2;
+ private static final float DAMPING_RATIO = DAMPING_RATIO_MEDIUM_BOUNCY;
+ private static final float VELOCITY_MULTIPLIER = 0.3f;
+
+ private static final FloatPropertyCompat<SpringRelativeLayout> DAMPED_SCROLL =
+ new FloatPropertyCompat<SpringRelativeLayout>("value") {
+
+ @Override
+ public float getValue(SpringRelativeLayout object) {
+ return object.mDampedScrollShift;
+ }
+
+ @Override
+ public void setValue(SpringRelativeLayout object, float value) {
+ object.setDampedScrollShift(value);
+ }
+ };
+
+ private final SparseBooleanArray mSpringViews = new SparseBooleanArray();
+ private final SpringAnimation mSpring;
+
+ private float mDampedScrollShift = 0;
+
+ public SpringRelativeLayout(Context context) {
+ this(context, null);
+ }
+
+ public SpringRelativeLayout(Context context, AttributeSet attrs) {
+ this(context, attrs, 0);
+ }
+
+ public SpringRelativeLayout(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mSpring = new SpringAnimation(this, DAMPED_SCROLL, 0);
+ mSpring.setSpring(new SpringForce(0)
+ .setStiffness(STIFFNESS)
+ .setDampingRatio(DAMPING_RATIO));
+ }
+
+ public void addSpringView(int id) {
+ mSpringViews.put(id, true);
+ }
+
+ @Override
+ protected boolean drawChild(Canvas canvas, View child, long drawingTime) {
+ if (mDampedScrollShift != 0 && mSpringViews.get(child.getId())) {
+ canvas.translate(0, mDampedScrollShift);
+ boolean result = super.drawChild(canvas, child, drawingTime);
+ canvas.translate(0, -mDampedScrollShift);
+ return result;
+ }
+ return super.drawChild(canvas, child, drawingTime);
+ }
+
+ private void setDampedScrollShift(float shift) {
+ if (shift != mDampedScrollShift) {
+ mDampedScrollShift = shift;
+ invalidate();
+ }
+ }
+
+ private void finishScrollWithVelocity(float velocity) {
+ mSpring.setStartVelocity(velocity);
+ mSpring.setStartValue(mDampedScrollShift);
+ mSpring.start();
+ }
+
+ public EdgeEffectFactory createEdgeEffectFactory() {
+ return new SpringEdgeEffectFactory();
+ }
+
+ private class SpringEdgeEffectFactory extends EdgeEffectFactory {
+
+ @NonNull @Override
+ protected EdgeEffect createEdgeEffect(RecyclerView view, int direction) {
+ switch (direction) {
+ case DIRECTION_TOP:
+ return new SpringEdgeEffect(getContext(), +VELOCITY_MULTIPLIER);
+ case DIRECTION_BOTTOM:
+ return new SpringEdgeEffect(getContext(), -VELOCITY_MULTIPLIER);
+ }
+ return super.createEdgeEffect(view, direction);
+ }
+ }
+
+ private class SpringEdgeEffect extends EdgeEffect {
+
+ private final float mVelocityMultiplier;
+
+ private float mDistance;
+
+ public SpringEdgeEffect(Context context, float velocityMultiplier) {
+ super(context);
+ mVelocityMultiplier = velocityMultiplier;
+ }
+
+ @Override
+ public boolean draw(Canvas canvas) {
+ return false;
+ }
+
+ @Override
+ public void onAbsorb(int velocity) {
+ finishScrollWithVelocity(velocity * mVelocityMultiplier);
+ }
+
+ @Override
+ public void onPull(float deltaDistance, float displacement) {
+ mDistance += deltaDistance * (mVelocityMultiplier / 3f);
+ setDampedScrollShift(mDistance * getHeight());
+ }
+
+ @Override
+ public void onRelease() {
+ mDistance = 0;
+ finishScrollWithVelocity(0);
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/com/android/launcher3/views/TopRoundedCornerView.java b/src/com/android/launcher3/views/TopRoundedCornerView.java
index 3ba8ca3..7888b08 100644
--- a/src/com/android/launcher3/views/TopRoundedCornerView.java
+++ b/src/com/android/launcher3/views/TopRoundedCornerView.java
@@ -29,7 +29,7 @@
/**
* View with top rounded corners.
*/
-public class TopRoundedCornerView extends FrameLayout {
+public class TopRoundedCornerView extends SpringRelativeLayout {
private final RectF mRect = new RectF();
private final Path mClipPath = new Path();
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index c51842d..10708d6 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -32,6 +32,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.ColorScrim;
+import com.android.launcher3.touch.ItemLongClickListener;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.launcher3.userevent.nano.LauncherLogProto.Target;
import com.android.launcher3.util.SystemUiController;
@@ -71,7 +72,7 @@
@Override
public final boolean onLongClick(View v) {
- if (!mLauncher.isDraggingEnabled()) return false;
+ if (!ItemLongClickListener.canStartDrag(mLauncher)) return false;
if (v instanceof WidgetCell) {
return beginDraggingWidget((WidgetCell) v);
diff --git a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
index 6970833..961799d 100644
--- a/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
+++ b/src/com/android/launcher3/widget/PendingAppWidgetHostView.java
@@ -43,6 +43,7 @@
import com.android.launcher3.Utilities;
import com.android.launcher3.graphics.DrawableFactory;
import com.android.launcher3.model.PackageItemInfo;
+import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.util.Themes;
import com.android.launcher3.widget.LauncherAppWidgetHostView;
@@ -83,7 +84,7 @@
setElevation(getResources().getDimension(R.dimen.pending_widget_elevation));
updateAppWidget(null);
- setOnClickListener(mLauncher);
+ setOnClickListener(ItemClickHandler.INSTANCE);
if (info.pendingItemInfo == null) {
info.pendingItemInfo = new PackageItemInfo(info.providerName.getPackageName());
diff --git a/src/com/android/launcher3/widget/WidgetsFullSheet.java b/src/com/android/launcher3/widget/WidgetsFullSheet.java
index b31feed..a622624 100644
--- a/src/com/android/launcher3/widget/WidgetsFullSheet.java
+++ b/src/com/android/launcher3/widget/WidgetsFullSheet.java
@@ -70,6 +70,9 @@
mRecyclerView.setAdapter(mAdapter);
mAdapter.setApplyBitmapDeferred(true, mRecyclerView);
+ TopRoundedCornerView springLayout = (TopRoundedCornerView) mContent;
+ springLayout.addSpringView(R.id.widgets_list_view);
+ mRecyclerView.setEdgeEffectFactory(springLayout.createEdgeEffectFactory());
onWidgetsBound();
}
diff --git a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
index 7d1da88..011aa22 100644
--- a/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
+++ b/tests/src/com/android/launcher3/ui/AbstractLauncherUiTest.java
@@ -15,9 +15,6 @@
*/
package com.android.launcher3.ui;
-import static org.junit.Assert.assertNotNull;
-import static org.junit.Assert.assertNull;
-
import android.app.Instrumentation;
import android.content.BroadcastReceiver;
import android.content.ComponentName;
@@ -37,22 +34,27 @@
import android.support.test.uiautomator.UiObject2;
import android.support.test.uiautomator.Until;
import android.view.MotionEvent;
+
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherAppWidgetProviderInfo;
import com.android.launcher3.LauncherSettings;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
-import com.android.launcher3.Utilities;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.testcomponent.AppWidgetNoConfig;
import com.android.launcher3.testcomponent.AppWidgetWithConfig;
+
+import org.junit.Before;
+
import java.util.Locale;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
-import org.junit.Before;
+
+import static org.junit.Assert.assertNotNull;
+import static org.junit.Assert.assertNull;
/**
* Base class for all instrumentation tests providing various utility methods.
@@ -63,6 +65,7 @@
public static final long DEFAULT_BROADCAST_TIMEOUT_SECS = 5;
public static final long DEFAULT_UI_TIMEOUT = 3000;
+ public static final long LARGE_UI_TIMEOUT = 10000;
public static final long DEFAULT_WORKER_TIMEOUT_SECS = 5;
protected MainThreadExecutor mMainThreadExecutor = new MainThreadExecutor();
@@ -95,8 +98,13 @@
protected UiObject2 openAllApps() {
mDevice.waitForIdle();
if (FeatureFlags.NO_ALL_APPS_ICON) {
- // clicking on the page indicator brings up all apps tray on non tablets.
- findViewById(R.id.page_indicator).click();
+ UiObject2 hotseat = mDevice.wait(
+ Until.findObject(getSelectorForId(R.id.hotseat)), 2500);
+ Point start = hotseat.getVisibleCenter();
+ int endY = (int) (mDevice.getDisplayHeight() * 0.1f);
+ // 100 px/step
+ mDevice.swipe(start.x, start.y, start.x, endY, (start.y - endY) / 100);
+
} else {
mDevice.wait(Until.findObject(
By.desc(mTargetContext.getString(R.string.all_apps_button_label))),
diff --git a/tests/src/com/android/launcher3/ui/WorkTabTest.java b/tests/src/com/android/launcher3/ui/WorkTabTest.java
new file mode 100644
index 0000000..ccee7da
--- /dev/null
+++ b/tests/src/com/android/launcher3/ui/WorkTabTest.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 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.ui;
+
+import android.support.test.filters.LargeTest;
+import android.support.test.runner.AndroidJUnit4;
+import android.support.test.uiautomator.UiObject2;
+import android.support.test.uiautomator.Until;
+
+import com.android.launcher3.R;
+import com.android.launcher3.util.Condition;
+import com.android.launcher3.util.Wait;
+import com.android.launcher3.util.rule.LauncherActivityRule;
+import com.android.launcher3.util.rule.ShellCommandRule;
+
+import org.junit.After;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+import static org.junit.Assert.assertTrue;
+
+@LargeTest
+@RunWith(AndroidJUnit4.class)
+public class WorkTabTest extends AbstractLauncherUiTest {
+ @Rule
+ public LauncherActivityRule mActivityMonitor = new LauncherActivityRule();
+ @Rule
+ public ShellCommandRule mDefaultLauncherRule = ShellCommandRule.setDefaultLauncher();
+
+ private int mProfileUserId;
+
+ @Before
+ public void createWorkProfile() throws Exception {
+ String output =
+ mDevice.executeShellCommand(
+ "pm create-user --profileOf 0 --managed TestProfile");
+ assertTrue("Failed to create work profile", output.startsWith("Success"));
+
+ String[] tokens = output.split("\\s+");
+ mProfileUserId = Integer.parseInt(tokens[tokens.length - 1]);
+
+ mDevice.executeShellCommand("am start-user " + mProfileUserId);
+ }
+
+ @After
+ public void removeWorkProfile() throws Exception {
+ mDevice.executeShellCommand("pm remove-user " + mProfileUserId);
+ }
+
+ @Test
+ public void workTabExists() {
+ mActivityMonitor.startLauncher();
+
+ // Open all apps and wait for load complete
+ final UiObject2 appsContainer = openAllApps();
+ assertTrue(Wait.atMost(Condition.minChildCount(appsContainer, 2), DEFAULT_UI_TIMEOUT));
+
+ assertTrue("Personal tab is missing",
+ mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_personal)),
+ LARGE_UI_TIMEOUT));
+ assertTrue("Work tab is missing",
+ mDevice.wait(Until.hasObject(getSelectorForId(R.id.tab_work)), LARGE_UI_TIMEOUT));
+ }
+}
\ No newline at end of file