From 4dd4159fdc47e8644cb557af186bed033a106106 Mon Sep 17 00:00:00 2001 From: Nick Chameyev Date: Fri, 27 Aug 2021 14:11:53 +0100 Subject: [PATCH] Add taskbar icons unfold animation Adds 'move from center' animation for taskbar icons when unfolding foldable devices. Moves unfold transition progress provider from quickstep launcher activity to TouchInteractionService to widen the scope when this provider is available to cover both launcher activity and taskbar. Launcher activity and taskbar get their own instances of unfold transition progress provider using ScopedUnfoldTransitionProgressProvider wrapper. This wrapper allows to get transition progress provider that emits events only when clients are ready to handle them. Bug: 193794563 Test: manual Change-Id: I27581bd4e145a74f526bf60f2a545e56ded322f9 --- .../launcher3/BaseQuickstepLauncher.java | 65 ++++++++ .../taskbar/TaskbarActivityContext.java | 22 +-- .../launcher3/taskbar/TaskbarControllers.java | 5 + .../launcher3/taskbar/TaskbarManager.java | 13 +- .../TaskbarUnfoldAnimationController.java | 87 +++++++++++ .../taskbar/TaskbarViewController.java | 53 ++++++- .../uioverrides/QuickstepLauncher.java | 54 ------- .../LauncherUnfoldAnimationController.java | 58 ++------ ...ViewsMoveFromCenterTranslationApplier.java | 45 ++++++ ...copedUnfoldTransitionProgressProvider.java | 140 ++++++++++++++++++ ...UnfoldMoveFromCenterWorkspaceAnimator.java | 21 +-- src/com/android/launcher3/BubbleTextView.java | 23 ++- .../android/launcher3/folder/FolderIcon.java | 33 ++++- 13 files changed, 484 insertions(+), 135 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java create mode 100644 quickstep/src/com/android/quickstep/util/LauncherViewsMoveFromCenterTranslationApplier.java create mode 100644 quickstep/src/com/android/quickstep/util/ScopedUnfoldTransitionProgressProvider.java diff --git a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java index b4b29aaae3..ca4256769e 100644 --- a/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/BaseQuickstepLauncher.java @@ -35,6 +35,8 @@ import android.content.Context; import android.content.Intent; import android.content.IntentSender; import android.content.ServiceConnection; +import android.hardware.SensorManager; +import android.hardware.devicestate.DeviceStateManager; import android.os.Bundle; import android.os.CancellationSignal; import android.os.Handler; @@ -73,6 +75,8 @@ import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskUtils; import com.android.quickstep.TouchInteractionService; import com.android.quickstep.TouchInteractionService.TISBinder; +import com.android.quickstep.util.LauncherUnfoldAnimationController; +import com.android.quickstep.util.ProxyScreenStatusProvider; import com.android.quickstep.util.RemoteAnimationProvider; import com.android.quickstep.util.RemoteFadeOutAnimationListener; import com.android.quickstep.util.SplitSelectStateController; @@ -82,6 +86,9 @@ import com.android.quickstep.views.SplitPlaceholderView; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.ActivityOptionsCompat; import com.android.systemui.shared.system.RemoteAnimationTargetCompat; +import com.android.systemui.unfold.UnfoldTransitionFactory; +import com.android.systemui.unfold.UnfoldTransitionProgressProvider; +import com.android.systemui.unfold.config.UnfoldTransitionConfig; import java.util.List; import java.util.stream.Stream; @@ -117,6 +124,7 @@ public abstract class BaseQuickstepLauncher extends Launcher public void onServiceConnected(ComponentName componentName, IBinder iBinder) { mTaskbarManager = ((TISBinder) iBinder).getTaskbarManager(); mTaskbarManager.setLauncher(BaseQuickstepLauncher.this); + Log.d(TAG, "TIS service connected"); resetServiceBindRetryState(); @@ -142,16 +150,41 @@ public abstract class BaseQuickstepLauncher extends Launcher private @Nullable DragOptions mNextWorkspaceDragOptions = null; private SplitPlaceholderView mSplitPlaceholderView; + private @Nullable UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider; + private @Nullable LauncherUnfoldAnimationController mLauncherUnfoldAnimationController; + @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SysUINavigationMode.INSTANCE.get(this).addModeChangeListener(this); addMultiWindowModeChangedListener(mDepthController); + initUnfoldTransitionProgressProvider(); + } + + @Override + protected void onResume() { + super.onResume(); + + if (mLauncherUnfoldAnimationController != null) { + mLauncherUnfoldAnimationController.onResume(); + } + } + + @Override + protected void onPause() { + if (mLauncherUnfoldAnimationController != null) { + mLauncherUnfoldAnimationController.onPause(); + } + + super.onPause(); } @Override public void onDestroy() { mAppTransitionManager.onActivityDestroyed(); + if (mUnfoldTransitionProgressProvider != null) { + mUnfoldTransitionProgressProvider.destroy(); + } SysUINavigationMode.INSTANCE.get(this).removeModeChangeListener(this); @@ -160,6 +193,11 @@ public abstract class BaseQuickstepLauncher extends Launcher mTaskbarManager.clearLauncher(this); } resetServiceBindRetryState(); + + if (mLauncherUnfoldAnimationController != null) { + mLauncherUnfoldAnimationController.onDestroy(); + } + super.onDestroy(); } @@ -334,6 +372,28 @@ public abstract class BaseQuickstepLauncher extends Launcher mConnectionAttempts = 0; } + private void initUnfoldTransitionProgressProvider() { + final UnfoldTransitionConfig config = UnfoldTransitionFactory.createConfig(this); + if (config.isEnabled()) { + mUnfoldTransitionProgressProvider = + UnfoldTransitionFactory.createUnfoldTransitionProgressProvider( + this, + config, + ProxyScreenStatusProvider.INSTANCE, + getSystemService(DeviceStateManager.class), + getSystemService(SensorManager.class), + getMainThreadHandler(), + getMainExecutor() + ); + + mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( + this, + getWindowManager(), + mUnfoldTransitionProgressProvider + ); + } + } + public void setTaskbarUIController(LauncherTaskbarUIController taskbarUIController) { mTaskbarUIController = taskbarUIController; } @@ -373,6 +433,11 @@ public abstract class BaseQuickstepLauncher extends Launcher return mTaskbarStateHandler; } + @Nullable + public UnfoldTransitionProgressProvider getUnfoldTransitionProgressProvider() { + return mUnfoldTransitionProgressProvider; + } + @Override public boolean supportsAdaptiveIconAnimation(View clickedView) { return mAppTransitionManager.hasControlRemoteAppTransitionPermission() diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index 8c12567ccf..51d031b3f2 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -62,6 +62,7 @@ import com.android.launcher3.util.ViewCache; import com.android.launcher3.views.ActivityContext; import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; +import com.android.quickstep.util.ScopedUnfoldTransitionProgressProvider; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.ActivityManagerWrapper; import com.android.systemui.shared.system.WindowManagerWrapper; @@ -98,7 +99,8 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ private boolean mIsDestroyed = false; public TaskbarActivityContext(Context windowContext, DeviceProfile dp, - TaskbarNavButtonController buttonController) { + TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider + unfoldTransitionProgressProvider) { super(windowContext, Themes.getActivityThemeRes(windowContext)); mDeviceProfile = dp; @@ -120,6 +122,14 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ FrameLayout navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view); StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle); + Display display = windowContext.getDisplay(); + Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY + ? windowContext.getApplicationContext() + : windowContext.getApplicationContext().createDisplayContext(display); + mWindowManager = c.getSystemService(WindowManager.class); + mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT); + mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT); + // Construct controllers. mControllers = new TaskbarControllers(this, new TaskbarDragController(this), @@ -129,18 +139,12 @@ public class TaskbarActivityContext extends ContextThemeWrapper implements Activ R.color.popup_color_primary_light), new TaskbarDragLayerController(this, mDragLayer), new TaskbarViewController(this, taskbarView), + new TaskbarUnfoldAnimationController(unfoldTransitionProgressProvider, + mWindowManager), new TaskbarKeyguardController(this), new StashedHandleViewController(this, stashedHandleView), new TaskbarStashController(this), new TaskbarEduController(this)); - - Display display = windowContext.getDisplay(); - Context c = display.getDisplayId() == Display.DEFAULT_DISPLAY - ? windowContext.getApplicationContext() - : windowContext.getApplicationContext().createDisplayContext(display); - mWindowManager = c.getSystemService(WindowManager.class); - mLeftCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_LEFT); - mRightCorner = display.getRoundedCorner(RoundedCorner.POSITION_BOTTOM_RIGHT); } public void init() { diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 11975430b1..6144881902 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -31,6 +31,7 @@ public class TaskbarControllers { public final RotationButtonController rotationButtonController; public final TaskbarDragLayerController taskbarDragLayerController; public final TaskbarViewController taskbarViewController; + public final TaskbarUnfoldAnimationController taskbarUnfoldAnimationController; public final TaskbarKeyguardController taskbarKeyguardController; public final StashedHandleViewController stashedHandleViewController; public final TaskbarStashController taskbarStashController; @@ -46,6 +47,7 @@ public class TaskbarControllers { RotationButtonController rotationButtonController, TaskbarDragLayerController taskbarDragLayerController, TaskbarViewController taskbarViewController, + TaskbarUnfoldAnimationController taskbarUnfoldAnimationController, TaskbarKeyguardController taskbarKeyguardController, StashedHandleViewController stashedHandleViewController, TaskbarStashController taskbarStashController, @@ -57,6 +59,7 @@ public class TaskbarControllers { this.rotationButtonController = rotationButtonController; this.taskbarDragLayerController = taskbarDragLayerController; this.taskbarViewController = taskbarViewController; + this.taskbarUnfoldAnimationController = taskbarUnfoldAnimationController; this.taskbarKeyguardController = taskbarKeyguardController; this.stashedHandleViewController = stashedHandleViewController; this.taskbarStashController = taskbarStashController; @@ -75,6 +78,7 @@ public class TaskbarControllers { } taskbarDragLayerController.init(this); taskbarViewController.init(this); + taskbarUnfoldAnimationController.init(this); taskbarKeyguardController.init(navbarButtonsViewController); stashedHandleViewController.init(this); taskbarStashController.init(this); @@ -89,6 +93,7 @@ public class TaskbarControllers { rotationButtonController.onDestroy(); taskbarDragLayerController.onDestroy(); taskbarKeyguardController.onDestroy(); + taskbarUnfoldAnimationController.onDestroy(); taskbarViewController.onDestroy(); stashedHandleViewController.onDestroy(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java index 4ed83f295e..ec98bbf05a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java @@ -42,6 +42,7 @@ import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TouchInteractionService; +import com.android.quickstep.util.ScopedUnfoldTransitionProgressProvider; /** * Class to manage taskbar lifecycle @@ -58,6 +59,10 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen private final TaskbarNavButtonController mNavButtonController; private final SettingsCache.OnChangeListener mUserSetupCompleteListener; + // The source for this provider is set when Launcher is available + private final ScopedUnfoldTransitionProgressProvider mUnfoldProgressProvider = + new ScopedUnfoldTransitionProgressProvider(); + private TaskbarActivityContext mTaskbarActivityContext; private BaseQuickstepLauncher mLauncher; /** @@ -120,6 +125,9 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen */ public void setLauncher(@NonNull BaseQuickstepLauncher launcher) { mLauncher = launcher; + mUnfoldProgressProvider.setSourceProvider(launcher + .getUnfoldTransitionProgressProvider()); + if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setUIController( new LauncherTaskbarUIController(launcher, mTaskbarActivityContext)); @@ -135,6 +143,7 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen if (mTaskbarActivityContext != null) { mTaskbarActivityContext.setUIController(TaskbarUIController.DEFAULT); } + mUnfoldProgressProvider.setSourceProvider(null); } } @@ -153,8 +162,8 @@ public class TaskbarManager implements DisplayController.DisplayInfoChangeListen return; } - mTaskbarActivityContext = new TaskbarActivityContext( - mContext, dp.copy(mContext), mNavButtonController); + mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp.copy(mContext), + mNavButtonController, mUnfoldProgressProvider); mTaskbarActivityContext.init(); if (mLauncher != null) { mTaskbarActivityContext.setUIController( diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java new file mode 100644 index 0000000000..43f015cd2d --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUnfoldAnimationController.java @@ -0,0 +1,87 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.launcher3.taskbar; + +import android.view.View; +import android.view.WindowManager; + +import com.android.quickstep.util.LauncherViewsMoveFromCenterTranslationApplier; +import com.android.quickstep.util.ScopedUnfoldTransitionProgressProvider; +import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator; +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener; + +/** + * Controls animation of taskbar icons when unfolding foldable devices + */ +public class TaskbarUnfoldAnimationController { + + private final ScopedUnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider; + private final UnfoldMoveFromCenterAnimator mMoveFromCenterAnimator; + private final TransitionListener mTransitionListener = new TransitionListener(); + private TaskbarViewController mTaskbarViewController; + + public TaskbarUnfoldAnimationController(ScopedUnfoldTransitionProgressProvider + unfoldTransitionProgressProvider, WindowManager windowManager) { + mUnfoldTransitionProgressProvider = unfoldTransitionProgressProvider; + mMoveFromCenterAnimator = new UnfoldMoveFromCenterAnimator(windowManager, + new LauncherViewsMoveFromCenterTranslationApplier()); + } + + /** + * Initializes the controller + * @param taskbarControllers references to all other taskbar controllers + */ + public void init(TaskbarControllers taskbarControllers) { + mTaskbarViewController = taskbarControllers.taskbarViewController; + mTaskbarViewController.addOneTimePreDrawListener(() -> + mUnfoldTransitionProgressProvider.setReadyToHandleTransition(true)); + mUnfoldTransitionProgressProvider.addCallback(mTransitionListener); + } + + /** + * Destroys the controller + */ + public void onDestroy() { + mUnfoldTransitionProgressProvider.setReadyToHandleTransition(false); + mUnfoldTransitionProgressProvider.removeCallback(mTransitionListener); + } + + private class TransitionListener implements TransitionProgressListener { + + @Override + public void onTransitionStarted() { + mMoveFromCenterAnimator.updateDisplayProperties(); + View[] icons = mTaskbarViewController.getIconViews(); + for (View icon : icons) { + // TODO(b/193794563) we should re-register views if they are re-bound/re-inflated + // during the animation + mMoveFromCenterAnimator.registerViewForAnimation(icon); + } + + mMoveFromCenterAnimator.onTransitionStarted(); + } + + @Override + public void onTransitionFinished() { + mMoveFromCenterAnimator.onTransitionFinished(); + } + + @Override + public void onTransitionProgress(float progress) { + mMoveFromCenterAnimator.onTransitionProgress(progress); + } + } +} diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index f1748afce3..f359a3dbaa 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -16,20 +16,24 @@ package com.android.launcher3.taskbar; import static com.android.launcher3.LauncherAnimUtils.SCALE_PROPERTY; -import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X; import static com.android.launcher3.Utilities.squaredHypot; import static com.android.launcher3.anim.Interpolators.LINEAR; import static com.android.quickstep.AnimatedFloat.VALUE; import android.graphics.Rect; +import android.util.FloatProperty; import android.view.MotionEvent; import android.view.View; +import android.view.ViewTreeObserver; +import android.view.ViewTreeObserver.OnPreDrawListener; +import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; import com.android.launcher3.LauncherAppState; import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.PendingAnimation; +import com.android.launcher3.folder.FolderIcon; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.util.MultiValueAlpha; import com.android.quickstep.AnimatedFloat; @@ -117,6 +121,25 @@ public class TaskbarViewController { mTaskbarView.setClickAndLongClickListenersForIcon(icon); } + /** + * Adds one time pre draw listener to the taskbar view, it is called before + * drawing a frame and invoked only once + * @param listener callback that will be invoked before drawing the next frame + */ + public void addOneTimePreDrawListener(Runnable listener) { + mTaskbarView.getViewTreeObserver().addOnPreDrawListener(new OnPreDrawListener() { + @Override + public boolean onPreDraw() { + final ViewTreeObserver viewTreeObserver = mTaskbarView.getViewTreeObserver(); + if (viewTreeObserver.isAlive()) { + listener.run(); + viewTreeObserver.removeOnPreDrawListener(this); + } + return true; + } + }); + } + public Rect getIconLayoutBounds() { return mTaskbarView.getIconLayoutBounds(); } @@ -194,7 +217,7 @@ public class TaskbarViewController { float childCenter = (child.getLeft() + child.getRight()) / 2; float hotseatIconCenter = hotseatPadding.left + hotseatCellSize * info.screenId + hotseatCellSize / 2; - setter.setFloat(child, VIEW_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR); + setter.setFloat(child, ICON_TRANSLATE_X, hotseatIconCenter - childCenter, LINEAR); } AnimatorPlaybackController controller = setter.createPlaybackController(); @@ -257,4 +280,30 @@ public class TaskbarViewController { return false; } } + + public static final FloatProperty ICON_TRANSLATE_X = + new FloatProperty("taskbarAligmentTranslateX") { + + @Override + public void setValue(View view, float v) { + if (view instanceof BubbleTextView) { + ((BubbleTextView) view).setTranslationXForTaskbarAlignmentAnimation(v); + } else if (view instanceof FolderIcon) { + ((FolderIcon) view).setTranslationForTaskbarAlignmentAnimation(v); + } else { + view.setTranslationX(v); + } + } + + @Override + public Float get(View view) { + if (view instanceof BubbleTextView) { + return ((BubbleTextView) view) + .getTranslationXForTaskbarAlignmentAnimation(); + } else if (view instanceof FolderIcon) { + return ((FolderIcon) view).getTranslationXForTaskbarAlignmentAnimation(); + } + return view.getTranslationX(); + } + }; } diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 14bc380b8b..2009cd75d9 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -36,13 +36,9 @@ import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SY import android.content.Intent; import android.content.SharedPreferences; import android.content.res.Configuration; -import android.hardware.SensorManager; -import android.hardware.devicestate.DeviceStateManager; import android.view.HapticFeedbackConstants; import android.view.View; -import androidx.annotation.Nullable; - import com.android.launcher3.BaseQuickstepLauncher; import com.android.launcher3.DeviceProfile; import com.android.launcher3.Launcher; @@ -79,14 +75,9 @@ import com.android.quickstep.SysUINavigationMode; import com.android.quickstep.SysUINavigationMode.Mode; import com.android.quickstep.SystemUiProxy; import com.android.quickstep.TaskUtils; -import com.android.quickstep.util.LauncherUnfoldAnimationController; -import com.android.quickstep.util.ProxyScreenStatusProvider; import com.android.quickstep.util.QuickstepOnboardingPrefs; import com.android.quickstep.views.RecentsView; import com.android.quickstep.views.TaskView; -import com.android.systemui.unfold.UnfoldTransitionFactory; -import com.android.systemui.unfold.UnfoldTransitionProgressProvider; -import com.android.systemui.unfold.config.UnfoldTransitionConfig; import java.io.FileDescriptor; import java.io.PrintWriter; @@ -106,51 +97,10 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { private FixedContainerItems mAllAppsPredictions; private HotseatPredictionController mHotseatPredictionController; - @Nullable - private LauncherUnfoldAnimationController mLauncherUnfoldAnimationController; - @Override protected void setupViews() { super.setupViews(); mHotseatPredictionController = new HotseatPredictionController(this); - - final UnfoldTransitionConfig config = UnfoldTransitionFactory.createConfig(this); - if (config.isEnabled()) { - final UnfoldTransitionProgressProvider unfoldTransitionProgressProvider = - UnfoldTransitionFactory.createUnfoldTransitionProgressProvider( - this, - config, - ProxyScreenStatusProvider.INSTANCE, - getSystemService(DeviceStateManager.class), - getSystemService(SensorManager.class), - getMainThreadHandler(), - getMainExecutor() - ); - - mLauncherUnfoldAnimationController = new LauncherUnfoldAnimationController( - this, - getWindowManager(), - unfoldTransitionProgressProvider - ); - } - } - - @Override - protected void onResume() { - super.onResume(); - - if (mLauncherUnfoldAnimationController != null) { - mLauncherUnfoldAnimationController.onResume(); - } - } - - @Override - protected void onPause() { - if (mLauncherUnfoldAnimationController != null) { - mLauncherUnfoldAnimationController.onPause(); - } - - super.onPause(); } @Override @@ -281,10 +231,6 @@ public class QuickstepLauncher extends BaseQuickstepLauncher { public void onDestroy() { super.onDestroy(); mHotseatPredictionController.destroy(); - - if (mLauncherUnfoldAnimationController != null) { - mLauncherUnfoldAnimationController.onDestroy(); - } } @Override diff --git a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java index c5ab84daf7..47d35808d6 100644 --- a/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java +++ b/quickstep/src/com/android/quickstep/util/LauncherUnfoldAnimationController.java @@ -37,26 +37,23 @@ public class LauncherUnfoldAnimationController { private static final float MAX_WIDTH_INSET_FRACTION = 0.15f; private final Launcher mLauncher; - private final UnfoldTransitionProgressProvider mUnfoldTransitionProgressProvider; - private final UnfoldMoveFromCenterWorkspaceAnimator mMoveFromCenterWorkspaceAnimation; @Nullable private HorizontalInsettableView mQsbInsettable; - private final AnimationListener mAnimationListener = new AnimationListener(); - - private boolean mIsTransitionRunning = false; - private boolean mIsReadyToPlayAnimation = false; + private final ScopedUnfoldTransitionProgressProvider mProgressProvider; public LauncherUnfoldAnimationController( Launcher launcher, WindowManager windowManager, UnfoldTransitionProgressProvider unfoldTransitionProgressProvider) { mLauncher = launcher; - mUnfoldTransitionProgressProvider = unfoldTransitionProgressProvider; - mMoveFromCenterWorkspaceAnimation = new UnfoldMoveFromCenterWorkspaceAnimator(launcher, - windowManager); - mUnfoldTransitionProgressProvider.addCallback(mAnimationListener); + mProgressProvider = new ScopedUnfoldTransitionProgressProvider( + unfoldTransitionProgressProvider); + + mProgressProvider.addCallback(new UnfoldMoveFromCenterWorkspaceAnimator(launcher, + windowManager)); + mProgressProvider.addCallback(new QsbAnimationListener()); } /** @@ -73,7 +70,7 @@ public class LauncherUnfoldAnimationController { @Override public boolean onPreDraw() { if (obs.isAlive()) { - onPreDrawAfterResume(); + mProgressProvider.setReadyToHandleTransition(true); obs.removeOnPreDrawListener(this); } return true; @@ -85,12 +82,7 @@ public class LauncherUnfoldAnimationController { * Called when launcher activity is paused */ public void onPause() { - if (mIsTransitionRunning) { - mIsTransitionRunning = false; - mAnimationListener.onTransitionFinished(); - } - - mIsReadyToPlayAnimation = false; + mProgressProvider.setReadyToHandleTransition(false); mQsbInsettable = null; } @@ -98,48 +90,24 @@ public class LauncherUnfoldAnimationController { * Called when launcher activity is destroyed */ public void onDestroy() { - mUnfoldTransitionProgressProvider.removeCallback(mAnimationListener); + mProgressProvider.destroy(); } - /** - * Called after performing layouting of the views after configuration change - */ - private void onPreDrawAfterResume() { - mIsReadyToPlayAnimation = true; - - if (mIsTransitionRunning) { - mMoveFromCenterWorkspaceAnimation.onTransitionStarted(); - } - } - - private class AnimationListener implements TransitionProgressListener { + private class QsbAnimationListener implements TransitionProgressListener { @Override public void onTransitionStarted() { - mIsTransitionRunning = true; - - if (mIsReadyToPlayAnimation) { - mMoveFromCenterWorkspaceAnimation.onTransitionStarted(); - } } @Override public void onTransitionFinished() { - if (mIsReadyToPlayAnimation) { - mMoveFromCenterWorkspaceAnimation.onTransitionFinished(); - - if (mQsbInsettable != null) { - mQsbInsettable.setHorizontalInsets(0); - } + if (mQsbInsettable != null) { + mQsbInsettable.setHorizontalInsets(0); } - - mIsTransitionRunning = false; } @Override public void onTransitionProgress(float progress) { - mMoveFromCenterWorkspaceAnimation.onTransitionProgress(progress); - if (mQsbInsettable != null) { float insetPercentage = comp(progress) * MAX_WIDTH_INSET_FRACTION; mQsbInsettable.setHorizontalInsets(insetPercentage); diff --git a/quickstep/src/com/android/quickstep/util/LauncherViewsMoveFromCenterTranslationApplier.java b/quickstep/src/com/android/quickstep/util/LauncherViewsMoveFromCenterTranslationApplier.java new file mode 100644 index 0000000000..effdfdd97b --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/LauncherViewsMoveFromCenterTranslationApplier.java @@ -0,0 +1,45 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import android.annotation.NonNull; +import android.view.View; + +import com.android.launcher3.BubbleTextView; +import com.android.launcher3.folder.FolderIcon; +import com.android.launcher3.widget.NavigableAppWidgetHostView; +import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.TranslationApplier; + +/** + * Class that allows to set translations for move from center animation independently + * from other translations for certain launcher views + */ +public class LauncherViewsMoveFromCenterTranslationApplier implements TranslationApplier { + + @Override + public void apply(@NonNull View view, float x, float y) { + if (view instanceof NavigableAppWidgetHostView) { + ((NavigableAppWidgetHostView) view).setTranslationForMoveFromCenterAnimation(x, y); + } else if (view instanceof BubbleTextView) { + ((BubbleTextView) view).setTranslationForMoveFromCenterAnimation(x, y); + } else if (view instanceof FolderIcon) { + ((FolderIcon) view).setTranslationForMoveFromCenterAnimation(x, y); + } else { + view.setTranslationX(x); + view.setTranslationY(y); + } + } +} diff --git a/quickstep/src/com/android/quickstep/util/ScopedUnfoldTransitionProgressProvider.java b/quickstep/src/com/android/quickstep/util/ScopedUnfoldTransitionProgressProvider.java new file mode 100644 index 0000000000..2ef311ff3e --- /dev/null +++ b/quickstep/src/com/android/quickstep/util/ScopedUnfoldTransitionProgressProvider.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2021 The Android Open Source Project + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.android.quickstep.util; + +import android.annotation.NonNull; +import android.annotation.Nullable; + +import com.android.systemui.unfold.UnfoldTransitionProgressProvider; +import com.android.systemui.unfold.UnfoldTransitionProgressProvider.TransitionProgressListener; + +import java.util.ArrayList; +import java.util.List; + +/** + * Manages progress listeners that can have smaller lifespan than the unfold animation. + * Allows to limit getting transition updates to only when + * {@link ScopedUnfoldTransitionProgressProvider#setReadyToHandleTransition} is called + * with readyToHandleTransition = true + * + * If the transition has already started by the moment when the clients are ready to play + * the transition then it will report transition started callback and current animation progress. + */ +public final class ScopedUnfoldTransitionProgressProvider implements + UnfoldTransitionProgressProvider, TransitionProgressListener { + + private static final float PROGRESS_UNSET = -1f; + + @Nullable + private UnfoldTransitionProgressProvider mSource; + + private final List mListeners = new ArrayList<>(); + + private boolean mIsReadyToHandleTransition; + private boolean mIsTransitionRunning; + private float mLastTransitionProgress = PROGRESS_UNSET; + + public ScopedUnfoldTransitionProgressProvider() { + this(null); + } + + public ScopedUnfoldTransitionProgressProvider(@Nullable UnfoldTransitionProgressProvider + source) { + setSourceProvider(source); + } + + /** + * Sets the source for the unfold transition progress updates, + * it replaces current provider if it is already set + * @param provider transition provider that emits transition progress updates + */ + public void setSourceProvider(@Nullable UnfoldTransitionProgressProvider provider) { + if (mSource != null) { + mSource.removeCallback(this); + } + + if (provider != null) { + mSource = provider; + mSource.addCallback(this); + } + } + + /** + * Allows to notify this provide whether the listeners can play the transition or not. + * Call this method with readyToHandleTransition = true when all listeners + * are ready to consume the transition progress events. + * Call it with readyToHandleTransition = false when listeners can't process the events. + */ + public void setReadyToHandleTransition(boolean isReadyToHandleTransition) { + if (mIsTransitionRunning) { + if (mIsReadyToHandleTransition) { + mListeners.forEach(TransitionProgressListener::onTransitionStarted); + + if (mLastTransitionProgress != PROGRESS_UNSET) { + mListeners.forEach(listener -> + listener.onTransitionProgress(mLastTransitionProgress)); + } + } else { + mIsTransitionRunning = false; + mListeners.forEach(TransitionProgressListener::onTransitionFinished); + } + } + + mIsReadyToHandleTransition = isReadyToHandleTransition; + } + + @Override + public void addCallback(@NonNull TransitionProgressListener listener) { + mListeners.add(listener); + } + + @Override + public void removeCallback(@NonNull TransitionProgressListener listener) { + mListeners.remove(listener); + } + + @Override + public void destroy() { + mSource.removeCallback(this); + } + + @Override + public void onTransitionStarted() { + this.mIsTransitionRunning = true; + if (mIsReadyToHandleTransition) { + mListeners.forEach(TransitionProgressListener::onTransitionStarted); + } + } + + @Override + public void onTransitionProgress(float progress) { + if (mIsReadyToHandleTransition) { + mListeners.forEach(listener -> listener.onTransitionProgress(progress)); + } + + mLastTransitionProgress = progress; + } + + @Override + public void onTransitionFinished() { + if (mIsReadyToHandleTransition) { + mListeners.forEach(TransitionProgressListener::onTransitionFinished); + } + + mIsTransitionRunning = false; + mLastTransitionProgress = PROGRESS_UNSET; + } +} diff --git a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java index 482092d367..95403b2d0c 100644 --- a/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java +++ b/quickstep/src/com/android/quickstep/util/UnfoldMoveFromCenterWorkspaceAnimator.java @@ -15,20 +15,16 @@ */ package com.android.quickstep.util; -import android.annotation.NonNull; import android.view.View; import android.view.ViewGroup; import android.view.WindowManager; -import com.android.launcher3.BubbleTextView; import com.android.launcher3.CellLayout; import com.android.launcher3.Hotseat; import com.android.launcher3.Launcher; import com.android.launcher3.ShortcutAndWidgetContainer; import com.android.launcher3.Workspace; -import com.android.launcher3.widget.NavigableAppWidgetHostView; import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator; -import com.android.systemui.shared.animation.UnfoldMoveFromCenterAnimator.TranslationApplier; import com.android.systemui.unfold.UnfoldTransitionProgressProvider; import java.util.HashMap; @@ -49,7 +45,7 @@ public class UnfoldMoveFromCenterWorkspaceAnimator public UnfoldMoveFromCenterWorkspaceAnimator(Launcher launcher, WindowManager windowManager) { mLauncher = launcher; mMoveFromCenterAnimation = new UnfoldMoveFromCenterAnimator(windowManager, - new WorkspaceViewsTranslationApplier()); + new LauncherViewsMoveFromCenterTranslationApplier()); } @Override @@ -122,19 +118,4 @@ public class UnfoldMoveFromCenterWorkspaceAnimator view.setClipChildren(originalClipChildren); } } - - private static class WorkspaceViewsTranslationApplier implements TranslationApplier { - - @Override - public void apply(@NonNull View view, float x, float y) { - if (view instanceof NavigableAppWidgetHostView) { - ((NavigableAppWidgetHostView) view).setTranslationForMoveFromCenterAnimation(x, y); - } else if (view instanceof BubbleTextView) { - ((BubbleTextView) view).setTranslationForMoveFromCenterAnimation(x, y); - } else { - view.setTranslationX(x); - view.setTranslationY(y); - } - } - } } diff --git a/src/com/android/launcher3/BubbleTextView.java b/src/com/android/launcher3/BubbleTextView.java index e52d1be18c..54920e1e17 100644 --- a/src/com/android/launcher3/BubbleTextView.java +++ b/src/com/android/launcher3/BubbleTextView.java @@ -90,6 +90,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private final PointF mTranslationForReorderBounce = new PointF(0, 0); private final PointF mTranslationForReorderPreview = new PointF(0, 0); + private float mTranslationXForTaskbarAlignmentAnimation = 0f; + private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0); private float mScaleForReorderBounce = 1f; @@ -825,7 +827,8 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, private void updateTranslation() { super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x - + mTranslationForMoveFromCenterAnimation.x); + + mTranslationForMoveFromCenterAnimation.x + + mTranslationXForTaskbarAlignmentAnimation); super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y + mTranslationForMoveFromCenterAnimation.y); } @@ -860,11 +863,29 @@ public class BubbleTextView extends TextView implements ItemInfoUpdateReceiver, return mScaleForReorderBounce; } + /** + * Sets translation values for move from center animation + */ public void setTranslationForMoveFromCenterAnimation(float x, float y) { mTranslationForMoveFromCenterAnimation.set(x, y); updateTranslation(); } + /** + * Sets translationX for taskbar to launcher alignment animation + */ + public void setTranslationXForTaskbarAlignmentAnimation(float translationX) { + mTranslationXForTaskbarAlignmentAnimation = translationX; + updateTranslation(); + } + + /** + * Returns translationX value for taskbar to launcher alignment animation + */ + public float getTranslationXForTaskbarAlignmentAnimation() { + return mTranslationXForTaskbarAlignmentAnimation; + } + public View getView() { return this; } diff --git a/src/com/android/launcher3/folder/FolderIcon.java b/src/com/android/launcher3/folder/FolderIcon.java index 60d8cdbd7c..439df80284 100644 --- a/src/com/android/launcher3/folder/FolderIcon.java +++ b/src/com/android/launcher3/folder/FolderIcon.java @@ -132,6 +132,9 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel private Rect mTouchArea = new Rect(); + private final PointF mTranslationForMoveFromCenterAnimation = new PointF(0, 0); + private float mTranslationXForTaskbarAlignmentAnimation = 0f; + private final PointF mTranslationForReorderBounce = new PointF(0, 0); private final PointF mTranslationForReorderPreview = new PointF(0, 0); private float mScaleForReorderBounce = 1f; @@ -765,8 +768,11 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel } private void updateTranslation() { - super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x); - super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y); + super.setTranslationX(mTranslationForReorderBounce.x + mTranslationForReorderPreview.x + + mTranslationForMoveFromCenterAnimation.x + + mTranslationXForTaskbarAlignmentAnimation); + super.setTranslationY(mTranslationForReorderBounce.y + mTranslationForReorderPreview.y + + mTranslationForMoveFromCenterAnimation.y); } public void setReorderBounceOffset(float x, float y) { @@ -778,6 +784,29 @@ public class FolderIcon extends FrameLayout implements FolderListener, IconLabel offset.set(mTranslationForReorderBounce); } + /** + * Sets translationX value for taskbar to launcher alignment animation + */ + public void setTranslationForTaskbarAlignmentAnimation(float translationX) { + mTranslationXForTaskbarAlignmentAnimation = translationX; + updateTranslation(); + } + + /** + * Returns translation values for taskbar to launcher alignment animation + */ + public float getTranslationXForTaskbarAlignmentAnimation() { + return mTranslationXForTaskbarAlignmentAnimation; + } + + /** + * Sets translation values for move from center animation + */ + public void setTranslationForMoveFromCenterAnimation(float x, float y) { + mTranslationForMoveFromCenterAnimation.set(x, y); + updateTranslation(); + } + @Override public void setReorderPreviewOffset(float x, float y) { mTranslationForReorderPreview.set(x, y);