From f535787571c37fea4a7a5c8ce5c97389c99a825c Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Mon, 20 May 2019 12:35:00 -0700 Subject: Use spring to update window/icon scale for swipe up animation. Bug: 123900446 Change-Id: I644dae6210ab3c8b72c777a556dfde4ae4cdce8f --- .../android/quickstep/util/RectFSpringAnim.java | 59 +++++++++------------- 1 file changed, 25 insertions(+), 34 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java index 3f4ad58ab..77dc6f32e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/RectFSpringAnim.java @@ -16,26 +16,22 @@ package com.android.quickstep.util; import android.animation.Animator; -import android.animation.ObjectAnimator; -import android.animation.PropertyValuesHolder; -import android.animation.ValueAnimator; import android.content.res.Resources; import android.graphics.PointF; import android.graphics.RectF; -import android.util.FloatProperty; import androidx.dynamicanimation.animation.DynamicAnimation.OnAnimationEndListener; import androidx.dynamicanimation.animation.FloatPropertyCompat; +import androidx.dynamicanimation.animation.SpringAnimation; +import androidx.dynamicanimation.animation.SpringForce; import com.android.launcher3.R; import com.android.launcher3.Utilities; -import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.FlingSpringAnim; import java.util.ArrayList; import java.util.List; -import static com.android.launcher3.anim.Interpolators.DEACCEL; /** * Applies spring forces to animate from a starting rect to a target rect, @@ -43,14 +39,6 @@ import static com.android.launcher3.anim.Interpolators.DEACCEL; */ public class RectFSpringAnim { - /** - * Although the rect position animation takes an indefinite amount of time since it depends on - * the initial velocity and applied forces, scaling from the starting rect to the target rect - * can be done in parallel at a fixed duration. Update callbacks are sent based on the progress - * of this animation, while the end callback is sent after all animations finish. - */ - private static final long RECT_SCALE_DURATION = 250; - private static final FloatPropertyCompat RECT_CENTER_X = new FloatPropertyCompat("rectCenterXSpring") { @Override @@ -79,17 +67,17 @@ public class RectFSpringAnim { } }; - private static final FloatProperty RECT_SCALE_PROGRESS = - new FloatProperty("rectScaleProgress") { + private static final FloatPropertyCompat RECT_SCALE_PROGRESS = + new FloatPropertyCompat("rectScaleProgress") { @Override - public Float get(RectFSpringAnim anim) { - return anim.mCurrentScaleProgress; + public float getValue(RectFSpringAnim object) { + return object.mCurrentScaleProgress; } @Override - public void setValue(RectFSpringAnim anim, float currentScaleProgress) { - anim.mCurrentScaleProgress = currentScaleProgress; - anim.onUpdate(); + public void setValue(RectFSpringAnim object, float value) { + object.mCurrentScaleProgress = value; + object.onUpdate(); } }; @@ -106,7 +94,7 @@ public class RectFSpringAnim { private float mCurrentScaleProgress; private FlingSpringAnim mRectXAnim; private FlingSpringAnim mRectYAnim; - private ValueAnimator mRectScaleAnim; + private SpringAnimation mRectScaleAnim; private boolean mAnimsStarted; private boolean mRectXAnimEnded; private boolean mRectYAnimEnded; @@ -177,17 +165,18 @@ public class RectFSpringAnim { mRectYAnim = new FlingSpringAnim(this, RECT_Y, startY, endY, startVelocityY, mMinVisChange, minYValue, maxYValue, springVelocityFactor, onYEndListener); - mRectScaleAnim = ObjectAnimator.ofPropertyValuesHolder(this, - PropertyValuesHolder.ofFloat(RECT_SCALE_PROGRESS, 1)) - .setDuration(RECT_SCALE_DURATION); - mRectScaleAnim.setInterpolator(DEACCEL); - mRectScaleAnim.addListener(new AnimationSuccessListener() { - @Override - public void onAnimationSuccess(Animator animator) { - mRectScaleAnimEnded = true; - maybeOnEnd(); - } - }); + float minVisibleChange = 1f / mStartRect.height(); + mRectScaleAnim = new SpringAnimation(this, RECT_SCALE_PROGRESS) + .setSpring(new SpringForce(1f) + .setDampingRatio(SpringForce.DAMPING_RATIO_LOW_BOUNCY) + .setStiffness(SpringForce.STIFFNESS_LOW)) + .setStartVelocity(velocityPxPerMs.y * minVisibleChange) + .setMaxValue(1f) + .setMinimumVisibleChange(minVisibleChange) + .addEndListener((animation, canceled, value, velocity) -> { + mRectScaleAnimEnded = true; + maybeOnEnd(); + }); mRectXAnim.start(); mRectYAnim.start(); @@ -202,7 +191,9 @@ public class RectFSpringAnim { if (mAnimsStarted) { mRectXAnim.end(); mRectYAnim.end(); - mRectScaleAnim.end(); + if (mRectScaleAnim.canSkipToEnd()) { + mRectScaleAnim.skipToEnd(); + } } } -- cgit v1.2.3 From 2524b82369265c3b8f5c6b5b6495376df6781770 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 17 May 2019 16:33:37 -0700 Subject: Remove unnecessary dispatchInsets routing Insets are dispatched to all views. We never consume the insets and let each view decide what to do with it. Also fixing scrim in all-apps when in full-gesture navigation Change-Id: Ib1c6bef5b32aac0c6ea03078b5138d2d0408c6d8 --- .../src/com/android/quickstep/fallback/RecentsRootView.java | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java index 09d323ee6..182072957 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/fallback/RecentsRootView.java @@ -20,7 +20,6 @@ import android.content.Context; import android.graphics.Point; import android.graphics.Rect; import android.util.AttributeSet; -import android.view.WindowInsets; import com.android.launcher3.BaseActivity; import com.android.launcher3.R; @@ -71,7 +70,7 @@ public class RecentsRootView extends BaseDragLayer { // Update device profile before notifying the children. mActivity.getDeviceProfile().updateInsets(insets); setInsets(insets); - return true; // I'll take it from here + return false; // Let children get the full insets } @Override @@ -89,10 +88,4 @@ public class RecentsRootView extends BaseDragLayer { mActivity.getDeviceProfile().updateInsets(mInsets); super.setInsets(mInsets); } - - @Override - public WindowInsets dispatchApplyWindowInsets(WindowInsets insets) { - updateTouchExcludeRegion(insets); - return super.dispatchApplyWindowInsets(insets); - } } \ No newline at end of file -- cgit v1.2.3 From aa8b2d86fcb709a23f7ef676500f11284cdd144b Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Wed, 22 May 2019 14:39:52 -0700 Subject: Capture screenshot when animating to home This is to ensure the task thumbnail is captured in the correct orientation, rather than waiting until after the task pauses which might be after the device rotates to portrait. Also update the state to wait until screenshot is captured before finishing the transition to home. Test: testStressPressHome Test: Swipe up from a forced landscape app, enter overview; ensure task view thumbnail is shown correctly Bug: 132687470 Change-Id: I5cd5f4b2a413628a8bdcb456e2d132c1c2da5258 --- .../android/quickstep/WindowTransformSwipeHandler.java | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 2ff5c0c6a..bbc6eb3a5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -170,7 +170,8 @@ public class WindowTransformSwipeHandler STATE_LAUNCHER_PRESENT | STATE_LAUNCHER_DRAWN | STATE_LAUNCHER_STARTED; public enum GestureEndTarget { - HOME(1, STATE_SCALED_CONTROLLER_HOME, true, false, ContainerType.WORKSPACE, false), + HOME(1, STATE_SCALED_CONTROLLER_HOME | STATE_CAPTURE_SCREENSHOT, true, false, + ContainerType.WORKSPACE, false), RECENTS(1, STATE_SCALED_CONTROLLER_RECENTS | STATE_CAPTURE_SCREENSHOT | STATE_SCREENSHOT_VIEW_SHOWN, true, false, ContainerType.TASKSWITCHER, true), @@ -331,9 +332,8 @@ public class WindowTransformSwipeHandler | STATE_SCALED_CONTROLLER_RECENTS, this::finishCurrentTransitionToRecents); - mStateCallback.addCallback(STATE_LAUNCHER_PRESENT | STATE_GESTURE_COMPLETED - | STATE_SCALED_CONTROLLER_HOME | STATE_APP_CONTROLLER_RECEIVED - | STATE_LAUNCHER_DRAWN, + mStateCallback.addCallback(STATE_SCREENSHOT_CAPTURED | STATE_GESTURE_COMPLETED + | STATE_SCALED_CONTROLLER_HOME, this::finishCurrentTransitionToHome); mStateCallback.addCallback(STATE_SCALED_CONTROLLER_HOME | STATE_CURRENT_TASK_FINISHED, this::reset); @@ -1251,7 +1251,14 @@ public class WindowTransformSwipeHandler if (mTaskSnapshot == null) { mTaskSnapshot = controller.screenshotTask(mRunningTaskId); } - TaskView taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot); + final TaskView taskView; + if (mGestureEndTarget == HOME) { + // Capture the screenshot before finishing the transition to home to ensure it's + // taken in the correct orientation, but no need to update the thumbnail. + taskView = null; + } else { + taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot); + } if (taskView != null) { // Defer finishing the animation until the next launcher frame with the // new thumbnail -- cgit v1.2.3 From f5d02b069a28e759dd3484ef2e807f32fe53516f Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 22 May 2019 14:52:37 -0700 Subject: Reading navigation_bar_gesture_height for bottom swipe region Bug: 132917885 Change-Id: I39d266fc34a69c3ba50246b5a66350942a85becb --- .../src/com/android/quickstep/TouchInteractionService.java | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 0c997dd59..6ba1bf5c5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -331,16 +331,8 @@ public class TouchInteractionService extends Service implements defaultDisplay.getRealSize(realSize); mSwipeTouchRegion.set(0, 0, realSize.x, realSize.y); if (mMode == Mode.NO_BUTTON) { - switch (defaultDisplay.getRotation()) { - case Surface.ROTATION_90: - case Surface.ROTATION_270: - mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize( - ResourceUtils.NAVBAR_LANDSCAPE_BOTTOM_SIZE); - break; - default: - mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - getNavbarSize( - ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE); - } + mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - + getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); } else { switch (defaultDisplay.getRotation()) { case Surface.ROTATION_90: @@ -353,7 +345,7 @@ public class TouchInteractionService extends Service implements break; default: mSwipeTouchRegion.top = mSwipeTouchRegion.bottom - - getNavbarSize(ResourceUtils.NAVBAR_PORTRAIT_BOTTOM_SIZE); + - getNavbarSize(ResourceUtils.NAVBAR_BOTTOM_GESTURE_SIZE); } } } -- cgit v1.2.3 From 0c1ed7cb4cf6f5e46211731bb243bdb308c1eaac Mon Sep 17 00:00:00 2001 From: vadimt Date: Thu, 23 May 2019 11:30:09 -0700 Subject: Quick patch for PredictionUiStateManager.applyState interrupting allapps Constructor of PredictionUiStateManager posts an action in 5 sec, which may interfere with the process of opening all apps. Waiting until the posted action happens. Hopefully this will fix massive flakes. Bug: 131854153 Change-Id: I6544eae1a3b063c03e78185826c05a76add1f71b --- .../com/android/launcher3/appprediction/PredictionUiStateManager.java | 3 +++ 1 file changed, 3 insertions(+) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java index 6dad9afe5..28ecce07e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java @@ -197,7 +197,10 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf } } + public boolean mDebugHadStateUpdate; + private void updatePredictionStateAfterCallback() { + mDebugHadStateUpdate = true; boolean validResults = false; for (List l : mPredictionServicePredictions) { validResults |= l != null && !l.isEmpty(); -- cgit v1.2.3 From 68ff2d91cf9bbbbbc2c43ed9a4dfbeb40fb59101 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 23 May 2019 14:15:38 -0700 Subject: Making some fields accessible to subclasses Bug: 132975416 Change-Id: Icc7043d8299c88fcf505068f8cabd4705d19010d --- .../src/com/android/launcher3/appprediction/PredictionAppTracker.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java index af67e1bbb..8f1282ded 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionAppTracker.java @@ -56,7 +56,7 @@ public class PredictionAppTracker extends AppLaunchTracker { private static final int MSG_LAUNCH = 2; private static final int MSG_PREDICT = 3; - private final Context mContext; + protected final Context mContext; private final Handler mMessageHandler; // Accessed only on worker thread -- cgit v1.2.3 From dd71ca04370a8885cfeeb1d2c6846f5299e8edcc Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 23 May 2019 13:56:10 -0700 Subject: Support individual lock task features - If screen pinning is enabled, disable gestures and wrap with input consumer to break out of screen pinning (existing logic) - If Home & Overview are both disabled, disable gestures completely - If only Home is disabled, then always launch the user into fallback recents (to simplify logic around breaking out of overview into Home) - If only Overview is disabled, then prevent swiping from going into overview or from triggering overview from home - Switch to using screen pinning flag check instead of binder call Bug: 133113732 Bug: 131698989 Change-Id: Ie6f447520d4cc3fa1eaaf8427ee014851688bf37 --- .../FlingAndHoldTouchController.java | 6 ++- .../QuickSwitchTouchController.java | 7 +++ .../android/quickstep/TouchInteractionService.java | 40 +++++++++-------- .../quickstep/WindowTransformSwipeHandler.java | 50 ++++++++++++++-------- 4 files changed, 66 insertions(+), 37 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java index 7a6cd2d55..e3e339add 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/FlingAndHoldTouchController.java @@ -22,6 +22,7 @@ import static com.android.launcher3.LauncherState.OVERVIEW_PEEK; import static com.android.launcher3.LauncherStateManager.ANIM_ALL; import static com.android.launcher3.LauncherStateManager.ATOMIC_OVERVIEW_PEEK_COMPONENT; import static com.android.launcher3.anim.Interpolators.OVERSHOOT_1_2; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; @@ -34,8 +35,10 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherState; import com.android.launcher3.anim.AnimatorSetBuilder; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; +import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.views.RecentsView; +import com.android.systemui.shared.system.QuickStepContract; /** * Touch controller which handles swipe and hold to go to Overview @@ -99,7 +102,8 @@ public class FlingAndHoldTouchController extends PortraitStatesTouchController { * having it as part of the existing animation to the target state. */ private boolean handlingOverviewAnim() { - return mStartState == NORMAL; + int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags(); + return mStartState == NORMAL && (stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java index e1dd124a9..18b8af4fa 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/uioverrides/touchcontrollers/QuickSwitchTouchController.java @@ -30,6 +30,7 @@ import static com.android.launcher3.anim.Interpolators.INSTANT; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.launcher3.util.SystemUiController.UI_STATE_OVERVIEW; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.view.MotionEvent; @@ -44,10 +45,12 @@ import com.android.launcher3.touch.AbstractStateChangeTouchController; import com.android.launcher3.touch.SwipeDetector; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; +import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.system.QuickStepContract; /** * Handles quick switching to a recent task from the home screen. @@ -80,6 +83,10 @@ public class QuickSwitchTouchController extends AbstractStateChangeTouchControll @Override protected LauncherState getTargetState(LauncherState fromState, boolean isDragTowardPositive) { + int stateFlags = OverviewInteractionState.INSTANCE.get(mLauncher).getSystemUiStateFlags(); + if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0) { + return NORMAL; + } return isDragTowardPositive ? QUICK_SWITCH : NORMAL; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 0c997dd59..906ce5d5f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -22,8 +22,11 @@ import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_INP import static com.android.systemui.shared.system.QuickStepContract.KEY_EXTRA_SYSUI_PROXY; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING; import android.annotation.TargetApi; import android.app.ActivityManager; @@ -79,6 +82,7 @@ import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputChannelCompat.InputEventReceiver; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.InputMonitorCompat; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; import java.io.FileDescriptor; @@ -197,6 +201,8 @@ public class TouchInteractionService extends Service implements public void onSystemUiStateChanged(int stateFlags) { mSystemUiStateFlags = stateFlags; + mOverviewInteractionState.setSystemUiStateFlags(stateFlags); + mOverviewComponentObserver.onSystemUiStateChanged(stateFlags); } /** Deprecated methods **/ @@ -472,16 +478,13 @@ public class TouchInteractionService extends Service implements private boolean validSystemUiFlags() { return (mSystemUiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) == 0 - && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0; - } - - private boolean topTaskLocked() { - return ActivityManagerWrapper.getInstance().isLockToAppActive(); + && (mSystemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED) == 0 + && ((mSystemUiStateFlags & SYSUI_STATE_HOME_DISABLED) == 0 + || (mSystemUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) == 0); } private InputConsumer newConsumer(boolean useSharedState, MotionEvent event) { - boolean topTaskLocked = topTaskLocked(); - boolean isInValidSystemUiState = validSystemUiFlags() && !topTaskLocked; + boolean isInValidSystemUiState = validSystemUiFlags(); if (!mIsUserUnlocked) { if (isInValidSystemUiState) { @@ -498,13 +501,15 @@ public class TouchInteractionService extends Service implements if (mMode == Mode.NO_BUTTON) { final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); - if (mAssistantAvailable && !topTaskLocked - && AssistantTouchConsumer.withinTouchRegion(this, event)) { + if (mAssistantAvailable + && !QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags) + && AssistantTouchConsumer.withinTouchRegion(this, event) + && !ActivityManagerWrapper.getInstance().isLockToAppActive()) { base = new AssistantTouchConsumer(this, mISystemUiProxy, activityControl, base, mInputMonitorCompat); } - if (ActivityManagerWrapper.getInstance().isScreenPinningActive()) { + if ((mSystemUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0) { // Note: we only allow accessibility to wrap this, and it replaces the previous // base input consumer (which should be NO_OP anyway since topTaskLocked == true). base = new ScreenPinnedInputConsumer(this, mISystemUiProxy, activityControl); @@ -593,17 +598,14 @@ public class TouchInteractionService extends Service implements // Dump everything pw.println("TouchState:"); pw.println(" navMode=" + mMode); - pw.println(" validSystemUiFlags=" + validSystemUiFlags() - + " flags=" + mSystemUiStateFlags); - pw.println(" topTaskLocked=" + topTaskLocked()); + pw.println(" validSystemUiFlags=" + validSystemUiFlags()); + pw.println(" systemUiFlags=" + mSystemUiStateFlags); + pw.println(" systemUiFlagsDesc=" + + QuickStepContract.getSystemUiStateString(mSystemUiStateFlags)); pw.println(" isDeviceLocked=" + mKM.isDeviceLocked()); - pw.println(" screenPinned=" + - ActivityManagerWrapper.getInstance().isScreenPinningActive()); pw.println(" assistantAvailable=" + mAssistantAvailable); - pw.println(" a11yClickable=" - + ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0)); - pw.println(" a11yLongClickable=" - + ((mSystemUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0)); + pw.println(" assistantDisabled=" + + QuickStepContract.isAssistantGestureDisabled(mSystemUiStateFlags)); pw.println(" resumed=" + mOverviewComponentObserver.getActivityControlHelper().isResumed()); pw.println(" useSharedState=" + mConsumer.useSharedSwipeState()); diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 2ff5c0c6a..2484d2f0e 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -39,6 +39,7 @@ import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.NEW_TASK; import static com.android.quickstep.WindowTransformSwipeHandler.GestureEndTarget.RECENTS; import static com.android.quickstep.views.RecentsView.UPDATE_SYSUI_FLAGS_THRESHOLD; +import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED; import android.animation.Animator; import android.animation.AnimatorSet; @@ -105,6 +106,7 @@ import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.LatencyTrackerCompat; +import com.android.systemui.shared.system.QuickStepContract; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; import com.android.systemui.shared.system.WindowCallbacksCompat; @@ -835,16 +837,9 @@ public class WindowTransformSwipeHandler } } - @UiThread - private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity, + private GestureEndTarget calculateEndTarget(PointF velocity, float endVelocity, boolean isFling, boolean isCancel) { - PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000); - long duration = MAX_SWIPE_DURATION; - float currentShift = mCurrentShift.value; final GestureEndTarget endTarget; - float endShift; - final float startShift; - Interpolator interpolator = DEACCEL; final boolean goingToNewTask; if (mRecentsView != null) { if (!mRecentsAnimationWrapper.hasTargets()) { @@ -859,7 +854,7 @@ public class WindowTransformSwipeHandler } else { goingToNewTask = false; } - final boolean reachedOverviewThreshold = currentShift >= MIN_PROGRESS_FOR_OVERVIEW; + final boolean reachedOverviewThreshold = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; if (!isFling) { if (isCancel) { endTarget = LAST_TASK; @@ -869,7 +864,7 @@ public class WindowTransformSwipeHandler } else if (goingToNewTask) { endTarget = NEW_TASK; } else { - endTarget = currentShift < MIN_PROGRESS_FOR_OVERVIEW ? LAST_TASK : HOME; + endTarget = !reachedOverviewThreshold ? LAST_TASK : HOME; } } else { endTarget = reachedOverviewThreshold && mGestureStarted @@ -878,12 +873,6 @@ public class WindowTransformSwipeHandler ? NEW_TASK : LAST_TASK; } - endShift = endTarget.endShift; - long expectedDuration = Math.abs(Math.round((endShift - currentShift) - * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER)); - duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); - startShift = currentShift; - interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL; } else { if (mMode == Mode.NO_BUTTON && endVelocity < 0 && !mIsShelfPeeking) { // If swiping at a diagonal, base end target on the faster velocity. @@ -896,7 +885,34 @@ public class WindowTransformSwipeHandler } else { endTarget = goingToNewTask ? NEW_TASK : LAST_TASK; } - endShift = endTarget.endShift; + } + + int stateFlags = OverviewInteractionState.INSTANCE.get(mActivity).getSystemUiStateFlags(); + if ((stateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0 + && (endTarget == RECENTS || endTarget == LAST_TASK)) { + return LAST_TASK; + } + return endTarget; + } + + @UiThread + private void handleNormalGestureEnd(float endVelocity, boolean isFling, PointF velocity, + boolean isCancel) { + PointF velocityPxPerMs = new PointF(velocity.x / 1000, velocity.y / 1000); + long duration = MAX_SWIPE_DURATION; + float currentShift = mCurrentShift.value; + final GestureEndTarget endTarget = calculateEndTarget(velocity, endVelocity, + isFling, isCancel); + float endShift = endTarget.endShift; + final float startShift; + Interpolator interpolator = DEACCEL; + if (!isFling) { + long expectedDuration = Math.abs(Math.round((endShift - currentShift) + * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER)); + duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); + startShift = currentShift; + interpolator = endTarget == RECENTS ? OVERSHOOT_1_2 : DEACCEL; + } else { startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y * SINGLE_FRAME_MS / mTransitionDragLength, 0, 1); float minFlingVelocity = mContext.getResources() -- cgit v1.2.3 From 9b832295c30a352be52922b3d542d6d7518aa93d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 23 May 2019 14:42:24 -0700 Subject: Set scroller to new max duration if snapping too slowly Change-Id: I87bfc8f767f7ae9cbe838c2a9ba229bec179f526 --- .../src/com/android/quickstep/WindowTransformSwipeHandler.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index 2ff5c0c6a..9cc65457b 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -936,8 +936,10 @@ public class WindowTransformSwipeHandler } else if (endTarget == RECENTS) { mLiveTileOverlay.startIconAnimation(); if (mRecentsView != null) { - duration = Utilities.boundToRange(mRecentsView.getScroller().getDuration(), - duration, MAX_SWIPE_DURATION); + if (mRecentsView.getScroller().getDuration() > MAX_SWIPE_DURATION) { + mRecentsView.snapToPage(mRecentsView.getNextPage(), (int) MAX_SWIPE_DURATION); + } + duration = Math.max(duration, mRecentsView.getScroller().getDuration()); } if (mMode == Mode.NO_BUTTON) { setShelfState(ShelfAnimState.OVERVIEW, interpolator, duration); -- cgit v1.2.3 From 9820c05f2bb091762f334269f11061467b4ba6ba Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 23 May 2019 16:54:59 -0700 Subject: Removing prediciton loading state Also fixing test flakyness due to delayed prediction loading Bug: 132993129 Bug: 131854153 Change-Id: I85f7afff0e3ee0ca9e40e92e91681f797a0bc2de --- .../launcher3/appprediction/PredictionRowView.java | 25 ++++------------------ .../appprediction/PredictionUiStateManager.java | 14 ------------ 2 files changed, 4 insertions(+), 35 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java index 55f4c98e9..4a486f8e5 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -28,7 +28,6 @@ import android.os.Build; import android.util.AttributeSet; import android.util.IntProperty; import android.util.Log; -import android.view.LayoutInflater; import android.view.View; import android.view.animation.Interpolator; import android.widget.LinearLayout; @@ -115,8 +114,6 @@ public class PredictionRowView extends LinearLayout implements private final AnimatedFloat mOverviewScrollFactor = new AnimatedFloat(this::updateTranslationAndAlpha); - private View mLoadingProgress; - private boolean mPredictionsEnabled = false; public PredictionRowView(@NonNull Context context) { @@ -165,7 +162,6 @@ public class PredictionRowView extends LinearLayout implements public void setup(FloatingHeaderView parent, FloatingHeaderRow[] rows, boolean tabsHidden) { mParent = parent; - setPredictionsEnabled(mPredictionUiStateManager.arePredictionsEnabled()); } private void setPredictionsEnabled(boolean predictionsEnabled) { @@ -205,7 +201,7 @@ public class PredictionRowView extends LinearLayout implements @Override public boolean hasVisibleContent() { - return mPredictionUiStateManager.arePredictionsEnabled(); + return mPredictionsEnabled; } /** @@ -241,9 +237,6 @@ public class PredictionRowView extends LinearLayout implements } private void applyPredictionApps() { - if (mLoadingProgress != null) { - removeView(mLoadingProgress); - } if (!mPredictionsEnabled) { mParent.onHeightUpdated(); return; @@ -290,15 +283,8 @@ public class PredictionRowView extends LinearLayout implements } if (predictionCount == 0) { - if (mLoadingProgress == null) { - mLoadingProgress = LayoutInflater.from(getContext()) - .inflate(R.layout.prediction_load_progress, this, false); - } - addView(mLoadingProgress); - } else { - mLoadingProgress = null; + setPredictionsEnabled(false); } - mParent.onHeightUpdated(); } @@ -342,11 +328,8 @@ public class PredictionRowView extends LinearLayout implements public void setTextAlpha(int alpha) { mIconCurrentTextAlpha = alpha; int iconColor = setColorAlphaBound(mIconTextColor, mIconCurrentTextAlpha); - - if (mLoadingProgress == null) { - for (int i = 0; i < getChildCount(); i++) { - ((BubbleTextView) getChildAt(i)).setTextColor(iconColor); - } + for (int i = 0; i < getChildCount(); i++) { + ((BubbleTextView) getChildAt(i)).setTextColor(iconColor); } } diff --git a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java index 28ecce07e..64cb4b465 100644 --- a/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java +++ b/quickstep/recents_ui_overrides/src/com/android/launcher3/appprediction/PredictionUiStateManager.java @@ -24,7 +24,6 @@ import android.app.prediction.AppPredictor; import android.app.prediction.AppTarget; import android.content.ComponentName; import android.content.Context; -import android.os.Handler; import android.view.ViewTreeObserver.OnGlobalLayoutListener; import com.android.launcher3.AppInfo; @@ -63,7 +62,6 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf OnIDPChangeListener, OnUpdateListener { public static final String LAST_PREDICTION_ENABLED_STATE = "last_prediction_enabled_state"; - private static final long INITIAL_CALLBACK_WAIT_TIMEOUT_MS = 5000; // TODO (b/129421797): Update the client constants public enum Client { @@ -110,13 +108,8 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf for (int i = 0; i < mPredictionServicePredictions.length; i++) { mPredictionServicePredictions[i] = Collections.emptyList(); } - mGettingValidPredictionResults = Utilities.getDevicePrefs(context) .getBoolean(LAST_PREDICTION_ENABLED_STATE, true); - if (mGettingValidPredictionResults) { - new Handler().postDelayed( - this::updatePredictionStateAfterCallback, INITIAL_CALLBACK_WAIT_TIMEOUT_MS); - } // Call this last mCurrentState = parseLastState(); @@ -197,10 +190,7 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf } } - public boolean mDebugHadStateUpdate; - private void updatePredictionStateAfterCallback() { - mDebugHadStateUpdate = true; boolean validResults = false; for (List l : mPredictionServicePredictions) { validResults |= l != null && !l.isEmpty(); @@ -296,10 +286,6 @@ public class PredictionUiStateManager implements OnGlobalLayoutListener, ItemInf dispatchOnChange(false); } - public boolean arePredictionsEnabled() { - return mCurrentState.isEnabled; - } - private boolean canApplyPredictions(PredictionState newState) { if (mAppsView == null) { // If there is no apps view, no need to schedule. -- cgit v1.2.3 From 55d1e44c47d118e23c0ec452c5e5b31e8cd32690 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 24 May 2019 17:17:45 -0700 Subject: Fixing user getting stuck in quick-switch state If we are cancelled after the animation has completed, but before the deferred frame was captured, we set the state as cancelled, and start the new consumer with the existing recents controller. But after the deferred frame, we finish the controller (and since the state was set to cancelled, do not launch the new task) Bug: 132756514 Change-Id: If30af713c76b6d895d0b01b93d31c0e1403b7214 --- .../src/com/android/quickstep/WindowTransformSwipeHandler.java | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index a1bcb9bf2..ffef1cf32 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -1261,7 +1261,7 @@ public class WindowTransformSwipeHandler } else { taskView = mRecentsView.updateThumbnail(mRunningTaskId, mTaskSnapshot); } - if (taskView != null) { + if (taskView != null && !mCanceled) { // Defer finishing the animation until the next launcher frame with the // new thumbnail finishTransitionPosted = new WindowCallbacksCompat(taskView) { @@ -1271,6 +1271,13 @@ public class WindowTransformSwipeHandler @Override public void onPostDraw(Canvas canvas) { + // If we were cancelled after this was attached, do not update + // the state. + if (mCanceled) { + detach(); + return; + } + if (mDeferFrameCount > 0) { mDeferFrameCount--; // Workaround, detach and reattach to invalidate the root node for -- cgit v1.2.3 From bef6a44e7b8869a4f311db778b9ebfe2f3d40428 Mon Sep 17 00:00:00 2001 From: Tony Date: Mon, 20 May 2019 21:35:59 -0400 Subject: Continue scaling down recents past final position in 0 button mode - Previously, we clamped the progress to 1 when reaching mTransitionDragLength. Now, we allow dragging all the way to the top of the screen, and store this new top progress in mDragLengthFactor (> 1f). - Because the launcher animation controller is inherently bound to a progress between 0 and 1, we have to do a bit of trickery involving interpolators. Specifically, we normalize the progress to 0 to 1 by dividing by mDragLengthFactor, but then we set the interpolators to multiply their progress by mDragLengthFactor. The result is that the animation progress appears to go from 0 to mDragLengthFactor, just like the window progress. - To avoid scaling too small, we start interpolating the progress at a certain point, ending at a specified max progress when reaching the top of the screen. Bug: 131741395 Change-Id: Ie8b4b56d37249cd1456f93c110c26c78fe052dc0 --- .../LauncherActivityControllerHelper.java | 38 +++++++++++++++++++--- .../quickstep/WindowTransformSwipeHandler.java | 33 ++++++++++++++++--- .../quickstep/util/ClipAnimationHelper.java | 9 ++--- .../src/com/android/quickstep/views/TaskView.java | 1 + 4 files changed, 68 insertions(+), 13 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 4b2e487da..00e4a9d5a 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -30,6 +30,7 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; +import android.animation.TimeInterpolator; import android.content.Context; import android.graphics.Rect; import android.graphics.RectF; @@ -68,6 +69,8 @@ import java.util.function.Consumer; */ public final class LauncherActivityControllerHelper implements ActivityControlHelper { + private Runnable mAdjustInterpolatorsRunnable; + @Override public int getSwipeUpDestinationAndLength(DeviceProfile dp, Context context, Rect outRect) { LayoutUtils.calculateLauncherTaskSize(context, dp, outRect); @@ -193,6 +196,13 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe } } + @Override + public void adjustActivityControllerInterpolators() { + if (mAdjustInterpolatorsRunnable != null) { + mAdjustInterpolatorsRunnable.run(); + } + } + @Override public void onTransitionCancelled() { activity.getStateManager().goToState(startState, false /* animate */); @@ -275,6 +285,7 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe playScaleDownAnim(anim, activity, fromState, endState); anim.setDuration(transitionLength * 2); + anim.setInterpolator(LINEAR); AnimatorPlaybackController controller = AnimatorPlaybackController.wrap(anim, transitionLength * 2); activity.getStateManager().setCurrentUserControlledAnimation(controller); @@ -291,7 +302,6 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe Animator shiftAnim = new SpringObjectAnimator<>(activity.getAllAppsController(), "allAppsSpringFromACH", activity.getAllAppsController().getShiftRange(), SPRING_DAMPING_RATIO, SPRING_STIFFNESS, progressValues); - shiftAnim.setInterpolator(LINEAR); return shiftAnim; } @@ -310,19 +320,37 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe = fromState.getOverviewScaleAndTranslation(launcher); LauncherState.ScaleAndTranslation endScaleAndTranslation = endState.getOverviewScaleAndTranslation(launcher); + float fromTranslationY = fromScaleAndTranslation.translationY; + float endTranslationY = endScaleAndTranslation.translationY; float fromFullscreenProgress = fromState.getOverviewFullscreenProgress(); float endFullscreenProgress = endState.getOverviewFullscreenProgress(); Animator scale = ObjectAnimator.ofFloat(recentsView, SCALE_PROPERTY, fromScaleAndTranslation.scale, endScaleAndTranslation.scale); Animator translateY = ObjectAnimator.ofFloat(recentsView, TRANSLATION_Y, - fromScaleAndTranslation.translationY, endScaleAndTranslation.translationY); + fromTranslationY, endTranslationY); Animator applyFullscreenProgress = ObjectAnimator.ofFloat(recentsView, RecentsView.FULLSCREEN_PROGRESS, fromFullscreenProgress, endFullscreenProgress); - scale.setInterpolator(LINEAR); - translateY.setInterpolator(LINEAR); - applyFullscreenProgress.setInterpolator(LINEAR); anim.playTogether(scale, translateY, applyFullscreenProgress); + + mAdjustInterpolatorsRunnable = () -> { + // Adjust the translateY interpolator to account for the running task's top inset. + // When progress <= 1, this is handled by each task view as they set their fullscreen + // progress. However, once we go to progress > 1, fullscreen progress stays at 0, so + // recents as a whole needs to translate further to keep up with the app window. + TaskView runningTaskView = recentsView.getRunningTaskView(); + if (runningTaskView == null) { + runningTaskView = recentsView.getTaskViewAt(recentsView.getCurrentPage()); + } + TimeInterpolator oldInterpolator = translateY.getInterpolator(); + Rect fallbackInsets = launcher.getDeviceProfile().getInsets(); + float extraTranslationY = runningTaskView.getThumbnail().getInsets(fallbackInsets).top; + float normalizedTranslationY = extraTranslationY / (fromTranslationY - endTranslationY); + translateY.setInterpolator(t -> { + float newT = oldInterpolator.getInterpolation(t); + return newT <= 1f ? newT : newT + normalizedTranslationY * (newT - 1); + }); + }; } @Override diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index ffef1cf32..16beb7952 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -217,6 +217,12 @@ public class WindowTransformSwipeHandler private static final long SHELF_ANIM_DURATION = 120; public static final long RECENTS_ATTACH_DURATION = 300; + // Start resisting when swiping past this factor of mTransitionDragLength. + private static final float DRAG_LENGTH_FACTOR_START_PULLBACK = 1.4f; + // This is how far down we can scale down, where 0f is full screen and 1f is recents. + private static final float DRAG_LENGTH_FACTOR_MAX_PULLBACK = 1.8f; + private static final Interpolator PULLBACK_INTERPOLATOR = DEACCEL; + /** * Used as the page index for logging when we return to the last task at the end of the gesture. */ @@ -231,7 +237,10 @@ public class WindowTransformSwipeHandler private RunningWindowAnim mRunningWindowAnim; private boolean mIsShelfPeeking; private DeviceProfile mDp; + // The distance needed to drag to reach the task size in recents. private int mTransitionDragLength; + // How much further we can drag past recents, as a factor of mTransitionDragLength. + private float mDragLengthFactor = 1; // Shift in the range of [0, 1]. // 0 => preview snapShot is completely visible, and hotseat is completely translated down @@ -375,6 +384,10 @@ public class WindowTransformSwipeHandler mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength( dp, mContext, tempRect); mClipAnimationHelper.updateTargetRect(tempRect); + if (mMode == Mode.NO_BUTTON) { + // We can drag all the way to the top of the screen. + mDragLengthFactor = (float) dp.heightPx / mTransitionDragLength; + } } private long getFadeInDuration() { @@ -546,11 +559,18 @@ public class WindowTransformSwipeHandler public void updateDisplacement(float displacement) { // We are moving in the negative x/y direction displacement = -displacement; - if (displacement > mTransitionDragLength && mTransitionDragLength > 0) { - mCurrentShift.updateValue(1); + if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) { + mCurrentShift.updateValue(mDragLengthFactor); } else { float translation = Math.max(displacement, 0); float shift = mTransitionDragLength == 0 ? 0 : translation / mTransitionDragLength; + if (shift > DRAG_LENGTH_FACTOR_START_PULLBACK) { + float pullbackProgress = Utilities.getProgress(shift, + DRAG_LENGTH_FACTOR_START_PULLBACK, mDragLengthFactor); + pullbackProgress = PULLBACK_INTERPOLATOR.getInterpolation(pullbackProgress); + shift = DRAG_LENGTH_FACTOR_START_PULLBACK + pullbackProgress + * (DRAG_LENGTH_FACTOR_MAX_PULLBACK - DRAG_LENGTH_FACTOR_START_PULLBACK); + } mCurrentShift.updateValue(shift); } } @@ -638,6 +658,8 @@ public class WindowTransformSwipeHandler private void onAnimatorPlaybackControllerCreated(AnimatorPlaybackController anim) { mLauncherTransitionController = anim; + mLauncherTransitionController.dispatchSetInterpolator(t -> t * mDragLengthFactor); + mAnimationFactory.adjustActivityControllerInterpolators(); mLauncherTransitionController.dispatchOnStart(); updateLauncherTransitionProgress(); } @@ -690,7 +712,9 @@ public class WindowTransformSwipeHandler if (mGestureEndTarget == HOME) { return; } - float progress = mCurrentShift.value; + // Normalize the progress to 0 to 1, as the animation controller will clamp it to that + // anyway. The controller mimics the drag length factor by applying it to its interpolators. + float progress = mCurrentShift.value / mDragLengthFactor; mLauncherTransitionController.setPlayFraction( progress <= mShiftAtGestureStart || mShiftAtGestureStart >= 1 ? 0 : (progress - mShiftAtGestureStart) / (1 - mShiftAtGestureStart)); @@ -898,7 +922,7 @@ public class WindowTransformSwipeHandler } endShift = endTarget.endShift; startShift = Utilities.boundToRange(currentShift - velocityPxPerMs.y - * SINGLE_FRAME_MS / mTransitionDragLength, 0, 1); + * SINGLE_FRAME_MS / mTransitionDragLength, 0, mDragLengthFactor); float minFlingVelocity = mContext.getResources() .getDimension(R.dimen.quickstep_fling_min_velocity); if (Math.abs(endVelocity) > minFlingVelocity && mTransitionDragLength > 0) { @@ -1057,6 +1081,7 @@ public class WindowTransformSwipeHandler mLauncherTransitionController.getAnimationPlayer().end(); } else { mLauncherTransitionController.dispatchSetInterpolator(adjustedInterpolator); + mAnimationFactory.adjustActivityControllerInterpolators(); mLauncherTransitionController.getAnimationPlayer().setDuration(duration); if (QUICKSTEP_SPRINGS.get()) { diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java index c164a2450..e2fb602d9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ClipAnimationHelper.java @@ -23,7 +23,6 @@ import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MOD import android.annotation.TargetApi; import android.content.Context; -import android.graphics.Canvas; import android.graphics.Matrix; import android.graphics.Matrix.ScaleToFit; import android.graphics.Rect; @@ -160,14 +159,16 @@ public class ClipAnimationHelper { public RectF applyTransform(RemoteAnimationTargetSet targetSet, TransformParams params, boolean launcherOnTop) { + float progress = params.progress; if (params.currentRect == null) { RectF currentRect; mTmpRectF.set(mTargetRect); Utilities.scaleRectFAboutCenter(mTmpRectF, params.offsetScale); - float progress = params.progress; currentRect = mRectFEvaluator.evaluate(progress, mSourceRect, mTmpRectF); currentRect.offset(params.offsetX, 0); + // Don't clip past progress > 1. + progress = Math.min(1, progress); final RectF sourceWindowClipInsets = params.forLiveTile ? mSourceWindowClipInsetsForLiveTile : mSourceWindowClipInsets; mClipRectF.left = sourceWindowClipInsets.left * progress; @@ -189,7 +190,7 @@ public class ClipAnimationHelper { float alpha = 1f; int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers); float cornerRadius = 0f; - float scale = params.currentRect.width() / crop.width(); + float scale = Math.max(params.currentRect.width(), mTargetRect.width()) / crop.width(); if (app.mode == targetSet.targetMode) { if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL); @@ -198,7 +199,7 @@ public class ClipAnimationHelper { if (mSupportsRoundedCornersOnWindows) { float windowCornerRadius = mUseRoundedCornersOnWindows ? mWindowCornerRadius : 0; - cornerRadius = Utilities.mapRange(params.progress, windowCornerRadius, + cornerRadius = Utilities.mapRange(progress, windowCornerRadius, mTaskCornerRadius); mCurrentCornerRadius = cornerRadius; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 053b7389c..3364377e9 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -633,6 +633,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { * @param progress: 0 = show icon and no insets; 1 = don't show icon and show full insets. */ public void setFullscreenProgress(float progress) { + progress = Utilities.boundToRange(progress, 0, 1); if (progress == mFullscreenProgress) { return; } -- cgit v1.2.3 From 221895d06b4e8c0cbe8c52b63115d673f1061a5d Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 28 May 2019 01:26:19 -0700 Subject: Improving swipe up interaction when device is locked When device is locked, only scale down the top task as a response to the user interaction. When user flings or lifts his finger, the task is dismissed to go to the lock screen LockScreenRecentsActivity is an empty activity which starts on top of lock screen and finishes immediately. This allows us to start a recents transition with just the top activity as the animation target. This target is then used for swipe up interaction Bug: 133167096 Change-Id: I466ed142ea33d626c78cb9cc5f6311bad26b8d98 --- .../quickstep/LockScreenRecentsActivity.java | 31 +++ .../android/quickstep/TouchInteractionService.java | 22 ++- .../inputconsumers/DeviceLockedInputConsumer.java | 208 ++++++++++++++++++++- 3 files changed, 248 insertions(+), 13 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java new file mode 100644 index 000000000..65f323c7d --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LockScreenRecentsActivity.java @@ -0,0 +1,31 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep; + +import android.app.Activity; +import android.os.Bundle; + +/** + * Empty activity to start a recents transition + */ +public class LockScreenRecentsActivity extends Activity { + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + finish(); + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java index 6ba1bf5c5..14bdec562 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TouchInteractionService.java @@ -479,7 +479,7 @@ public class TouchInteractionService extends Service implements if (isInValidSystemUiState) { // This handles apps launched in direct boot mode (e.g. dialer) as well as apps // launched while device is locked even after exiting direct boot mode (e.g. camera). - return new DeviceLockedInputConsumer(this); + return createDeviceLockedInputConsumer(mAM.getRunningTask(0)); } else { return InputConsumer.NO_OP; } @@ -512,16 +512,15 @@ public class TouchInteractionService extends Service implements } private InputConsumer newBaseConsumer(boolean useSharedState, MotionEvent event) { - if (mKM.isDeviceLocked()) { - // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched - // while device is locked even after exiting direct boot mode (e.g. camera). - return new DeviceLockedInputConsumer(this); - } - final RunningTaskInfo runningTaskInfo = mAM.getRunningTask(0); if (!useSharedState) { mSwipeSharedState.clearAllState(); } + if (mKM.isDeviceLocked()) { + // This handles apps launched in direct boot mode (e.g. dialer) as well as apps launched + // while device is locked even after exiting direct boot mode (e.g. camera). + return createDeviceLockedInputConsumer(runningTaskInfo); + } final ActivityControlHelper activityControl = mOverviewComponentObserver.getActivityControlHelper(); @@ -559,6 +558,15 @@ public class TouchInteractionService extends Service implements mSwipeSharedState, mInputMonitorCompat, mSwipeTouchRegion); } + private InputConsumer createDeviceLockedInputConsumer(RunningTaskInfo taskInfo) { + if (mMode == Mode.NO_BUTTON && taskInfo != null) { + return new DeviceLockedInputConsumer(this, mSwipeSharedState, mInputMonitorCompat, + mSwipeTouchRegion, taskInfo.taskId); + } else { + return InputConsumer.NO_OP; + } + } + /** * To be called by the consumer when it's no longer active. */ diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java index d01b5ec19..db2af59ac 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/DeviceLockedInputConsumer.java @@ -15,26 +15,102 @@ */ package com.android.quickstep.inputconsumers; +import static android.view.MotionEvent.ACTION_CANCEL; +import static android.view.MotionEvent.ACTION_POINTER_DOWN; +import static android.view.MotionEvent.ACTION_UP; + import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.Utilities.squaredTouchSlop; +import static com.android.quickstep.MultiStateCallback.DEBUG_STATES; +import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; +import android.content.ComponentName; import android.content.Context; import android.content.Intent; +import android.graphics.Point; import android.graphics.PointF; +import android.graphics.Rect; +import android.graphics.RectF; import android.view.MotionEvent; +import android.view.VelocityTracker; +import android.view.ViewConfiguration; +import android.view.WindowManager; + +import com.android.launcher3.R; +import com.android.launcher3.Utilities; +import com.android.quickstep.LockScreenRecentsActivity; +import com.android.quickstep.MultiStateCallback; +import com.android.quickstep.SwipeSharedState; +import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.RecentsAnimationListenerSet; +import com.android.quickstep.util.SwipeAnimationTargetSet; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.BackgroundExecutor; +import com.android.systemui.shared.system.InputMonitorCompat; +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; /** * A dummy input consumer used when the device is still locked, e.g. from secure camera. */ -public class DeviceLockedInputConsumer implements InputConsumer { +public class DeviceLockedInputConsumer implements InputConsumer, + SwipeAnimationTargetSet.SwipeAnimationListener { + + private static final float SCALE_DOWN = 0.75f; + + private static final String[] STATE_NAMES = DEBUG_STATES ? new String[2] : null; + private static int getFlagForIndex(int index, String name) { + if (DEBUG_STATES) { + STATE_NAMES[index] = name; + } + return 1 << index; + } + + private static final int STATE_TARGET_RECEIVED = + getFlagForIndex(0, "STATE_TARGET_RECEIVED"); + private static final int STATE_HANDLER_INVALIDATED = + getFlagForIndex(1, "STATE_HANDLER_INVALIDATED"); private final Context mContext; private final float mTouchSlopSquared; + private final SwipeSharedState mSwipeSharedState; + private final InputMonitorCompat mInputMonitorCompat; + private final PointF mTouchDown = new PointF(); + private final ClipAnimationHelper mClipAnimationHelper; + private final ClipAnimationHelper.TransformParams mTransformParams; + private final Point mDisplaySize; + private final MultiStateCallback mStateCallback; + private final RectF mSwipeTouchRegion; + public final int mRunningTaskId; + + private VelocityTracker mVelocityTracker; + private float mProgress; - public DeviceLockedInputConsumer(Context context) { + private boolean mThresholdCrossed = false; + + private SwipeAnimationTargetSet mTargetSet; + + public DeviceLockedInputConsumer(Context context, SwipeSharedState swipeSharedState, + InputMonitorCompat inputMonitorCompat, RectF swipeTouchRegion, int runningTaskId) { mContext = context; mTouchSlopSquared = squaredTouchSlop(context); + mSwipeSharedState = swipeSharedState; + mClipAnimationHelper = new ClipAnimationHelper(context); + mTransformParams = new ClipAnimationHelper.TransformParams(); + mInputMonitorCompat = inputMonitorCompat; + mSwipeTouchRegion = swipeTouchRegion; + mRunningTaskId = runningTaskId; + + // Do not use DeviceProfile as the user data might be locked + mDisplaySize = new Point(); + context.getSystemService(WindowManager.class).getDefaultDisplay().getRealSize(mDisplaySize); + + // Init states + mStateCallback = new MultiStateCallback(STATE_NAMES); + mStateCallback.addCallback(STATE_TARGET_RECEIVED | STATE_HANDLER_INVALIDATED, + this::endRemoteAnimation); + + mVelocityTracker = VelocityTracker.obtain(); } @Override @@ -44,17 +120,137 @@ public class DeviceLockedInputConsumer implements InputConsumer { @Override public void onMotionEvent(MotionEvent ev) { + if (mVelocityTracker == null) { + return; + } + mVelocityTracker.addMovement(ev); + float x = ev.getX(); float y = ev.getY(); - if (ev.getAction() == MotionEvent.ACTION_DOWN) { - mTouchDown.set(x, y); - } else if (ev.getAction() == MotionEvent.ACTION_MOVE) { - if (squaredHypot(x - mTouchDown.x, y - mTouchDown.y) > mTouchSlopSquared) { + switch (ev.getAction()) { + case MotionEvent.ACTION_DOWN: + mTouchDown.set(x, y); + break; + case ACTION_POINTER_DOWN: { + if (!mThresholdCrossed) { + // Cancel interaction in case of multi-touch interaction + int ptrIdx = ev.getActionIndex(); + if (!mSwipeTouchRegion.contains(ev.getX(ptrIdx), ev.getY(ptrIdx))) { + int action = ev.getAction(); + ev.setAction(ACTION_CANCEL); + finishTouchTracking(ev); + ev.setAction(action); + } + } + break; + } + case MotionEvent.ACTION_MOVE: { + if (!mThresholdCrossed) { + if (squaredHypot(x - mTouchDown.x, y - mTouchDown.y) > mTouchSlopSquared) { + startRecentsTransition(); + } + } else { + float dy = Math.max(mTouchDown.y - y, 0); + mProgress = dy / mDisplaySize.y; + mTransformParams.setProgress(mProgress); + if (mTargetSet != null) { + mClipAnimationHelper.applyTransform(mTargetSet, mTransformParams); + } + } + break; + } + case MotionEvent.ACTION_CANCEL: + case MotionEvent.ACTION_UP: + finishTouchTracking(ev); + break; + } + } + + /** + * Called when the gesture has ended. Does not correlate to the completion of the interaction as + * the animation can still be running. + */ + private void finishTouchTracking(MotionEvent ev) { + mStateCallback.setState(STATE_HANDLER_INVALIDATED); + if (mThresholdCrossed && ev.getAction() == ACTION_UP) { + mVelocityTracker.computeCurrentVelocity(1000, + ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity()); + + float velocityY = mVelocityTracker.getYVelocity(); + float flingThreshold = mContext.getResources() + .getDimension(R.dimen.quickstep_fling_threshold_velocity); + + boolean dismissTask; + if (Math.abs(velocityY) > flingThreshold) { + // Is fling + dismissTask = velocityY < 0; + } else { + dismissTask = mProgress >= (1 - MIN_PROGRESS_FOR_OVERVIEW); + } + if (dismissTask) { // For now, just start the home intent so user is prompted to unlock the device. mContext.startActivity(new Intent(Intent.ACTION_MAIN) .addCategory(Intent.CATEGORY_HOME) .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); } } + mVelocityTracker.recycle(); + mVelocityTracker = null; + } + + private void startRecentsTransition() { + mThresholdCrossed = true; + RecentsAnimationListenerSet newListenerSet = + mSwipeSharedState.newRecentsAnimationListenerSet(); + newListenerSet.addListener(this); + Intent intent = new Intent(Intent.ACTION_MAIN) + .addCategory(Intent.CATEGORY_DEFAULT) + .setComponent(new ComponentName(mContext, LockScreenRecentsActivity.class)) + .setFlags(Intent.FLAG_ACTIVITY_NEW_TASK | Intent.FLAG_ACTIVITY_CLEAR_TASK); + + mInputMonitorCompat.pilferPointers(); + BackgroundExecutor.get().submit( + () -> ActivityManagerWrapper.getInstance().startRecentsActivity( + intent, null, newListenerSet, null, null)); + } + + @Override + public void onRecentsAnimationStart(SwipeAnimationTargetSet targetSet) { + mTargetSet = targetSet; + + Rect displaySize = new Rect(0, 0, mDisplaySize.x, mDisplaySize.y); + RemoteAnimationTargetCompat targetCompat = targetSet.findTask(mRunningTaskId); + if (targetCompat != null) { + mClipAnimationHelper.updateSource(displaySize, targetCompat); + } + + Utilities.scaleRectAboutCenter(displaySize, SCALE_DOWN); + displaySize.offsetTo(displaySize.left, 0); + mClipAnimationHelper.updateTargetRect(displaySize); + mClipAnimationHelper.applyTransform(mTargetSet, mTransformParams); + + mStateCallback.setState(STATE_TARGET_RECEIVED); + } + + @Override + public void onRecentsAnimationCanceled() { + mTargetSet = null; + } + + private void endRemoteAnimation() { + if (mTargetSet != null) { + mTargetSet.finishController( + false /* toRecents */, null /* callback */, false /* sendUserLeaveHint */); + } + } + + @Override + public void onConsumerAboutToBeSwitched() { + mStateCallback.setState(STATE_HANDLER_INVALIDATED); + } + + @Override + public boolean allowInterceptByParent() { + return !mThresholdCrossed; } } -- cgit v1.2.3 From 928fc8d1e26b0af9cec86dd12237bed808c19dc2 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Wed, 29 May 2019 14:19:16 -0700 Subject: Fix bug where shape reveal progress gets started too early. * This caused the shape to not match the window size on app close. Bug: 123900446 Change-Id: Iaa2c06f19c535f72ae4c080b4bc847d336f1a77d --- .../src/com/android/quickstep/WindowTransformSwipeHandler.java | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index ca966c8fd..081682288 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -1134,12 +1134,10 @@ public class WindowTransformSwipeHandler // FolderIconView can be seen morphing into the icon shape. final float windowAlphaThreshold = isFloatingIconView ? 1f - SHAPE_PROGRESS_DURATION : 1f; anim.addOnUpdateListener((currentRect, progress) -> { - float interpolatedProgress = Interpolators.ACCEL_1_5.getInterpolation(progress); - homeAnim.setPlayFraction(progress); - float windowAlpha = Utilities.mapToRange(interpolatedProgress, 0, - windowAlphaThreshold, 1f, 0f, Interpolators.LINEAR); + float windowAlpha = Math.max(0, Utilities.mapToRange(progress, 0, + windowAlphaThreshold, 1f, 0f, Interpolators.LINEAR)); mTransformParams.setProgress(progress) .setCurrentRectAndTargetAlpha(currentRect, windowAlpha); mClipAnimationHelper.applyTransform(targetSet, mTransformParams, -- cgit v1.2.3 From c69d1ffd923e37166cc3dadf8938dc8a8b38e0c7 Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Tue, 28 May 2019 13:03:02 -0700 Subject: Add staggered springs animation when swiping up to home. Bug: 123900446 Change-Id: I275e34c6dca5b026f272ab216b18651c0df27bc4 --- .../LauncherActivityControllerHelper.java | 16 ++- .../quickstep/WindowTransformSwipeHandler.java | 1 + .../quickstep/util/StaggeredWorkspaceAnim.java | 154 +++++++++++++++++++++ 3 files changed, 170 insertions(+), 1 deletion(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java index 00e4a9d5a..5af09f7fd 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/LauncherActivityControllerHelper.java @@ -57,6 +57,7 @@ import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.views.FloatingIconView; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.util.LayoutUtils; +import com.android.quickstep.util.StaggeredWorkspaceAnim; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; @@ -151,8 +152,21 @@ public final class LauncherActivityControllerHelper implements ActivityControlHe @NonNull @Override public AnimatorPlaybackController createActivityAnimationToHome() { + // Return an empty APC here since we have an non-user controlled animation to home. long accuracy = 2 * Math.max(dp.widthPx, dp.heightPx); - return activity.getStateManager().createAnimationToNewWorkspace(NORMAL, accuracy); + AnimatorSet as = new AnimatorSet(); + as.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationStart(Animator animation) { + activity.getStateManager().goToState(NORMAL, false); + } + }); + return AnimatorPlaybackController.wrap(as, accuracy); + } + + @Override + public void playAtomicAnimation(float velocity) { + new StaggeredWorkspaceAnim(activity, workspaceView, velocity).start(); } }; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java index ca966c8fd..187e5317f 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -1057,6 +1057,7 @@ public class WindowTransformSwipeHandler setStateOnUiThread(target.endState); } }); + homeAnimFactory.playAtomicAnimation(velocityPxPerMs.y); windowAnim.start(velocityPxPerMs); mRunningWindowAnim = RunningWindowAnim.wrap(windowAnim); mLauncherTransitionController = null; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java new file mode 100644 index 000000000..93b6e4ba5 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java @@ -0,0 +1,154 @@ +/* + * Copyright (C) 2019 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import android.animation.Animator; +import android.animation.ObjectAnimator; +import android.animation.ValueAnimator; +import android.view.View; +import android.view.ViewGroup; + +import androidx.annotation.Nullable; +import androidx.dynamicanimation.animation.SpringForce; + +import com.android.launcher3.CellLayout; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAnimUtils.ViewProgressProperty; +import com.android.launcher3.R; +import com.android.launcher3.ShortcutAndWidgetContainer; +import com.android.launcher3.anim.SpringObjectAnimator; + +import java.util.ArrayList; +import java.util.List; + +import static com.android.launcher3.anim.Interpolators.LINEAR; + +/** + * Creates an animation where all the workspace items are moved into their final location, + * staggered row by row from the bottom up. + * This is used in conjunction with the swipe up to home animation. + */ +public class StaggeredWorkspaceAnim { + + private static final int APP_CLOSE_ROW_START_DELAY_MS = 16; + private static final int ALPHA_DURATION_MS = 200; + + private static final float MAX_VELOCITY_PX_PER_S = 22f; + + private static final float DAMPING_RATIO = + (SpringForce.DAMPING_RATIO_MEDIUM_BOUNCY + SpringForce.DAMPING_RATIO_LOW_BOUNCY) / 2f; + private static final float STIFFNESS = SpringForce.STIFFNESS_LOW; + + private final float mVelocity; + private final float mSpringTransY; + private final View mViewToIgnore; + + private final List mAnimators = new ArrayList<>(); + + /** + * @param floatingViewOriginalView The FloatingIconView's original view. + */ + public StaggeredWorkspaceAnim(Launcher launcher, @Nullable View floatingViewOriginalView, + float velocity) { + mVelocity = velocity; + // We ignore this view since it's visibility and position is controlled by + // the FloatingIconView. + mViewToIgnore = floatingViewOriginalView; + + // Scale the translationY based on the initial velocity to better sync the workspace items + // with the floating view. + float transFactor = 0.1f + 0.9f * Math.abs(velocity) / MAX_VELOCITY_PX_PER_S; + mSpringTransY = transFactor * launcher.getResources() + .getDimensionPixelSize(R.dimen.swipe_up_max_workspace_trans_y);; + + DeviceProfile grid = launcher.getDeviceProfile(); + ShortcutAndWidgetContainer currentPage = ((CellLayout) launcher.getWorkspace() + .getChildAt(launcher.getWorkspace().getCurrentPage())) + .getShortcutsAndWidgets(); + + // Hotseat and QSB takes up two additional rows. + int totalRows = grid.inv.numRows + (grid.isVerticalBarLayout() ? 0 : 2); + + // Set up springs on workspace items. + for (int i = currentPage.getChildCount() - 1; i >= 0; i--) { + View child = currentPage.getChildAt(i); + CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); + addStaggeredAnimationForView(child, lp.cellY + lp.cellVSpan, totalRows); + } + + // Set up springs for the hotseat and qsb. + if (grid.isVerticalBarLayout()) { + ViewGroup hotseat = (ViewGroup) launcher.getHotseat().getChildAt(0); + for (int i = hotseat.getChildCount() - 1; i >= 0; i--) { + View child = hotseat.getChildAt(i); + CellLayout.LayoutParams lp = ((CellLayout.LayoutParams) child.getLayoutParams()); + addStaggeredAnimationForView(child, lp.cellY + 1, totalRows); + } + } else { + View hotseat = launcher.getHotseat().getChildAt(0); + addStaggeredAnimationForView(hotseat, grid.inv.numRows + 1, totalRows); + + View qsb = launcher.findViewById(R.id.search_container_all_apps); + addStaggeredAnimationForView(qsb, grid.inv.numRows + 2, totalRows); + } + } + + /** + * Starts the animation. + */ + public void start() { + for (Animator a : mAnimators) { + if (a instanceof SpringObjectAnimator) { + ((SpringObjectAnimator) a).startSpring(1f, mVelocity, null); + } else { + a.start(); + } + } + } + + /** + * Adds an alpha/trans animator for {@param v}, with a start delay based on the view's row. + * + * @param v A view on the workspace. + * @param row The bottom-most row that contains the view. + * @param totalRows Total number of rows. + */ + private void addStaggeredAnimationForView(View v, int row, int totalRows) { + if (v == mViewToIgnore) { + return; + } + + // Invert the rows, because we stagger starting from the bottom of the screen. + int invertedRow = totalRows - row; + // Add 1 to the inverted row so that the bottom most row has a start delay. + long startDelay = (long) ((invertedRow + 1) * APP_CLOSE_ROW_START_DELAY_MS); + + v.setTranslationY(mSpringTransY); + SpringObjectAnimator springTransY = new SpringObjectAnimator<>( + new ViewProgressProperty(v, View.TRANSLATION_Y), "staggeredSpringTransY", 1f, + DAMPING_RATIO, STIFFNESS, mSpringTransY, 0); + springTransY.setStartDelay(startDelay); + mAnimators.add(springTransY); + + v.setAlpha(0); + ObjectAnimator alpha = ObjectAnimator.ofFloat(v, View.ALPHA, 0f, 1f); + alpha.setInterpolator(LINEAR); + alpha.setDuration(ALPHA_DURATION_MS); + alpha.setStartDelay(startDelay); + mAnimators.add(alpha); + } +} -- cgit v1.2.3 From 3f6019fde4d7fed20f6919c0df0e34dd7b24170d Mon Sep 17 00:00:00 2001 From: Zak Cohen Date: Wed, 29 May 2019 16:53:29 -0700 Subject: Overview - Add motion to the footer shown on overview tasks. The motion mirrors the icon view. Bug: 125844074 Test: manual Change-Id: Ib980657763aa82c45319c7c93be652f6fc89ffe4 --- .../src/com/android/quickstep/views/TaskView.java | 42 +++++++++++++++++++++- 1 file changed, 41 insertions(+), 1 deletion(-) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 053b7389c..022201fe2 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -145,11 +145,13 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { }; private final TaskOutlineProvider mOutlineProvider; + private final FooterOutlineProvider mFooterOutlineProvider; private Task mTask; private TaskThumbnailView mSnapshotView; private TaskMenuView mMenuView; private IconView mIconView; + private View mTaskFooterContainer; private DigitalWellBeingToast mDigitalWellBeingToast; private float mCurveScale; private float mFullscreenProgress; @@ -203,6 +205,7 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mWindowCornerRadius = QuickStepContract.getWindowCornerRadius(context.getResources()); mCurrentFullscreenParams = new FullscreenDrawParams(mCornerRadius); mOutlineProvider = new TaskOutlineProvider(getResources(), mCurrentFullscreenParams); + mFooterOutlineProvider = new FooterOutlineProvider(mCurrentFullscreenParams); setOutlineProvider(mOutlineProvider); } @@ -212,6 +215,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { mSnapshotView = findViewById(R.id.snapshot); mIconView = findViewById(R.id.icon); mDigitalWellBeingToast = findViewById(R.id.digital_well_being_toast); + mTaskFooterContainer = findViewById(R.id.task_footer_container); + mTaskFooterContainer.setOutlineProvider(mFooterOutlineProvider); + mTaskFooterContainer.setClipToOutline(true); } public TaskMenuView getMenuView() { @@ -410,6 +416,15 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { .getInterpolation(progress); mIconView.setScaleX(scale); mIconView.setScaleY(scale); + + int footerVerticalOffset = (int) (mTaskFooterContainer.getHeight() * (1.0f - scale)); + mTaskFooterContainer.setTranslationY( + mCurrentFullscreenParams.mCurrentDrawnInsets.bottom + + mCurrentFullscreenParams.mCurrentDrawnInsets.top + + footerVerticalOffset); + mFooterOutlineProvider.setFullscreenDrawParams( + mCurrentFullscreenParams, footerVerticalOffset); + mTaskFooterContainer.invalidateOutline(); } public void setIconScaleAnimStartProgress(float startProgress) { @@ -550,6 +565,29 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } } + private static final class FooterOutlineProvider extends ViewOutlineProvider { + + private FullscreenDrawParams mFullscreenDrawParams; + private int mVerticalOffset; + private final Rect mOutlineRect = new Rect(); + + FooterOutlineProvider(FullscreenDrawParams params) { + mFullscreenDrawParams = params; + } + + void setFullscreenDrawParams(FullscreenDrawParams params, int verticalOffset) { + mFullscreenDrawParams = params; + mVerticalOffset = verticalOffset; + } + + @Override + public void getOutline(View view, Outline outline) { + mOutlineRect.set(0, 0, view.getWidth(), view.getHeight()); + mOutlineRect.offset(0, -mVerticalOffset); + outline.setRoundRect(mOutlineRect, mFullscreenDrawParams.mCurrentDrawnCornerRadius); + } + } + @Override public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); @@ -638,7 +676,6 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { } mFullscreenProgress = progress; boolean isFullscreen = mFullscreenProgress > 0; - setIconScaleAndDim(progress, true /* invert */); mIconView.setVisibility(progress < 1 ? VISIBLE : INVISIBLE); setClipChildren(!isFullscreen); setClipToPadding(!isFullscreen); @@ -662,6 +699,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { / (getWidth() + currentInsetsLeft + currentInsetsRight)); } + // Some of the items in here are dependent on the current fullscreen params + setIconScaleAndDim(progress, true /* invert */); + thumbnail.setFullscreenParams(mCurrentFullscreenParams); mOutlineProvider.setFullscreenParams(mCurrentFullscreenParams); invalidateOutline(); -- cgit v1.2.3 From 26185e1feddbb92cbf251c4910116e81923e79a5 Mon Sep 17 00:00:00 2001 From: vadimt Date: Tue, 28 May 2019 12:03:05 -0700 Subject: Adding debug tracing for a lab-only issue Task doesn't get resumed upon clicking at it. Bug: 133765434 Change-Id: I8c5c1308041949d94c6982c78b8337ea81ad400f --- .../src/com/android/quickstep/views/TaskView.java | 10 ++++++++++ 1 file changed, 10 insertions(+) (limited to 'quickstep/recents_ui_overrides/src/com/android') diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index 917465f63..f8d454f34 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -52,6 +52,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.testing.TestProtocol; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; @@ -182,6 +183,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { super(context, attrs, defStyleAttr); mActivity = BaseDraggingActivity.fromContext(context); setOnClickListener((view) -> { + if (com.android.launcher3.testing.TestProtocol.sDebugTracing) { + android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "TaskView onClick"); + } if (getTask() == null) { return; } @@ -285,6 +289,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { public void launchTask(boolean animate, boolean freezeTaskList, Consumer resultCallback, Handler resultCallbackHandler) { + if (com.android.launcher3.testing.TestProtocol.sDebugTracing) { + android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTask"); + } if (ENABLE_QUICKSTEP_LIVE_TILE.get()) { if (isRunningTask()) { getRecentsView().finishRecentsAnimation(false /* toRecents */, @@ -299,6 +306,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { private void launchTaskInternal(boolean animate, boolean freezeTaskList, Consumer resultCallback, Handler resultCallbackHandler) { + if (com.android.launcher3.testing.TestProtocol.sDebugTracing) { + android.util.Log.d(TestProtocol.NO_START_TASK_TAG, "launchTaskInternal"); + } if (mTask != null) { final ActivityOptions opts; if (animate) { -- cgit v1.2.3