Loading .gitignore +2 −1 Original line number Diff line number Diff line Loading @@ -14,3 +14,4 @@ local.properties gradle/ build/ gradlew* .DS_Store quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +8 −2 Original line number Diff line number Diff line Loading @@ -178,6 +178,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) { if (hasControlRemoteAppTransitionPermission()) { boolean fromRecents = mLauncher.getStateManager().getState().overviewUi && findTaskViewToLaunch(launcher, v, null) != null; RecentsView recentsView = mLauncher.getOverviewPanel(); if (fromRecents && recentsView.getQuickScrubController().isQuickSwitch()) { return ActivityOptions.makeCustomAnimation(mLauncher, R.anim.no_anim, R.anim.no_anim); } RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler, true /* startAtFrontOfQueue */) { Loading Loading @@ -218,8 +226,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } }; boolean fromRecents = mLauncher.getStateManager().getState().overviewUi && findTaskViewToLaunch(launcher, v, null) != null; int duration = fromRecents ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION; Loading quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +14 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ public class FastOverviewState extends OverviewState { * Vertical transition of the task previews relative to the full container. */ public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f; public static final float OVERVIEW_CENTERED_TRANSLATION_FACTOR = 0.5f; private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY; Loading @@ -60,12 +61,17 @@ public class FastOverviewState extends OverviewState { RecentsView recentsView = launcher.getOverviewPanel(); recentsView.getTaskSize(sTempRect); return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher), OVERVIEW_TRANSLATION_FACTOR}; boolean isQuickSwitch = recentsView.getQuickScrubController().isQuickSwitch(); float translationYFactor = isQuickSwitch ? OVERVIEW_CENTERED_TRANSLATION_FACTOR : OVERVIEW_TRANSLATION_FACTOR; return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher, isQuickSwitch), translationYFactor}; } public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context) { if (dp.isVerticalBarLayout()) { public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context, boolean isQuickSwitch) { if (dp.isVerticalBarLayout() && !isQuickSwitch) { return 1f; } Loading @@ -73,6 +79,10 @@ public class FastOverviewState extends OverviewState { float usedHeight = taskRect.height() + res.getDimension(R.dimen.task_thumbnail_top_margin); float usedWidth = taskRect.width() + 2 * (res.getDimension(R.dimen.recents_page_spacing) + res.getDimension(R.dimen.quickscrub_adjacent_visible_width)); if (isQuickSwitch) { usedWidth = taskRect.width(); return Math.max(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth); } return Math.min(Math.min(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP); } Loading quickstep/src/com/android/quickstep/ActivityControlHelper.java +3 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.quickstep; import static android.view.View.TRANSLATION_Y; import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherState.BACKGROUND_APP; Loading Loading @@ -58,6 +57,7 @@ import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.uioverrides.FastOverviewState; import com.android.launcher3.userevent.nano.LauncherLogProto; Loading Loading @@ -192,7 +192,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { @InteractionType int interactionType, TransformedRect outRect) { LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect); if (interactionType == INTERACTION_QUICK_SCRUB) { outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context); outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context, FeatureFlags.QUICK_SWITCH.get()); } if (dp.isVerticalBarLayout()) { Rect targetInsets = dp.getInsets(); Loading quickstep/src/com/android/quickstep/QuickScrubController.java +134 −8 Original line number Diff line number Diff line Loading @@ -16,8 +16,18 @@ package com.android.quickstep; import static com.android.launcher3.Utilities.SINGLE_FRAME_MS; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.os.Build; import android.util.FloatProperty; import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.animation.Interpolator; Loading @@ -37,8 +47,10 @@ import com.android.quickstep.views.TaskView; * The behavior is to evenly divide the progress into sections, each of which scrolls one page. * The first and last section set an alarm to auto-advance backwards or forwards, respectively. */ @TargetApi(Build.VERSION_CODES.P) public class QuickScrubController implements OnAlarmListener { public static final int QUICK_SWITCH_FROM_APP_START_DURATION = 0; public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240; public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200; // We want the translation y to finish faster than the rest of the animation. Loading @@ -52,6 +64,19 @@ public class QuickScrubController implements OnAlarmListener { 0.05f, 0.20f, 0.35f, 0.50f, 0.65f, 0.80f, 0.95f }; private static final FloatProperty<QuickScrubController> PROGRESS = new FloatProperty<QuickScrubController>("progress") { @Override public void setValue(QuickScrubController quickScrubController, float progress) { quickScrubController.onQuickScrubProgress(progress); } @Override public Float get(QuickScrubController quickScrubController) { return quickScrubController.mEndProgress; } }; private static final String TAG = "QuickScrubController"; private static final boolean ENABLE_AUTO_ADVANCE = true; private static final long AUTO_ADVANCE_DELAY = 500; Loading @@ -72,6 +97,13 @@ public class QuickScrubController implements OnAlarmListener { private ActivityControlHelper mActivityControlHelper; private TouchInteractionLog mTouchInteractionLog; private boolean mIsQuickSwitch; private float mStartProgress; private float mEndProgress; private float mPrevProgressDelta; private float mPrevPrevProgressDelta; private boolean mShouldSwitchToNext; public QuickScrubController(BaseActivity activity, RecentsView recentsView) { mActivity = activity; mRecentsView = recentsView; Loading @@ -91,17 +123,26 @@ public class QuickScrubController implements OnAlarmListener { mActivityControlHelper = controlHelper; mTouchInteractionLog = touchInteractionLog; if (mIsQuickSwitch) { mShouldSwitchToNext = true; mPrevProgressDelta = 0; if (mRecentsView.getTaskViewCount() > 0) { mRecentsView.getTaskViewAt(0).setFullscreen(true); } if (mRecentsView.getTaskViewCount() > 1) { mRecentsView.getTaskViewAt(1).setFullscreen(true); } } snapToNextTaskIfAvailable(); mActivity.getUserEventDispatcher().resetActionDurationMillis(); } public void onQuickScrubEnd() { mInQuickScrub = false; if (ENABLE_AUTO_ADVANCE) { mAutoAdvanceAlarm.cancelAlarm(); } int page = mRecentsView.getNextPage(); Runnable launchTaskRunnable = () -> { int page = mRecentsView.getPageNearestToCenterOfScreen(); TaskView taskView = mRecentsView.getTaskViewAt(page); if (taskView != null) { mWaitingForTaskLaunch = true; Loading @@ -118,12 +159,49 @@ public class QuickScrubController implements OnAlarmListener { TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key)); } mWaitingForTaskLaunch = false; if (mIsQuickSwitch) { mIsQuickSwitch = false; if (mRecentsView.getTaskViewCount() > 0) { mRecentsView.getTaskViewAt(0).setFullscreen(false); } if (mRecentsView.getTaskViewCount() > 1) { mRecentsView.getTaskViewAt(1).setFullscreen(false); } } }, taskView.getHandler()); } else { breakOutOfQuickScrub(); } mActivityControlHelper = null; }; if (mIsQuickSwitch) { float progressVelocity = mPrevPrevProgressDelta / SINGLE_FRAME_MS; // Move to the next frame immediately, then start the animation from the // following frame since it starts a frame later. float singleFrameProgress = progressVelocity * SINGLE_FRAME_MS; float fromProgress = mEndProgress + singleFrameProgress; onQuickScrubProgress(fromProgress); fromProgress += singleFrameProgress; float toProgress = mShouldSwitchToNext ? 1 : 0; int duration = (int) Math.abs((toProgress - fromProgress) / progressVelocity); duration = Utilities.boundToRange(duration, 80, 300); Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, fromProgress, toProgress); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { launchTaskRunnable.run(); } }); anim.setDuration(duration).start(); return; } if (ENABLE_AUTO_ADVANCE) { mAutoAdvanceAlarm.cancelAlarm(); } int page = mRecentsView.getNextPage(); int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) { Loading Loading @@ -151,19 +229,28 @@ public class QuickScrubController implements OnAlarmListener { mLaunchingTaskId = 0; } public boolean prepareQuickScrub(String tag) { return prepareQuickScrub(tag, mIsQuickSwitch); } /** * Initializes the UI for quick scrub, returns true if success. */ public boolean prepareQuickScrub(String tag) { public boolean prepareQuickScrub(String tag, boolean isQuickSwitch) { if (mWaitingForTaskLaunch || mInQuickScrub) { Log.d(tag, "Waiting for last scrub to finish, will skip this interaction"); return false; } mOnFinishedTransitionToQuickScrubRunnable = null; mRecentsView.setNextPageSwitchRunnable(null); mIsQuickSwitch = isQuickSwitch; return true; } public boolean isQuickSwitch() { return mIsQuickSwitch; } public boolean isWaitingForTaskLaunch() { return mWaitingForTaskLaunch; } Loading @@ -179,6 +266,40 @@ public class QuickScrubController implements OnAlarmListener { } public void onQuickScrubProgress(float progress) { if (mIsQuickSwitch) { TaskView currentPage = mRecentsView.getTaskViewAt(0); TaskView nextPage = mRecentsView.getTaskViewAt(1); if (currentPage == null || nextPage == null) { return; } if (!mFinishedTransitionToQuickScrub) { mStartProgress = mEndProgress = progress; } else { float progressDelta = progress - mEndProgress; mEndProgress = progress; progress = Utilities.boundToRange(progress, mStartProgress, 1); progress = Utilities.mapToRange(progress, mStartProgress, 1, 0, 1, LINEAR); if (mInQuickScrub) { mShouldSwitchToNext = mPrevProgressDelta > 0.007f || progressDelta > 0.007f || progress >= 0.5f; } mPrevPrevProgressDelta = mPrevProgressDelta; mPrevProgressDelta = progressDelta; float scrollDiff = nextPage.getWidth() + mRecentsView.getPageSpacing(); int scrollDir = mRecentsView.isRtl() ? -1 : 1; int linearScrollDiff = (int) (progress * scrollDiff * scrollDir); float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff * scrollDir; currentPage.setZoomScale(1 - DEACCEL_3.getInterpolation(progress) * TaskView.EDGE_SCALE_DOWN_FACTOR); currentPage.setTranslationX(linearScrollDiff + accelScrollDiff); nextPage.setTranslationZ(1); nextPage.setTranslationY(currentPage.getTranslationY()); int startScroll = mRecentsView.isRtl() ? mRecentsView.getMaxScrollX() : 0; mRecentsView.setScrollX(startScroll + linearScrollDiff); } return; } int quickScrubSection = 0; for (float threshold : QUICK_SCRUB_THRESHOLDS) { if (progress < threshold) { Loading Loading @@ -228,9 +349,14 @@ public class QuickScrubController implements OnAlarmListener { public void snapToNextTaskIfAvailable() { if (mInQuickScrub && mRecentsView.getChildCount() > 0) { int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION int duration = mIsQuickSwitch ? QUICK_SWITCH_FROM_APP_START_DURATION : mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION : QUICK_SCRUB_FROM_APP_START_DURATION; int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1; int pageToGoTo = mStartedFromHome || mIsQuickSwitch ? 0 : mRecentsView.getNextPage() + 1; goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */, QUICK_SCRUB_START_INTERPOLATOR); } Loading Loading
.gitignore +2 −1 Original line number Diff line number Diff line Loading @@ -14,3 +14,4 @@ local.properties gradle/ build/ gradlew* .DS_Store
quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +8 −2 Original line number Diff line number Diff line Loading @@ -178,6 +178,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag @Override public ActivityOptions getActivityLaunchOptions(Launcher launcher, View v) { if (hasControlRemoteAppTransitionPermission()) { boolean fromRecents = mLauncher.getStateManager().getState().overviewUi && findTaskViewToLaunch(launcher, v, null) != null; RecentsView recentsView = mLauncher.getOverviewPanel(); if (fromRecents && recentsView.getQuickScrubController().isQuickSwitch()) { return ActivityOptions.makeCustomAnimation(mLauncher, R.anim.no_anim, R.anim.no_anim); } RemoteAnimationRunnerCompat runner = new LauncherAnimationRunner(mHandler, true /* startAtFrontOfQueue */) { Loading Loading @@ -218,8 +226,6 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag } }; boolean fromRecents = mLauncher.getStateManager().getState().overviewUi && findTaskViewToLaunch(launcher, v, null) != null; int duration = fromRecents ? RECENTS_LAUNCH_DURATION : APP_LAUNCH_DURATION; Loading
quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +14 −4 Original line number Diff line number Diff line Loading @@ -35,6 +35,7 @@ public class FastOverviewState extends OverviewState { * Vertical transition of the task previews relative to the full container. */ public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f; public static final float OVERVIEW_CENTERED_TRANSLATION_FACTOR = 0.5f; private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY; Loading @@ -60,12 +61,17 @@ public class FastOverviewState extends OverviewState { RecentsView recentsView = launcher.getOverviewPanel(); recentsView.getTaskSize(sTempRect); return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher), OVERVIEW_TRANSLATION_FACTOR}; boolean isQuickSwitch = recentsView.getQuickScrubController().isQuickSwitch(); float translationYFactor = isQuickSwitch ? OVERVIEW_CENTERED_TRANSLATION_FACTOR : OVERVIEW_TRANSLATION_FACTOR; return new float[] {getOverviewScale(launcher.getDeviceProfile(), sTempRect, launcher, isQuickSwitch), translationYFactor}; } public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context) { if (dp.isVerticalBarLayout()) { public static float getOverviewScale(DeviceProfile dp, Rect taskRect, Context context, boolean isQuickSwitch) { if (dp.isVerticalBarLayout() && !isQuickSwitch) { return 1f; } Loading @@ -73,6 +79,10 @@ public class FastOverviewState extends OverviewState { float usedHeight = taskRect.height() + res.getDimension(R.dimen.task_thumbnail_top_margin); float usedWidth = taskRect.width() + 2 * (res.getDimension(R.dimen.recents_page_spacing) + res.getDimension(R.dimen.quickscrub_adjacent_visible_width)); if (isQuickSwitch) { usedWidth = taskRect.width(); return Math.max(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth); } return Math.min(Math.min(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP); } Loading
quickstep/src/com/android/quickstep/ActivityControlHelper.java +3 −2 Original line number Diff line number Diff line Loading @@ -16,7 +16,6 @@ package com.android.quickstep; import static android.view.View.TRANSLATION_Y; import static com.android.launcher3.LauncherAnimUtils.OVERVIEW_TRANSITION_MS; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; import static com.android.launcher3.LauncherState.BACKGROUND_APP; Loading Loading @@ -58,6 +57,7 @@ import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.compat.AccessibilityManagerCompat; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.uioverrides.FastOverviewState; import com.android.launcher3.userevent.nano.LauncherLogProto; Loading Loading @@ -192,7 +192,8 @@ public interface ActivityControlHelper<T extends BaseDraggingActivity> { @InteractionType int interactionType, TransformedRect outRect) { LayoutUtils.calculateLauncherTaskSize(context, dp, outRect.rect); if (interactionType == INTERACTION_QUICK_SCRUB) { outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context); outRect.scale = FastOverviewState.getOverviewScale(dp, outRect.rect, context, FeatureFlags.QUICK_SWITCH.get()); } if (dp.isVerticalBarLayout()) { Rect targetInsets = dp.getInsets(); Loading
quickstep/src/com/android/quickstep/QuickScrubController.java +134 −8 Original line number Diff line number Diff line Loading @@ -16,8 +16,18 @@ package com.android.quickstep; import static com.android.launcher3.Utilities.SINGLE_FRAME_MS; import static com.android.launcher3.anim.Interpolators.ACCEL; import static com.android.launcher3.anim.Interpolators.DEACCEL_3; import static com.android.launcher3.anim.Interpolators.FAST_OUT_SLOW_IN; import static com.android.launcher3.anim.Interpolators.LINEAR; import android.animation.Animator; import android.animation.AnimatorListenerAdapter; import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.os.Build; import android.util.FloatProperty; import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.animation.Interpolator; Loading @@ -37,8 +47,10 @@ import com.android.quickstep.views.TaskView; * The behavior is to evenly divide the progress into sections, each of which scrolls one page. * The first and last section set an alarm to auto-advance backwards or forwards, respectively. */ @TargetApi(Build.VERSION_CODES.P) public class QuickScrubController implements OnAlarmListener { public static final int QUICK_SWITCH_FROM_APP_START_DURATION = 0; public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240; public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 200; // We want the translation y to finish faster than the rest of the animation. Loading @@ -52,6 +64,19 @@ public class QuickScrubController implements OnAlarmListener { 0.05f, 0.20f, 0.35f, 0.50f, 0.65f, 0.80f, 0.95f }; private static final FloatProperty<QuickScrubController> PROGRESS = new FloatProperty<QuickScrubController>("progress") { @Override public void setValue(QuickScrubController quickScrubController, float progress) { quickScrubController.onQuickScrubProgress(progress); } @Override public Float get(QuickScrubController quickScrubController) { return quickScrubController.mEndProgress; } }; private static final String TAG = "QuickScrubController"; private static final boolean ENABLE_AUTO_ADVANCE = true; private static final long AUTO_ADVANCE_DELAY = 500; Loading @@ -72,6 +97,13 @@ public class QuickScrubController implements OnAlarmListener { private ActivityControlHelper mActivityControlHelper; private TouchInteractionLog mTouchInteractionLog; private boolean mIsQuickSwitch; private float mStartProgress; private float mEndProgress; private float mPrevProgressDelta; private float mPrevPrevProgressDelta; private boolean mShouldSwitchToNext; public QuickScrubController(BaseActivity activity, RecentsView recentsView) { mActivity = activity; mRecentsView = recentsView; Loading @@ -91,17 +123,26 @@ public class QuickScrubController implements OnAlarmListener { mActivityControlHelper = controlHelper; mTouchInteractionLog = touchInteractionLog; if (mIsQuickSwitch) { mShouldSwitchToNext = true; mPrevProgressDelta = 0; if (mRecentsView.getTaskViewCount() > 0) { mRecentsView.getTaskViewAt(0).setFullscreen(true); } if (mRecentsView.getTaskViewCount() > 1) { mRecentsView.getTaskViewAt(1).setFullscreen(true); } } snapToNextTaskIfAvailable(); mActivity.getUserEventDispatcher().resetActionDurationMillis(); } public void onQuickScrubEnd() { mInQuickScrub = false; if (ENABLE_AUTO_ADVANCE) { mAutoAdvanceAlarm.cancelAlarm(); } int page = mRecentsView.getNextPage(); Runnable launchTaskRunnable = () -> { int page = mRecentsView.getPageNearestToCenterOfScreen(); TaskView taskView = mRecentsView.getTaskViewAt(page); if (taskView != null) { mWaitingForTaskLaunch = true; Loading @@ -118,12 +159,49 @@ public class QuickScrubController implements OnAlarmListener { TaskUtils.getLaunchComponentKeyForTask(taskView.getTask().key)); } mWaitingForTaskLaunch = false; if (mIsQuickSwitch) { mIsQuickSwitch = false; if (mRecentsView.getTaskViewCount() > 0) { mRecentsView.getTaskViewAt(0).setFullscreen(false); } if (mRecentsView.getTaskViewCount() > 1) { mRecentsView.getTaskViewAt(1).setFullscreen(false); } } }, taskView.getHandler()); } else { breakOutOfQuickScrub(); } mActivityControlHelper = null; }; if (mIsQuickSwitch) { float progressVelocity = mPrevPrevProgressDelta / SINGLE_FRAME_MS; // Move to the next frame immediately, then start the animation from the // following frame since it starts a frame later. float singleFrameProgress = progressVelocity * SINGLE_FRAME_MS; float fromProgress = mEndProgress + singleFrameProgress; onQuickScrubProgress(fromProgress); fromProgress += singleFrameProgress; float toProgress = mShouldSwitchToNext ? 1 : 0; int duration = (int) Math.abs((toProgress - fromProgress) / progressVelocity); duration = Utilities.boundToRange(duration, 80, 300); Animator anim = ObjectAnimator.ofFloat(this, PROGRESS, fromProgress, toProgress); anim.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { launchTaskRunnable.run(); } }); anim.setDuration(duration).start(); return; } if (ENABLE_AUTO_ADVANCE) { mAutoAdvanceAlarm.cancelAlarm(); } int page = mRecentsView.getNextPage(); int snapDuration = Math.abs(page - mRecentsView.getPageNearestToCenterOfScreen()) * QUICKSCRUB_END_SNAP_DURATION_PER_PAGE; if (mRecentsView.getChildCount() > 0 && mRecentsView.snapToPage(page, snapDuration)) { Loading Loading @@ -151,19 +229,28 @@ public class QuickScrubController implements OnAlarmListener { mLaunchingTaskId = 0; } public boolean prepareQuickScrub(String tag) { return prepareQuickScrub(tag, mIsQuickSwitch); } /** * Initializes the UI for quick scrub, returns true if success. */ public boolean prepareQuickScrub(String tag) { public boolean prepareQuickScrub(String tag, boolean isQuickSwitch) { if (mWaitingForTaskLaunch || mInQuickScrub) { Log.d(tag, "Waiting for last scrub to finish, will skip this interaction"); return false; } mOnFinishedTransitionToQuickScrubRunnable = null; mRecentsView.setNextPageSwitchRunnable(null); mIsQuickSwitch = isQuickSwitch; return true; } public boolean isQuickSwitch() { return mIsQuickSwitch; } public boolean isWaitingForTaskLaunch() { return mWaitingForTaskLaunch; } Loading @@ -179,6 +266,40 @@ public class QuickScrubController implements OnAlarmListener { } public void onQuickScrubProgress(float progress) { if (mIsQuickSwitch) { TaskView currentPage = mRecentsView.getTaskViewAt(0); TaskView nextPage = mRecentsView.getTaskViewAt(1); if (currentPage == null || nextPage == null) { return; } if (!mFinishedTransitionToQuickScrub) { mStartProgress = mEndProgress = progress; } else { float progressDelta = progress - mEndProgress; mEndProgress = progress; progress = Utilities.boundToRange(progress, mStartProgress, 1); progress = Utilities.mapToRange(progress, mStartProgress, 1, 0, 1, LINEAR); if (mInQuickScrub) { mShouldSwitchToNext = mPrevProgressDelta > 0.007f || progressDelta > 0.007f || progress >= 0.5f; } mPrevPrevProgressDelta = mPrevProgressDelta; mPrevProgressDelta = progressDelta; float scrollDiff = nextPage.getWidth() + mRecentsView.getPageSpacing(); int scrollDir = mRecentsView.isRtl() ? -1 : 1; int linearScrollDiff = (int) (progress * scrollDiff * scrollDir); float accelScrollDiff = ACCEL.getInterpolation(progress) * scrollDiff * scrollDir; currentPage.setZoomScale(1 - DEACCEL_3.getInterpolation(progress) * TaskView.EDGE_SCALE_DOWN_FACTOR); currentPage.setTranslationX(linearScrollDiff + accelScrollDiff); nextPage.setTranslationZ(1); nextPage.setTranslationY(currentPage.getTranslationY()); int startScroll = mRecentsView.isRtl() ? mRecentsView.getMaxScrollX() : 0; mRecentsView.setScrollX(startScroll + linearScrollDiff); } return; } int quickScrubSection = 0; for (float threshold : QUICK_SCRUB_THRESHOLDS) { if (progress < threshold) { Loading Loading @@ -228,9 +349,14 @@ public class QuickScrubController implements OnAlarmListener { public void snapToNextTaskIfAvailable() { if (mInQuickScrub && mRecentsView.getChildCount() > 0) { int duration = mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION int duration = mIsQuickSwitch ? QUICK_SWITCH_FROM_APP_START_DURATION : mStartedFromHome ? QUICK_SCRUB_FROM_HOME_START_DURATION : QUICK_SCRUB_FROM_APP_START_DURATION; int pageToGoTo = mStartedFromHome ? 0 : mRecentsView.getNextPage() + 1; int pageToGoTo = mStartedFromHome || mIsQuickSwitch ? 0 : mRecentsView.getNextPage() + 1; goToPageWithHaptic(pageToGoTo, duration, true /* forceHaptic */, QUICK_SCRUB_START_INTERPOLATOR); } Loading