diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml index 332e0fa360..546548036e 100644 --- a/quickstep/AndroidManifest.xml +++ b/quickstep/AndroidManifest.xml @@ -23,6 +23,7 @@ package="com.android.launcher3" > + mVibrator.vibrate(effect)); + } + + protected float getShiftForDisplacement(float displacement) { + // We are moving in the negative x/y direction + displacement = -displacement; + if (displacement > mTransitionDragLength * mDragLengthFactor && mTransitionDragLength > 0) { + return 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); + } + return shift; + } + } +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java index fc29a5663b..52e8ba26d0 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/RecentsActivity.java @@ -28,8 +28,10 @@ import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.AnimatorSet; import android.app.ActivityOptions; +import android.content.Intent; import android.content.res.Configuration; import android.os.Handler; +import android.os.IBinder; import android.os.Looper; import android.view.View; @@ -42,7 +44,9 @@ import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.fallback.FallbackRecentsView; import com.android.quickstep.fallback.RecentsRootView; import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.ObjectWrapper; import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationAdapterCompat; import com.android.systemui.shared.system.RemoteAnimationRunnerCompat; @@ -54,6 +58,9 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; */ public final class RecentsActivity extends BaseRecentsActivity { + public static final String EXTRA_THUMBNAIL = "thumbnailData"; + public static final String EXTRA_TASK_ID = "taskID"; + private Handler mUiHandler = new Handler(Looper.getMainLooper()); private RecentsRootView mRecentsRootView; private FallbackRecentsView mFallbackRecentsView; @@ -78,6 +85,20 @@ public final class RecentsActivity extends BaseRecentsActivity { } } + @Override + protected void onNewIntent(Intent intent) { + int taskID = intent.getIntExtra(EXTRA_TASK_ID, 0); + IBinder thumbnail = intent.getExtras().getBinder(EXTRA_THUMBNAIL); + if (taskID != 0 && thumbnail instanceof ObjectWrapper) { + ThumbnailData thumbnailData = ((ObjectWrapper) thumbnail).get(); + mFallbackRecentsView.showCurrentTask(taskID); + mFallbackRecentsView.updateThumbnail(taskID, thumbnailData); + } + intent.removeExtra(EXTRA_TASK_ID); + intent.removeExtra(EXTRA_THUMBNAIL); + super.onNewIntent(intent); + } + @Override protected void onHandleConfigChanged() { super.onHandleConfigChanged(); 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 ac7ba3fc3d..da9c6cb5fe 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -43,7 +43,6 @@ import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_O import android.animation.Animator; import android.animation.AnimatorSet; -import android.animation.ObjectAnimator; import android.animation.TimeInterpolator; import android.animation.ValueAnimator; import android.annotation.TargetApi; @@ -59,7 +58,6 @@ import android.os.Handler; import android.os.Looper; import android.os.SystemClock; import android.util.Log; -import android.view.HapticFeedbackConstants; import android.view.MotionEvent; import android.view.View; import android.view.View.OnApplyWindowInsetsListener; @@ -97,7 +95,7 @@ import com.android.quickstep.ActivityControlHelper.HomeAnimationFactory; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.inputconsumers.InputConsumer; import com.android.quickstep.inputconsumers.OverviewInputConsumer; -import com.android.quickstep.util.ClipAnimationHelper; +import com.android.quickstep.util.ClipAnimationHelper.TargetAlphaProvider; import com.android.quickstep.util.RectFSpringAnim; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.quickstep.util.SwipeAnimationTargetSet; @@ -112,11 +110,10 @@ import com.android.systemui.shared.system.RemoteAnimationTargetCompat; import com.android.systemui.shared.system.SyncRtSurfaceTransactionApplierCompat; import com.android.systemui.shared.system.WindowCallbacksCompat; -import java.util.function.BiFunction; import java.util.function.Consumer; @TargetApi(Build.VERSION_CODES.O) -public class WindowTransformSwipeHandler +public class WindowTransformSwipeHandler extends BaseSwipeUpHandler implements SwipeAnimationListener, OnApplyWindowInsetsListener { private static final String TAG = WindowTransformSwipeHandler.class.getSimpleName(); @@ -220,30 +217,17 @@ public class WindowTransformSwipeHandler private static final long SHELF_ANIM_DURATION = 240; 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. */ private static final int LOG_NO_OP_PAGE_INDEX = -1; - private final ClipAnimationHelper mClipAnimationHelper; - private final ClipAnimationHelper.TransformParams mTransformParams; - private Runnable mGestureEndCallback; private GestureEndTarget mGestureEndTarget; // Either RectFSpringAnim (if animating home) or ObjectAnimator (from mCurrentShift) otherwise 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 @@ -256,7 +240,6 @@ public class WindowTransformSwipeHandler private final Handler mMainThreadHandler = MAIN_THREAD_EXECUTOR.getHandler(); - private final Context mContext; private final ActivityControlHelper mActivityControlHelper; private final ActivityInitListener mActivityInitListener; @@ -294,7 +277,7 @@ public class WindowTransformSwipeHandler public WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, ActivityControlHelper controller, boolean continuingLastGesture, InputConsumerController inputConsumer) { - mContext = context; + super(context); mRunningTaskId = runningTaskInfo.id; mTouchTimeMs = touchTimeMs; mActivityControlHelper = controller; @@ -303,8 +286,6 @@ public class WindowTransformSwipeHandler mContinuingLastGesture = continuingLastGesture; mRecentsAnimationWrapper = new RecentsAnimationWrapper(inputConsumer, this::createNewInputProxyHandler); - mClipAnimationHelper = new ClipAnimationHelper(context); - mTransformParams = new ClipAnimationHelper.TransformParams(); mMode = SysUINavigationMode.getMode(context); initStateCallbacks(); @@ -394,18 +375,6 @@ public class WindowTransformSwipeHandler } } - private long getFadeInDuration() { - if (mCurrentShift.getCurrentAnimation() != null) { - ObjectAnimator anim = mCurrentShift.getCurrentAnimation(); - long theirDuration = anim.getDuration() - anim.getCurrentPlayTime(); - - // TODO: Find a better heuristic - return Math.min(MAX_SWIPE_DURATION, Math.max(theirDuration, MIN_SWIPE_DURATION)); - } else { - return MAX_SWIPE_DURATION; - } - } - public void initWhenReady() { mActivityInitListener.register(); } @@ -583,22 +552,7 @@ public class WindowTransformSwipeHandler @UiThread public void updateDisplacement(float displacement) { - // We are moving in the negative x/y direction - displacement = -displacement; - 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); - } + mCurrentShift.updateValue(getShiftForDisplacement(displacement)); } public void onMotionPauseChanged(boolean isPaused) { @@ -666,9 +620,8 @@ public class WindowTransformSwipeHandler if (mIsShelfPeeking != wasShelfPeeking) { maybeUpdateRecentsAttachedState(); } - if (mRecentsView != null && shelfState.shouldPreformHaptic) { - mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + if (shelfState.shouldPreformHaptic) { + performHapticFeedback(); } } @@ -722,9 +675,8 @@ public class WindowTransformSwipeHandler final boolean passed = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW; if (passed != mPassedOverviewThreshold) { mPassedOverviewThreshold = passed; - if (mRecentsView != null && mMode != Mode.NO_BUTTON) { - mRecentsView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY, - HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING); + if (mMode != Mode.NO_BUTTON) { + performHapticFeedback(); } } @@ -1450,13 +1402,12 @@ public class WindowTransformSwipeHandler mGestureEndCallback = gestureEndCallback; } - private void setTargetAlphaProvider( - BiFunction provider) { + private void setTargetAlphaProvider(TargetAlphaProvider provider) { mClipAnimationHelper.setTaskAlphaCallback(provider); updateFinalShift(); } - public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, Float expectedAlpha) { + public static float getHiddenTargetAlpha(RemoteAnimationTargetCompat app, float expectedAlpha) { if (!isNotInRecents(app)) { return 0; } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java index d17bba49b5..cdd91b78f4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/inputconsumers/FallbackNoButtonInputConsumer.java @@ -23,22 +23,27 @@ import static android.view.MotionEvent.ACTION_POINTER_UP; import static android.view.MotionEvent.ACTION_UP; import static android.view.MotionEvent.INVALID_POINTER_ID; -import static com.android.quickstep.WindowTransformSwipeHandler.MAX_SWIPE_DURATION; +import static com.android.quickstep.RecentsActivity.EXTRA_TASK_ID; +import static com.android.quickstep.RecentsActivity.EXTRA_THUMBNAIL; import static com.android.quickstep.WindowTransformSwipeHandler.MIN_PROGRESS_FOR_OVERVIEW; -import static com.android.quickstep.WindowTransformSwipeHandler.MIN_SWIPE_DURATION; +import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.HOME; +import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.LAST_TASK; +import static com.android.quickstep.inputconsumers.FallbackNoButtonInputConsumer.GestureEndTarget.RECENTS; import static com.android.quickstep.inputconsumers.OtherActivityInputConsumer.QUICKSTEP_TOUCH_SLOP_RATIO; import static com.android.quickstep.TouchInteractionService.startRecentsActivityAsync; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_RECENTS; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; -import android.animation.ValueAnimator; +import android.animation.AnimatorSet; import android.app.ActivityManager.RunningTaskInfo; +import android.app.ActivityOptions; import android.content.Context; import android.content.Intent; import android.graphics.PointF; import android.graphics.Rect; import android.graphics.RectF; +import android.os.Bundle; import android.view.MotionEvent; import android.view.VelocityTracker; import android.view.ViewConfiguration; @@ -48,38 +53,50 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.R; import com.android.quickstep.ActivityControlHelper; +import com.android.quickstep.AnimatedFloat; +import com.android.quickstep.BaseSwipeUpHandler; import com.android.quickstep.OverviewComponentObserver; import com.android.quickstep.SwipeSharedState; -import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.ClipAnimationHelper.TransformParams; +import com.android.quickstep.util.MotionPauseDetector; import com.android.quickstep.util.NavBarPosition; +import com.android.quickstep.util.ObjectWrapper; import com.android.quickstep.util.RecentsAnimationListenerSet; import com.android.quickstep.util.SwipeAnimationTargetSet; import com.android.quickstep.util.SwipeAnimationTargetSet.SwipeAnimationListener; +import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputMonitorCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; -public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimationListener { +public class FallbackNoButtonInputConsumer extends BaseSwipeUpHandler + implements InputConsumer, SwipeAnimationListener { - private static final int STATE_NOT_FINISHED = 0; - private static final int STATE_FINISHED_TO_HOME = 1; - private static final int STATE_FINISHED_TO_APP = 2; + public enum GestureEndTarget { + HOME(3, 100, 1), + RECENTS(1, 300, 0), + LAST_TASK(0, 150, 1); - private static final float PROGRESS_TO_END_GESTURE = -2; + private final float mEndProgress; + private final long mDurationMultiplier; + private final float mLauncherAlpha; + GestureEndTarget(float endProgress, long durationMultiplier, float launcherAlpha) { + mEndProgress = endProgress; + mDurationMultiplier = durationMultiplier; + mLauncherAlpha = launcherAlpha; + } + } private final ActivityControlHelper mActivityControlHelper; private final InputMonitorCompat mInputMonitor; - private final Context mContext; private final NavBarPosition mNavBarPosition; private final SwipeSharedState mSwipeSharedState; private final OverviewComponentObserver mOverviewComponentObserver; private final int mRunningTaskId; - private final ClipAnimationHelper mClipAnimationHelper; - private final TransformParams mTransformParams = new TransformParams(); - private final float mTransitionDragLength; private final DeviceProfile mDP; + private final MotionPauseDetector mMotionPauseDetector; + private final float mMotionPauseMinDisplacement; + private final Rect mTargetRect = new Rect(); private final RectF mSwipeTouchRegion; private final boolean mDisableHorizontalSwipe; @@ -87,6 +104,9 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat private final PointF mDownPos = new PointF(); private final PointF mLastPos = new PointF(); + private final AnimatedFloat mLauncherAlpha = new AnimatedFloat(this::onLauncherAlphaChanged); + private final AnimatedFloat mProgress = new AnimatedFloat(this::onProgressChanged); + private int mActivePointerId = -1; // Slop used to determine when we say that the gesture has started. private boolean mPassedPilferInputSlop; @@ -99,21 +119,26 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat // Might be displacement in X or Y, depending on the direction we are swiping from the nav bar. private float mStartDisplacement; private SwipeAnimationTargetSet mSwipeAnimationTargetSet; - private float mProgress; - private int mState = STATE_NOT_FINISHED; + private boolean mIsMotionPaused = false; + private GestureEndTarget mEndTarget; public FallbackNoButtonInputConsumer(Context context, ActivityControlHelper activityControlHelper, InputMonitorCompat inputMonitor, SwipeSharedState swipeSharedState, RectF swipeTouchRegion, OverviewComponentObserver overviewComponentObserver, boolean disableHorizontalSwipe, RunningTaskInfo runningTaskInfo) { - mContext = context; + super(context); mActivityControlHelper = activityControlHelper; mInputMonitor = inputMonitor; mOverviewComponentObserver = overviewComponentObserver; mRunningTaskId = runningTaskInfo.id; + mMotionPauseDetector = new MotionPauseDetector(context); + mMotionPauseMinDisplacement = context.getResources().getDimension( + R.dimen.motion_pause_detector_min_displacement_from_app); + mMotionPauseDetector.setOnMotionPauseListener(this::onMotionPauseChanged); + mSwipeSharedState = swipeSharedState; mSwipeTouchRegion = swipeTouchRegion; mDisableHorizontalSwipe = disableHorizontalSwipe; @@ -124,13 +149,11 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat mTouchSlop = QUICKSTEP_TOUCH_SLOP_RATIO * ViewConfiguration.get(context).getScaledTouchSlop(); - mClipAnimationHelper = new ClipAnimationHelper(context); - mDP = InvariantDeviceProfile.INSTANCE.get(context).getDeviceProfile(context).copy(context); - Rect tempRect = new Rect(); - mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength( - mDP, context, tempRect); - mClipAnimationHelper.updateTargetRect(tempRect); + mLauncherAlpha.value = 1; + + mClipAnimationHelper.setBaseAlphaCallback((t, a) -> mLauncherAlpha.value); + initTransitionTarget(); } @Override @@ -138,6 +161,19 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat return TYPE_FALLBACK_NO_BUTTON; } + private void onLauncherAlphaChanged() { + if (mSwipeAnimationTargetSet != null && mEndTarget == null) { + mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams); + } + } + + private void onMotionPauseChanged(boolean isPaused) { + mIsMotionPaused = isPaused; + mLauncherAlpha.animateToValue(mLauncherAlpha.value, isPaused ? 0 : 1) + .setDuration(150).start(); + performHapticFeedback(); + } + @Override public void onMotionEvent(MotionEvent ev) { if (mVelocityTracker == null) { @@ -147,6 +183,7 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat mVelocityTracker.addMovement(ev); if (ev.getActionMasked() == ACTION_POINTER_UP) { mVelocityTracker.clear(); + mMotionPauseDetector.clear(); } switch (ev.getActionMasked()) { @@ -204,6 +241,9 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat } } else { updateDisplacement(displacement - mStartDisplacement); + mMotionPauseDetector.setDisallowPause( + -displacement < mMotionPauseMinDisplacement); + mMotionPauseDetector.addPosition(displacement, ev.getEventTime()); } break; } @@ -230,9 +270,11 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat } private void updateDisplacement(float displacement) { - mProgress = displacement / mTransitionDragLength; - mTransformParams.setProgress(mProgress); + mProgress.updateValue(getShiftForDisplacement(displacement)); + } + private void onProgressChanged() { + mTransformParams.setProgress(mProgress.value); if (mSwipeAnimationTargetSet != null) { mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams); } @@ -251,7 +293,7 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat */ private void finishTouchTracking(MotionEvent ev) { if (ev.getAction() == ACTION_CANCEL) { - mState = STATE_FINISHED_TO_APP; + mEndTarget = LAST_TASK; } else { mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.get(mContext).getScaledMaximumFlingVelocity()); @@ -264,53 +306,68 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat .getDimension(R.dimen.quickstep_fling_threshold_velocity); boolean isFling = Math.abs(velocity) > flingThreshold; - boolean goingHome; - if (!isFling) { - goingHome = -mProgress >= MIN_PROGRESS_FOR_OVERVIEW; + if (isFling) { + mEndTarget = velocity < 0 ? HOME : LAST_TASK; + } else if (mIsMotionPaused) { + mEndTarget = RECENTS; } else { - goingHome = velocity < 0; - } - - if (goingHome) { - mState = STATE_FINISHED_TO_HOME; - } else { - mState = STATE_FINISHED_TO_APP; + mEndTarget = mProgress.value >= MIN_PROGRESS_FOR_OVERVIEW ? HOME : LAST_TASK; } } if (mSwipeAnimationTargetSet != null) { finishAnimationTargetSet(); } + mMotionPauseDetector.clear(); + } + + private void finishAnimationTargetSetAnimationComplete() { + switch (mEndTarget) { + case HOME: + mSwipeAnimationTargetSet.finishController(true, null, true); + break; + case LAST_TASK: + mSwipeAnimationTargetSet.finishController(false, null, false); + break; + case RECENTS: { + ThumbnailData thumbnail = + mSwipeAnimationTargetSet.controller.screenshotTask(mRunningTaskId); + mSwipeAnimationTargetSet.controller.setCancelWithDeferredScreenshot(true); + + ActivityOptions options = ActivityOptions.makeCustomAnimation(mContext, 0, 0); + Bundle extras = new Bundle(); + extras.putBinder(EXTRA_THUMBNAIL, new ObjectWrapper<>(thumbnail)); + extras.putInt(EXTRA_TASK_ID, mRunningTaskId); + + Intent intent = new Intent(mOverviewComponentObserver.getOverviewIntent()) + .putExtras(extras); + mContext.startActivity(intent, options.toBundle()); + mSwipeAnimationTargetSet.controller.cleanupScreenshot(); + break; + } + } } private void finishAnimationTargetSet() { - if (mState == STATE_FINISHED_TO_APP) { - mSwipeAnimationTargetSet.finishController(false, null, false); - } else { - if (mProgress < PROGRESS_TO_END_GESTURE) { - mSwipeAnimationTargetSet.finishController(true, null, true); - } else { - long duration = (long) (Math.min(mProgress - PROGRESS_TO_END_GESTURE, 1) - * MAX_SWIPE_DURATION / Math.abs(PROGRESS_TO_END_GESTURE)); - if (duration < 0) { - duration = MIN_SWIPE_DURATION; - } + float endProgress = mEndTarget.mEndProgress; - ValueAnimator anim = ValueAnimator.ofFloat(mProgress, PROGRESS_TO_END_GESTURE); - anim.addUpdateListener(a -> { - float p = (Float) anim.getAnimatedValue(); - mTransformParams.setProgress(p); - mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams); - }); - anim.setDuration(duration); - anim.addListener(new AnimatorListenerAdapter() { - @Override - public void onAnimationEnd(Animator animation) { - mSwipeAnimationTargetSet.finishController(true, null, true); - } - }); - anim.start(); - } + if (mProgress.value != endProgress) { + AnimatorSet anim = new AnimatorSet(); + anim.play(mLauncherAlpha.animateToValue( + mLauncherAlpha.value, mEndTarget.mLauncherAlpha)); + anim.play(mProgress.animateToValue(mProgress.value, endProgress)); + + anim.setDuration((long) (mEndTarget.mDurationMultiplier * + Math.abs(endProgress - mProgress.value))); + anim.addListener(new AnimatorListenerAdapter() { + @Override + public void onAnimationEnd(Animator animation) { + finishAnimationTargetSetAnimationComplete(); + } + }); + anim.start(); + } else { + finishAnimationTargetSetAnimationComplete(); } } @@ -321,21 +378,29 @@ public class FallbackNoButtonInputConsumer implements InputConsumer, SwipeAnimat RemoteAnimationTargetCompat runningTaskTarget = targetSet.findTask(mRunningTaskId); mDP.updateIsSeascape(mContext.getSystemService(WindowManager.class)); + if (targetSet.homeContentInsets != null) { + mDP.updateInsets(targetSet.homeContentInsets); + } + if (runningTaskTarget != null) { mClipAnimationHelper.updateSource(overviewStackBounds, runningTaskTarget); } mClipAnimationHelper.prepareAnimation(mDP, false /* isOpening */); - - overviewStackBounds - .inset(-overviewStackBounds.width() / 5, -overviewStackBounds.height() / 5); - mClipAnimationHelper.updateTargetRect(overviewStackBounds); + initTransitionTarget(); mClipAnimationHelper.applyTransform(mSwipeAnimationTargetSet, mTransformParams); - if (mState != STATE_NOT_FINISHED) { + if (mEndTarget != null) { finishAnimationTargetSet(); } } + private void initTransitionTarget() { + mTransitionDragLength = mActivityControlHelper.getSwipeUpDestinationAndLength( + mDP, mContext, mTargetRect); + mDragLengthFactor = (float) mDP.heightPx / mTransitionDragLength; + mClipAnimationHelper.updateTargetRect(mTargetRect); + } + @Override public void onRecentsAnimationCanceled() { } 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 de671e04aa..f0a290333c 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 @@ -99,8 +99,8 @@ public class ClipAnimationHelper { // Whether to boost the opening animation target layers, or the closing private int mBoostModeTargetLayers = -1; - private BiFunction mTaskAlphaCallback = - (t, a1) -> a1; + private TargetAlphaProvider mTaskAlphaCallback = (t, a) -> a; + private TargetAlphaProvider mBaseAlphaCallback = (t, a) -> 1; public ClipAnimationHelper(Context context) { mWindowCornerRadius = getWindowCornerRadius(context.getResources()); @@ -187,12 +187,12 @@ public class ClipAnimationHelper { Rect crop = mTmpRect; crop.set(app.sourceContainerBounds); crop.offsetTo(0, 0); - float alpha = 1f; + float alpha; int layer = RemoteAnimationProvider.getLayer(app, mBoostModeTargetLayers); float cornerRadius = 0f; float scale = Math.max(params.currentRect.width(), mTargetRect.width()) / crop.width(); if (app.mode == targetSet.targetMode) { - alpha = mTaskAlphaCallback.apply(app, params.targetAlpha); + alpha = mTaskAlphaCallback.getAlpha(app, params.targetAlpha); if (app.activityType != RemoteAnimationTargetCompat.ACTIVITY_TYPE_HOME) { mTmpMatrix.setRectToRect(mSourceRect, params.currentRect, ScaleToFit.FILL); mTmpMatrix.postTranslate(app.position.x, app.position.y); @@ -214,9 +214,12 @@ public class ClipAnimationHelper { // home target. alpha = 1 - (progress * params.targetAlpha); } - } else if (ENABLE_QUICKSTEP_LIVE_TILE.get() && launcherOnTop) { - crop = null; - layer = Integer.MAX_VALUE; + } else { + alpha = mBaseAlphaCallback.getAlpha(app, progress); + if (ENABLE_QUICKSTEP_LIVE_TILE.get() && launcherOnTop) { + crop = null; + layer = Integer.MAX_VALUE; + } } // Since radius is in Surface space, but we draw the rounded corners in screen space, we @@ -247,11 +250,14 @@ public class ClipAnimationHelper { } } - public void setTaskAlphaCallback( - BiFunction callback) { + public void setTaskAlphaCallback(TargetAlphaProvider callback) { mTaskAlphaCallback = callback; } + public void setBaseAlphaCallback(TargetAlphaProvider callback) { + mBaseAlphaCallback = callback; + } + public void fromTaskThumbnailView(TaskThumbnailView ttv, RecentsView rv) { fromTaskThumbnailView(ttv, rv, null); } @@ -357,6 +363,10 @@ public class ClipAnimationHelper { return mCurrentCornerRadius; } + public interface TargetAlphaProvider { + float getAlpha(RemoteAnimationTargetCompat target, float expectedAlpha); + } + public static class TransformParams { float progress; public float offsetX; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ObjectWrapper.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ObjectWrapper.java new file mode 100644 index 0000000000..abfe3adbff --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/util/ObjectWrapper.java @@ -0,0 +1,41 @@ +/* + * 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.os.Binder; +import android.os.IBinder; + +/** + * Utility class to pass non-parcealable objects within same process using parcealable payload. + * + * It wraps the object in a binder as binders are singleton within a process + */ +public class ObjectWrapper extends Binder { + + private final T mObject; + + public ObjectWrapper(T object) { + mObject = object; + } + + public T get() { + return mObject; + } + + public static IBinder wrap(Object obj) { + return new ObjectWrapper<>(obj); + } +}