Merge "Turn on feature flags to eanble all apps personal/work tabs." into ub-launcher3-master
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
similarity index 80%
rename from src/com/android/launcher3/states/AllAppsState.java
rename to quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
index ed3023a..1064492 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/AllAppsState.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.states;
+package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
import android.view.View;
@@ -30,8 +31,6 @@
*/
public class AllAppsState extends LauncherState {
- public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
-
private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
public AllAppsState(int id) {
@@ -57,4 +56,15 @@
public View getFinalFocus(Launcher launcher) {
return launcher.getAppsView();
}
+
+ @Override
+ public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+ // TODO: interpolate
+ return LauncherState.OVERVIEW.getWorkspaceScaleAndTranslation(launcher);
+ }
+
+ @Override
+ public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+ return (i) -> 0;
+ }
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
index 1176034..3458a3f 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/OverviewState.java
@@ -17,10 +17,12 @@
import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS;
+import android.graphics.Rect;
import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
+import com.android.launcher3.Workspace;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
import com.android.quickstep.RecentsView;
@@ -29,7 +31,8 @@
*/
public class OverviewState extends LauncherState {
- private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE;
+ private static final int STATE_FLAGS = FLAG_SHOW_SCRIM
+ | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED;
public OverviewState(int id) {
super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, 1f, STATE_FLAGS);
@@ -37,8 +40,20 @@
@Override
public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
- // TODO: Find a better transition
- return new float[] {0f, 0};
+ Rect pageRect = new Rect();
+ RecentsView.getPageRect(launcher, pageRect);
+ Workspace ws = launcher.getWorkspace();
+ float childWidth = ws.getNormalChildWidth();
+ if (childWidth <= 0 || pageRect.isEmpty()) {
+ return super.getWorkspaceScaleAndTranslation(launcher);
+ }
+
+ Rect insets = launcher.getDragLayer().getInsets();
+ float scale = pageRect.width() / childWidth;
+
+ float halfHeight = ws.getHeight() / 2;
+ float childTop = halfHeight - scale * (halfHeight - ws.getPaddingTop() - insets.top);
+ return new float[] {scale, pageRect.top - childTop};
}
@Override
diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
index da1eff9..b59e4ee 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java
@@ -15,39 +15,91 @@
*/
package com.android.launcher3.uioverrides;
-import static com.android.launcher3.WorkspaceStateTransitionAnimation.NO_ANIM_PROPERTY_SETTER;
-
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
+import android.view.View;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.LauncherStateManager.StateHandler;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.AnimatedPropertySetter;
-import com.android.launcher3.WorkspaceStateTransitionAnimation.PropertySetter;
import com.android.launcher3.anim.AnimationLayerSet;
+import com.android.launcher3.anim.AnimationSuccessListener;
+import com.android.launcher3.anim.Interpolators;
+import com.android.quickstep.AnimatedFloat;
+import com.android.quickstep.RecentsView;
public class RecentsViewStateController implements StateHandler {
private final Launcher mLauncher;
+ private final RecentsView mRecentsView;
+
+ private final AnimatedFloat mTransitionProgress = new AnimatedFloat(this::applyProgress);
+ // 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::applyProgress);
public RecentsViewStateController(Launcher launcher) {
mLauncher = launcher;
+ mRecentsView = launcher.getOverviewPanel();
+ mRecentsView.setStateController(this);
}
@Override
public void setState(LauncherState state) {
- setState(state, NO_ANIM_PROPERTY_SETTER);
+ setVisibility(state == LauncherState.OVERVIEW);
+ setTransitionProgress(state == LauncherState.OVERVIEW ? 1 : 0);
}
@Override
public void setStateWithAnimation(LauncherState toState, AnimationLayerSet layerViews,
AnimatorSet anim, AnimationConfig config) {
- setState(toState, new AnimatedPropertySetter(config.duration, layerViews, anim));
+ ObjectAnimator progressAnim =
+ mTransitionProgress.animateToValue(toState == LauncherState.OVERVIEW ? 1 : 0);
+ progressAnim.setDuration(config.duration);
+ progressAnim.setInterpolator(Interpolators.LINEAR);
+ anim.play(progressAnim);
+
+ ObjectAnimator visibilityAnim = animateVisibility(toState == LauncherState.OVERVIEW);
+ visibilityAnim.setDuration(config.duration);
+ visibilityAnim.setInterpolator(Interpolators.LINEAR);
+ anim.play(visibilityAnim);
}
- private void setState(LauncherState state, PropertySetter setter) {
- setter.setViewAlpha(null, mLauncher.getOverviewPanel(),
- state == LauncherState.OVERVIEW ? 1 : 0);
+ public void setVisibility(boolean isVisible) {
+ mVisibilityMultiplier.cancelAnimation();
+ mRecentsView.setVisibility(isVisible ? View.VISIBLE : View.GONE);
+ mVisibilityMultiplier.updateValue(isVisible ? 1 : 0);
+ }
+
+ public ObjectAnimator animateVisibility(boolean isVisible) {
+ ObjectAnimator anim = mVisibilityMultiplier.animateToValue(isVisible ? 1 : 0);
+ if (isVisible) {
+ anim.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationStart(Animator animation) {
+ mRecentsView.setVisibility(View.VISIBLE);
+ }
+ });
+ } else {
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mRecentsView.setVisibility(View.GONE);
+ }
+ });
+ }
+ return anim;
+ }
+
+ public void setTransitionProgress(float progress) {
+ mTransitionProgress.cancelAnimation();
+ mTransitionProgress.updateValue(progress);
+ }
+
+ private void applyProgress() {
+ mRecentsView.setAlpha(mTransitionProgress.value * mVisibilityMultiplier.value);
}
}
diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java
index 1f6781e..214b3f3 100644
--- a/quickstep/src/com/android/quickstep/AnimatedFloat.java
+++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java
@@ -47,9 +47,7 @@
}
public ObjectAnimator animateToValue(float v) {
- if (mValueAnimator != null) {
- mValueAnimator.cancel();
- }
+ cancelAnimation();
mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, v);
mValueAnimator.addListener(new AnimatorListenerAdapter() {
@Override
@@ -73,6 +71,12 @@
}
}
+ public void cancelAnimation() {
+ if (mValueAnimator != null) {
+ mValueAnimator.cancel();
+ }
+ }
+
public ObjectAnimator getCurrentAnimation() {
return mValueAnimator;
}
diff --git a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
index 4c3a9ad..75db45b 100644
--- a/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
+++ b/quickstep/src/com/android/quickstep/NavBarSwipeInteractionHandler.java
@@ -42,6 +42,7 @@
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragLayer;
import com.android.launcher3.states.InternalStateHandler;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.launcher3.util.TraceHelper;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.Task;
@@ -94,6 +95,7 @@
private Launcher mLauncher;
private SnapshotDragView mDragView;
private RecentsView mRecentsView;
+ private RecentsViewStateController mStateController;
private Hotseat mHotseat;
private RecentsTaskLoadPlan mLoadPlan;
@@ -178,11 +180,13 @@
mDragView.setPivotX(0);
mDragView.setPivotY(0);
mRecentsView = mLauncher.getOverviewPanel();
+ mStateController = mRecentsView.getStateController();
mHotseat = mLauncher.getHotseat();
// Optimization
mLauncher.getAppsView().setVisibility(View.GONE);
- mRecentsView.setVisibility(View.GONE);
+ mStateController.setTransitionProgress(1);
+ mStateController.setVisibility(false);
TraceHelper.partitionSection("TouchInt", "Launcher on new intent");
}
@@ -209,17 +213,9 @@
}
if (mTargetRect.isEmpty()) {
+ RecentsView.getPageRect(mLauncher, mTargetRect);
DragLayer dl = mLauncher.getDragLayer();
mSourceRect.set(0, 0, dl.getWidth(), dl.getHeight());
- Rect targetPadding = RecentsView.getPadding(mLauncher);
- Rect insets = dl.getInsets();
- mTargetRect.set(
- targetPadding.left + insets.left,
- targetPadding.top + insets.top,
- mSourceRect.right - targetPadding.right - insets.right,
- mSourceRect.bottom - targetPadding.bottom - insets.bottom);
- mTargetRect.top += mLauncher.getResources()
- .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
}
float shift = mCurrentShift.value * mActivityMultiplier.value;
@@ -246,12 +242,15 @@
private void setTaskPlanToUi() {
mRecentsView.update(mLoadPlan);
- mRecentsView.setVisibility(View.VISIBLE);
-
- // Animate alpha
- mRecentsView.setAlpha(0);
- mRecentsView.animate().alpha(1).setDuration(RECENTS_VIEW_VISIBILITY_DURATION)
- .withEndAction(() -> mStateCallback.setState(STATE_RECENTS_FULLY_VISIBLE));
+ ObjectAnimator anim = mStateController.animateVisibility(true /* isVisible */)
+ .setDuration(RECENTS_VIEW_VISIBILITY_DURATION);
+ anim.addListener(new AnimationSuccessListener() {
+ @Override
+ public void onAnimationSuccess(Animator animator) {
+ mStateCallback.setState(STATE_RECENTS_FULLY_VISIBLE);
+ }
+ });
+ anim.start();
}
@UiThread
diff --git a/quickstep/src/com/android/quickstep/RecentsView.java b/quickstep/src/com/android/quickstep/RecentsView.java
index ba88f99..c0fd2cf 100644
--- a/quickstep/src/com/android/quickstep/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/RecentsView.java
@@ -27,6 +27,8 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.PagedView;
import com.android.launcher3.R;
+import com.android.launcher3.dragndrop.DragLayer;
+import com.android.launcher3.uioverrides.RecentsViewStateController;
import com.android.systemui.shared.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.shared.recents.model.RecentsTaskLoader;
import com.android.systemui.shared.recents.model.Task;
@@ -48,6 +50,11 @@
/** A circular 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) (1 - Math.sqrt(1 - Math.pow(x, 2)));
+ /**
+ * 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 boolean mOverviewStateEnabled;
private boolean mTaskStackListenerRegistered;
@@ -65,6 +72,8 @@
}
};
+ private RecentsViewStateController mStateController;
+
public RecentsView(Context context) {
this(context, null);
}
@@ -106,6 +115,14 @@
updateTaskStackListenerState();
}
+ public void setStateController(RecentsViewStateController stateController) {
+ mStateController = stateController;
+ }
+
+ public RecentsViewStateController getStateController() {
+ return mStateController;
+ }
+
public void setOverviewStateEnabled(boolean enabled) {
mOverviewStateEnabled = enabled;
updateTaskStackListenerState();
@@ -166,7 +183,7 @@
}
}
- public static Rect getPadding(Launcher launcher) {
+ private static Rect getPadding(Launcher launcher) {
DeviceProfile profile = launcher.getDeviceProfile();
Rect stableInsets = new Rect();
WindowManagerWrapper.getInstance().getStableInsets(stableInsets);
@@ -180,9 +197,22 @@
return padding;
}
+ public static void getPageRect(Launcher launcher, Rect outRect) {
+ DragLayer dl = launcher.getDragLayer();
+ Rect targetPadding = getPadding(launcher);
+ Rect insets = dl.getInsets();
+ outRect.set(
+ targetPadding.left + insets.left,
+ targetPadding.top + insets.top,
+ dl.getWidth() - targetPadding.right - insets.right,
+ dl.getHeight() - targetPadding.bottom - insets.bottom);
+ outRect.top += launcher.getResources()
+ .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin);
+ }
+
@Override
- public void scrollTo(int x, int y) {
- super.scrollTo(x, y);
+ public void computeScroll() {
+ super.computeScroll();
updateCurveProperties();
}
@@ -212,6 +242,10 @@
// Make sure the biggest card (i.e. the one in front) shows on top of the adjacent ones.
page.setTranslationZ(scale);
page.setTranslationX((screenCenter - pageCenter) * curveInterpolation * CURVE_FACTOR);
+ if (page instanceof TaskView) {
+ TaskThumbnailView thumbnail = ((TaskView) page).getThumbnail();
+ thumbnail.setDimAlpha(1 - curveInterpolation * MAX_PAGE_SCRIM_ALPHA);
+ }
}
}
}
diff --git a/quickstep/src/com/android/quickstep/TaskView.java b/quickstep/src/com/android/quickstep/TaskView.java
index 029afd6..ac9a778 100644
--- a/quickstep/src/com/android/quickstep/TaskView.java
+++ b/quickstep/src/com/android/quickstep/TaskView.java
@@ -62,6 +62,7 @@
@Override
protected void onFinishInflate() {
+ super.onFinishInflate();
mSnapshotView = findViewById(R.id.snapshot);
mIconView = findViewById(R.id.icon);
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index eacc393..7b220d8 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -15,8 +15,15 @@
*/
package com.android.quickstep;
+import static android.view.MotionEvent.ACTION_CANCEL;
+import static android.view.MotionEvent.ACTION_DOWN;
+import static android.view.MotionEvent.ACTION_MOVE;
+import static android.view.MotionEvent.ACTION_POINTER_DOWN;
+import static android.view.MotionEvent.ACTION_POINTER_UP;
+import static android.view.MotionEvent.ACTION_UP;
import static android.view.MotionEvent.INVALID_POINTER_ID;
+import android.annotation.TargetApi;
import android.app.ActivityManager.RunningTaskInfo;
import android.app.ActivityOptions;
import android.app.Service;
@@ -29,6 +36,7 @@
import android.graphics.Point;
import android.graphics.PointF;
import android.graphics.Rect;
+import android.os.Build;
import android.os.IBinder;
import android.os.RemoteException;
import android.os.UserHandle;
@@ -37,9 +45,12 @@
import android.view.Display;
import android.view.MotionEvent;
import android.view.VelocityTracker;
+import android.view.View;
import android.view.ViewConfiguration;
import android.view.WindowManager;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAppState;
import com.android.launcher3.MainThreadExecutor;
import com.android.launcher3.R;
import com.android.launcher3.util.TraceHelper;
@@ -51,9 +62,12 @@
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.BackgroundExecutor;
+import java.util.function.Consumer;
+
/**
* Service connected by system-UI for handling touch interaction.
*/
+@TargetApi(Build.VERSION_CODES.O)
public class TouchInteractionService extends Service {
private static final String TAG = "TouchInteractionService";
@@ -73,6 +87,10 @@
}
};
+ private final Consumer<MotionEvent> mOtherActivityTouchConsumer
+ = this::handleTouchDownOnOtherActivity;
+ private final Consumer<MotionEvent> mNoOpTouchConsumer = (ev) -> {};
+
private ActivityManagerWrapper mAM;
private RunningTaskInfo mRunningTask;
private Intent mHomeIntent;
@@ -80,8 +98,6 @@
private MotionEventQueue mEventQueue;
private MainThreadExecutor mMainThreadExecutor;
- private int mDisplayRotation;
- private final Point mDisplaySize = new Point();
private final PointF mDownPos = new PointF();
private final PointF mLastPos = new PointF();
private int mActivePointerId = INVALID_POINTER_ID;
@@ -91,6 +107,7 @@
private NavBarSwipeInteractionHandler mInteractionHandler;
private ISystemUiProxy mISystemUiProxy;
+ private Consumer<MotionEvent> mCurrentConsumer = mNoOpTouchConsumer;
@Override
public void onCreate() {
@@ -128,25 +145,31 @@
}
private void handleMotionEvent(MotionEvent ev) {
- if (ev.getActionMasked() != MotionEvent.ACTION_DOWN && mVelocityTracker == null) {
+ if (ev.getActionMasked() == ACTION_DOWN) {
+ mRunningTask = mAM.getRunningTask();
+
+ if (mRunningTask == null) {
+ mCurrentConsumer = mNoOpTouchConsumer;
+ } else if (mRunningTask.topActivity.equals(mLauncher)) {
+ mCurrentConsumer = getLauncherConsumer();
+ } else {
+ mCurrentConsumer = mOtherActivityTouchConsumer;
+ }
+ }
+ mCurrentConsumer.accept(ev);
+ }
+
+ private void handleTouchDownOnOtherActivity(MotionEvent ev) {
+ if (ev.getActionMasked() != ACTION_DOWN && mVelocityTracker == null) {
return;
}
switch (ev.getActionMasked()) {
- case MotionEvent.ACTION_DOWN: {
+ case ACTION_DOWN: {
TraceHelper.beginSection("TouchInt");
mActivePointerId = ev.getPointerId(0);
mDownPos.set(ev.getX(), ev.getY());
mLastPos.set(mDownPos);
mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
- Display display = getSystemService(WindowManager.class).getDefaultDisplay();
- display.getRealSize(mDisplaySize);
- mDisplayRotation = display.getRotation();
-
- mRunningTask = mAM.getRunningTask();
- if (mRunningTask == null || mRunningTask.topActivity.equals(mLauncher)) {
- // TODO: We could drive all-apps in this case. For now just ignore swipe.
- break;
- }
if (mVelocityTracker == null) {
mVelocityTracker = VelocityTracker.obtain();
@@ -160,7 +183,7 @@
}
break;
}
- case MotionEvent.ACTION_POINTER_UP: {
+ case ACTION_POINTER_UP: {
int ptrIdx = ev.getActionIndex();
int ptrId = ev.getPointerId(ptrIdx);
if (ptrId == mActivePointerId) {
@@ -174,7 +197,7 @@
}
break;
}
- case MotionEvent.ACTION_MOVE: {
+ case ACTION_MOVE: {
int pointerIndex = ev.findPointerIndex(mActivePointerId);
if (pointerIndex == INVALID_POINTER_ID) {
break;
@@ -194,17 +217,19 @@
}
break;
}
- case MotionEvent.ACTION_CANCEL:
+ case ACTION_CANCEL:
// TODO: Should be different than ACTION_UP
- case MotionEvent.ACTION_UP: {
+ case ACTION_UP: {
TraceHelper.endSection("TouchInt");
endInteraction();
+ mCurrentConsumer = mNoOpTouchConsumer;
break;
}
}
}
+
private void startTouchTracking() {
// Create the shared handler
final NavBarSwipeInteractionHandler handler =
@@ -262,9 +287,12 @@
TraceHelper.beginSection("TaskSnapshot");
// TODO: We are using some hardcoded layers for now, to best approximate the activity layers
+ Point displaySize = new Point();
+ Display display = getSystemService(WindowManager.class).getDefaultDisplay();
+ display.getRealSize(displaySize);
try {
- return mISystemUiProxy.screenshot(new Rect(), mDisplaySize.x, mDisplaySize.y, 0, 100000,
- false, mDisplayRotation).toBitmap();
+ return mISystemUiProxy.screenshot(new Rect(), displaySize.x, displaySize.y, 0, 100000,
+ false, display.getRotation()).toBitmap();
} catch (RemoteException e) {
Log.e(TAG, "Error capturing snapshot", e);
return null;
@@ -272,4 +300,76 @@
TraceHelper.endSection("TaskSnapshot");
}
}
+
+ private Consumer<MotionEvent> getLauncherConsumer() {
+
+ Launcher launcher = (Launcher) LauncherAppState.getInstance(this).getModel().getCallback();
+ if (launcher == null) {
+ return mNoOpTouchConsumer;
+ }
+
+ View target = launcher.getDragLayer();
+ if (!target.getWindowId().isFocused()) {
+ return mNoOpTouchConsumer;
+ }
+ return new LauncherTouchConsumer(target);
+ }
+
+ private class LauncherTouchConsumer implements Consumer<MotionEvent> {
+
+ private final View mTarget;
+ private final int[] mLocationOnScreen = new int[2];
+
+ private boolean mTrackingStarted = false;
+
+ LauncherTouchConsumer(View target) {
+ mTarget = target;
+ }
+
+ @Override
+ public void accept(MotionEvent ev) {
+ int action = ev.getActionMasked();
+ if (action == ACTION_DOWN) {
+ mTrackingStarted = false;
+ mDownPos.set(ev.getX(), ev.getY());
+ mTouchSlop = ViewConfiguration.get(mTarget.getContext()).getScaledTouchSlop();
+ } else if (!mTrackingStarted) {
+ switch (action) {
+ case ACTION_POINTER_UP:
+ case ACTION_POINTER_DOWN:
+ if (!mTrackingStarted) {
+ mCurrentConsumer = mNoOpTouchConsumer;
+ }
+ break;
+ case ACTION_MOVE: {
+ float displacement = ev.getY() - mDownPos.y;
+ if (Math.abs(displacement) >= mTouchSlop) {
+ mTrackingStarted = true;
+ mTarget.getLocationOnScreen(mLocationOnScreen);
+
+ // Send a down event only when mTouchSlop is crossed.
+ MotionEvent down = MotionEvent.obtain(ev);
+ down.setAction(ACTION_DOWN);
+ sendEvent(down);
+ down.recycle();
+ }
+ }
+ }
+ }
+
+ if (mTrackingStarted) {
+ sendEvent(ev);
+ }
+
+ if (action == ACTION_UP || action == ACTION_CANCEL) {
+ mCurrentConsumer = mNoOpTouchConsumer;
+ }
+ }
+
+ private void sendEvent(MotionEvent ev) {
+ ev.offsetLocation(-mLocationOnScreen[0], -mLocationOnScreen[1]);
+ mTarget.dispatchTouchEvent(ev);
+ ev.offsetLocation(mLocationOnScreen[0], mLocationOnScreen[1]);
+ }
+ }
}
diff --git a/res/drawable-hdpi/work_tab_user_education.png b/res/drawable-hdpi/work_tab_user_education.png
new file mode 100644
index 0000000..1879dfb
--- /dev/null
+++ b/res/drawable-hdpi/work_tab_user_education.png
Binary files differ
diff --git a/res/drawable-mdpi/work_tab_user_education.png b/res/drawable-mdpi/work_tab_user_education.png
new file mode 100644
index 0000000..65c7e63
--- /dev/null
+++ b/res/drawable-mdpi/work_tab_user_education.png
Binary files differ
diff --git a/res/drawable-xhdpi/work_tab_user_education.png b/res/drawable-xhdpi/work_tab_user_education.png
new file mode 100644
index 0000000..59df7a8
--- /dev/null
+++ b/res/drawable-xhdpi/work_tab_user_education.png
Binary files differ
diff --git a/res/drawable-xxhdpi/work_tab_user_education.png b/res/drawable-xxhdpi/work_tab_user_education.png
new file mode 100644
index 0000000..3c6aa20
--- /dev/null
+++ b/res/drawable-xxhdpi/work_tab_user_education.png
Binary files differ
diff --git a/res/layout-land/all_apps_fast_scroller.xml b/res/layout-land/all_apps_fast_scroller.xml
index 6a68f84..16aa2af 100644
--- a/res/layout-land/all_apps_fast_scroller.xml
+++ b/res/layout-land/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginTop="-5dp"
android:layout_marginEnd="-45dp" />
@@ -31,7 +31,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignParentTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="-88dp"
android:layout_marginTop="14dp"
launcher:canThumbDetach="true" />
diff --git a/res/layout-sw720dp/all_apps_fast_scroller.xml b/res/layout-sw720dp/all_apps_fast_scroller.xml
index 12c15cc..5537bc6 100644
--- a/res/layout-sw720dp/all_apps_fast_scroller.xml
+++ b/res/layout-sw720dp/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
diff --git a/res/layout/all_apps.xml b/res/layout/all_apps.xml
index c42c15c..be509ed 100644
--- a/res/layout/all_apps.xml
+++ b/res/layout/all_apps.xml
@@ -31,7 +31,7 @@
<include layout="@layout/all_apps_fast_scroller" />
- <RelativeLayout
+ <com.android.launcher3.allapps.FloatingHeaderView
android:id="@+id/all_apps_header"
android:layout_width="match_parent"
android:layout_height="wrap_content"
@@ -48,12 +48,16 @@
android:id="@+id/divider"
android:layout_width="match_parent"
android:layout_height="wrap_content"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
android:layout_alignBottom="@+id/tabs" />
<com.android.launcher3.views.SlidingTabStrip
android:id="@+id/tabs"
android:layout_width="match_parent"
android:layout_height="@dimen/all_apps_header_tab_height"
+ android:layout_marginLeft="@dimen/all_apps_tabs_side_padding"
+ android:layout_marginRight="@dimen/all_apps_tabs_side_padding"
android:layout_below="@id/header_content"
android:orientation="horizontal" >
<Button
@@ -73,7 +77,7 @@
android:textColor="@color/all_apps_tab_text"
android:background="?android:attr/selectableItemBackground"/>
</com.android.launcher3.views.SlidingTabStrip>
- </RelativeLayout>
+ </com.android.launcher3.allapps.FloatingHeaderView>
<!-- Note: we are reusing/repurposing a system attribute for search layout, because of a
platform bug, which prevents using custom attributes in <include> tag -->
diff --git a/res/layout/all_apps_fast_scroller.xml b/res/layout/all_apps_fast_scroller.xml
index 12c15cc..5537bc6 100644
--- a/res/layout/all_apps_fast_scroller.xml
+++ b/res/layout/all_apps_fast_scroller.xml
@@ -21,7 +21,7 @@
android:id="@+id/fast_scroller_popup"
style="@style/FastScrollerPopup"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_popup_margin" />
<com.android.launcher3.views.RecyclerViewFastScroller
@@ -30,7 +30,7 @@
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_alignParentEnd="true"
- android:layout_alignTop="@+id/apps_list_view"
+ android:layout_below="@+id/search_container_all_apps"
android:layout_marginEnd="@dimen/fastscroll_end_margin"
launcher:canThumbDetach="true" />
diff --git a/res/layout/work_tab_bottom_user_education_view.xml b/res/layout/work_tab_bottom_user_education_view.xml
new file mode 100644
index 0000000..2a4ba5d
--- /dev/null
+++ b/res/layout/work_tab_bottom_user_education_view.xml
@@ -0,0 +1,57 @@
+<?xml version="1.0" encoding="utf-8"?>
+<!-- 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.
+-->
+<com.android.launcher3.views.BottomUserEducationView
+ xmlns:android="http://schemas.android.com/apk/res/android"
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:layout_gravity="bottom"
+ android:background="?android:attr/colorAccent"
+ android:elevation="2dp"
+ android:orientation="horizontal"
+ android:paddingLeft="20dp"
+ android:paddingRight="20dp">
+
+ <ImageView
+ android:layout_width="134dp"
+ android:layout_height="134dp"
+ android:layout_gravity="center_vertical"
+ android:src="@drawable/work_tab_user_education"/>
+
+ <LinearLayout
+ android:layout_width="match_parent"
+ android:layout_height="wrap_content"
+ android:orientation="vertical"
+ android:paddingBottom="12dp"
+ android:paddingStart="24dp"
+ android:paddingTop="12dp">
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:fontFamily="roboto-medium"
+ android:text="@string/bottom_work_tab_user_education_title"
+ android:textColor="@android:color/white"
+ android:textSize="20sp"/>
+
+ <TextView
+ android:layout_width="wrap_content"
+ android:layout_height="wrap_content"
+ android:text="@string/bottom_work_tab_user_education_body"
+ android:textColor="@android:color/white"
+ android:textSize="14sp"/>
+ </LinearLayout>
+
+</com.android.launcher3.views.BottomUserEducationView>
\ No newline at end of file
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e7f45c2..e22c7c2 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -96,6 +96,7 @@
<dimen name="all_apps_prediction_row_divider_height">17dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_top_padding">16dp</dimen>
<dimen name="all_apps_work_profile_tab_footer_bottom_padding">20dp</dimen>
+ <dimen name="all_apps_tabs_side_padding">12dp</dimen>
<!-- Search bar in All Apps -->
<dimen name="all_apps_header_max_elevation">3dp</dimen>
diff --git a/res/values/strings.xml b/res/values/strings.xml
index cbba9a2..eca64c8 100644
--- a/res/values/strings.xml
+++ b/res/values/strings.xml
@@ -326,5 +326,9 @@
<!-- Label of the work mode toggle -->
<string name="work_profile_toggle_label">Work profile</string>
+ <!-- Title in bottom user education view in work tab -->
+ <string name="bottom_work_tab_user_education_title">Find work apps here</string>
+ <!-- Body text in bottom user education view in work tab -->
+ <string name="bottom_work_tab_user_education_body">Each work app has an orange badge, which means it\'s kept secure by your organization. Work apps can be moved to your Home Screen for easier access.</string>
</resources>
diff --git a/src/com/android/launcher3/AbstractFloatingView.java b/src/com/android/launcher3/AbstractFloatingView.java
index 26024e5..da464c0 100644
--- a/src/com/android/launcher3/AbstractFloatingView.java
+++ b/src/com/android/launcher3/AbstractFloatingView.java
@@ -42,7 +42,8 @@
TYPE_WIDGETS_BOTTOM_SHEET,
TYPE_WIDGET_RESIZE_FRAME,
TYPE_WIDGETS_FULL_SHEET,
- TYPE_QUICKSTEP_PREVIEW
+ TYPE_QUICKSTEP_PREVIEW,
+ TYPE_ON_BOARD_POPUP
})
@Retention(RetentionPolicy.SOURCE)
public @interface FloatingViewType {}
@@ -52,10 +53,15 @@
public static final int TYPE_WIDGET_RESIZE_FRAME = 1 << 3;
public static final int TYPE_WIDGETS_FULL_SHEET = 1 << 4;
public static final int TYPE_QUICKSTEP_PREVIEW = 1 << 5;
+ public static final int TYPE_ON_BOARD_POPUP = 1 << 6;
public static final int TYPE_ALL = TYPE_FOLDER | TYPE_ACTION_POPUP
| TYPE_WIDGETS_BOTTOM_SHEET | TYPE_WIDGET_RESIZE_FRAME | TYPE_WIDGETS_FULL_SHEET
- | TYPE_QUICKSTEP_PREVIEW;
+ | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP;
+
+ // Type of popups which should be kept open during launcher rebind
+ public static final int TYPE_REBIND_SAFE = TYPE_WIDGETS_FULL_SHEET
+ | TYPE_QUICKSTEP_PREVIEW | TYPE_ON_BOARD_POPUP;
protected boolean mIsOpen;
diff --git a/src/com/android/launcher3/BaseRecyclerView.java b/src/com/android/launcher3/BaseRecyclerView.java
index b315980..76c7845 100644
--- a/src/com/android/launcher3/BaseRecyclerView.java
+++ b/src/com/android/launcher3/BaseRecyclerView.java
@@ -17,13 +17,11 @@
package com.android.launcher3;
import android.content.Context;
-import android.graphics.Canvas;
import android.support.v7.widget.RecyclerView;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewGroup;
-import android.widget.TextView;
import com.android.launcher3.views.RecyclerViewFastScroller;
@@ -68,6 +66,7 @@
ViewGroup parent = (ViewGroup) getParent().getParent();
mScrollbar = parent.findViewById(R.id.fast_scroller);
mScrollbar.setRecyclerView(this, parent.findViewById(R.id.fast_scroller_popup));
+ onUpdateScrollbar(0);
}
/**
@@ -90,8 +89,10 @@
*/
private boolean handleTouchEvent(MotionEvent ev) {
// Move to mScrollbar's coordinate system.
- int left = getLeft() - mScrollbar.getLeft();
- int top = getTop() - mScrollbar.getTop();
+ // We need to take parent into account (view pager's location)
+ ViewGroup parent = (ViewGroup) getParent();
+ int left = parent.getLeft() + getLeft() - mScrollbar.getLeft();
+ int top = parent.getTop() + getTop() - mScrollbar.getTop() - getScrollBarTop();
ev.offsetLocation(left, top);
try {
return mScrollbar.handleTouchEvent(ev);
@@ -112,7 +113,7 @@
* Returns the height of the fast scroll bar
*/
public int getScrollbarTrackHeight() {
- return getHeight() - getScrollBarTop() - getPaddingBottom();
+ return mScrollbar.getHeight() - getScrollBarTop() - getPaddingBottom();
}
/**
@@ -130,12 +131,6 @@
return availableScrollBarHeight;
}
- @Override
- protected void dispatchDraw(Canvas canvas) {
- onUpdateScrollbar(0);
- super.dispatchDraw(canvas);
- }
-
/**
* Updates the scrollbar thumb offset to match the visible scroll of the recycler view. It does
* this by mapping the available scroll area of the recycler view to the available space for the
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index b7986da..a9b1619 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -60,7 +60,6 @@
import android.content.pm.PackageManager;
import android.database.sqlite.SQLiteDatabase;
import android.graphics.Point;
-import android.graphics.PointF;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.os.AsyncTask;
@@ -99,10 +98,10 @@
import com.android.launcher3.accessibility.LauncherAccessibilityDelegate;
import com.android.launcher3.allapps.AllAppsContainerView;
import com.android.launcher3.allapps.AllAppsTransitionController;
+import com.android.launcher3.allapps.DiscoveryBounce;
import com.android.launcher3.compat.AppWidgetManagerCompat;
import com.android.launcher3.compat.LauncherAppsCompat;
import com.android.launcher3.compat.LauncherAppsCompatVO;
-import com.android.launcher3.compat.UserManagerCompat;
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.dragndrop.DragController;
import com.android.launcher3.dragndrop.DragLayer;
@@ -121,7 +120,6 @@
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
import com.android.launcher3.shortcuts.DeepShortcutManager;
-import com.android.launcher3.states.AllAppsState;
import com.android.launcher3.states.InternalStateHandler;
import com.android.launcher3.uioverrides.UiFactory;
import com.android.launcher3.userevent.nano.LauncherLogProto;
@@ -848,9 +846,7 @@
// Refresh shortcuts if the permission changed.
mModel.refreshShortcutsIfRequired();
- if (shouldShowDiscoveryBounce()) {
- mAllAppsController.showDiscoveryBounce();
- }
+ DiscoveryBounce.showIfNeeded(this);
if (mLauncherCallbacks != null) {
mLauncherCallbacks.onResume();
}
@@ -1007,7 +1003,7 @@
int stateOrdinal = savedState.getInt(RUNTIME_STATE, NORMAL.ordinal);
LauncherState[] stateValues = LauncherState.values();
LauncherState state = stateValues[stateOrdinal];
- if (!state.doNotRestore) {
+ if (!state.disableRestore) {
mStateManager.goToState(state, false /* animated */);
}
@@ -1040,7 +1036,7 @@
| View.SYSTEM_UI_FLAG_LAYOUT_STABLE);
// Setup the drag layer
- mDragLayer.setup(this, mDragController, mAllAppsController);
+ mDragLayer.setup(this, mDragController);
// Setup the hotseat
mHotseat = (Hotseat) findViewById(R.id.hotseat);
@@ -1969,7 +1965,8 @@
final ShortcutInfo shortcut = (ShortcutInfo) tag;
if (shortcut.isDisabled()) {
- if ((shortcut.runtimeStatusFlags &
+ 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.
@@ -2428,7 +2425,7 @@
// we are starting a fresh bind, close all such panels as all the icons are about
// to go away.
AbstractFloatingView.closeOpenViews(this, true,
- AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_WIDGETS_FULL_SHEET);
+ AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE);
setWorkspaceLoading(true);
@@ -3069,12 +3066,6 @@
return mRotationEnabled;
}
- private boolean shouldShowDiscoveryBounce() {
- return isInState(NORMAL)
- && !mSharedPrefs.getBoolean(AllAppsState.APPS_VIEW_SHOWN, false)
- && !UserManagerCompat.getInstance(this).isDemoUser();
- }
-
/**
* $ adb shell dumpsys activity com.android.launcher3.Launcher [--all]
*/
diff --git a/src/com/android/launcher3/LauncherState.java b/src/com/android/launcher3/LauncherState.java
index d6cd8a3..dfb935f 100644
--- a/src/com/android/launcher3/LauncherState.java
+++ b/src/com/android/launcher3/LauncherState.java
@@ -21,7 +21,7 @@
import android.view.View;
-import com.android.launcher3.states.AllAppsState;
+import com.android.launcher3.uioverrides.AllAppsState;
import com.android.launcher3.states.SpringLoadedState;
import com.android.launcher3.uioverrides.OverviewState;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
@@ -37,12 +37,16 @@
protected static final int FLAG_SHOW_SCRIM = 1 << 0;
protected static final int FLAG_MULTI_PAGE = 1 << 1;
protected static final int FLAG_DISABLE_ACCESSIBILITY = 1 << 2;
- protected static final int FLAG_DO_NOT_RESTORE = 1 << 3;
+ protected static final int FLAG_DISABLE_RESTORE = 1 << 3;
+ protected static final int FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED = 1 << 4;
+ protected static final int FLAG_DISABLE_PAGE_CLIPPING = 1 << 5;
+
+ protected static final PageAlphaProvider DEFAULT_ALPHA_PROVIDER = (i) -> 1f;
private static final LauncherState[] sAllStates = new LauncherState[4];
public static final LauncherState NORMAL = new LauncherState(0, ContainerType.WORKSPACE,
- 0, 1f, FLAG_DO_NOT_RESTORE);
+ 0, 1f, FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED);
public static final LauncherState ALL_APPS = new AllAppsState(1);
@@ -60,7 +64,7 @@
/**
* True if the state can be persisted across activity restarts.
*/
- public final boolean doNotRestore;
+ public final boolean disableRestore;
/**
* True if workspace has multiple pages visible.
@@ -88,6 +92,17 @@
*/
public final float verticalProgress;
+ /**
+ * True if the state allows workspace icons to be dragged.
+ */
+ public final boolean workspaceIconsCanBeDragged;
+
+ /**
+ * True if the workspace pages should not be clipped relative to the workspace bounds
+ * for this state.
+ */
+ public final boolean disablePageClipping;
+
public LauncherState(int id, int containerType, int transitionDuration, float verticalProgress,
int flags) {
this.containerType = containerType;
@@ -98,7 +113,9 @@
this.workspaceAccessibilityFlag = (flags & FLAG_DISABLE_ACCESSIBILITY) != 0
? IMPORTANT_FOR_ACCESSIBILITY_NO_HIDE_DESCENDANTS
: IMPORTANT_FOR_ACCESSIBILITY_AUTO;
- this.doNotRestore = (flags & FLAG_DO_NOT_RESTORE) != 0;
+ this.disableRestore = (flags & FLAG_DISABLE_RESTORE) != 0;
+ this.workspaceIconsCanBeDragged = (flags & FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED) != 0;
+ this.disablePageClipping = (flags & FLAG_DISABLE_PAGE_CLIPPING) != 0;
this.verticalProgress = verticalProgress;
@@ -128,7 +145,20 @@
return launcher.getWorkspace().getCurrentPageDescription();
}
+ public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+ if (this != NORMAL || !launcher.getDeviceProfile().shouldFadeAdjacentWorkspaceScreens()) {
+ return DEFAULT_ALPHA_PROVIDER;
+ }
+ int centerPage = launcher.getWorkspace().getPageNearestToCenterOfScreen();
+ return (childIndex) -> childIndex != centerPage ? 0 : 1f;
+ }
+
protected static void dispatchWindowStateChanged(Launcher launcher) {
launcher.getWindow().getDecorView().sendAccessibilityEvent(TYPE_WINDOW_STATE_CHANGED);
}
+
+ public interface PageAlphaProvider {
+
+ float getPageAlpha(int pageIndex);
+ }
}
diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java
index 1e6016b..2cad95e 100644
--- a/src/com/android/launcher3/LauncherStateManager.java
+++ b/src/com/android/launcher3/LauncherStateManager.java
@@ -158,14 +158,14 @@
mConfig.reset();
if (!animated) {
- setState(state);
+ onStateTransitionStart(state);
for (StateHandler handler : getStateHandlers()) {
handler.setState(state);
}
if (mStateListener != null) {
mStateListener.onStateSetImmediately(state);
}
- mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+ onStateTransitionEnd(state);
// Run any queued runnable
if (onCompleteRunnable != null) {
@@ -217,7 +217,7 @@
@Override
public void onAnimationStart(Animator animation) {
// Change the internal state only when the transition actually starts
- setState(state);
+ onStateTransitionStart(state);
if (mStateListener != null) {
mStateListener.onStateTransitionStart(state);
}
@@ -237,19 +237,28 @@
if (onCompleteRunnable != null) {
onCompleteRunnable.run();
}
-
- mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
+ onStateTransitionEnd(state);
}
});
mConfig.setAnimation(animation);
return mConfig.mCurrentAnimation;
}
- private void setState(LauncherState state) {
+ private void onStateTransitionStart(LauncherState state) {
mState.onStateDisabled(mLauncher);
mState = state;
mState.onStateEnabled(mLauncher);
mLauncher.getAppWidgetHost().setResumed(state == LauncherState.NORMAL);
+
+ if (state.disablePageClipping) {
+ // Only disable clipping if needed, otherwise leave it as previous value.
+ mLauncher.getWorkspace().setClipChildren(false);
+ }
+ }
+
+ private void onStateTransitionEnd(LauncherState state) {
+ mLauncher.getWorkspace().setClipChildren(!state.disablePageClipping);
+ mLauncher.getUserEventDispatcher().resetElapsedContainerMillis();
}
/**
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 9f6efb3..b23568e 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -593,6 +593,11 @@
- mInsets.top - mInsets.bottom;
}
+ public int getNormalChildWidth() {
+ return getViewportWidth() - getPaddingLeft() - getPaddingRight()
+ - mInsets.left - mInsets.right;
+ }
+
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
if (getChildCount() == 0) {
diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java
index 0db5a16..3d59bad 100644
--- a/src/com/android/launcher3/Workspace.java
+++ b/src/com/android/launcher3/Workspace.java
@@ -193,10 +193,6 @@
private static final int HOTSEAT_STATE_ALPHA_INDEX = 2;
/**
- * These values correspond to {@link Direction#X} & {@link Direction#Y}
- */
- private final float[] mPageAlpha = new float[] {1, 1};
- /**
* Hotseat alpha can be changed when moving horizontally, vertically, changing states.
* The values correspond to {@link Direction#X}, {@link Direction#Y} &
* {@link #HOTSEAT_STATE_ALPHA_INDEX} respectively.
@@ -436,7 +432,6 @@
mCurrentPage = DEFAULT_PAGE;
DeviceProfile grid = mLauncher.getDeviceProfile();
setWillNotDraw(false);
- setClipChildren(false);
setClipToPadding(false);
setupLayoutTransition();
@@ -1191,33 +1186,21 @@
// TODO(adamcohen): figure out a final effect here. We may need to recommend
// different effects based on device performance. On at least one relatively high-end
// device I've tried, translating the launcher causes things to get quite laggy.
- setWorkspaceTranslationAndAlpha(Direction.X, transX, alpha);
+ setWorkspaceTranslationAndAlpha(transX, alpha);
setHotseatTranslationAndAlpha(Direction.X, transX, alpha);
}
/**
- * Moves the workspace UI in the Y direction.
- * @param translation the amount of shift.
- * @param alpha the alpha for the workspace page
- */
- public void setWorkspaceYTranslationAndAlpha(float translation, float alpha) {
- setWorkspaceTranslationAndAlpha(Direction.Y, translation, alpha);
- }
-
- /**
* Moves the workspace UI in the provided direction.
- * @param direction the direction to move the workspace
- * @param translation the amount of shift.
+ * @param translation the amount of horizontal shift.
* @param alpha the alpha for the workspace page
*/
- private void setWorkspaceTranslationAndAlpha(Direction direction, float translation, float alpha) {
- Property<View, Float> property = direction.viewProperty;
- mPageAlpha[direction.ordinal()] = alpha;
- float finalAlpha = mPageAlpha[0] * mPageAlpha[1];
+ private void setWorkspaceTranslationAndAlpha(float translation, float alpha) {
+ float finalAlpha = alpha;
View currentChild = getChildAt(getCurrentPage());
if (currentChild != null) {
- property.set(currentChild, translation);
+ currentChild.setTranslationX(translation);
currentChild.setAlpha(finalAlpha);
}
@@ -1225,7 +1208,7 @@
if (Float.compare(translation, 0) == 0) {
for (int i = getChildCount() - 1; i >= 0; i--) {
View child = getChildAt(i);
- property.set(child, translation);
+ child.setTranslationX(0);
child.setAlpha(finalAlpha);
}
}
@@ -1407,7 +1390,7 @@
/** Returns whether a drag should be allowed to be started from the current workspace state. */
public boolean workspaceIconsCanBeDragged() {
- return mLauncher.isInState(NORMAL) || mLauncher.isInState(SPRING_LOADED);
+ return mLauncher.getStateManager().getState().workspaceIconsCanBeDragged;
}
private void updateChildrenLayersEnabled() {
diff --git a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
index 8edec40..edf5ada 100644
--- a/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
+++ b/src/com/android/launcher3/WorkspaceStateTransitionAnimation.java
@@ -26,11 +26,11 @@
import android.animation.TimeInterpolator;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.res.Resources;
import android.util.Property;
import android.view.View;
import android.view.accessibility.AccessibilityManager;
+import com.android.launcher3.LauncherState.PageAlphaProvider;
import com.android.launcher3.LauncherStateManager.AnimationConfig;
import com.android.launcher3.anim.AnimationLayerSet;
import com.android.launcher3.anim.Interpolators;
@@ -97,18 +97,13 @@
private final Launcher mLauncher;
private final Workspace mWorkspace;
- private final boolean mWorkspaceFadeInAdjacentScreens;
-
private float mNewScale;
public WorkspaceStateTransitionAnimation(Launcher launcher, Workspace workspace) {
mLauncher = launcher;
mWorkspace = workspace;
-
- DeviceProfile grid = mLauncher.getDeviceProfile();
- Resources res = launcher.getResources();
- mWorkspaceScrimAlpha = res.getInteger(R.integer.config_workspaceScrimAlpha);
- mWorkspaceFadeInAdjacentScreens = grid.shouldFadeAdjacentWorkspaceScreens();
+ mWorkspaceScrimAlpha = launcher.getResources()
+ .getInteger(R.integer.config_workspaceScrimAlpha);
}
public void setState(LauncherState toState) {
@@ -134,10 +129,10 @@
mNewScale = scaleAndTranslationY[0];
final float finalWorkspaceTranslationY = scaleAndTranslationY[1];
- int toPage = mWorkspace.getPageNearestToCenterOfScreen();
+ PageAlphaProvider pageAlphaProvider = state.getWorkspacePageAlphaProvider(mLauncher);
final int childCount = mWorkspace.getChildCount();
for (int i = 0; i < childCount; i++) {
- applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, toPage,
+ applyChildState(state, (CellLayout) mWorkspace.getChildAt(i), i, pageAlphaProvider,
propertySetter);
}
@@ -151,21 +146,16 @@
}
public void applyChildState(LauncherState state, CellLayout cl, int childIndex) {
- applyChildState(state, cl, childIndex, mWorkspace.getPageNearestToCenterOfScreen(),
+ applyChildState(state, cl, childIndex, state.getWorkspacePageAlphaProvider(mLauncher),
NO_ANIM_PROPERTY_SETTER);
}
private void applyChildState(LauncherState state, CellLayout cl, int childIndex,
- int centerPage, PropertySetter propertySetter) {
+ PageAlphaProvider pageAlphaProvider, PropertySetter propertySetter) {
propertySetter.setInt(cl.getScrimBackground(),
DRAWABLE_ALPHA, state.hasScrim ? 255 : 0, Interpolators.ZOOM_IN);
-
- // Only animate the page alpha when we actually fade pages
- if (mWorkspaceFadeInAdjacentScreens) {
- float finalAlpha = state == LauncherState.NORMAL && childIndex != centerPage ? 0 : 1f;
- propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
- finalAlpha, Interpolators.ZOOM_IN);
- }
+ propertySetter.setFloat(cl.getShortcutsAndWidgets(), View.ALPHA,
+ pageAlphaProvider.getPageAlpha(childIndex), Interpolators.DEACCEL_2);
}
public static class PropertySetter {
diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java
index a6c1e6e..23a694c 100644
--- a/src/com/android/launcher3/allapps/AllAppsContainerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java
@@ -27,6 +27,7 @@
import android.support.v7.widget.RecyclerView;
import android.text.Selection;
import android.text.SpannableStringBuilder;
+import android.text.TextUtils;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
@@ -59,6 +60,7 @@
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.PackageUserKey;
import com.android.launcher3.util.TransformingTouchDelegate;
+import com.android.launcher3.views.BottomUserEducationView;
import com.android.launcher3.views.SlidingTabStrip;
import java.util.HashMap;
@@ -83,8 +85,7 @@
private SearchUiManager mSearchUiManager;
private View mSearchContainer;
private InterceptingViewPager mViewPager;
- private ViewGroup mHeader;
- private FloatingHeaderHandler mFloatingHeaderHandler;
+ private FloatingHeaderView mHeader;
private TabsPagerAdapter mTabsPagerAdapter;
private SpannableStringBuilder mSearchQueryBuilder = null;
@@ -95,6 +96,7 @@
private TransformingTouchDelegate mTouchDelegate;
private boolean mUsingTabs;
private boolean mHasPredictions = false;
+ private boolean mSearchModeWhileUsingTabs = false;
private final HashMap<ComponentKey, AppInfo> mComponentToAppMap = new HashMap<>();
@@ -231,8 +233,8 @@
for (int i = 0; i < mAH.length; i++) {
updatePromiseAppProgress(app, mAH[i].recyclerView);
}
- if (mFloatingHeaderHandler != null) {
- updatePromiseAppProgress(app, mFloatingHeaderHandler.getContentView());
+ if (isHeaderVisible()) {
+ updatePromiseAppProgress(app, mHeader.getPredictionRow());
}
}
@@ -259,9 +261,6 @@
if (mLauncher.getDragLayer().isEventOverView(mSearchContainer, ev)) {
return true;
}
- if (mUsingTabs && mLauncher.getDragLayer().isEventOverView(mHeader, ev)) {
- return true;
- }
AllAppsRecyclerView rv = getActiveRecyclerView();
return rv == null || rv.shouldContainerScroll(ev, mLauncher.getDragLayer());
}
@@ -283,8 +282,8 @@
mAH[i].recyclerView.scrollToTop();
}
}
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.reset();
+ if (isHeaderVisible()) {
+ mHeader.reset();
}
// Reset the search bar and base recycler view after transitioning home
mSearchUiManager.reset();
@@ -306,7 +305,6 @@
});
mHeader = findViewById(R.id.all_apps_header);
- mFloatingHeaderHandler = new FloatingHeaderHandler(mHeader);
rebindAdapters(mUsingTabs);
mSearchContainer = findViewById(R.id.search_container_all_apps);
@@ -444,7 +442,6 @@
if (FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
setupHeader();
} else {
- mFloatingHeaderHandler = null;
mHeader.setVisibility(View.GONE);
}
}
@@ -490,35 +487,29 @@
mViewPager.setAdapter(mTabsPagerAdapter = new TabsPagerAdapter());
mViewPager.addOnPageChangeListener(new ViewPager.OnPageChangeListener() {
- boolean mVisible = true;
-
@Override
public void onPageScrolled(int position, float positionOffset, int positionOffsetPixels) {
tabs.updateIndicatorPosition(position, positionOffset);
- if (positionOffset == 0 && !mVisible || positionOffset > 0 && mVisible) {
- mVisible = positionOffset == 0;
- for (int i = 0; i < mAH.length; i++) {
- if (mAH[i].recyclerView != null) {
- mAH[i].recyclerView.getScrollbar().setAlpha(mVisible ? 1 : 0);
- }
- }
- }
}
@Override
public void onPageSelected(int pos) {
tabs.updateTabTextColor(pos);
- mFloatingHeaderHandler.setMainActive(pos == 0);
+ mHeader.setMainActive(pos == 0);
applyTouchDelegate();
if (mAH[pos].recyclerView != null) {
mAH[pos].recyclerView.bindFastScrollbar();
}
+ if (pos == AdapterHolder.WORK) {
+ BottomUserEducationView.showIfNeeded(mLauncher);
+ }
}
@Override
public void onPageScrollStateChanged(int state) {
}
});
+ mAH[AdapterHolder.MAIN].recyclerView.bindFastScrollbar();
findViewById(R.id.tab_personal)
.setOnClickListener((View view) -> mViewPager.setCurrentItem(0));
@@ -527,14 +518,16 @@
}
public void setPredictedApps(List<ComponentKeyMapper<AppInfo>> apps) {
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.getContentView().setPredictedApps(apps);
+ if (isHeaderVisible()) {
+ mHeader.getPredictionRow().setPredictedApps(apps);
}
mAH[AdapterHolder.MAIN].appsList.setPredictedApps(apps);
boolean hasPredictions = !apps.isEmpty();
if (mHasPredictions != hasPredictions) {
mHasPredictions = hasPredictions;
- setupHeader();
+ if (FeatureFlags.ALL_APPS_PREDICTION_ROW_VIEW) {
+ setupHeader();
+ }
}
}
@@ -550,24 +543,26 @@
return mUsingTabs;
}
- public FloatingHeaderHandler getFloatingHeaderHandler() {
- return mFloatingHeaderHandler;
+ public FloatingHeaderView getFloatingHeaderView() {
+ return mHeader;
}
private void setupHeader() {
- if (mFloatingHeaderHandler == null) {
+ if (mHeader == null) {
return;
}
mHeader.setVisibility(View.VISIBLE);
- int contentHeight = mHasPredictions ? mLauncher.getDeviceProfile().allAppsCellHeightPx : 0;
- if (mHasPredictions && !mUsingTabs) {
+
+ boolean usePredictionRow = mHasPredictions && !mSearchModeWhileUsingTabs;
+ int contentHeight = usePredictionRow ? mLauncher.getDeviceProfile().allAppsCellHeightPx : 0;;
+ if (usePredictionRow && !mUsingTabs) {
contentHeight += getResources()
.getDimensionPixelSize(R.dimen.all_apps_prediction_row_divider_height);
}
- RecyclerView mainRV = mAH[AdapterHolder.MAIN].recyclerView;
- RecyclerView workRV = mAH[AdapterHolder.WORK].recyclerView;
- mFloatingHeaderHandler.setup(mainRV, workRV, contentHeight);
- mFloatingHeaderHandler.getContentView().setup(mAH[AdapterHolder.MAIN].adapter,
+ AllAppsRecyclerView mainRV = mAH[AdapterHolder.MAIN].recyclerView;
+ AllAppsRecyclerView workRV = mAH[AdapterHolder.WORK].recyclerView;
+ mHeader.setup(mainRV, workRV, contentHeight);
+ mHeader.getPredictionRow().setup(mAH[AdapterHolder.MAIN].adapter,
mComponentToAppMap, mNumPredictedAppsPerRow);
int padding = contentHeight;
@@ -584,6 +579,14 @@
for (int i = 0; i < mAH.length; i++) {
mAH[i].adapter.setLastSearchQuery(query);
}
+ boolean hasQuery = !TextUtils.isEmpty(query);
+ if (mUsingTabs && hasQuery) {
+ mSearchModeWhileUsingTabs = true;
+ rebindAdapters(false); // hide tabs
+ } else if (mSearchModeWhileUsingTabs && !hasQuery) {
+ mSearchModeWhileUsingTabs = false;
+ rebindAdapters(true); // show tabs
+ }
}
public void onSearchResultsChanged() {
@@ -623,12 +626,16 @@
public List<AppInfo> getPredictedApps() {
if (mUsingTabs) {
- return mFloatingHeaderHandler.getContentView().getPredictedApps();
+ return mHeader.getPredictionRow().getPredictedApps();
} else {
return mAH[AdapterHolder.MAIN].appsList.getPredictedApps();
}
}
+ private boolean isHeaderVisible() {
+ return mHeader != null && mHeader.getVisibility() == View.VISIBLE;
+ }
+
public class AdapterHolder {
public static final int MAIN = 0;
public static final int WORK = 1;
@@ -678,8 +685,8 @@
? paddingTopForTabs : padding.top;
recyclerView.setPadding(padding.left, paddingTop, padding.right, padding.bottom);
}
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.getContentView()
+ if (isHeaderVisible()) {
+ mHeader.getPredictionRow()
.setPadding(padding.left, 0 , padding.right, 0);
}
}
@@ -691,8 +698,8 @@
}
adapter.setNumAppsPerRow(mNumAppsPerRow);
appsList.setNumAppsPerRow(mNumAppsPerRow, mNumPredictedAppsPerRow);
- if (mFloatingHeaderHandler != null) {
- mFloatingHeaderHandler.getContentView()
+ if (isHeaderVisible()) {
+ mHeader.getPredictionRow()
.setNumAppsPerRow(mNumPredictedAppsPerRow);
}
}
diff --git a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
index 5789b67..fd80784 100644
--- a/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
+++ b/src/com/android/launcher3/allapps/AllAppsRecyclerView.java
@@ -31,7 +31,6 @@
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
import com.android.launcher3.R;
import com.android.launcher3.anim.SpringAnimationHandler;
import com.android.launcher3.config.FeatureFlags;
@@ -53,7 +52,6 @@
private AlphabeticalAppsList mApps;
private AllAppsFastScrollHelper mFastScrollHelper;
private int mNumAppsPerRow;
- private int mUserProfileTabContentHeight;
// The specific view heights that we use to calculate scroll
private SparseIntArray mViewHeights = new SparseIntArray();
@@ -127,8 +125,6 @@
public void setApps(AlphabeticalAppsList apps, boolean usingTabs) {
mApps = apps;
mFastScrollHelper = new AllAppsFastScrollHelper(this, apps);
- mUserProfileTabContentHeight = usingTabs
- ? Launcher.getLauncher(getContext()).getDeviceProfile().allAppsCellHeightPx : 0;;
}
public AlphabeticalAppsList getApps() {
@@ -362,6 +358,9 @@
*/
@Override
public void onUpdateScrollbar(int dy) {
+ if (mApps == null) {
+ return;
+ }
List<AlphabeticalAppsList.AdapterItem> items = mApps.getAdapterItems();
// Skip early if there are no items or we haven't been measured
@@ -488,18 +487,11 @@
@Override
protected int getAvailableScrollHeight() {
return getPaddingTop() + getCurrentScrollY(getAdapter().getItemCount(), 0)
- - getHeight() + getPaddingBottom() + mUserProfileTabContentHeight;
+ - getHeight() + getPaddingBottom();
}
public int getScrollBarTop() {
- return super.getScrollBarTop() + mUserProfileTabContentHeight;
- }
-
- /**
- * Returns the height of the fast scroll bar
- */
- public int getScrollbarTrackHeight() {
- return super.getScrollbarTrackHeight() + mUserProfileTabContentHeight;
+ return getResources().getDimensionPixelOffset(R.dimen.all_apps_header_top_padding);
}
public RecyclerViewFastScroller getScrollbar() {
diff --git a/src/com/android/launcher3/allapps/AllAppsTransitionController.java b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
index eb26704..7ce032f 100644
--- a/src/com/android/launcher3/allapps/AllAppsTransitionController.java
+++ b/src/com/android/launcher3/allapps/AllAppsTransitionController.java
@@ -4,7 +4,6 @@
import static com.android.launcher3.anim.Interpolators.LINEAR;
import android.animation.Animator;
-import android.animation.AnimatorInflater;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
@@ -54,10 +53,9 @@
}
};
- private final Interpolator mWorkspaceAccelnterpolator = Interpolators.ACCEL_2;
private final Interpolator mHotseatAccelInterpolator = Interpolators.ACCEL_1_5;
- private static final float PARALLAX_COEFFICIENT = .125f;
+ public static final float PARALLAX_COEFFICIENT = .125f;
private AllAppsContainerView mAppsView;
private Workspace mWorkspace;
@@ -77,8 +75,6 @@
private static final float DEFAULT_SHIFT_RANGE = 10;
- private boolean mIsTranslateWithoutWorkspace = false;
- private Animator mDiscoBounceAnimation;
private GradientView mGradientView;
public AllAppsTransitionController(Launcher l) {
@@ -134,7 +130,6 @@
float workspaceHotseatAlpha = Utilities.boundToRange(progress, 0f, 1f);
float alpha = 1 - workspaceHotseatAlpha;
- float workspaceAlpha = mWorkspaceAccelnterpolator.getInterpolation(workspaceHotseatAlpha);
float hotseatAlpha = mHotseatAccelInterpolator.getInterpolation(workspaceHotseatAlpha);
updateAllAppsBg(alpha);
@@ -150,12 +145,6 @@
hotseatAlpha);
}
- if (mIsTranslateWithoutWorkspace) {
- return;
- }
- mWorkspace.setWorkspaceYTranslationAndAlpha(
- PARALLAX_COEFFICIENT * (-mShiftRange + shiftCurrent), workspaceAlpha);
-
updateLightStatusBar(shiftCurrent);
}
@@ -191,7 +180,13 @@
this, PROGRESS, mProgress, toState.verticalProgress);
anim.setDuration(config.duration);
anim.setInterpolator(interpolator);
- anim.addListener(new AnimationSuccessListener() {
+ anim.addListener(getProgressAnimatorListener());
+
+ animationOut.play(anim);
+ }
+
+ public AnimatorListenerAdapter getProgressAnimatorListener() {
+ return new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
onProgressAnimationEnd();
@@ -201,50 +196,7 @@
public void onAnimationStart(Animator animation) {
onProgressAnimationStart();
}
- });
-
- animationOut.play(anim);
- }
-
- public void showDiscoveryBounce() {
- // cancel existing animation in case user locked and unlocked at a super human speed.
- cancelDiscoveryAnimation();
-
- // assumption is that this variable is always null
- mDiscoBounceAnimation = AnimatorInflater.loadAnimator(mLauncher,
- R.animator.discovery_bounce);
- mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationStart(Animator animator) {
- mIsTranslateWithoutWorkspace = true;
- onProgressAnimationStart();
- }
-
- @Override
- public void onAnimationEnd(Animator animator) {
- onProgressAnimationEnd();
- mDiscoBounceAnimation = null;
- mIsTranslateWithoutWorkspace = false;
- }
- });
- mDiscoBounceAnimation.setTarget(this);
- mAppsView.post(new Runnable() {
- @Override
- public void run() {
- if (mDiscoBounceAnimation == null) {
- return;
- }
- mDiscoBounceAnimation.start();
- }
- });
- }
-
- public void cancelDiscoveryAnimation() {
- if (mDiscoBounceAnimation == null) {
- return;
- }
- mDiscoBounceAnimation.cancel();
- mDiscoBounceAnimation = null;
+ };
}
public void setupViews(AllAppsContainerView appsView, Hotseat hotseat, Workspace workspace) {
diff --git a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
index 12715cb..2b9cba3 100644
--- a/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
+++ b/src/com/android/launcher3/allapps/AlphabeticalAppsList.java
@@ -301,7 +301,7 @@
if (mSearchResults != f) {
boolean same = mSearchResults != null && mSearchResults.equals(f);
mSearchResults = f;
- updateAdapterItems();
+ onAppsUpdated();
return !same;
}
return false;
@@ -403,7 +403,7 @@
mApps.clear();
for (AppInfo app : mComponentToAppMap.values()) {
- if (mItemFilter == null || mItemFilter.matches(app, null)) {
+ if (mItemFilter == null || mItemFilter.matches(app, null) || hasFilter()) {
mApps.add(app);
}
}
diff --git a/src/com/android/launcher3/allapps/DiscoveryBounce.java b/src/com/android/launcher3/allapps/DiscoveryBounce.java
new file mode 100644
index 0000000..550fcf9
--- /dev/null
+++ b/src/com/android/launcher3/allapps/DiscoveryBounce.java
@@ -0,0 +1,109 @@
+/*
+ * 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.allapps;
+
+import static com.android.launcher3.LauncherState.NORMAL;
+
+import android.animation.Animator;
+import android.animation.AnimatorInflater;
+import android.animation.AnimatorListenerAdapter;
+import android.view.MotionEvent;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.compat.UserManagerCompat;
+
+/**
+ * Floating view responsible for showing discovery bounce animation
+ */
+public class DiscoveryBounce extends AbstractFloatingView {
+
+ public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
+
+ private final Launcher mLauncher;
+ private final Animator mDiscoBounceAnimation;
+
+ public DiscoveryBounce(Launcher launcher) {
+ super(launcher, null);
+ mLauncher = launcher;
+
+ mDiscoBounceAnimation = AnimatorInflater.loadAnimator(mLauncher,
+ R.animator.discovery_bounce);
+ AllAppsTransitionController controller = mLauncher.getAllAppsController();
+ mDiscoBounceAnimation.setTarget(controller);
+ mDiscoBounceAnimation.addListener(controller.getProgressAnimatorListener());
+
+ mDiscoBounceAnimation.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ handleClose(false);
+ }
+ });
+ }
+
+ @Override
+ protected void onAttachedToWindow() {
+ super.onAttachedToWindow();
+ mDiscoBounceAnimation.start();
+ }
+
+ @Override
+ protected void onDetachedFromWindow() {
+ super.onDetachedFromWindow();
+ if (mDiscoBounceAnimation.isRunning()) {
+ mDiscoBounceAnimation.end();
+ }
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ handleClose(false);
+ return false;
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ if (mIsOpen) {
+ mIsOpen = false;
+ mLauncher.getDragLayer().removeView(this);
+ }
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // Since this is on-boarding popup, it is not a user controlled action.
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_ON_BOARD_POPUP) != 0;
+ }
+
+ public static void showIfNeeded(Launcher launcher) {
+ if (!launcher.isInState(NORMAL)
+ || launcher.getSharedPrefs().getBoolean(APPS_VIEW_SHOWN, false)
+ || AbstractFloatingView.getTopOpenView(launcher) != null
+ || UserManagerCompat.getInstance(launcher).isDemoUser()) {
+ return;
+ }
+
+ DiscoveryBounce view = new DiscoveryBounce(launcher);
+ view.mIsOpen = true;
+ launcher.getDragLayer().addView(view);
+ }
+}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderHandler.java b/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
deleted file mode 100644
index c4b533b..0000000
--- a/src/com/android/launcher3/allapps/FloatingHeaderHandler.java
+++ /dev/null
@@ -1,215 +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.allapps;
-
-import android.animation.ValueAnimator;
-import android.content.res.Resources;
-import android.graphics.Rect;
-import android.support.annotation.NonNull;
-import android.support.annotation.Nullable;
-import android.support.v7.widget.RecyclerView;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.RelativeLayout;
-
-import com.android.launcher3.R;
-
-public class FloatingHeaderHandler extends RecyclerView.OnScrollListener
- implements ValueAnimator.AnimatorUpdateListener {
-
- private final View mHeaderView;
- private final PredictionRowView mPredictionRow;
- private final ViewGroup mTabLayout;
- private final View mDivider;
- private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
- private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
-
- private RecyclerView mMainRV;
- private RecyclerView mWorkRV;
- private boolean mTopOnlyMode;
- private boolean mHeaderHidden;
- private int mMaxTranslation;
- private int mSnappedScrolledY;
- private int mTranslationY;
- private int mMainScrolledY;
- private int mWorkScrolledY;
- private boolean mMainRVActive;
-
- public FloatingHeaderHandler(@NonNull ViewGroup header) {
- mHeaderView = header;
- mTabLayout = header.findViewById(R.id.tabs);
- mDivider = header.findViewById(R.id.divider);
- mPredictionRow = header.findViewById(R.id.header_content);
- }
-
- public void setup(@NonNull RecyclerView personalRV, @Nullable RecyclerView workRV,
- int predictionRowHeight) {
- mTopOnlyMode = workRV == null;
- mTabLayout.setVisibility(mTopOnlyMode ? View.GONE : View.VISIBLE);
- mPredictionRow.getLayoutParams().height = predictionRowHeight;
- mMaxTranslation = predictionRowHeight;
- mMainRV = personalRV;
- mMainRV.addOnScrollListener(this);
- mWorkRV = workRV;
- if (workRV != null) {
- workRV.addOnScrollListener(this);
- }
- setMainActive(true);
- setupDivider();
- }
-
- private void setupDivider() {
- Resources res = mHeaderView.getResources();
- int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
- int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
- mDivider.setPadding(sideGap, verticalGap,sideGap, mTopOnlyMode ? verticalGap : 0);
- RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
- lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
- lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTopOnlyMode ? R.id.header_content : R.id.tabs);
- mDivider.setLayoutParams(lp);
- }
-
- public void setMainActive(boolean active) {
- mMainRVActive = active;
- mSnappedScrolledY = getCurrentScroll() - mMaxTranslation;
- setExpanded(true);
- }
-
- public View getHeaderView() {
- return mHeaderView;
- }
-
- public PredictionRowView getContentView() {
- return mPredictionRow;
- }
-
- public ViewGroup getTabLayout() {
- return mTabLayout;
- }
-
- public View getDivider() {
- return mDivider;
- }
-
- @Override
- public void onScrolled(RecyclerView rv, int dx, int dy) {
- boolean isMainRV = rv == mMainRV;
- if (isMainRV != mMainRVActive) {
- return;
- }
-
- if (mAnimator.isStarted()) {
- mAnimator.cancel();
- }
-
- int current = isMainRV
- ? (mMainScrolledY -= dy)
- : (mWorkScrolledY -= dy);
-
- moved(current);
- apply();
- }
-
- public void reset() {
- mMainScrolledY = 0;
- mWorkScrolledY = 0;
- setExpanded(true);
- }
-
- private boolean canSnapAt(int currentScrollY) {
- return !mTopOnlyMode || Math.abs(currentScrollY) <= mPredictionRow.getHeight();
- }
-
- private void moved(final int currentScrollY) {
- if (mHeaderHidden) {
- if (currentScrollY <= mSnappedScrolledY) {
- if (canSnapAt(currentScrollY)) {
- mSnappedScrolledY = currentScrollY;
- }
- } else {
- mHeaderHidden = false;
- }
- mTranslationY = currentScrollY;
- } else if (!mHeaderHidden) {
- mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
-
- // update state vars
- if (mTranslationY >= 0) { // expanded: must not move down further
- mTranslationY = 0;
- mSnappedScrolledY = currentScrollY - mMaxTranslation;
- } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
- mHeaderHidden = true;
- mSnappedScrolledY = currentScrollY;
- }
- }
- }
-
- private void apply() {
- int uncappedTranslationY = mTranslationY;
- mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
- if (mTranslationY != uncappedTranslationY) {
- // we hide it completely if already capped (for opening search anim)
- mPredictionRow.setVisibility(View.INVISIBLE);
- } else {
- mPredictionRow.setVisibility(View.VISIBLE);
- mPredictionRow.setTranslationY(uncappedTranslationY);
- }
- mTabLayout.setTranslationY(mTranslationY);
- mDivider.setTranslationY(mTopOnlyMode ? uncappedTranslationY : mTranslationY);
- mClip.top = mMaxTranslation + mTranslationY;
- // clipping on a draw might cause additional redraw
- mMainRV.setClipBounds(mClip);
- if (mWorkRV != null) {
- mWorkRV.setClipBounds(mClip);
- }
- }
-
- @Override
- public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
- if (!mTopOnlyMode && newState == RecyclerView.SCROLL_STATE_IDLE
- && mTranslationY != -mMaxTranslation && mTranslationY != 0) {
- float scroll = Math.abs(getCurrentScroll());
- boolean expand = scroll > mMaxTranslation
- ? Math.abs(mTranslationY) < mMaxTranslation / 2 : true;
- setExpanded(expand);
- }
- }
-
- private void setExpanded(boolean expand) {
- int translateTo = expand ? 0 : -mMaxTranslation;
- mAnimator.setIntValues(mTranslationY, translateTo);
- mAnimator.addUpdateListener(this);
- mAnimator.setDuration(150);
- mAnimator.start();
- mHeaderHidden = !expand;
- mSnappedScrolledY = expand ? getCurrentScroll() - mMaxTranslation : getCurrentScroll();
- }
-
- public boolean isExpanded() {
- return !mHeaderHidden;
- }
-
- private int getCurrentScroll() {
- return mMainRVActive ? mMainScrolledY : mWorkScrolledY;
- }
-
- @Override
- public void onAnimationUpdate(ValueAnimator animation) {
- mTranslationY = (Integer) animation.getAnimatedValue();
- apply();
- }
-
-}
diff --git a/src/com/android/launcher3/allapps/FloatingHeaderView.java b/src/com/android/launcher3/allapps/FloatingHeaderView.java
new file mode 100644
index 0000000..4f1a0d5
--- /dev/null
+++ b/src/com/android/launcher3/allapps/FloatingHeaderView.java
@@ -0,0 +1,273 @@
+/*
+ * 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.allapps;
+
+
+import android.animation.ValueAnimator;
+import android.content.Context;
+import android.content.res.Resources;
+import android.graphics.Point;
+import android.graphics.Rect;
+import android.support.annotation.NonNull;
+import android.support.annotation.Nullable;
+import android.support.v7.widget.RecyclerView;
+import android.util.AttributeSet;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.RelativeLayout;
+
+import com.android.launcher3.R;
+
+public class FloatingHeaderView extends RelativeLayout implements
+ ValueAnimator.AnimatorUpdateListener {
+
+ private static final boolean SHOW_PREDICTIONS_ONLY_ON_TOP = true;
+
+ private final Rect mClip = new Rect(0, 0, Integer.MAX_VALUE, Integer.MAX_VALUE);
+ private final ValueAnimator mAnimator = ValueAnimator.ofInt(0, 0);
+ private final Point mTempOffset = new Point();
+ private final RecyclerView.OnScrollListener mOnScrollListener = new RecyclerView.OnScrollListener() {
+ @Override
+ public void onScrollStateChanged(RecyclerView recyclerView, int newState) {
+ if (SHOW_PREDICTIONS_ONLY_ON_TOP) {
+ return;
+ }
+ if (!mTopOnlyMode && newState == RecyclerView.SCROLL_STATE_IDLE
+ && mTranslationY != -mMaxTranslation && mTranslationY != 0) {
+ float scroll = Math.abs(getCurrentScroll());
+ boolean expand = scroll > mMaxTranslation
+ ? Math.abs(mTranslationY) < mMaxTranslation / 2 : true;
+ setExpanded(expand);
+ }
+ }
+
+ @Override
+ public void onScrolled(RecyclerView rv, int dx, int dy) {
+ boolean isMainRV = rv == mMainRV;
+ if (isMainRV != mMainRVActive) {
+ return;
+ }
+
+ if (mAnimator.isStarted()) {
+ mAnimator.cancel();
+ }
+
+ int current = - (isMainRV
+ ? mMainRV.getCurrentScrollY()
+ : mWorkRV.getCurrentScrollY());
+ moved(current);
+ apply();
+ }
+ };
+
+ private PredictionRowView mPredictionRow;
+ private ViewGroup mTabLayout;
+ private View mDivider;
+ private AllAppsRecyclerView mMainRV;
+ private AllAppsRecyclerView mWorkRV;
+ private ViewGroup mParent;
+ private boolean mTopOnlyMode;
+ private boolean mHeaderHidden;
+ private int mMaxTranslation;
+ private int mSnappedScrolledY;
+ private int mTranslationY;
+ private int mMainScrolledY;
+ private int mWorkScrolledY;
+ private boolean mMainRVActive = true;
+ private boolean mForwardToRecyclerView;
+
+ public FloatingHeaderView(@NonNull Context context) {
+ this(context, null);
+ }
+
+ public FloatingHeaderView(@NonNull Context context, @Nullable AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mTabLayout = findViewById(R.id.tabs);
+ mDivider = findViewById(R.id.divider);
+ mPredictionRow = findViewById(R.id.header_content);
+ }
+
+ public void setup(@NonNull AllAppsRecyclerView personalRV, @Nullable AllAppsRecyclerView workRV,
+ int predictionRowHeight) {
+ mTopOnlyMode = workRV == null;
+ mTabLayout.setVisibility(mTopOnlyMode ? View.GONE : View.VISIBLE);
+ mPredictionRow.getLayoutParams().height = predictionRowHeight;
+ mMaxTranslation = predictionRowHeight;
+ mMainRV = setupRV(mMainRV, personalRV);
+ mWorkRV = setupRV(mWorkRV, workRV);
+ mParent = (ViewGroup) getRV().getParent();
+ setMainActive(true);
+ setupDivider();
+ }
+
+ private AllAppsRecyclerView setupRV(AllAppsRecyclerView old, AllAppsRecyclerView updated) {
+ if (old != updated && updated != null ) {
+ updated.addOnScrollListener(mOnScrollListener);
+ }
+ return updated;
+ }
+
+ private void setupDivider() {
+ Resources res = getResources();
+ int verticalGap = res.getDimensionPixelSize(R.dimen.all_apps_divider_margin_vertical);
+ int sideGap = res.getDimensionPixelSize(R.dimen.dynamic_grid_edge_margin);
+ mDivider.setPadding(sideGap, verticalGap,sideGap, mTopOnlyMode ? verticalGap : 0);
+ RelativeLayout.LayoutParams lp = (RelativeLayout.LayoutParams) mDivider.getLayoutParams();
+ lp.removeRule(RelativeLayout.ALIGN_BOTTOM);
+ lp.addRule(RelativeLayout.ALIGN_BOTTOM, mTopOnlyMode ? R.id.header_content : R.id.tabs);
+ mDivider.setLayoutParams(lp);
+ }
+
+ public void setMainActive(boolean active) {
+ mMainRVActive = active;
+ mSnappedScrolledY = getCurrentScroll() - mMaxTranslation;
+ setExpanded(true);
+ }
+
+ public PredictionRowView getPredictionRow() {
+ return mPredictionRow;
+ }
+
+ public ViewGroup getTabLayout() {
+ return mTabLayout;
+ }
+
+ public View getDivider() {
+ return mDivider;
+ }
+
+ public void reset() {
+ mMainScrolledY = 0;
+ mWorkScrolledY = 0;
+ setExpanded(true);
+ }
+
+ private boolean canSnapAt(int currentScrollY) {
+ boolean snapOnlyOnTop = SHOW_PREDICTIONS_ONLY_ON_TOP || mTopOnlyMode;
+ return !snapOnlyOnTop || Math.abs(currentScrollY) <= mPredictionRow.getHeight();
+ }
+
+ private void moved(final int currentScrollY) {
+ if (mHeaderHidden) {
+ if (currentScrollY <= mSnappedScrolledY) {
+ if (canSnapAt(currentScrollY)) {
+ mSnappedScrolledY = currentScrollY;
+ }
+ } else {
+ mHeaderHidden = false;
+ }
+ mTranslationY = currentScrollY;
+ } else if (!mHeaderHidden) {
+ mTranslationY = currentScrollY - mSnappedScrolledY - mMaxTranslation;
+
+ // update state vars
+ if (mTranslationY >= 0) { // expanded: must not move down further
+ mTranslationY = 0;
+ mSnappedScrolledY = currentScrollY - mMaxTranslation;
+ } else if (mTranslationY <= -mMaxTranslation) { // hide or stay hidden
+ mHeaderHidden = true;
+ mSnappedScrolledY = currentScrollY;
+ }
+ }
+ }
+
+ private void apply() {
+ int uncappedTranslationY = mTranslationY;
+ mTranslationY = Math.max(mTranslationY, -mMaxTranslation);
+ if (mTranslationY != uncappedTranslationY) {
+ // we hide it completely if already capped (for opening search anim)
+ mPredictionRow.setVisibility(View.INVISIBLE);
+ } else {
+ mPredictionRow.setVisibility(View.VISIBLE);
+ mPredictionRow.setTranslationY(uncappedTranslationY);
+ }
+ mTabLayout.setTranslationY(mTranslationY);
+ mDivider.setTranslationY(mTopOnlyMode ? uncappedTranslationY : mTranslationY);
+ mClip.top = mMaxTranslation + mTranslationY;
+ // clipping on a draw might cause additional redraw
+ mMainRV.setClipBounds(mClip);
+ if (mWorkRV != null) {
+ mWorkRV.setClipBounds(mClip);
+ }
+ }
+
+ private void setExpanded(boolean expand) {
+ int translateTo = expand ? 0 : -mMaxTranslation;
+ mAnimator.setIntValues(mTranslationY, translateTo);
+ mAnimator.addUpdateListener(this);
+ mAnimator.setDuration(150);
+ mAnimator.start();
+ mHeaderHidden = !expand;
+ mSnappedScrolledY = expand ? getCurrentScroll() - mMaxTranslation : getCurrentScroll();
+ }
+
+ public boolean isExpanded() {
+ return !mHeaderHidden;
+ }
+
+ private int getCurrentScroll() {
+ return mMainRVActive ? mMainScrolledY : mWorkScrolledY;
+ }
+
+ @Override
+ public void onAnimationUpdate(ValueAnimator animation) {
+ mTranslationY = (Integer) animation.getAnimatedValue();
+ apply();
+ }
+
+ private AllAppsRecyclerView getRV() {
+ return mMainRVActive ? mMainRV : mWorkRV;
+ }
+
+ @Override
+ public boolean onInterceptTouchEvent(MotionEvent ev) {
+ calcOffset(mTempOffset);
+ ev.offsetLocation(mTempOffset.x, mTempOffset.y);
+ mForwardToRecyclerView = getRV().onInterceptTouchEvent(ev);
+ ev.offsetLocation(-mTempOffset.x, -mTempOffset.y);
+ return mForwardToRecyclerView || super.onInterceptTouchEvent(ev);
+ }
+
+ @Override
+ public boolean onTouchEvent(MotionEvent event) {
+ if (mForwardToRecyclerView) {
+ // take this view's and parent view's (view pager) location into account
+ calcOffset(mTempOffset);
+ event.offsetLocation(mTempOffset.x, mTempOffset.y);
+ try {
+ return getRV().onTouchEvent(event);
+ } finally {
+ event.offsetLocation(-mTempOffset.x, -mTempOffset.y);
+ }
+ } else {
+ return super.onTouchEvent(event);
+ }
+ }
+
+ private void calcOffset(Point p) {
+ p.x = getLeft() - getRV().getLeft() - mParent.getLeft();
+ p.y = getTop() - getRV().getTop() - mParent.getTop();
+ }
+
+}
+
+
diff --git a/src/com/android/launcher3/dragndrop/DragLayer.java b/src/com/android/launcher3/dragndrop/DragLayer.java
index 9f9822c..cf76e2e 100644
--- a/src/com/android/launcher3/dragndrop/DragLayer.java
+++ b/src/com/android/launcher3/dragndrop/DragLayer.java
@@ -45,7 +45,6 @@
import com.android.launcher3.R;
import com.android.launcher3.ShortcutAndWidgetContainer;
import com.android.launcher3.Utilities;
-import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
@@ -90,9 +89,6 @@
private final ViewGroupFocusHelper mFocusIndicatorHelper;
private final PageCutOutScrimDrawable mPageCutOutScrim;
- // Handles all apps pull up interaction
- private AllAppsTransitionController mAllAppsController;
-
protected TouchController[] mControllers;
private TouchController mActiveController;
/**
@@ -113,11 +109,9 @@
mPageCutOutScrim.setCallback(this);
}
- public void setup(Launcher launcher, DragController dragController,
- AllAppsTransitionController allAppsTransitionController) {
+ public void setup(Launcher launcher, DragController dragController) {
mLauncher = launcher;
mDragController = dragController;
- mAllAppsController = allAppsTransitionController;
mControllers = UiFactory.createTouchControllers(mLauncher);
}
@@ -156,12 +150,7 @@
public boolean onInterceptTouchEvent(MotionEvent ev) {
int action = ev.getAction();
- if (action == MotionEvent.ACTION_DOWN) {
- // Cancel discovery bounce animation when a user start interacting on anywhere on
- // dray layer even if mAllAppsController is NOT the active controller.
- // TODO: handle other input other than touch
- mAllAppsController.cancelDiscoveryAnimation();
- } else if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
+ if (action == MotionEvent.ACTION_UP || action == MotionEvent.ACTION_CANCEL) {
if (mTouchCompleteListener != null) {
mTouchCompleteListener.onTouchComplete();
}
@@ -800,6 +789,6 @@
}
public interface TouchCompleteListener {
- public void onTouchComplete();
+ void onTouchComplete();
}
}
diff --git a/src/com/android/launcher3/states/SpringLoadedState.java b/src/com/android/launcher3/states/SpringLoadedState.java
index 3864e3a..995cdaa 100644
--- a/src/com/android/launcher3/states/SpringLoadedState.java
+++ b/src/com/android/launcher3/states/SpringLoadedState.java
@@ -35,7 +35,8 @@
public class SpringLoadedState extends LauncherState {
private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
- FLAG_DISABLE_ACCESSIBILITY | FLAG_DO_NOT_RESTORE;
+ FLAG_DISABLE_ACCESSIBILITY | FLAG_DISABLE_RESTORE | FLAG_WORKSPACE_ICONS_CAN_BE_DRAGGED |
+ FLAG_DISABLE_PAGE_CLIPPING;
// Determines how long to wait after a rotation before restoring the screen orientation to
// match the sensor state.
diff --git a/src/com/android/launcher3/views/AbstractSlideInView.java b/src/com/android/launcher3/views/AbstractSlideInView.java
new file mode 100644
index 0000000..7c4529d
--- /dev/null
+++ b/src/com/android/launcher3/views/AbstractSlideInView.java
@@ -0,0 +1,182 @@
+/*
+ * 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.views;
+
+import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
+
+import android.animation.Animator;
+import android.animation.AnimatorListenerAdapter;
+import android.animation.ObjectAnimator;
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.util.AttributeSet;
+import android.util.Property;
+import android.view.MotionEvent;
+import android.view.View;
+import android.view.animation.Interpolator;
+
+import com.android.launcher3.AbstractFloatingView;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.LauncherAnimUtils;
+import com.android.launcher3.Utilities;
+import com.android.launcher3.anim.Interpolators;
+import com.android.launcher3.touch.SwipeDetector;
+
+/**
+ * Extension of AbstractFloatingView with common methods for sliding in from bottom
+ */
+public abstract class AbstractSlideInView extends AbstractFloatingView
+ implements SwipeDetector.Listener {
+
+ protected static Property<AbstractSlideInView, Float> TRANSLATION_SHIFT =
+ new Property<AbstractSlideInView, Float>(Float.class, "translationShift") {
+
+ @Override
+ public Float get(AbstractSlideInView view) {
+ return view.mTranslationShift;
+ }
+
+ @Override
+ public void set(AbstractSlideInView view, Float value) {
+ view.setTranslationShift(value);
+ }
+ };
+ protected static final float TRANSLATION_SHIFT_CLOSED = 1f;
+ protected static final float TRANSLATION_SHIFT_OPENED = 0f;
+
+ protected final Launcher mLauncher;
+ protected final SwipeDetector mSwipeDetector;
+ protected final ObjectAnimator mOpenCloseAnimator;
+
+ protected View mContent;
+ protected Interpolator mScrollInterpolator;
+
+ // range [0, 1], 0=> completely open, 1=> completely closed
+ protected float mTranslationShift = TRANSLATION_SHIFT_CLOSED;
+
+ protected boolean mNoIntercept;
+
+ public AbstractSlideInView(Context context, AttributeSet attrs, int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mLauncher = Launcher.getLauncher(context);
+
+ mScrollInterpolator = Interpolators.SCROLL_CUBIC;
+ mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
+
+ mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
+ mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ mSwipeDetector.finishedScrolling();
+ }
+ });
+ }
+
+ protected void setTranslationShift(float translationShift) {
+ mTranslationShift = translationShift;
+ mContent.setTranslationY(mTranslationShift * mContent.getHeight());
+ }
+
+ @Override
+ public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
+ if (mNoIntercept) {
+ return false;
+ }
+
+ int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
+ SwipeDetector.DIRECTION_NEGATIVE : 0;
+ mSwipeDetector.setDetectableScrollConditions(
+ directionsToDetectScroll, false);
+ mSwipeDetector.onTouchEvent(ev);
+ return mSwipeDetector.isDraggingOrSettling()
+ || !mLauncher.getDragLayer().isEventOverView(mContent, ev);
+ }
+
+ @Override
+ public boolean onControllerTouchEvent(MotionEvent ev) {
+ mSwipeDetector.onTouchEvent(ev);
+ if (ev.getAction() == MotionEvent.ACTION_UP && mSwipeDetector.isIdleState()) {
+ // If we got ACTION_UP without ever starting swipe, close the panel.
+ if (!mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
+ close(true);
+ }
+ }
+ return true;
+ }
+
+ /* SwipeDetector.Listener */
+
+ @Override
+ public void onDragStart(boolean start) { }
+
+ @Override
+ public boolean onDrag(float displacement, float velocity) {
+ float range = mContent.getHeight();
+ displacement = Utilities.boundToRange(displacement, 0, range);
+ setTranslationShift(displacement / range);
+ return true;
+ }
+
+ @Override
+ public void onDragEnd(float velocity, boolean fling) {
+ if ((fling && velocity > 0) || mTranslationShift > 0.5f) {
+ mScrollInterpolator = scrollInterpolatorForVelocity(velocity);
+ mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(
+ velocity, TRANSLATION_SHIFT_CLOSED - mTranslationShift));
+ close(true);
+ } else {
+ mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(
+ TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator.setDuration(
+ SwipeDetector.calculateDuration(velocity, mTranslationShift))
+ .setInterpolator(Interpolators.DEACCEL);
+ mOpenCloseAnimator.start();
+ }
+ }
+
+ protected void handleClose(boolean animate, long defaultDuration) {
+ if (mIsOpen && !animate) {
+ mOpenCloseAnimator.cancel();
+ setTranslationShift(TRANSLATION_SHIFT_CLOSED);
+ onCloseComplete();
+ return;
+ }
+ if (!mIsOpen || mOpenCloseAnimator.isRunning()) {
+ return;
+ }
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_CLOSED));
+ mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
+ @Override
+ public void onAnimationEnd(Animator animation) {
+ onCloseComplete();
+ }
+ });
+ if (mSwipeDetector.isIdleState()) {
+ mOpenCloseAnimator
+ .setDuration(defaultDuration)
+ .setInterpolator(Interpolators.ACCEL);
+ } else {
+ mOpenCloseAnimator.setInterpolator(mScrollInterpolator);
+ }
+ mOpenCloseAnimator.start();
+ }
+
+ protected void onCloseComplete() {
+ mIsOpen = false;
+ mLauncher.getDragLayer().removeView(this);
+ }
+}
diff --git a/src/com/android/launcher3/views/BottomUserEducationView.java b/src/com/android/launcher3/views/BottomUserEducationView.java
new file mode 100644
index 0000000..d79d0ce
--- /dev/null
+++ b/src/com/android/launcher3/views/BottomUserEducationView.java
@@ -0,0 +1,113 @@
+/*
+ * 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.views;
+
+import android.animation.PropertyValuesHolder;
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.LayoutInflater;
+
+import com.android.launcher3.Insettable;
+import com.android.launcher3.Launcher;
+import com.android.launcher3.R;
+import com.android.launcher3.anim.Interpolators;
+
+public class BottomUserEducationView extends AbstractSlideInView implements Insettable {
+
+ private static final String KEY_SHOWED_BOTTOM_USER_EDUCATION = "showed_bottom_user_education";
+
+ private static final int DEFAULT_CLOSE_DURATION = 200;
+
+ private final Rect mInsets = new Rect();
+
+ public BottomUserEducationView(Context context, AttributeSet attr) {
+ this(context, attr, 0);
+ }
+
+ public BottomUserEducationView(Context context, AttributeSet attrs,
+ int defStyleAttr) {
+ super(context, attrs, defStyleAttr);
+ mContent = this;
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int l, int t, int r, int b) {
+ super.onLayout(changed, l, t, r, b);
+ setTranslationShift(mTranslationShift);
+ }
+
+ @Override
+ public void logActionCommand(int command) {
+ // Since this is on-boarding popup, it is not a user controlled action.
+ }
+
+ @Override
+ protected boolean isOfType(int type) {
+ return (type & TYPE_ON_BOARD_POPUP) != 0;
+ }
+
+ @Override
+ public void setInsets(Rect insets) {
+ // Extend behind left, right, and bottom insets.
+ int leftInset = insets.left - mInsets.left;
+ int rightInset = insets.right - mInsets.right;
+ int bottomInset = insets.bottom - mInsets.bottom;
+ mInsets.set(insets);
+ setPadding(getPaddingLeft() + leftInset, getPaddingTop(),
+ getPaddingRight() + rightInset, getPaddingBottom() + bottomInset);
+ }
+
+ @Override
+ protected void handleClose(boolean animate) {
+ handleClose(animate, DEFAULT_CLOSE_DURATION);
+ if (animate) {
+ // We animate only when the user is visible, which is a proxy for an explicit
+ // close action.
+ mLauncher.getSharedPrefs().edit()
+ .putBoolean(KEY_SHOWED_BOTTOM_USER_EDUCATION, true).apply();
+ }
+ }
+
+ private void open(boolean animate) {
+ if (mIsOpen || mOpenCloseAnimator.isRunning()) {
+ return;
+ }
+ mIsOpen = true;
+ if (animate) {
+ mOpenCloseAnimator.setValues(
+ PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
+ mOpenCloseAnimator.setInterpolator(Interpolators.FAST_OUT_SLOW_IN);
+ mOpenCloseAnimator.start();
+ } else {
+ setTranslationShift(TRANSLATION_SHIFT_OPENED);
+ }
+ }
+
+ public static void showIfNeeded(Launcher launcher) {
+ if (launcher.getSharedPrefs().getBoolean(KEY_SHOWED_BOTTOM_USER_EDUCATION, false)) {
+ return;
+ }
+
+ LayoutInflater layoutInflater = LayoutInflater.from(launcher);
+ BottomUserEducationView bottomUserEducationView =
+ (BottomUserEducationView) layoutInflater.inflate(
+ R.layout.work_tab_bottom_user_education_view, launcher.getDragLayer(),
+ false);
+ launcher.getDragLayer().addView(bottomUserEducationView);
+ bottomUserEducationView.open(true);
+ }
+}
diff --git a/src/com/android/launcher3/views/RecyclerViewFastScroller.java b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
index 8f20a8d..fc121d3 100644
--- a/src/com/android/launcher3/views/RecyclerViewFastScroller.java
+++ b/src/com/android/launcher3/views/RecyclerViewFastScroller.java
@@ -141,10 +141,11 @@
}
public void setRecyclerView(BaseRecyclerView rv, TextView popupView) {
- mRv = rv;
- if (mOnScrollListener != null) {
+ if (mRv != null && mOnScrollListener != null) {
mRv.removeOnScrollListener(mOnScrollListener);
}
+ mRv = rv;
+
mRv.addOnScrollListener(mOnScrollListener = new RecyclerView.OnScrollListener() {
@Override
public void onScrolled(RecyclerView recyclerView, int dx, int dy) {
@@ -321,7 +322,7 @@
* Returns whether the specified point is inside the thumb bounds.
*/
private boolean isNearThumb(int x, int y) {
- int offset = y - mRv.getScrollBarTop() - mThumbOffsetY;
+ int offset = y - mThumbOffsetY;
return x >= 0 && x < getWidth() && offset >= 0 && offset <= mThumbHeight;
}
diff --git a/src/com/android/launcher3/widget/BaseWidgetSheet.java b/src/com/android/launcher3/widget/BaseWidgetSheet.java
index e328759..fa82714 100644
--- a/src/com/android/launcher3/widget/BaseWidgetSheet.java
+++ b/src/com/android/launcher3/widget/BaseWidgetSheet.java
@@ -15,94 +15,43 @@
*/
package com.android.launcher3.widget;
-import static com.android.launcher3.anim.Interpolators.scrollInterpolatorForVelocity;
import static com.android.launcher3.logging.LoggerUtils.newContainerTarget;
-import android.animation.Animator;
-import android.animation.AnimatorListenerAdapter;
-import android.animation.ObjectAnimator;
-import android.animation.PropertyValuesHolder;
import android.content.Context;
import android.graphics.Point;
import android.util.AttributeSet;
-import android.util.Property;
-import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
-import android.view.animation.Interpolator;
import android.widget.Toast;
-import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.DragSource;
import com.android.launcher3.DropTarget.DragObject;
import com.android.launcher3.ItemInfo;
-import com.android.launcher3.Launcher;
-import com.android.launcher3.LauncherAnimUtils;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.anim.Interpolators;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.graphics.GradientView;
-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.util.SystemUiController;
import com.android.launcher3.util.Themes;
+import com.android.launcher3.views.AbstractSlideInView;
/**
* Base class for various widgets popup
*/
-abstract class BaseWidgetSheet extends AbstractFloatingView
- implements OnClickListener, OnLongClickListener, DragSource, SwipeDetector.Listener {
+abstract class BaseWidgetSheet extends AbstractSlideInView
+ implements OnClickListener, OnLongClickListener, DragSource {
- protected static Property<BaseWidgetSheet, Float> TRANSLATION_SHIFT =
- new Property<BaseWidgetSheet, Float>(Float.class, "translationShift") {
-
- @Override
- public Float get(BaseWidgetSheet view) {
- return view.mTranslationShift;
- }
-
- @Override
- public void set(BaseWidgetSheet view, Float value) {
- view.setTranslationShift(value);
- }
- };
- protected static final float TRANSLATION_SHIFT_CLOSED = 1f;
- protected static final float TRANSLATION_SHIFT_OPENED = 0f;
-
/* Touch handling related member variables. */
private Toast mWidgetInstructionToast;
- protected final Launcher mLauncher;
- protected final SwipeDetector mSwipeDetector;
- protected final ObjectAnimator mOpenCloseAnimator;
-
- protected View mContent;
protected GradientView mGradientView;
- protected Interpolator mScrollInterpolator;
-
- // range [0, 1], 0=> completely open, 1=> completely closed
- protected float mTranslationShift = TRANSLATION_SHIFT_CLOSED;
-
- protected boolean mNoIntercept;
public BaseWidgetSheet(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
- mLauncher = Launcher.getLauncher(context);
-
- mScrollInterpolator = Interpolators.SCROLL_CUBIC;
- mSwipeDetector = new SwipeDetector(context, this, SwipeDetector.VERTICAL);
-
- mOpenCloseAnimator = LauncherAnimUtils.ofPropertyValuesHolder(this);
- mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- mSwipeDetector.finishedScrolling();
- }
- });
}
@Override
@@ -130,9 +79,8 @@
}
protected void setTranslationShift(float translationShift) {
- mTranslationShift = translationShift;
+ super.setTranslationShift(translationShift);
mGradientView.setAlpha(1 - mTranslationShift);
- mContent.setTranslationY(mTranslationShift * mContent.getHeight());
}
private boolean beginDraggingWidget(WidgetCell v) {
@@ -163,94 +111,8 @@
public void onDropCompleted(View target, DragObject d, boolean success) { }
- @Override
- public boolean onControllerInterceptTouchEvent(MotionEvent ev) {
- if (ev.getAction() == MotionEvent.ACTION_UP && !mNoIntercept) {
- // If we got ACTION_UP without ever returning true on intercept,
- // the user never started dragging the bottom sheet.
- if (!mLauncher.getDragLayer().isEventOverView(mContent, ev)) {
- close(true);
- return false;
- }
- }
-
- if (mNoIntercept) {
- return false;
- }
-
- int directionsToDetectScroll = mSwipeDetector.isIdleState() ?
- SwipeDetector.DIRECTION_NEGATIVE : 0;
- mSwipeDetector.setDetectableScrollConditions(
- directionsToDetectScroll, false);
- mSwipeDetector.onTouchEvent(ev);
- return mSwipeDetector.isDraggingOrSettling();
- }
-
- @Override
- public boolean onControllerTouchEvent(MotionEvent ev) {
- return mSwipeDetector.onTouchEvent(ev);
- }
-
- /* SwipeDetector.Listener */
-
- @Override
- public void onDragStart(boolean start) { }
-
- @Override
- public boolean onDrag(float displacement, float velocity) {
- float range = mContent.getHeight();
- displacement = Utilities.boundToRange(displacement, 0, range);
- setTranslationShift(displacement / range);
- return true;
- }
-
- @Override
- public void onDragEnd(float velocity, boolean fling) {
- if ((fling && velocity > 0) || mTranslationShift > 0.5f) {
- mScrollInterpolator = scrollInterpolatorForVelocity(velocity);
- mOpenCloseAnimator.setDuration(SwipeDetector.calculateDuration(
- velocity, TRANSLATION_SHIFT_CLOSED - mTranslationShift));
- close(true);
- } else {
- mOpenCloseAnimator.setValues(PropertyValuesHolder.ofFloat(
- TRANSLATION_SHIFT, TRANSLATION_SHIFT_OPENED));
- mOpenCloseAnimator.setDuration(
- SwipeDetector.calculateDuration(velocity, mTranslationShift))
- .setInterpolator(Interpolators.DEACCEL);
- mOpenCloseAnimator.start();
- }
- }
-
- protected void handleClose(boolean animate, long defaultDuration) {
- if (!mIsOpen || mOpenCloseAnimator.isRunning()) {
- return;
- }
- if (animate) {
- mOpenCloseAnimator.setValues(
- PropertyValuesHolder.ofFloat(TRANSLATION_SHIFT, TRANSLATION_SHIFT_CLOSED));
- mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() {
- @Override
- public void onAnimationEnd(Animator animation) {
- onCloseComplete();
- }
- });
- if (mSwipeDetector.isIdleState()) {
- mOpenCloseAnimator
- .setDuration(defaultDuration)
- .setInterpolator(Interpolators.ACCEL);
- } else {
- mOpenCloseAnimator.setInterpolator(mScrollInterpolator);
- }
- mOpenCloseAnimator.start();
- } else {
- setTranslationShift(TRANSLATION_SHIFT_CLOSED);
- onCloseComplete();
- }
- }
-
protected void onCloseComplete() {
- mIsOpen = false;
- mLauncher.getDragLayer().removeView(this);
+ super.onCloseComplete();
mLauncher.getSystemUiController().updateUiState(
SystemUiController.UI_STATE_WIDGET_BOTTOM_SHEET, 0);
}
diff --git a/src/com/android/launcher3/states/AllAppsState.java b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
similarity index 76%
copy from src/com/android/launcher3/states/AllAppsState.java
copy to src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
index ed3023a..bd5ddfe 100644
--- a/src/com/android/launcher3/states/AllAppsState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/AllAppsState.java
@@ -13,9 +13,10 @@
* See the License for the specific language governing permissions and
* limitations under the License.
*/
-package com.android.launcher3.states;
+package com.android.launcher3.uioverrides;
import static com.android.launcher3.LauncherAnimUtils.ALL_APPS_TRANSITION_MS;
+import static com.android.launcher3.allapps.DiscoveryBounce.APPS_VIEW_SHOWN;
import android.view.View;
@@ -23,6 +24,7 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.R;
+import com.android.launcher3.allapps.AllAppsTransitionController;
import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType;
/**
@@ -30,8 +32,6 @@
*/
public class AllAppsState extends LauncherState {
- public static final String APPS_VIEW_SHOWN = "launcher.apps_view_shown";
-
private static final int STATE_FLAGS = FLAG_DISABLE_ACCESSIBILITY;
public AllAppsState(int id) {
@@ -57,4 +57,16 @@
public View getFinalFocus(Launcher launcher) {
return launcher.getAppsView();
}
+
+ @Override
+ public float[] getWorkspaceScaleAndTranslation(Launcher launcher) {
+ return new float[] { 1f,
+ -launcher.getAllAppsController().getShiftRange()
+ * AllAppsTransitionController.PARALLAX_COEFFICIENT};
+ }
+
+ @Override
+ public PageAlphaProvider getWorkspacePageAlphaProvider(Launcher launcher) {
+ return (i) -> 0;
+ }
}
diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
index dcf7453..2cd3731 100644
--- a/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
+++ b/src_ui_overrides/com/android/launcher3/uioverrides/OverviewState.java
@@ -36,7 +36,8 @@
// The percent to shrink the workspace during overview mode
private static final float SCALE_FACTOR = 0.7f;
- private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE;
+ private static final int STATE_FLAGS = FLAG_SHOW_SCRIM | FLAG_MULTI_PAGE |
+ FLAG_DISABLE_PAGE_CLIPPING;
public OverviewState(int id) {
super(id, ContainerType.WORKSPACE, OVERVIEW_TRANSITION_MS, 1f, STATE_FLAGS);