From 0fb1e4b5a77cf169629b2d89cdeda54ea3995b24 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 24 May 2018 12:16:38 -0700 Subject: [PATCH 01/23] Cancelling quickscrub state incease we missed quickscrub end event > This can happen when the remote transition is cancelled while animating down during quickscrub, cause WindowTransformSwipeHandler to get invalidated and miss onQuickscrubEnd Bug: 80140388 Change-Id: I0221e301d4d633bab0defaa6af76e0054776a95a --- .../launcher3/uioverrides/FastOverviewState.java | 6 ++++++ .../com/android/quickstep/QuickScrubController.java | 11 +++++++++++ .../quickstep/WindowTransformSwipeHandler.java | 1 + 3 files changed, 18 insertions(+) diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java index 43d982230b..cd92314a73 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java @@ -76,4 +76,10 @@ public class FastOverviewState extends OverviewState { return Math.min(Math.min(dp.availableHeightPx / usedHeight, dp.availableWidthPx / usedWidth), MAX_PREVIEW_SCALE_UP); } + + @Override + public void onStateDisabled(Launcher launcher) { + super.onStateDisabled(launcher); + launcher.getOverviewPanel().getQuickScrubController().cancelActiveQuickscrub(); + } } diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index 8e1a3d5d8a..95a82dd860 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -132,6 +132,17 @@ public class QuickScrubController implements OnAlarmListener { } } + public void cancelActiveQuickscrub() { + if (!mInQuickScrub) { + return; + } + Log.d(TAG, "Quickscrub was active, cancelling"); + mInQuickScrub = false; + mActivityControlHelper = null; + mOnFinishedTransitionToQuickScrubRunnable = null; + mRecentsView.setNextPageSwitchRunnable(null); + } + /** * Initializes the UI for quick scrub, returns true if success. */ diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index e93c80789f..695e046b1b 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -700,6 +700,7 @@ public class WindowTransformSwipeHandler { mRecentsView.setRunningTaskHidden(false); mRecentsView.setRunningTaskIconScaledDown(false /* isScaledDown */, false /* animate */); + mQuickScrubController.cancelActiveQuickscrub(); } private void notifyTransitionCancelled() { From 4ff7d8e7b37f92420159e0eda41f38b34aaada24 Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Thu, 24 May 2018 17:13:36 -0700 Subject: [PATCH 02/23] Use correct interpolator for recents scale when quick scrubbing Use same interpolator for scale and translationY so that they feel more coordinated. (They were already the same in all cases except when scrubbing when already in overview, which never had a scale component before.) Bug: 80139193 Change-Id: Id143b5cc9279d55aaa1b0444db5fe4b41ce92170 --- .../uioverrides/RecentsViewStateController.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java index e3aabd6c87..ea27eb25b9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java +++ b/quickstep/src/com/android/launcher3/uioverrides/RecentsViewStateController.java @@ -76,15 +76,16 @@ public class RecentsViewStateController implements StateHandler { } PropertySetter setter = config.getPropertySetter(builder); float[] scaleTranslationYFactor = toState.getOverviewScaleAndTranslationYFactor(mLauncher); - Interpolator scaleInterpolator = builder.getInterpolator(ANIM_OVERVIEW_SCALE, LINEAR); - setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationYFactor[0], scaleInterpolator); - Interpolator transYInterpolator = scaleInterpolator; + Interpolator scaleAndTransYInterpolator = builder.getInterpolator( + ANIM_OVERVIEW_SCALE, LINEAR); if (mLauncher.getStateManager().getState() == OVERVIEW && toState == FAST_OVERVIEW) { - transYInterpolator = Interpolators.clampToProgress(QUICK_SCRUB_START_INTERPOLATOR, 0, - QUICK_SCRUB_TRANSLATION_Y_FACTOR); + scaleAndTransYInterpolator = Interpolators.clampToProgress( + QUICK_SCRUB_START_INTERPOLATOR, 0, QUICK_SCRUB_TRANSLATION_Y_FACTOR); } + setter.setFloat(mRecentsView, SCALE_PROPERTY, scaleTranslationYFactor[0], + scaleAndTransYInterpolator); setter.setFloat(mRecentsView, TRANSLATION_Y_FACTOR, scaleTranslationYFactor[1], - transYInterpolator); + scaleAndTransYInterpolator); setter.setFloat(mRecentsViewContainer, CONTENT_ALPHA, toState.overviewUi ? 1 : 0, builder.getInterpolator(ANIM_OVERVIEW_FADE, AGGRESSIVE_EASE_IN_OUT)); From 012d39a0e954614d41229e35af5152dbd3b27efb Mon Sep 17 00:00:00 2001 From: Jon Miranda Date: Fri, 25 May 2018 10:37:53 -0700 Subject: [PATCH 03/23] Fix crash caused by removing update listener in update listener. Bug: 80236772 Test: Fling all apps open, and catch it before it reaches the top Change-Id: I082a26b97afb7dbc162758ff9654e4a3707f9d7e --- .../android/launcher3/allapps/AllAppsContainerView.java | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/allapps/AllAppsContainerView.java b/src/com/android/launcher3/allapps/AllAppsContainerView.java index 68ad6e346f..72ba418b25 100644 --- a/src/com/android/launcher3/allapps/AllAppsContainerView.java +++ b/src/com/android/launcher3/allapps/AllAppsContainerView.java @@ -466,9 +466,12 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo */ public void addSpringFromFlingUpdateListener(ValueAnimator animator, float velocity) { animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { + boolean shouldSpring = true; + @Override public void onAnimationUpdate(ValueAnimator valueAnimator) { - if (valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { + if (shouldSpring + && valueAnimator.getAnimatedFraction() >= FLING_ANIMATION_THRESHOLD) { int searchViewId = getSearchView().getId(); addSpringView(searchViewId); @@ -481,7 +484,7 @@ public class AllAppsContainerView extends SpringRelativeLayout implements DragSo } }); - animator.removeUpdateListener(this); + shouldSpring = false; } } }); From db9f86a472844aa3a24c422983839ffd0253e2f8 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 23 May 2018 15:49:39 -0700 Subject: [PATCH 04/23] Accounting for view translation when calculating the focus location Bug: 80160107 Change-Id: Ibb0cb82c33c141bb3abf9b7576be4253630cb8c5 --- .../keyboard/ViewGroupFocusHelper.java | 23 ++----------------- 1 file changed, 2 insertions(+), 21 deletions(-) diff --git a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java index bd5c06e5b1..fde220cbf6 100644 --- a/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java +++ b/src/com/android/launcher3/keyboard/ViewGroupFocusHelper.java @@ -18,7 +18,6 @@ package com.android.launcher3.keyboard; import android.graphics.Rect; import android.view.View; -import android.view.View.OnFocusChangeListener; import com.android.launcher3.PagedView; @@ -52,8 +51,8 @@ public class ViewGroupFocusHelper extends FocusIndicatorHelper { private void computeLocationRelativeToContainer(View child, Rect outRect) { View parent = (View) child.getParent(); - outRect.left += child.getLeft(); - outRect.top += child.getTop(); + outRect.left += child.getX(); + outRect.top += child.getY(); if (parent != mContainer) { if (parent instanceof PagedView) { @@ -64,22 +63,4 @@ public class ViewGroupFocusHelper extends FocusIndicatorHelper { computeLocationRelativeToContainer(parent, outRect); } } - - /** - * Sets the alpha of this FocusIndicatorHelper to 0 when a view with this listener - * receives focus. - */ - public View.OnFocusChangeListener getHideIndicatorOnFocusListener() { - return new OnFocusChangeListener() { - @Override - public void onFocusChange(View v, boolean hasFocus) { - if (hasFocus) { - endCurrentAnimation(); - setCurrentView(null); - setAlpha(0); - invalidateDirty(); - } - } - }; - } } From de184a243d7e5190d6e2b5fb6cc57f372e9210cc Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Thu, 24 May 2018 13:05:50 -0700 Subject: [PATCH 05/23] Add logging for selected text and split screen Bug: 79787082 action:LONGPRESS Source child:TASK_PREVIEW action:TAP Source child:SPLIT_SCREEN_TARGET Change-Id: Ica5a3955f092c6678e646b6df76567cdfa3485df --- protos/launcher_log.proto | 2 ++ quickstep/src/com/android/quickstep/TaskSystemShortcut.java | 6 +++++- 2 files changed, 7 insertions(+), 1 deletion(-) diff --git a/protos/launcher_log.proto b/protos/launcher_log.proto index cab20a3bee..06e6a923d4 100644 --- a/protos/launcher_log.proto +++ b/protos/launcher_log.proto @@ -110,6 +110,8 @@ enum ControlType { QUICK_SCRUB_BUTTON = 12; CLEAR_ALL_BUTTON = 13; CANCEL_TARGET = 14; + TASK_PREVIEW = 15; + SPLIT_SCREEN_TARGET = 16; } enum TipType { diff --git a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java index 228af8e907..f82ff8c535 100644 --- a/quickstep/src/com/android/quickstep/TaskSystemShortcut.java +++ b/quickstep/src/com/android/quickstep/TaskSystemShortcut.java @@ -16,6 +16,8 @@ package com.android.quickstep; +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; + import android.content.ComponentName; import android.content.Intent; import android.graphics.Bitmap; @@ -35,6 +37,7 @@ import com.android.launcher3.ItemInfo; import com.android.launcher3.R; import com.android.launcher3.ShortcutInfo; import com.android.launcher3.popup.SystemShortcut; +import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.util.InstantAppResolver; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskThumbnailView; @@ -166,7 +169,8 @@ public class TaskSystemShortcut extends SystemShortcut Log.w(TAG, "Failed to notify SysUI of split screen: ", e); return; } - + activity.getUserEventDispatcher().logActionOnControl(TAP, + LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET); // Add a device profile change listener to kick off animating the side tasks // once we enter multiwindow mode and relayout activity.addOnDeviceProfileChangeListener(onDeviceProfileChangeListener); From 35cde20a171a774f048b6c25013d1389c734c0c8 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Thu, 24 May 2018 16:45:26 -0700 Subject: [PATCH 06/23] Tweaking quickscrub launch animation for new task sizes. Bug: 79945202 Change-Id: Ibe1e53d45bc3fda325cebc14aa6a61f61f08edb0 --- .../LauncherAppTransitionManagerImpl.java | 16 +++++++++++----- .../android/quickstep/QuickScrubController.java | 6 +++++- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 6703bb546e..87854234bb 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -105,6 +105,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag private static final int APP_LAUNCH_ALPHA_DURATION = 50; public static final int RECENTS_LAUNCH_DURATION = 336; + public static final int RECENTS_QUICKSCRUB_LAUNCH_DURATION = 300; private static final int LAUNCHER_RESUME_START_DELAY = 100; private static final int CLOSING_TRANSITION_DURATION_MS = 250; @@ -253,15 +254,21 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag RecentsView recentsView = mLauncher.getOverviewPanel(); boolean launcherClosing = launcherIsATargetWithMode(targets, MODE_CLOSING); boolean skipLauncherChanges = !launcherClosing; + boolean isLaunchingFromQuickscrub = + recentsView.getQuickScrubController().isWaitingForTaskLaunch(); TaskView taskView = findTaskViewToLaunch(mLauncher, v, targets); if (taskView == null) { return false; } + int duration = isLaunchingFromQuickscrub + ? RECENTS_QUICKSCRUB_LAUNCH_DURATION + : RECENTS_LAUNCH_DURATION; + ClipAnimationHelper helper = new ClipAnimationHelper(); target.play(getRecentsWindowAnimator(taskView, skipLauncherChanges, targets, helper) - .setDuration(RECENTS_LAUNCH_DURATION)); + .setDuration(duration)); Animator childStateAnimation = null; // Found a visible recents task that matches the opening app, lets launch the app from there @@ -270,7 +277,7 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag if (launcherClosing) { launcherAnim = recentsView.createAdjacentPageAnimForTaskLaunch(taskView, helper); launcherAnim.setInterpolator(Interpolators.TOUCH_RESPONSE_INTERPOLATOR); - launcherAnim.setDuration(RECENTS_LAUNCH_DURATION); + launcherAnim.setDuration(duration); // Make sure recents gets fixed up by resetting task alphas and scales, etc. windowAnimEndListener = new AnimatorListenerAdapter() { @@ -282,11 +289,10 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag }; } else { AnimatorPlaybackController controller = - mLauncher.getStateManager() - .createAnimationToNewWorkspace(NORMAL, RECENTS_LAUNCH_DURATION); + mLauncher.getStateManager().createAnimationToNewWorkspace(NORMAL, duration); controller.dispatchOnStart(); childStateAnimation = controller.getTarget(); - launcherAnim = controller.getAnimationPlayer().setDuration(RECENTS_LAUNCH_DURATION); + launcherAnim = controller.getAnimationPlayer().setDuration(duration); windowAnimEndListener = new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { diff --git a/quickstep/src/com/android/quickstep/QuickScrubController.java b/quickstep/src/com/android/quickstep/QuickScrubController.java index 8e1a3d5d8a..3cd6b01756 100644 --- a/quickstep/src/com/android/quickstep/QuickScrubController.java +++ b/quickstep/src/com/android/quickstep/QuickScrubController.java @@ -40,7 +40,7 @@ import com.android.quickstep.views.TaskView; public class QuickScrubController implements OnAlarmListener { public static final int QUICK_SCRUB_FROM_APP_START_DURATION = 240; - public static final int QUICK_SCRUB_FROM_HOME_START_DURATION = 150; + 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. public static final float QUICK_SCRUB_TRANSLATION_Y_FACTOR = 5f / 6; public static final Interpolator QUICK_SCRUB_START_INTERPOLATOR = FAST_OUT_SLOW_IN; @@ -145,6 +145,10 @@ public class QuickScrubController implements OnAlarmListener { return true; } + public boolean isWaitingForTaskLaunch() { + return mWaitingForTaskLaunch; + } + /** * Attempts to go to normal overview or back to home, so UI doesn't prevent user interaction. */ From 4dcda06542648f19ca496085a76c3184492d1d48 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Fri, 25 May 2018 10:32:40 -0700 Subject: [PATCH 07/23] Fixing launcher going to a different state when dragging an icon from different activity Bug: 80191074 Change-Id: I45ea646dc2bd21627e8b724dac9c9fc23c18797d --- .../LauncherAppTransitionManagerImpl.java | 9 +++- .../launcher3/LauncherInitListener.java | 6 ++- .../launcher3/uioverrides/UiFactory.java | 24 +++++++++ .../util/RemoteFadeOutAnimationListener.java | 53 +++++++++++++++++++ .../dragndrop/BaseItemDragListener.java | 2 +- .../dragndrop/PinItemDragListener.java | 20 +++++++ .../launcher3/uioverrides/UiFactory.java | 4 ++ 7 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 6703bb546e..fe2a98fea2 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -50,6 +50,7 @@ import android.graphics.Matrix; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.CancellationSignal; import android.os.Handler; import android.os.Looper; import android.util.Log; @@ -236,8 +237,14 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag return bounds; } - public void setRemoteAnimationProvider(RemoteAnimationProvider animationProvider) { + public void setRemoteAnimationProvider(final RemoteAnimationProvider animationProvider, + CancellationSignal cancellationSignal) { mRemoteAnimationProvider = animationProvider; + cancellationSignal.setOnCancelListener(() -> { + if (animationProvider == mRemoteAnimationProvider) { + mRemoteAnimationProvider = null; + } + }); } /** diff --git a/quickstep/src/com/android/launcher3/LauncherInitListener.java b/quickstep/src/com/android/launcher3/LauncherInitListener.java index e5e377f83b..08b6bfc6a0 100644 --- a/quickstep/src/com/android/launcher3/LauncherInitListener.java +++ b/quickstep/src/com/android/launcher3/LauncherInitListener.java @@ -20,6 +20,7 @@ import android.content.Context; import android.content.Intent; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.os.Handler; import com.android.launcher3.states.InternalStateHandler; @@ -48,10 +49,11 @@ public class LauncherInitListener extends InternalStateHandler implements Activi // Set a one-time animation provider. After the first call, this will get cleared. // TODO: Probably also check the intended target id. + CancellationSignal cancellationSignal = new CancellationSignal(); appTransitionManager.setRemoteAnimationProvider((targets) -> { // On the first call clear the reference. - appTransitionManager.setRemoteAnimationProvider(null); + cancellationSignal.cancel(); RemoteAnimationProvider provider = mRemoteAnimationProvider; mRemoteAnimationProvider = null; @@ -59,7 +61,7 @@ public class LauncherInitListener extends InternalStateHandler implements Activi return provider.createWindowAnimation(targets); } return null; - }); + }, cancellationSignal); } OverviewCallbacks.get(launcher).onInitOverviewTransition(); return mOnInitListener.test(launcher, alreadyOnHome); diff --git a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java index d0c7b21172..dd5dcbeaf8 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java +++ b/quickstep/src/com/android/launcher3/uioverrides/UiFactory.java @@ -25,14 +25,19 @@ import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.allapps.DiscoveryBounce.HOME_BOUNCE_SEEN; import static com.android.launcher3.allapps.DiscoveryBounce.SHELF_BOUNCE_SEEN; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; +import android.animation.AnimatorSet; +import android.animation.ValueAnimator; import android.app.Activity; import android.content.Context; +import android.os.CancellationSignal; import android.util.Base64; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; +import com.android.launcher3.LauncherAppTransitionManagerImpl; import com.android.launcher3.LauncherState; import com.android.launcher3.LauncherStateManager; import com.android.launcher3.LauncherStateManager.StateHandler; @@ -41,6 +46,8 @@ import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.util.TouchController; import com.android.quickstep.OverviewInteractionState; import com.android.quickstep.RecentsModel; +import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.ActivityCompat; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -179,6 +186,23 @@ public class UiFactory { } } + public static void useFadeOutAnimationForLauncherStart(Launcher launcher, + CancellationSignal cancellationSignal) { + LauncherAppTransitionManagerImpl appTransitionManager = + (LauncherAppTransitionManagerImpl) launcher.getAppTransitionManager(); + appTransitionManager.setRemoteAnimationProvider((targets) -> { + + // On the first call clear the reference. + cancellationSignal.cancel(); + + ValueAnimator fadeAnimation = ValueAnimator.ofFloat(1, 0); + fadeAnimation.addUpdateListener(new RemoteFadeOutAnimationListener(targets)); + AnimatorSet anim = new AnimatorSet(); + anim.play(fadeAnimation); + return anim; + }, cancellationSignal); + } + public static boolean dumpActivity(Activity activity, PrintWriter writer) { if (!Utilities.IS_DEBUG_DEVICE) { return false; diff --git a/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java new file mode 100644 index 0000000000..40dd74bbb5 --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/RemoteFadeOutAnimationListener.java @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2018 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import static com.android.quickstep.util.RemoteAnimationProvider.prepareTargetsForFirstFrame; +import static com.android.systemui.shared.system.RemoteAnimationTargetCompat.MODE_CLOSING; + +import android.animation.ValueAnimator; +import android.animation.ValueAnimator.AnimatorUpdateListener; + +import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.shared.system.TransactionCompat; + +/** + * Animation listener which fades out the closing targets + */ +public class RemoteFadeOutAnimationListener implements AnimatorUpdateListener { + + private final RemoteAnimationTargetSet mTarget; + private boolean mFirstFrame = true; + + public RemoteFadeOutAnimationListener(RemoteAnimationTargetCompat[] targets) { + mTarget = new RemoteAnimationTargetSet(targets, MODE_CLOSING); + } + + @Override + public void onAnimationUpdate(ValueAnimator valueAnimator) { + TransactionCompat t = new TransactionCompat(); + if (mFirstFrame) { + prepareTargetsForFirstFrame(mTarget.unfilteredApps, t, MODE_CLOSING); + mFirstFrame = false; + } + + float alpha = 1 - valueAnimator.getAnimatedFraction(); + for (RemoteAnimationTargetCompat app : mTarget.apps) { + t.setAlpha(app.leash, alpha); + } + t.apply(); + } +} diff --git a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java index df4a7c1f56..1e84b416b3 100644 --- a/src/com/android/launcher3/dragndrop/BaseItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/BaseItemDragListener.java @@ -159,7 +159,7 @@ public abstract class BaseItemDragListener extends InternalStateHandler implemen postCleanup(); } - private void postCleanup() { + protected void postCleanup() { clearReference(); if (mLauncher != null) { // Remove any drag params from the launcher intent since the drag operation is complete. diff --git a/src/com/android/launcher3/dragndrop/PinItemDragListener.java b/src/com/android/launcher3/dragndrop/PinItemDragListener.java index 924bb4c25e..07eb0d60bc 100644 --- a/src/com/android/launcher3/dragndrop/PinItemDragListener.java +++ b/src/com/android/launcher3/dragndrop/PinItemDragListener.java @@ -22,14 +22,17 @@ import android.content.pm.LauncherApps.PinItemRequest; import android.graphics.Rect; import android.os.Build; import android.os.Bundle; +import android.os.CancellationSignal; import android.view.DragEvent; import android.view.View; import android.widget.RemoteViews; import com.android.launcher3.DragSource; import com.android.launcher3.ItemInfo; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppWidgetProviderInfo; import com.android.launcher3.PendingAddItemInfo; +import com.android.launcher3.uioverrides.UiFactory; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.widget.PendingAddShortcutInfo; import com.android.launcher3.widget.PendingAddWidgetInfo; @@ -44,11 +47,13 @@ import com.android.launcher3.widget.WidgetAddFlowHandler; public class PinItemDragListener extends BaseItemDragListener { private final PinItemRequest mRequest; + private final CancellationSignal mCancelSignal; public PinItemDragListener(PinItemRequest request, Rect previewRect, int previewBitmapWidth, int previewViewWidth) { super(previewRect, previewBitmapWidth, previewViewWidth); mRequest = request; + mCancelSignal = new CancellationSignal(); } @Override @@ -59,6 +64,15 @@ public class PinItemDragListener extends BaseItemDragListener { return super.onDragStart(event); } + @Override + public boolean init(Launcher launcher, boolean alreadyOnHome) { + super.init(launcher, alreadyOnHome); + if (!alreadyOnHome) { + UiFactory.useFadeOutAnimationForLauncherStart(launcher, mCancelSignal); + } + return false; + } + @Override protected PendingItemDragHelper createDragHelper() { final PendingAddItemInfo item; @@ -95,6 +109,12 @@ public class PinItemDragListener extends BaseItemDragListener { targetParent.containerType = LauncherLogProto.ContainerType.PINITEM; } + @Override + protected void postCleanup() { + super.postCleanup(); + mCancelSignal.cancel(); + } + public static RemoteViews getPreview(PinItemRequest request) { Bundle extras = request.getExtras(); if (extras != null && diff --git a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java index db98f9a80b..5a7e50fae5 100644 --- a/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java +++ b/src_ui_overrides/com/android/launcher3/uioverrides/UiFactory.java @@ -18,6 +18,7 @@ package com.android.launcher3.uioverrides; import android.app.Activity; import android.content.Context; +import android.os.CancellationSignal; import com.android.launcher3.Launcher; import com.android.launcher3.LauncherStateManager.StateHandler; @@ -51,6 +52,9 @@ public class UiFactory { public static void onTrimMemory(Launcher launcher, int level) { } + public static void useFadeOutAnimationForLauncherStart(Launcher launcher, + CancellationSignal cancellationSignal) { } + public static boolean dumpActivity(Activity activity, PrintWriter writer) { return false; } From 528b9e0615e9427eda667599b387a67ff1a393a8 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Thu, 24 May 2018 18:22:03 -0700 Subject: [PATCH 08/23] Reporting range of visible tasks Also fixes task position being incorrectly reported specifically for swipe events due to using stale getCurrentPage(). Bug: 72222505 Test: Manual Change-Id: Ic79b67f8a6ffbfabc397b411b14afc309405197e --- .../android/quickstep/views/RecentsView.java | 9 +++--- src/com/android/launcher3/PagedView.java | 31 +++++++++++++++++++ src/com/android/launcher3/Workspace.java | 25 ++------------- 3 files changed, 39 insertions(+), 26 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index dee15d0d7b..02cdd3a7c4 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1307,10 +1307,11 @@ public abstract class RecentsView extends PagedView impl super.onInitializeAccessibilityEvent(event); if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { - final int visiblePageNumber = getChildCount() - getCurrentPage() - 1; - event.setFromIndex(visiblePageNumber); - event.setToIndex(visiblePageNumber); - event.setItemCount(getChildCount()); + final int childCount = getChildCount(); + final int[] visibleTasks = getVisibleChildrenRange(); + event.setFromIndex(childCount - visibleTasks[1] - 1); + event.setToIndex(childCount - visibleTasks[0] - 1); + event.setItemCount(childCount); } } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 5cc2e8fc55..62b581f83e 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -152,6 +152,8 @@ public abstract class PagedView extends ViewGrou // Similar to the platform implementation of isLayoutValid(); protected boolean mIsLayoutValid; + private int[] mTmpIntPair = new int[2]; + public PagedView(Context context) { this(context, null); } @@ -1600,4 +1602,33 @@ public abstract class PagedView extends ViewGrou boolean shouldIncludeView(View view); } + + public int[] getVisibleChildrenRange() { + float visibleLeft = 0; + float visibleRight = visibleLeft + getMeasuredWidth(); + float scaleX = getScaleX(); + if (scaleX < 1 && scaleX > 0) { + float mid = getMeasuredWidth() / 2; + visibleLeft = mid - ((mid - visibleLeft) / scaleX); + visibleRight = mid + ((visibleRight - mid) / scaleX); + } + + int leftChild = -1; + int rightChild = -1; + final int childCount = getChildCount(); + for (int i = 0; i < childCount; i++) { + final View child = getPageAt(i); + + float left = child.getLeft() + child.getTranslationX() - getScrollX(); + if (left <= visibleRight && (left + child.getMeasuredWidth()) >= visibleLeft) { + if (leftChild == -1) { + leftChild = i; + } + rightChild = i; + } + } + mTmpIntPair[0] = leftChild; + mTmpIntPair[1] = rightChild; + return mTmpIntPair; + } } diff --git a/src/com/android/launcher3/Workspace.java b/src/com/android/launcher3/Workspace.java index 42e8fde3b4..7e652cbc5a 100644 --- a/src/com/android/launcher3/Workspace.java +++ b/src/com/android/launcher3/Workspace.java @@ -1381,28 +1381,9 @@ public class Workspace extends PagedView if (mChildrenLayersEnabled) { final int screenCount = getChildCount(); - float visibleLeft = 0; - float visibleRight = visibleLeft + getMeasuredWidth(); - float scaleX = getScaleX(); - if (scaleX < 1 && scaleX > 0) { - float mid = getMeasuredWidth() / 2; - visibleLeft = mid - ((mid - visibleLeft) / scaleX); - visibleRight = mid + ((visibleRight - mid) / scaleX); - } - - int leftScreen = -1; - int rightScreen = -1; - for (int i = 0; i < screenCount; i++) { - final View child = getPageAt(i); - - float left = child.getLeft() + child.getTranslationX() - getScrollX(); - if (left <= visibleRight && (left + child.getMeasuredWidth()) >= visibleLeft) { - if (leftScreen == -1) { - leftScreen = i; - } - rightScreen = i; - } - } + final int[] visibleScreens = getVisibleChildrenRange(); + int leftScreen = visibleScreens[0]; + int rightScreen = visibleScreens[1]; if (mForceDrawAdjacentPages) { // In overview mode, make sure that the two side pages are visible. leftScreen = Utilities.boundToRange(getCurrentPage() - 1, 0, rightScreen); From 49df554dc22521b2b4cb56f879846ccce81f4e0d Mon Sep 17 00:00:00 2001 From: Hyunyoung Song Date: Fri, 25 May 2018 16:30:23 -0700 Subject: [PATCH 09/23] Fix clipping of adaptive icons Bug:62372639 Context: only noticeable on large form factor AND Large display setting Ceiling operation is needed to calculate offset of the drawing. Change-Id: I7c77fa53f0811990b8cfdc3a12e2b43eb4d2d73e --- src/com/android/launcher3/graphics/LauncherIcons.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/com/android/launcher3/graphics/LauncherIcons.java b/src/com/android/launcher3/graphics/LauncherIcons.java index f020d2d7cd..89ba72abf5 100644 --- a/src/com/android/launcher3/graphics/LauncherIcons.java +++ b/src/com/android/launcher3/graphics/LauncherIcons.java @@ -330,9 +330,9 @@ public class LauncherIcons implements AutoCloseable { mOldBounds.set(icon.getBounds()); if (Utilities.ATLEAST_OREO && icon instanceof AdaptiveIconDrawable) { - int offset = Math.max((int)(BLUR_FACTOR * textureWidth), Math.min(left, top)); + int offset = Math.max((int) Math.ceil(BLUR_FACTOR * textureWidth), Math.max(left, top)); int size = Math.max(width, height); - icon.setBounds(offset, offset, size, size); + icon.setBounds(offset, offset, offset + size, offset + size); } else { icon.setBounds(left, top, left+width, top+height); } From 68ac46da0c79408c6b0f66960cfb0a87ce266e2a Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Fri, 25 May 2018 20:03:52 -0700 Subject: [PATCH 10/23] Fix testWidgetsContainerFling It relies on the presence of the popup in the accessibility view. Bug: 72967764 Test: atest google/perf/jank/SystemUI/UbSystemUIJankTests:android.platform.systemui.tests.jank.LauncherJankTests#testWidgetsContainerFling Change-Id: I9d41ddcd60f9dc7626a96762b4e78a7b862aa1c9 --- res/layout/longpress_options_menu.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/res/layout/longpress_options_menu.xml b/res/layout/longpress_options_menu.xml index 168dbc3a2e..20bb5b81be 100644 --- a/res/layout/longpress_options_menu.xml +++ b/res/layout/longpress_options_menu.xml @@ -22,4 +22,5 @@ android:clipToPadding="false" android:clipChildren="false" android:elevation="@dimen/deep_shortcuts_elevation" + android:importantForAccessibility="yes" android:orientation="vertical" /> From 1d1a3d7242d0c0e89c856d00e06bc3df7b55bc9d Mon Sep 17 00:00:00 2001 From: Jorim Jaggi Date: Mon, 28 May 2018 18:08:40 +0200 Subject: [PATCH 11/23] Fix binder call for app opening Needs to acquire the AM/WM lock, which may cause jank during the animation. Test: Open app, observe no binder calls. Bug: 78611607 Change-Id: I3459383c9597801405dd9c688837a2bffeeb7f9e --- .../launcher3/LauncherAppTransitionManagerImpl.java | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java index 6703bb546e..3075c3f48d 100644 --- a/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java +++ b/quickstep/src/com/android/launcher3/LauncherAppTransitionManagerImpl.java @@ -581,11 +581,8 @@ public class LauncherAppTransitionManagerImpl extends LauncherAppTransitionManag float offsetX = (scaledWindowWidth - iconWidth) / 2; float offsetY = (scaledWindowHeight - iconHeight) / 2; - if (mLauncher.isInMultiWindowModeCompat()) { - mFloatingView.getLocationOnScreen(floatingViewBounds); - } else { - mFloatingView.getLocationInWindow(floatingViewBounds); - } + mFloatingView.getLocationOnScreen(floatingViewBounds); + float transX0 = floatingViewBounds[0] - offsetX; float transY0 = floatingViewBounds[1] - offsetY; matrix.postTranslate(transX0, transY0); From a3e48d8035c39f47e5dde30061adc0b53824e9e3 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Thu, 24 May 2018 14:21:05 -0700 Subject: [PATCH 12/23] Enable accessibility of Clear All button. The button appears in the accessibility hierarchy as a child of RecentsView. This makes both Talkback and Switch access to work with it normally. Bug: 80156299 Test: Manual Change-Id: Ife2044b2ef78fb27b32f2d33fb17744662a2b054 --- .../quickstep/views/ClearAllButton.java | 13 ++---- .../android/quickstep/views/RecentsView.java | 44 ++++++++++++++++++- .../quickstep/views/RecentsViewContainer.java | 5 +++ 3 files changed, 51 insertions(+), 11 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/ClearAllButton.java b/quickstep/src/com/android/quickstep/views/ClearAllButton.java index 25e3dc6c14..0025df136d 100644 --- a/quickstep/src/com/android/quickstep/views/ClearAllButton.java +++ b/quickstep/src/com/android/quickstep/views/ClearAllButton.java @@ -16,13 +16,11 @@ package com.android.quickstep.views; -import static android.view.accessibility.AccessibilityNodeInfo.ACTION_ACCESSIBILITY_FOCUS; - import android.content.Context; import android.graphics.Rect; -import android.os.Bundle; import android.support.annotation.Nullable; import android.util.AttributeSet; +import android.view.accessibility.AccessibilityNodeInfo; import android.widget.Button; public class ClearAllButton extends Button { @@ -37,12 +35,9 @@ public class ClearAllButton extends Button { } @Override - public boolean performAccessibilityAction(int action, Bundle arguments) { - final boolean res = super.performAccessibilityAction(action, arguments); - if (action == ACTION_ACCESSIBILITY_FOCUS) { - mRecentsView.revealClearAllButton(); - } - return res; + public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { + super.onInitializeAccessibilityNodeInfo(info); + info.setParent(mRecentsView); // Pretend we are a part of the task carousel. } @Override diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 02cdd3a7c4..e98b16a449 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -39,6 +39,7 @@ import android.graphics.Point; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.os.Build; +import android.os.Bundle; import android.os.Handler; import android.os.UserHandle; import android.support.annotation.Nullable; @@ -386,7 +387,13 @@ public abstract class RecentsView extends PagedView impl private void updateClearAllButtonAlpha() { if (mClearAllButton != null) { final float alpha = calculateClearAllButtonAlpha(); - mIsClearAllButtonFullyRevealed = alpha == 1; + final boolean revealed = alpha == 1; + if (mIsClearAllButtonFullyRevealed != revealed) { + mIsClearAllButtonFullyRevealed = revealed; + mClearAllButton.setImportantForAccessibility(revealed ? + IMPORTANT_FOR_ACCESSIBILITY_YES : + IMPORTANT_FOR_ACCESSIBILITY_NO); + } mClearAllButton.setAlpha(alpha * mContentAlpha); } } @@ -1284,8 +1291,31 @@ public abstract class RecentsView extends PagedView impl scrollTo(mIsRtl ? 0 : computeMaxScrollX(), 0); } + @Override + public boolean performAccessibilityAction(int action, Bundle arguments) { + if (getChildCount() > 0) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + if (!mIsClearAllButtonFullyRevealed && getCurrentPage() == getPageCount() - 1) { + revealClearAllButton(); + return true; + } + } + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + if (mIsClearAllButtonFullyRevealed) { + setCurrentPage(getChildCount() - 1); + return true; + } + } + break; + } + } + return super.performAccessibilityAction(action, arguments); + } + @Override public void addChildrenForAccessibility(ArrayList outChildren) { + outChildren.add(mClearAllButton); for (int i = getChildCount() - 1; i >= 0; --i) { outChildren.add(getChildAt(i)); } @@ -1295,6 +1325,13 @@ public abstract class RecentsView extends PagedView impl public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) { super.onInitializeAccessibilityNodeInfo(info); + if (getChildCount() > 0) { + info.addAction(mIsClearAllButtonFullyRevealed ? + AccessibilityNodeInfo.ACTION_SCROLL_FORWARD : + AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); + info.setScrollable(true); + } + final AccessibilityNodeInfo.CollectionInfo collectionInfo = AccessibilityNodeInfo.CollectionInfo.obtain( 1, getChildCount(), false, @@ -1306,7 +1343,10 @@ public abstract class RecentsView extends PagedView impl public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); - if (event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { + event.setScrollable(getPageCount() > 0); + + if (!mIsClearAllButtonFullyRevealed + && event.getEventType() == AccessibilityEvent.TYPE_VIEW_SCROLLED) { final int childCount = getChildCount(); final int[] visibleTasks = getVisibleChildrenRange(); event.setFromIndex(childCount - visibleTasks[1] - 1); diff --git a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java index 31c8b64480..c6cd52769e 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java +++ b/quickstep/src/com/android/quickstep/views/RecentsViewContainer.java @@ -124,4 +124,9 @@ public class RecentsViewContainer extends InsettableFrameLayout { return mRecentsView.requestFocus(direction, previouslyFocusedRect) || super.requestFocus(direction, previouslyFocusedRect); } + + @Override + public void addChildrenForAccessibility(ArrayList outChildren) { + outChildren.add(mRecentsView); + } } \ No newline at end of file From 615ad40c38a75a197c2adf266a539e8a0258245d Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 29 May 2018 12:09:57 -0700 Subject: [PATCH 13/23] Fix clipping recents when scaling down - Parent shouldn't clip scaled down child - Remove outline provider from scaled down child so it doesn't clip Bug: 80267476 Change-Id: I9feb1ccf2069b8c88d8499e2813c818f9aea19af --- quickstep/res/layout/fallback_recents_activity.xml | 2 ++ quickstep/res/layout/overview_panel.xml | 2 ++ 2 files changed, 4 insertions(+) diff --git a/quickstep/res/layout/fallback_recents_activity.xml b/quickstep/res/layout/fallback_recents_activity.xml index 7ecab32016..84e13add58 100644 --- a/quickstep/res/layout/fallback_recents_activity.xml +++ b/quickstep/res/layout/fallback_recents_activity.xml @@ -24,6 +24,7 @@ android:id="@+id/overview_panel_container" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipChildren="false" > @@ -33,6 +34,7 @@ android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" + android:outlineProvider="none" android:focusableInTouchMode="true" android:theme="@style/HomeScreenElementTheme" > diff --git a/quickstep/res/layout/overview_panel.xml b/quickstep/res/layout/overview_panel.xml index 919afdb37f..840b040ac0 100644 --- a/quickstep/res/layout/overview_panel.xml +++ b/quickstep/res/layout/overview_panel.xml @@ -18,6 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" + android:clipChildren="false" android:visibility="invisible" > @@ -28,6 +29,7 @@ android:layout_height="match_parent" android:clipChildren="false" android:clipToPadding="false" + android:outlineProvider="none" android:focusableInTouchMode="true" android:accessibilityPaneTitle="@string/accessibility_recent_apps" android:theme="@style/HomeScreenElementTheme" From 9bb8ffb5e303597bd65ee4cae957c64c1f532d10 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Thu, 24 May 2018 17:11:16 -0700 Subject: [PATCH 14/23] Various quickscrub fixes > Fixing PagedView resetting the currentPage, if scrollToPage was called before first layout This causes quickscrub to jump back to the current task if launcher activity was dead. > Fixing missing callbacks in DeferredTouchConsumer causing missed quick scrub flings > Sending the resents animation callbacks on the motion queue thread, to avoid synchronization issues with sysui callbacks. > Waiting until the recents animation is received before starting the scale down animation > Calculating the offset for quickscrub statically incase launcher activity was dead Bug: 80214390 Change-Id: I1b7d00b7b266655a92fcd6239f25ba191655150f --- .../quickstep/ActivityControlHelper.java | 20 +++-- .../quickstep/DeferredTouchConsumer.java | 15 ++++ .../android/quickstep/MotionEventQueue.java | 11 +++ .../quickstep/OtherActivityTouchConsumer.java | 90 +++++++++++++------ .../quickstep/RecentsAnimationWrapper.java | 21 +++++ .../com/android/quickstep/TouchConsumer.java | 2 + .../WindowTransformSwipeHandler.java | 73 +++++++++------ .../android/quickstep/views/RecentsView.java | 1 + .../com/android/quickstep/views/TaskView.java | 4 +- src/com/android/launcher3/PagedView.java | 4 + 10 files changed, 179 insertions(+), 62 deletions(-) diff --git a/quickstep/src/com/android/quickstep/ActivityControlHelper.java b/quickstep/src/com/android/quickstep/ActivityControlHelper.java index e202c574ad..52a6dd5fe5 100644 --- a/quickstep/src/com/android/quickstep/ActivityControlHelper.java +++ b/quickstep/src/com/android/quickstep/ActivityControlHelper.java @@ -46,6 +46,7 @@ import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherInitListener; import com.android.launcher3.LauncherState; +import com.android.launcher3.R; import com.android.launcher3.allapps.AllAppsTransitionController; import com.android.launcher3.allapps.DiscoveryBounce; import com.android.launcher3.anim.AnimatorPlaybackController; @@ -82,7 +83,8 @@ public interface ActivityControlHelper { void onQuickInteractionStart(T activity, @Nullable RunningTaskInfo taskInfo, boolean activityVisible); - float getTranslationYForQuickScrub(T activity); + float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp, + Context context); void executeOnWindowAvailable(T activity, Runnable action); @@ -151,10 +153,15 @@ public interface ActivityControlHelper { } @Override - public float getTranslationYForQuickScrub(Launcher activity) { - LauncherRecentsView recentsView = activity.getOverviewPanel(); - return recentsView.computeTranslationYForFactor( - FastOverviewState.OVERVIEW_TRANSLATION_FACTOR); + public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp, + Context context) { + // The padding calculations are exactly same as that of RecentsView.setInsets + int topMargin = context.getResources() + .getDimensionPixelSize(R.dimen.task_thumbnail_top_margin); + int paddingTop = targetRect.rect.top - topMargin - dp.getInsets().top; + int paddingBottom = dp.availableHeightPx + dp.getInsets().top - targetRect.rect.bottom; + + return FastOverviewState.OVERVIEW_TRANSLATION_FACTOR * (paddingBottom - paddingTop); } @Override @@ -380,7 +387,8 @@ public interface ActivityControlHelper { } @Override - public float getTranslationYForQuickScrub(RecentsActivity activity) { + public float getTranslationYForQuickScrub(TransformedRect targetRect, DeviceProfile dp, + Context context) { return 0; } diff --git a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java index b92678a2ef..8e83bd0792 100644 --- a/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/DeferredTouchConsumer.java @@ -63,6 +63,16 @@ public class DeferredTouchConsumer implements TouchConsumer { mTarget.onQuickScrubProgress(progress); } + @Override + public void onQuickStep(MotionEvent ev) { + mTarget.onQuickStep(ev); + } + + @Override + public void onCommand(int command) { + mTarget.onCommand(command); + } + @Override public void preProcessMotionEvent(MotionEvent ev) { mVelocityTracker.addMovement(ev); @@ -92,6 +102,11 @@ public class DeferredTouchConsumer implements TouchConsumer { return target == null ? true : target.deferNextEventToMainThread(); } + @Override + public void onShowOverviewFromAltTab() { + mTarget.onShowOverviewFromAltTab(); + } + public interface DeferredTouchProvider { TouchConsumer createTouchConsumer(VelocityTracker tracker); diff --git a/quickstep/src/com/android/quickstep/MotionEventQueue.java b/quickstep/src/com/android/quickstep/MotionEventQueue.java index 15f5aa5247..f73be6cba9 100644 --- a/quickstep/src/com/android/quickstep/MotionEventQueue.java +++ b/quickstep/src/com/android/quickstep/MotionEventQueue.java @@ -55,6 +55,8 @@ public class MotionEventQueue { ACTION_VIRTUAL | (6 << ACTION_POINTER_INDEX_SHIFT); private static final int ACTION_QUICK_STEP = ACTION_VIRTUAL | (7 << ACTION_POINTER_INDEX_SHIFT); + private static final int ACTION_COMMAND = + ACTION_VIRTUAL | (8 << ACTION_POINTER_INDEX_SHIFT); private final EventArray mEmptyArray = new EventArray(); private final Object mExecutionLock = new Object(); @@ -165,6 +167,9 @@ public class MotionEventQueue { case ACTION_QUICK_STEP: mConsumer.onQuickStep(event); break; + case ACTION_COMMAND: + mConsumer.onCommand(event.getSource()); + break; default: Log.e(TAG, "Invalid virtual event: " + event.getAction()); } @@ -222,6 +227,12 @@ public class MotionEventQueue { queueVirtualAction(ACTION_DEFER_INIT, 0); } + public void onCommand(int command) { + MotionEvent ev = MotionEvent.obtain(0, 0, ACTION_COMMAND, 0, 0, 0); + ev.setSource(command); + queueNoPreProcess(ev); + } + public TouchConsumer getConsumer() { return mConsumer; } diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 9ba3328319..23357ea597 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -37,6 +37,7 @@ import android.os.Build; import android.os.Bundle; import android.os.Looper; import android.os.SystemClock; +import android.util.SparseArray; import android.view.Choreographer; import android.view.Display; import android.view.MotionEvent; @@ -69,6 +70,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private static final long LAUNCHER_DRAW_TIMEOUT_MS = 150; + private final SparseArray mAnimationStates = new SparseArray<>(); private final RunningTaskInfo mRunningTask; private final RecentsModel mRecentsModel; private final Intent mHomeIntent; @@ -212,8 +214,9 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC private void startTouchTrackingForWindowAnimation(long touchTimeMs) { // Create the shared handler + RecentsAnimationState animationState = new RecentsAnimationState(); final WindowTransformSwipeHandler handler = new WindowTransformSwipeHandler( - mRunningTask, this, touchTimeMs, mActivityControlHelper); + animationState.id, mRunningTask, this, touchTimeMs, mActivityControlHelper); // Preload the plan mRecentsModel.loadTasks(mRunningTask.id, null); @@ -237,31 +240,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC public void onHandleAssistData(Bundle bundle) { mRecentsModel.preloadAssistData(mRunningTask.id, bundle); } - }, - new RecentsAnimationListener() { - public void onAnimationStart( - RecentsAnimationControllerCompat controller, - RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, - Rect minimizedHomeBounds) { - if (mInteractionHandler == handler) { - TraceHelper.partitionSection("RecentsController", "Received"); - handler.onRecentsAnimationStart(controller, - new RemoteAnimationTargetSet(apps, MODE_CLOSING), - homeContentInsets, minimizedHomeBounds); - } else { - TraceHelper.endSection("RecentsController", "Finishing no handler"); - controller.finish(false /* toHome */); - } - } - - public void onAnimationCanceled() { - TraceHelper.endSection("RecentsController", - "Cancelled: " + mInteractionHandler); - if (mInteractionHandler == handler) { - handler.onRecentsAnimationCanceled(); - } - } - }, null, null); + }, animationState, null, null); if (Looper.myLooper() != Looper.getMainLooper()) { startActivity.run(); @@ -277,6 +256,14 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC } } + @Override + public void onCommand(int command) { + RecentsAnimationState state = mAnimationStates.get(command); + if (state != null) { + state.execute(); + } + } + /** * Called when the gesture has ended. Does not correlate to the completion of the interaction as * the animation can still be running. @@ -398,4 +385,55 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC // TODO: Consider also check if the eventQueue is using mainThread of not. return mInteractionHandler != null; } + + private class RecentsAnimationState implements RecentsAnimationListener { + + private final int id; + + private RecentsAnimationControllerCompat mController; + private RemoteAnimationTargetSet mTargets; + private Rect mHomeContentInsets; + private Rect mMinimizedHomeBounds; + private boolean mCancelled; + + public RecentsAnimationState() { + id = mAnimationStates.size(); + mAnimationStates.put(id, this); + } + + @Override + public void onAnimationStart( + RecentsAnimationControllerCompat controller, + RemoteAnimationTargetCompat[] apps, Rect homeContentInsets, + Rect minimizedHomeBounds) { + mController = controller; + mTargets = new RemoteAnimationTargetSet(apps, MODE_CLOSING); + mHomeContentInsets = homeContentInsets; + mMinimizedHomeBounds = minimizedHomeBounds; + mEventQueue.onCommand(id); + } + + @Override + public void onAnimationCanceled() { + mCancelled = true; + mEventQueue.onCommand(id); + } + + public void execute() { + if (mInteractionHandler == null || mInteractionHandler.id != id) { + if (!mCancelled && mController != null) { + TraceHelper.endSection("RecentsController", "Finishing no handler"); + mController.finish(false /* toHome */); + } + } else if (mCancelled) { + TraceHelper.endSection("RecentsController", + "Cancelled: " + mInteractionHandler); + mInteractionHandler.onRecentsAnimationCanceled(); + } else { + TraceHelper.partitionSection("RecentsController", "Received"); + mInteractionHandler.onRecentsAnimationStart(mController, mTargets, + mHomeContentInsets, mMinimizedHomeBounds); + } + } + } } diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java index 30b10b0eab..34d42ac927 100644 --- a/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java +++ b/quickstep/src/com/android/quickstep/RecentsAnimationWrapper.java @@ -20,6 +20,8 @@ import com.android.launcher3.util.TraceHelper; import com.android.launcher3.util.UiThreadHelper; import com.android.quickstep.util.RemoteAnimationTargetSet; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; + +import java.util.ArrayList; import java.util.concurrent.ExecutorService; /** @@ -27,6 +29,10 @@ import java.util.concurrent.ExecutorService; */ public class RecentsAnimationWrapper { + // A list of callbacks to run when we receive the recents animation target. There are different + // than the state callbacks as these run on the current worker thread. + private final ArrayList mCallbacks = new ArrayList<>(); + public RemoteAnimationTargetSet targetSet; private RecentsAnimationControllerCompat mController; @@ -46,6 +52,21 @@ public class RecentsAnimationWrapper { if (mInputConsumerEnabled) { enableInputConsumer(); } + + if (!mCallbacks.isEmpty()) { + for (Runnable action : new ArrayList<>(mCallbacks)) { + action.run(); + } + mCallbacks.clear(); + } + } + + public synchronized void runOnInit(Runnable action) { + if (targetSet == null) { + mCallbacks.add(action); + } else { + action.run(); + } } /** diff --git a/quickstep/src/com/android/quickstep/TouchConsumer.java b/quickstep/src/com/android/quickstep/TouchConsumer.java index aa844d80df..4cecffa2be 100644 --- a/quickstep/src/com/android/quickstep/TouchConsumer.java +++ b/quickstep/src/com/android/quickstep/TouchConsumer.java @@ -48,6 +48,8 @@ public interface TouchConsumer extends Consumer { default void onQuickStep(MotionEvent ev) { } + default void onCommand(int command) { } + /** * Called on the binder thread to allow the consumer to process the motion event before it is * posted on a handler thread. diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index d171f69452..939811bd11 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -29,6 +29,7 @@ import android.animation.ObjectAnimator; import android.annotation.TargetApi; import android.app.ActivityManager.RunningTaskInfo; import android.content.Context; +import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.Point; import android.graphics.Rect; @@ -36,6 +37,7 @@ import android.os.Build; import android.os.Handler; import android.os.Looper; import android.os.SystemClock; +import android.os.UserHandle; import android.support.annotation.AnyThread; import android.support.annotation.UiThread; import android.support.annotation.WorkerThread; @@ -51,6 +53,7 @@ import com.android.launcher3.DeviceProfile; import com.android.launcher3.InvariantDeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.logging.UserEventDispatcher; @@ -65,11 +68,12 @@ import com.android.quickstep.ActivityControlHelper.AnimationFactory; import com.android.quickstep.ActivityControlHelper.LayoutListener; import com.android.quickstep.TouchConsumer.InteractionType; import com.android.quickstep.util.ClipAnimationHelper; -import com.android.quickstep.util.TransformedRect; import com.android.quickstep.util.RemoteAnimationTargetSet; +import com.android.quickstep.util.TransformedRect; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.ThumbnailData; +import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.InputConsumerController; import com.android.systemui.shared.system.LatencyTrackerCompat; import com.android.systemui.shared.system.RecentsAnimationControllerCompat; @@ -167,6 +171,12 @@ public class WindowTransformSwipeHandler { private final Handler mMainThreadHandler = new Handler(Looper.getMainLooper()); + // An increasing identifier per single instance of OtherActivityTouchConsumer. Generally one + // instance of OtherActivityTouchConsumer will only have one swipe handle, but sometimes we can + // end up with multiple handlers if we get recents command in the middle of a swipe gesture. + // This is used to match the corresponding activity manager callbacks in + // OtherActivityTouchConsumer + public final int id; private final Context mContext; private final ActivityControlHelper mActivityControlHelper; private final ActivityInitListener mActivityInitListener; @@ -199,6 +209,7 @@ public class WindowTransformSwipeHandler { InputConsumerController.getRecentsAnimationInputConsumer(); private final RecentsAnimationWrapper mRecentsAnimationWrapper = new RecentsAnimationWrapper(); + private final long mTouchTimeMs; private long mLauncherFrameDrawnTime; @@ -207,8 +218,9 @@ public class WindowTransformSwipeHandler { private float mLongSwipeDisplacement = 0; private LongSwipeHelper mLongSwipeController; - WindowTransformSwipeHandler(RunningTaskInfo runningTaskInfo, Context context, long touchTimeMs, - ActivityControlHelper controller) { + WindowTransformSwipeHandler(int id, RunningTaskInfo runningTaskInfo, Context context, + long touchTimeMs, ActivityControlHelper controller) { + this.id = id; mContext = context; mRunningTaskInfo = runningTaskInfo; mRunningTaskId = runningTaskInfo.id; @@ -453,6 +465,7 @@ public class WindowTransformSwipeHandler { "Can't change interaction type to " + interactionType); } mInteractionType = interactionType; + mRecentsAnimationWrapper.runOnInit(this::shiftAnimationDestinationForQuickscrub); setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED); @@ -460,6 +473,34 @@ public class WindowTransformSwipeHandler { animateToProgress(1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR); } + private void shiftAnimationDestinationForQuickscrub() { + TransformedRect tempRect = new TransformedRect(); + mActivityControlHelper + .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect); + mClipAnimationHelper.updateTargetRect(tempRect); + + float offsetY = + mActivityControlHelper.getTranslationYForQuickScrub(tempRect, mDp, mContext); + float scale, offsetX; + Resources res = mContext.getResources(); + + if (ActivityManagerWrapper.getInstance().getRecentTasks(2, UserHandle.myUserId()).size() + < 2) { + // There are not enough tasks, we don't need to shift + offsetX = 0; + scale = 1; + } else { + offsetX = res.getDimensionPixelSize(R.dimen.recents_page_spacing) + + tempRect.rect.width(); + float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 + + res.getDimensionPixelSize(R.dimen.recents_page_spacing); + float interpolation = Math.min(1, offsetX / distanceToReachEdge); + scale = TaskView.getCurveScaleForInterpolation(interpolation); + } + mClipAnimationHelper.offsetTarget(scale, Utilities.isRtl(res) ? -offsetX : offsetX, offsetY, + QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR); + } + @WorkerThread public void updateDisplacement(float displacement) { // We are moving in the negative x/y direction @@ -658,7 +699,7 @@ public class WindowTransformSwipeHandler { : STATE_SCALED_CONTROLLER_APP); } }); - anim.start(); + mRecentsAnimationWrapper.runOnInit(anim::start); } @UiThread @@ -786,30 +827,6 @@ public class WindowTransformSwipeHandler { // Inform the last progress in case we skipped before. mQuickScrubController.onQuickScrubProgress(mCurrentQuickScrubProgress); - - // Make sure the window follows the first task if it moves, e.g. during quick scrub. - TaskView firstTask = mRecentsView.getPageAt(0); - // The first task may be null if we are swiping up from a task that does not - // appear in the list (i.e. the assistant) - if (firstTask != null) { - int scrollForFirstTask = mRecentsView.getScrollForPage(0); - int scrollForSecondTask = mRecentsView.getChildCount() > 1 - ? mRecentsView.getScrollForPage(1) : scrollForFirstTask; - float offsetFromFirstTask = scrollForFirstTask - scrollForSecondTask; - - TransformedRect tempRect = new TransformedRect(); - mActivityControlHelper - .getSwipeUpDestinationAndLength(mDp, mContext, mInteractionType, tempRect); - float distanceToReachEdge = mDp.widthPx / 2 + tempRect.rect.width() / 2 + - mContext.getResources().getDimensionPixelSize(R.dimen.recents_page_spacing); - float interpolation = Math.min(1, - Math.abs(offsetFromFirstTask) / distanceToReachEdge); - - mClipAnimationHelper.offsetTarget( - firstTask.getCurveScaleForInterpolation(interpolation), offsetFromFirstTask, - mActivityControlHelper.getTranslationYForQuickScrub(mActivity), - QuickScrubController.QUICK_SCRUB_START_INTERPOLATOR); - } } private void onFinishedTransitionToQuickScrub() { diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 02cdd3a7c4..776509c855 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -507,6 +507,7 @@ public abstract class RecentsView extends PagedView impl DeviceProfile dp = mActivity.getDeviceProfile(); getTaskSize(dp, mTempRect); + // Keep this logic in sync with ActivityControlHelper.getTranslationYForQuickScrub. mTempRect.top -= mTaskTopMargin; setPadding(mTempRect.left - mInsets.left, mTempRect.top - mInsets.top, dp.availableWidthPx + mInsets.left - mTempRect.right, diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 5413a13199..91c0fa5be1 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -250,12 +250,12 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback setPivotY(mSnapshotView.getTop() + mSnapshotView.getHeight() * 0.5f); } - public float getCurveScaleForInterpolation(float linearInterpolation) { + public static float getCurveScaleForInterpolation(float linearInterpolation) { float curveInterpolation = CURVE_INTERPOLATOR.getInterpolation(linearInterpolation); return getCurveScaleForCurveInterpolation(curveInterpolation); } - private float getCurveScaleForCurveInterpolation(float curveInterpolation) { + private static float getCurveScaleForCurveInterpolation(float curveInterpolation) { return 1 - curveInterpolation * EDGE_SCALE_DOWN_FACTOR; } diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index 62b581f83e..de9cd986f2 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -1450,6 +1450,10 @@ public abstract class PagedView extends ViewGrou protected boolean snapToPage(int whichPage, int delta, int duration, boolean immediate, TimeInterpolator interpolator) { + if (mFirstLayout) { + setCurrentPage(whichPage); + return false; + } if (FeatureFlags.IS_DOGFOOD_BUILD) { duration *= Settings.System.getFloat(getContext().getContentResolver(), From 9c3f172d9c10d8144c44c069e19d854b375e6112 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 29 May 2018 12:12:59 -0700 Subject: [PATCH 15/23] Accounting for one frame jump when starting a fling animation Bug: 80292740 Change-Id: I47bca071d42d1d217068c128f9793e87210d0286 --- .../src/com/android/quickstep/AnimatedFloat.java | 4 ++-- .../quickstep/WindowTransformSwipeHandler.java | 16 +++++++++++----- 2 files changed, 13 insertions(+), 7 deletions(-) diff --git a/quickstep/src/com/android/quickstep/AnimatedFloat.java b/quickstep/src/com/android/quickstep/AnimatedFloat.java index 84dfa457e9..84dfdbd1dd 100644 --- a/quickstep/src/com/android/quickstep/AnimatedFloat.java +++ b/quickstep/src/com/android/quickstep/AnimatedFloat.java @@ -46,9 +46,9 @@ public class AnimatedFloat { mUpdateCallback = updateCallback; } - public ObjectAnimator animateToValue(float v) { + public ObjectAnimator animateToValue(float start, float end) { cancelAnimation(); - mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, v); + mValueAnimator = ObjectAnimator.ofFloat(this, VALUE, start, end); mValueAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animator) { diff --git a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java index 939811bd11..b1663b169a 100644 --- a/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java +++ b/quickstep/src/com/android/quickstep/WindowTransformSwipeHandler.java @@ -16,6 +16,7 @@ package com.android.quickstep; import static com.android.launcher3.BaseActivity.INVISIBLE_BY_STATE_HANDLER; +import static com.android.launcher3.Utilities.SINGLE_FRAME_MS; import static com.android.launcher3.Utilities.postAsyncCallback; import static com.android.launcher3.anim.Interpolators.DEACCEL; import static com.android.launcher3.anim.Interpolators.LINEAR; @@ -470,7 +471,7 @@ public class WindowTransformSwipeHandler { setStateOnUiThread(STATE_QUICK_SCRUB_START | STATE_GESTURE_COMPLETED); // Start the window animation without waiting for launcher. - animateToProgress(1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR); + animateToProgress(mCurrentShift.value, 1f, QUICK_SCRUB_FROM_APP_START_DURATION, LINEAR); } private void shiftAnimationDestinationForQuickscrub() { @@ -647,11 +648,13 @@ public class WindowTransformSwipeHandler { private void handleNormalGestureEnd(float endVelocity, boolean isFling) { long duration = MAX_SWIPE_DURATION; final float endShift; + final float startShift; if (!isFling) { endShift = mCurrentShift.value >= MIN_PROGRESS_FOR_OVERVIEW && mGestureStarted ? 1 : 0; long expectedDuration = Math.abs(Math.round((endShift - mCurrentShift.value) * MAX_SWIPE_DURATION * SWIPE_DURATION_MULTIPLIER)); duration = Math.min(MAX_SWIPE_DURATION, expectedDuration); + startShift = mCurrentShift.value; } else { endShift = endVelocity < 0 ? 1 : 0; float minFlingVelocity = mContext.getResources() @@ -665,9 +668,11 @@ public class WindowTransformSwipeHandler { long baseDuration = Math.round(1000 * Math.abs(distanceToTravel / endVelocity)); duration = Math.min(MAX_SWIPE_DURATION, 2 * baseDuration); } + startShift = Utilities.boundToRange(mCurrentShift.value - endVelocity * SINGLE_FRAME_MS + / (mTransitionDragLength * 1000), 0, 1); } - animateToProgress(endShift, duration, DEACCEL); + animateToProgress(startShift, endShift, duration, DEACCEL); } private void doLogGesture(boolean toLauncher) { @@ -687,9 +692,10 @@ public class WindowTransformSwipeHandler { } /** Animates to the given progress, where 0 is the current app and 1 is overview. */ - private void animateToProgress(float progress, long duration, Interpolator interpolator) { - mIsGoingToHome = Float.compare(progress, 1) == 0; - ObjectAnimator anim = mCurrentShift.animateToValue(progress).setDuration(duration); + private void animateToProgress(float start, float end, long duration, + Interpolator interpolator) { + mIsGoingToHome = Float.compare(end, 1) == 0; + ObjectAnimator anim = mCurrentShift.animateToValue(start, end).setDuration(duration); anim.setInterpolator(interpolator); anim.addListener(new AnimationSuccessListener() { @Override From bb9378aead84fe55c2a0edcf190008b0b7b52c20 Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 29 May 2018 14:44:41 -0700 Subject: [PATCH 16/23] Unhide badge when popup closes without animation Bug: 80379412 Change-Id: I7d6c1b67a07747078b43b17612d8c67a46c8cc0e --- src/com/android/launcher3/popup/PopupContainerWithArrow.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index f276fbfea4..172cf41e08 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -527,6 +527,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, protected void closeComplete() { super.closeComplete(); mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible()); + mOriginalIcon.forceHideBadge(false); } @Override From 8935d9515c17db0d717757022d9d2442153ecf0d Mon Sep 17 00:00:00 2001 From: Tony Wickham Date: Fri, 18 May 2018 16:12:54 -0700 Subject: [PATCH 17/23] Set mState = mCurrentStableState in onAnimationCancel mState is set when the transition starts toward that state even if it is never reached. If the animation is canceled, therefore, we should reset mState = mCurrentStableState since that is the state we came from. For instance, when swiping up from overview, mState = ALL_APPS, but when swiping back down we cancel that animation and create the task launch animation. When creating the task launch animation, we reapplyState(), which, before this change, was still ALL_APPS instead of OVERVIEW. Bug: 79935289 Change-Id: I59c5799e92350747e4ef1d99a80ba678a2ce7b98 --- src/com/android/launcher3/LauncherStateManager.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index b5eef8bd3f..02fa916b14 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -347,6 +347,12 @@ public class LauncherStateManager { } } + @Override + public void onAnimationCancel(Animator animation) { + super.onAnimationCancel(animation); + mState = mCurrentStableState; + } + @Override public void onAnimationSuccess(Animator animator) { // Run any queued runnables @@ -432,7 +438,6 @@ public class LauncherStateManager { } public void setCurrentUserControlledAnimation(AnimatorPlaybackController controller) { - clearCurrentAnimation(); setCurrentAnimation(controller.getTarget()); mConfig.userControlled = true; mConfig.playbackController = controller; From ab66067defad22a632c390df8d0afaecc04bbe19 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 29 May 2018 15:54:16 -0700 Subject: [PATCH 18/23] Update displacement on ACTION_UP as well, in case ACTION_UP and came in a different frame than last ACTION_MOVE Bug: 80292740 Change-Id: Ie75ac3ebb74024073965a7455a6503e8ed3f6d99 --- .../com/android/quickstep/OtherActivityTouchConsumer.java | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java index 23357ea597..c856282636 100644 --- a/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java +++ b/quickstep/src/com/android/quickstep/OtherActivityTouchConsumer.java @@ -185,7 +185,7 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC case ACTION_UP: { TraceHelper.endSection("TouchInt"); - finishTouchTracking(); + finishTouchTracking(ev); break; } } @@ -268,8 +268,10 @@ public class OtherActivityTouchConsumer extends ContextWrapper implements TouchC * 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() { + private void finishTouchTracking(MotionEvent ev) { if (mPassedInitialSlop && mInteractionHandler != null) { + mInteractionHandler.updateDisplacement(getDisplacement(ev) - mStartDisplacement); + mVelocityTracker.computeCurrentVelocity(1000, ViewConfiguration.get(this).getScaledMaximumFlingVelocity()); From 67f9cad75a5fd3088b7e5c1e987ba501a99b6d0a Mon Sep 17 00:00:00 2001 From: Tony Date: Tue, 29 May 2018 17:33:16 -0700 Subject: [PATCH 19/23] Fix animation not playing when going home while another animation is playing When going to a new state, we cancel any currently playing animation. When canceling the animation, we reset mState = mCurrentStableState. Thus, when determining the duration of the new animation, we have both state == NORMAL and mState == NORMAL, leading to a duration of 0 and therefore no animation. Storing the fromState before canceling/resetting fixes the issue. Change-Id: I92332deae8058c4dd41212fe7f749955ede28b1c --- src/com/android/launcher3/LauncherStateManager.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/com/android/launcher3/LauncherStateManager.java b/src/com/android/launcher3/LauncherStateManager.java index 02fa916b14..05c515bf42 100644 --- a/src/com/android/launcher3/LauncherStateManager.java +++ b/src/com/android/launcher3/LauncherStateManager.java @@ -17,7 +17,6 @@ package com.android.launcher3; import static android.view.View.VISIBLE; - import static com.android.launcher3.LauncherState.NORMAL; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_FADE; import static com.android.launcher3.anim.AnimatorSetBuilder.ANIM_OVERVIEW_SCALE; @@ -222,7 +221,8 @@ public class LauncherStateManager { } } - // Cancel the current animation + // Cancel the current animation. This will reset mState to mCurrentStableState, so store it. + LauncherState fromState = mState; mConfig.reset(); if (!animated) { @@ -245,10 +245,10 @@ public class LauncherStateManager { // Since state NORMAL can be reached from multiple states, just assume that the // transition plays in reverse and use the same duration as previous state. - mConfig.duration = state == NORMAL ? mState.transitionDuration : state.transitionDuration; + mConfig.duration = state == NORMAL ? fromState.transitionDuration : state.transitionDuration; AnimatorSetBuilder builder = new AnimatorSetBuilder(); - prepareForAtomicAnimation(mState, state, builder); + prepareForAtomicAnimation(fromState, state, builder); AnimatorSet animation = createAnimationToNewWorkspaceInternal( state, builder, onCompleteRunnable); Runnable runnable = new StartAnimRunnable(animation); From 442fc108c365f8759c157996e1e6603c17a4bf35 Mon Sep 17 00:00:00 2001 From: Vadim Tryshev Date: Tue, 29 May 2018 17:29:03 -0700 Subject: [PATCH 20/23] Removing accessibility action for Clear-all Now that Clear-all button is visible for accessibility, there is no need in it. Bug: 80156299 Test: Manual Change-Id: I5997692be015947692a8bb720a449d1d36302526 --- .../fallback/FallbackRecentsView.java | 19 -------- .../android/quickstep/views/RecentsView.java | 3 -- .../quickstep/views/ShelfScrimView.java | 43 ------------------- .../com/android/quickstep/views/TaskView.java | 2 - 4 files changed, 67 deletions(-) diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java index c5d74c7d93..9e2de33954 100644 --- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java +++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java @@ -20,10 +20,8 @@ import android.graphics.Canvas; import android.graphics.Rect; import android.util.AttributeSet; import android.view.View; -import android.view.accessibility.AccessibilityNodeInfo; import com.android.launcher3.DeviceProfile; -import com.android.launcher3.R; import com.android.quickstep.RecentsActivity; import com.android.quickstep.util.LayoutUtils; import com.android.quickstep.views.RecentsView; @@ -73,21 +71,4 @@ public class FallbackRecentsView extends RecentsView { // Just use the activity task size for multi-window as well. return false; } - - @Override - public void addTaskAccessibilityActionsExtra(AccessibilityNodeInfo info) { - info.addAction( - new AccessibilityNodeInfo.AccessibilityAction( - R.string.recents_clear_all, - getContext().getText(R.string.recents_clear_all))); - } - - @Override - public boolean performTaskAccessibilityActionExtra(int action) { - if (action == R.string.recents_clear_all) { - dismissAllTasks(); - return true; - } - return false; - } } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 4c2795ba0f..d550edcd33 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -1367,9 +1367,6 @@ public abstract class RecentsView extends PagedView impl return true; } - public void addTaskAccessibilityActionsExtra(AccessibilityNodeInfo info) { - } - public boolean performTaskAccessibilityActionExtra(int action) { return false; } diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index aca8351a06..1ea112da09 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -28,9 +28,6 @@ import android.graphics.Paint; import android.graphics.Path; import android.graphics.Path.Direction; import android.graphics.Path.Op; -import android.os.Bundle; -import android.support.annotation.NonNull; -import android.support.v4.view.accessibility.AccessibilityNodeInfoCompat; import android.util.AttributeSet; import com.android.launcher3.DeviceProfile; @@ -51,7 +48,6 @@ public class ShelfScrimView extends ScrimView { private static final int THRESHOLD_ALPHA_DARK = 102; private static final int THRESHOLD_ALPHA_LIGHT = 46; private static final int THRESHOLD_ALPHA_SUPER_LIGHT = 128; - private static final int CLEAR_ALL_TASKS = R.string.recents_clear_all; // In transposed layout, we simply draw a flat color. private boolean mDrawingFlatColor; @@ -208,43 +204,4 @@ public class ShelfScrimView extends ScrimView { mRadius, mRadius, mPaint); return minTop - mDragHandleSize - top; } - - @NonNull - @Override - protected AccessibilityHelper createAccessibilityHelper() { - return new ShelfScrimAccessibilityHelper(); - } - - protected class ShelfScrimAccessibilityHelper extends AccessibilityHelper { - @Override - protected void onPopulateNodeForVirtualView(int virtualViewId, - AccessibilityNodeInfoCompat node) { - super.onPopulateNodeForVirtualView(virtualViewId, node); - - if (mLauncher.isInState(OVERVIEW)) { - final RecentsView overviewPanel = mLauncher.getOverviewPanel(); - if (overviewPanel.getChildCount() != 0) { - node.addAction( - new AccessibilityNodeInfoCompat.AccessibilityActionCompat( - CLEAR_ALL_TASKS, - getContext().getText(CLEAR_ALL_TASKS))); - } - } - } - - @Override - protected boolean onPerformActionForVirtualView( - int virtualViewId, int action, Bundle arguments) { - if (super.onPerformActionForVirtualView(virtualViewId, action, arguments)) return true; - - if (action == CLEAR_ALL_TASKS) { - if (mLauncher.isInState(OVERVIEW)) { - mLauncher.getOverviewPanel().dismissAllTasks(); - } - return true; - } - - return false; - } - } } diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 91c0fa5be1..b5f31b8e2e 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -321,8 +321,6 @@ public class TaskView extends FrameLayout implements TaskCallbacks, PageCallback } final RecentsView recentsView = getRecentsView(); - recentsView.addTaskAccessibilityActionsExtra(info); - final AccessibilityNodeInfo.CollectionItemInfo itemInfo = AccessibilityNodeInfo.CollectionItemInfo.obtain( 0, 1, recentsView.getChildCount() - recentsView.indexOfChild(this) - 1, 1, From 2f347149afae96848efc6a6f16529556fbce4878 Mon Sep 17 00:00:00 2001 From: Tony Date: Wed, 30 May 2018 13:13:37 -0700 Subject: [PATCH 21/23] Shift recents up slightly in quick scrub Bug: 79883290 Change-Id: If57fd52505d7f965ea8a28e90e715c5723915e57 --- .../com/android/launcher3/uioverrides/FastOverviewState.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java index cd92314a73..26453022f0 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java +++ b/quickstep/src/com/android/launcher3/uioverrides/FastOverviewState.java @@ -34,7 +34,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.5f; + public static final float OVERVIEW_TRANSLATION_FACTOR = 0.4f; private static final int STATE_FLAGS = FLAG_DISABLE_RESTORE | FLAG_DISABLE_INTERACTION | FLAG_OVERVIEW_UI | FLAG_HIDE_BACK_BUTTON | FLAG_DISABLE_ACCESSIBILITY; From 337fcb7983e318e245b9b08a5d748a7500ae6675 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Wed, 30 May 2018 12:00:43 -0700 Subject: [PATCH 22/23] Theme updates for dark text: > Using white scrim on adjescent tiles in overview > Using a ligher scrim in dark-theme+dark-text Bug: 80253867 Change-Id: I3f257d3addaca8bc5970a61722f5ae0e7af89382 --- .../quickstep/views/ShelfScrimView.java | 12 +------ .../quickstep/views/TaskThumbnailView.java | 35 +++++++++++++------ res/values/attrs.xml | 1 + res/values/styles.xml | 4 +++ src/com/android/launcher3/util/Themes.java | 7 ++++ 5 files changed, 38 insertions(+), 21 deletions(-) diff --git a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java index 1ea112da09..c780b62340 100644 --- a/quickstep/src/com/android/quickstep/views/ShelfScrimView.java +++ b/quickstep/src/com/android/quickstep/views/ShelfScrimView.java @@ -45,10 +45,6 @@ import com.android.launcher3.views.ScrimView; */ public class ShelfScrimView extends ScrimView { - private static final int THRESHOLD_ALPHA_DARK = 102; - private static final int THRESHOLD_ALPHA_LIGHT = 46; - private static final int THRESHOLD_ALPHA_SUPER_LIGHT = 128; - // In transposed layout, we simply draw a flat color. private boolean mDrawingFlatColor; @@ -77,13 +73,7 @@ public class ShelfScrimView extends ScrimView { mMaxScrimAlpha = OVERVIEW.getWorkspaceScrimAlpha(mLauncher); mEndAlpha = Color.alpha(mEndScrim); - if (Themes.getAttrBoolean(mLauncher, R.attr.isMainColorDark)) { - mThresholdAlpha = THRESHOLD_ALPHA_DARK; - } else if (Themes.getAttrBoolean(mLauncher, R.attr.isWorkspaceDarkText)) { - mThresholdAlpha = THRESHOLD_ALPHA_SUPER_LIGHT; - } else { - mThresholdAlpha = THRESHOLD_ALPHA_LIGHT; - } + mThresholdAlpha = Themes.getAttrInteger(context, R.attr.allAppsInterimScrimAlpha); mRadius = mLauncher.getResources().getDimension(R.dimen.shelf_surface_radius); mPaint = new Paint(Paint.ANTI_ALIAS_FLAG); diff --git a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java index 128a19e06a..d9dfd1815d 100644 --- a/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java +++ b/quickstep/src/com/android/quickstep/views/TaskThumbnailView.java @@ -29,6 +29,7 @@ import android.graphics.Matrix; import android.graphics.Paint; import android.graphics.Rect; import android.graphics.Shader; +import android.support.v4.graphics.ColorUtils; import android.util.AttributeSet; import android.util.FloatProperty; import android.util.Property; @@ -37,8 +38,10 @@ import android.view.View; import com.android.launcher3.BaseActivity; import com.android.launcher3.DeviceProfile; import com.android.launcher3.R; +import com.android.launcher3.Utilities; import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.util.SystemUiController; +import com.android.launcher3.util.Themes; import com.android.quickstep.TaskOverlayFactory; import com.android.quickstep.TaskOverlayFactory.TaskOverlay; import com.android.systemui.shared.recents.model.Task; @@ -50,6 +53,7 @@ import com.android.systemui.shared.recents.model.ThumbnailData; public class TaskThumbnailView extends View { private static final LightingColorFilter[] sDimFilterCache = new LightingColorFilter[256]; + private static final LightingColorFilter[] sHighlightFilterCache = new LightingColorFilter[256]; public static final Property DIM_ALPHA_MULTIPLIER = new FloatProperty("dimAlphaMultiplier") { @@ -68,6 +72,7 @@ public class TaskThumbnailView extends View { private final BaseActivity mActivity; private final TaskOverlay mOverlay; + private final boolean mIsDarkTextTheme; private final Paint mPaint = new Paint(); private final Paint mBackgroundPaint = new Paint(); @@ -97,6 +102,7 @@ public class TaskThumbnailView extends View { mPaint.setFilterBitmap(true); mBackgroundPaint.setColor(Color.WHITE); mActivity = BaseActivity.fromContext(context); + mIsDarkTextTheme = Themes.getAttrBoolean(mActivity, R.attr.isWorkspaceDarkText); } public void bind() { @@ -198,7 +204,7 @@ public class TaskThumbnailView extends View { private void updateThumbnailPaintFilter() { int mul = (int) ((1 - mDimAlpha * mDimAlphaMultiplier) * 255); if (mBitmapShader != null) { - LightingColorFilter filter = getLightingColorFilter(mul); + LightingColorFilter filter = getDimmingColorFilter(mul, mIsDarkTextTheme); mPaint.setColorFilter(filter); mBackgroundPaint.setColorFilter(filter); } else { @@ -287,16 +293,25 @@ public class TaskThumbnailView extends View { updateThumbnailMatrix(); } - private static LightingColorFilter getLightingColorFilter(int dimColor) { - if (dimColor < 0) { - dimColor = 0; - } else if (dimColor > 255) { - dimColor = 255; + private static LightingColorFilter getDimmingColorFilter(int intensity, boolean shouldLighten) { + intensity = Utilities.boundToRange(intensity, 0, 255); + if (intensity == 255) { + return null; } - if (sDimFilterCache[dimColor] == null) { - sDimFilterCache[dimColor] = - new LightingColorFilter(Color.argb(255, dimColor, dimColor, dimColor), 0); + if (shouldLighten) { + if (sHighlightFilterCache[intensity] == null) { + int colorAdd = 255 - intensity; + sHighlightFilterCache[intensity] = new LightingColorFilter( + Color.argb(255, intensity, intensity, intensity), + Color.argb(255, colorAdd, colorAdd, colorAdd)); + } + return sHighlightFilterCache[intensity]; + } else { + if (sDimFilterCache[intensity] == null) { + sDimFilterCache[intensity] = new LightingColorFilter( + Color.argb(255, intensity, intensity, intensity), 0); + } + return sDimFilterCache[intensity]; } - return sDimFilterCache[dimColor]; } } diff --git a/res/values/attrs.xml b/res/values/attrs.xml index 64ca05e3c2..30091a5f77 100644 --- a/res/values/attrs.xml +++ b/res/values/attrs.xml @@ -20,6 +20,7 @@ + diff --git a/res/values/styles.xml b/res/values/styles.xml index 2b760f3493..31cbaa11af 100644 --- a/res/values/styles.xml +++ b/res/values/styles.xml @@ -29,6 +29,7 @@