Merge "Fix grid previewing so it matches the applied layout" into main
diff --git a/AndroidManifest-common.xml b/AndroidManifest-common.xml
index fe57da1..46f0e41 100644
--- a/AndroidManifest-common.xml
+++ b/AndroidManifest-common.xml
@@ -131,13 +131,11 @@
android:writePermission="${applicationId}.permission.WRITE_SETTINGS"
android:readPermission="${applicationId}.permission.READ_SETTINGS" />
- <!--
- The content provider for exposing various launcher grid options.
- TODO: Add proper permissions
- -->
+ <!-- The content provider for exposing various launcher grid options. -->
<provider
android:name="com.android.launcher3.graphics.LauncherCustomizationProvider"
android:authorities="${applicationId}.grid_control"
+ android:permission="android.permission.BIND_WALLPAPER"
android:exported="true" />
<!--
diff --git a/quickstep/res/layout/activity_allset.xml b/quickstep/res/layout/activity_allset.xml
index 625d9b3..3d68dfb 100644
--- a/quickstep/res/layout/activity_allset.xml
+++ b/quickstep/res/layout/activity_allset.xml
@@ -29,7 +29,6 @@
android:layout_height="match_parent"
android:gravity="center"
android:scaleType="centerCrop"
- app:lottie_autoPlay="true"
app:lottie_loop="true"
app:layout_constraintTop_toTopOf="parent"
@@ -49,11 +48,10 @@
app:layout_constraintEnd_toEndOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout
- android:id="@+id/text_content_view"
+ android:id="@+id/content"
android:layout_width="match_parent"
android:layout_height="wrap_content"
- android:layout_marginStart="@dimen/allset_page_margin_horizontal"
- android:layout_marginEnd="@dimen/allset_page_margin_horizontal"
+ android:paddingHorizontal="@dimen/allset_page_padding_horizontal"
android:layoutDirection="locale"
android:textDirection="locale"
android:forceHasOverlappingRendering="false"
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 0052a73..cf7ba00 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -16,7 +16,7 @@
-->
<resources>
<!-- All Set page -->
- <dimen name="allset_page_margin_horizontal">48dp</dimen>
+ <dimen name="allset_page_padding_horizontal">48dp</dimen>
<!-- Gesture Tutorial menu page -->
<dimen name="gesture_tutorial_menu_padding_horizontal">48dp</dimen>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index 4996582..3e72651 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -37,7 +37,7 @@
<dimen name="overview_actions_top_margin">24dp</dimen>
<!-- All Set page -->
- <dimen name="allset_page_margin_horizontal">120dp</dimen>
+ <dimen name="allset_page_padding_horizontal">120dp</dimen>
<dimen name="allset_page_allset_text_size">38sp</dimen>
<dimen name="allset_page_swipe_up_text_size">15sp</dimen>
</resources>
diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml
index 05f0695..52ebdae 100644
--- a/quickstep/res/values/dimens.xml
+++ b/quickstep/res/values/dimens.xml
@@ -277,7 +277,7 @@
<dimen name="gesture_tutorial_taskbar_margin_bottom">24dp</dimen>
<!-- All Set page -->
- <dimen name="allset_page_margin_horizontal">40dp</dimen>
+ <dimen name="allset_page_padding_horizontal">40dp</dimen>
<dimen name="allset_page_allset_text_size">36sp</dimen>
<dimen name="allset_page_swipe_up_text_size">14sp</dimen>
diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
index 67feb6a..84ae0fe 100644
--- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
+++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java
@@ -56,7 +56,6 @@
import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE;
import static com.android.launcher3.util.DisplayController.isTransientTaskbar;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
-import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs;
import static com.android.launcher3.views.FloatingIconView.SHAPE_PROGRESS_DURATION;
@@ -79,7 +78,6 @@
import android.content.ComponentName;
import android.content.Context;
import android.content.res.Resources;
-import android.database.ContentObserver;
import android.graphics.Color;
import android.graphics.Matrix;
import android.graphics.Point;
@@ -94,7 +92,6 @@
import android.os.SystemProperties;
import android.os.UserHandle;
import android.provider.Settings;
-import android.provider.Settings.Global;
import android.util.Pair;
import android.util.Size;
import android.view.CrossWindowBlurListeners;
@@ -249,16 +246,6 @@
// {@link TaskRestartedDuringLaunchListener}, and remove them on activity destroy.
private final List<TaskRestartedDuringLaunchListener> mRegisteredTaskStackChangeListener =
new ArrayList<>();
- private final ContentObserver mAnimationRemovalObserver = new ContentObserver(
- ORDERED_BG_EXECUTOR.getHandler()) {
- @Override
- public void onChange(boolean selfChange) {
- mAreAnimationsEnabled = Global.getFloat(mLauncher.getContentResolver(),
- Global.ANIMATOR_DURATION_SCALE, 1f) > 0
- || Global.getFloat(mLauncher.getContentResolver(),
- Global.TRANSITION_ANIMATION_SCALE, 1f) > 0;
- }
- };
private DeviceProfile mDeviceProfile;
@@ -287,7 +274,6 @@
// Pairs of window starting type and starting window background color for starting tasks
// Will never be larger than MAX_NUM_TASKS
private LinkedHashMap<Integer, Pair<Integer, Integer>> mTaskStartParams;
- private boolean mAreAnimationsEnabled = true;
private final Interpolator mOpeningXInterpolator;
private final Interpolator mOpeningInterpolator;
@@ -298,7 +284,6 @@
mHandler = new Handler(Looper.getMainLooper());
mDeviceProfile = mLauncher.getDeviceProfile();
mBackAnimationController = new LauncherBackAnimationController(mLauncher, this);
- checkAndMonitorIfAnimationsAreEnabled();
Resources res = mLauncher.getResources();
mClosingWindowTransY = res.getDimensionPixelSize(R.dimen.closing_window_trans_y);
@@ -1220,8 +1205,6 @@
unregisterRemoteTransitions();
mLauncher.removeOnDeviceProfileChangeListener(this);
SystemUiProxy.INSTANCE.get(mLauncher).setStartingWindowListener(null);
- ORDERED_BG_EXECUTOR.execute(() -> mLauncher.getContentResolver()
- .unregisterContentObserver(mAnimationRemovalObserver));
if (BuildConfig.IS_STUDIO_BUILD && !mRegisteredTaskStackChangeListener.isEmpty()) {
throw new IllegalStateException("Failed to run onEndCallback created from"
+ " getActivityLaunchOptions()");
@@ -1275,17 +1258,6 @@
}
}
- private void checkAndMonitorIfAnimationsAreEnabled() {
- ORDERED_BG_EXECUTOR.execute(() -> {
- mAnimationRemovalObserver.onChange(true);
- mLauncher.getContentResolver().registerContentObserver(Global.getUriFor(
- Global.ANIMATOR_DURATION_SCALE), false, mAnimationRemovalObserver);
- mLauncher.getContentResolver().registerContentObserver(Global.getUriFor(
- Global.TRANSITION_ANIMATION_SCALE), false, mAnimationRemovalObserver);
-
- });
- }
-
private boolean launcherIsATargetWithMode(RemoteAnimationTarget[] targets, int mode) {
for (RemoteAnimationTarget target : targets) {
if (target.mode == mode && target.taskInfo != null
@@ -1421,7 +1393,8 @@
(LauncherAppWidgetHostView) launcherView, targetRect, windowSize,
mDeviceProfile.isMultiWindowMode ? 0 : getWindowCornerRadius(mLauncher),
isTransluscent, fallbackBackgroundColor);
- } else if (launcherView != null && mAreAnimationsEnabled) {
+ } else if (launcherView != null && !RemoveAnimationSettingsTracker.INSTANCE.get(
+ mLauncher).isRemoveAnimationEnabled()) {
floatingIconView = getFloatingIconView(mLauncher, launcherView, null,
mLauncher.getTaskbarUIController() == null
? null
@@ -1811,8 +1784,8 @@
}
/** Get animation duration for taskbar for going to home. */
- public static int getTaskbarToHomeDuration(boolean isPinnedTaskbar) {
- return getTaskbarToHomeDuration(false, isPinnedTaskbar);
+ public static int getTaskbarToHomeDuration(boolean isPinnedTaskbarAndNotInDesktopMode) {
+ return getTaskbarToHomeDuration(false, isPinnedTaskbarAndNotInDesktopMode);
}
/**
@@ -1821,8 +1794,8 @@
* @param shouldOverrideToFastAnimation should overwrite scaling reveal home animation duration
*/
public static int getTaskbarToHomeDuration(boolean shouldOverrideToFastAnimation,
- boolean isPinnedTaskbar) {
- if (isPinnedTaskbar) {
+ boolean isPinnedTaskbarAndNotInDesktopMode) {
+ if (isPinnedTaskbarAndNotInDesktopMode) {
return PINNED_TASKBAR_TRANSITION_DURATION;
} else if (enableScalingRevealHomeAnimation() && !shouldOverrideToFastAnimation) {
return TASKBAR_TO_HOME_DURATION_SLOW;
diff --git a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
index 138f40a..eb24df1 100644
--- a/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
+++ b/quickstep/src/com/android/launcher3/statehandlers/DesktopVisibilityController.kt
@@ -32,7 +32,8 @@
import com.android.launcher3.uioverrides.QuickstepLauncher
import com.android.launcher3.util.DaggerSingletonObject
import com.android.launcher3.util.DaggerSingletonTracker
-import com.android.launcher3.util.Executors
+import com.android.launcher3.util.DisplayController
+import com.android.launcher3.util.Executors.MAIN_EXECUTOR
import com.android.launcher3.util.window.WindowManagerProxy.DesktopVisibilityListener
import com.android.quickstep.GestureState.GestureEndTarget
import com.android.quickstep.SystemUiProxy
@@ -87,9 +88,22 @@
private val desktopVisibilityListeners: MutableSet<DesktopVisibilityListener> = HashSet()
private val taskbarDesktopModeListeners: MutableSet<TaskbarDesktopModeListener> = HashSet()
+ // This simply indicates that user is currently in desktop mode or not.
+ var isInDesktopMode = false
+ private set
+
+ // to track if any pending notification to be done.
+ var isNotifyingDesktopVisibilityPending = false
+
+ // to let launcher hold off on notifying desktop visibility listeners.
+ var launcherAnimationRunning = false
+
// TODO: b/394387739 - Deprecate this and replace it with something that tracks the count per
// desk.
- /** Number of visible desktop windows in desktop mode. */
+ /**
+ * Number of visible desktop windows in desktop mode. This can be > 0 when user goes to overview
+ * from desktop window mode.
+ */
var visibleDesktopTasksCount: Int = 0
/**
* Sets the number of desktop windows that are visible and updates launcher visibility based
@@ -107,13 +121,27 @@
}
if (visibleTasksCount != field) {
+ if (visibleDesktopTasksCount == 0 && visibleTasksCount == 1) {
+ isInDesktopMode = true
+ }
+ if (visibleDesktopTasksCount == 1 && visibleTasksCount == 0) {
+ isInDesktopMode = false
+ }
val wasVisible = field > 0
val isVisible = visibleTasksCount > 0
val wereDesktopTasksVisibleBefore = areDesktopTasksVisibleAndNotInOverview()
field = visibleTasksCount
val areDesktopTasksVisibleNow = areDesktopTasksVisibleAndNotInOverview()
- if (wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow) {
- notifyIsInDesktopModeChanged(DEFAULT_DISPLAY, areDesktopTasksVisibleNow)
+
+ if (
+ wereDesktopTasksVisibleBefore != areDesktopTasksVisibleNow ||
+ wasVisible != isVisible
+ ) {
+ if (!launcherAnimationRunning) {
+ notifyIsInDesktopModeChanged(DEFAULT_DISPLAY, areDesktopTasksVisibleNow)
+ } else {
+ isNotifyingDesktopVisibilityPending = true
+ }
}
if (
@@ -169,7 +197,7 @@
/** Returns whether a desk is currently active on the display with the given [displayId]. */
fun isInDesktopMode(displayId: Int): Boolean {
if (!DesktopModeStatus.enableMultipleDesktops(context)) {
- return areDesktopTasksVisible()
+ return isInDesktopMode
}
val activeDeskId = getDisplayDeskConfig(displayId)?.activeDeskId ?: INACTIVE_DESK_ID
@@ -196,15 +224,6 @@
}
/** Whether desktop tasks are visible in desktop mode. */
- private fun areDesktopTasksVisible(): Boolean {
- val desktopTasksVisible: Boolean = visibleDesktopTasksCount > 0
- if (DEBUG) {
- Log.d(TAG, "areDesktopTasksVisible: desktopVisible=$desktopTasksVisible")
- }
- return desktopTasksVisible
- }
-
- /** Whether desktop tasks are visible in desktop mode. */
private fun areDesktopTasksVisibleAndNotInOverview(): Boolean {
val desktopTasksVisible: Boolean = visibleDesktopTasksCount > 0
if (DEBUG) {
@@ -237,6 +256,22 @@
)
}
+ /**
+ * Launcher Driven Desktop Mode changes. For example, swipe to home and quick switch from
+ * Desktop Windowing Mode. if there is any pending notification please notify desktop visibility
+ * listeners.
+ */
+ fun onLauncherAnimationFromDesktopEnd() {
+ launcherAnimationRunning = false
+ if (isNotifyingDesktopVisibilityPending) {
+ isNotifyingDesktopVisibilityPending = false
+ notifyIsInDesktopModeChanged(
+ DEFAULT_DISPLAY,
+ isInDesktopModeAndNotInOverview(DEFAULT_DISPLAY),
+ )
+ }
+ }
+
fun onLauncherStateChanged(state: RecentsState) {
onLauncherStateChanged(
state,
@@ -346,6 +381,26 @@
}
}
+ private fun notifyTaskbarDesktopModeListenersForEntry(duration: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTaskbarDesktopModeListenersForEntry: duration=" + duration)
+ }
+ for (listener in taskbarDesktopModeListeners) {
+ listener.onEnterDesktopMode(duration)
+ }
+ DisplayController.INSTANCE.get(context).notifyConfigChange()
+ }
+
+ private fun notifyTaskbarDesktopModeListenersForExit(duration: Int) {
+ if (DEBUG) {
+ Log.d(TAG, "notifyTaskbarDesktopModeListenersForExit: duration=" + duration)
+ }
+ for (listener in taskbarDesktopModeListeners) {
+ listener.onExitDesktopMode(duration)
+ }
+ DisplayController.INSTANCE.get(context).notifyConfigChange()
+ }
+
/** TODO: b/333533253 - Remove after flag rollout */
private fun setBackgroundStateEnabled(backgroundStateEnabled: Boolean) {
if (DEBUG) {
@@ -552,14 +607,14 @@
displayDeskStates: Array<DisplayDeskState>,
canCreateDesks: Boolean,
) {
- Executors.MAIN_EXECUTOR.execute {
+ MAIN_EXECUTOR.execute {
controller.get()?.onListenerConnected(displayDeskStates, canCreateDesks)
}
}
override fun onTasksVisibilityChanged(displayId: Int, visibleTasksCount: Int) {
if (displayId != this.displayId) return
- Executors.MAIN_EXECUTOR.execute {
+ MAIN_EXECUTOR.execute {
controller.get()?.apply {
if (DEBUG) {
Log.d(TAG, "desktop visible tasks count changed=$visibleTasksCount")
@@ -575,7 +630,7 @@
override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {
if (!DesktopModeStatus.useRoundedCorners()) return
- Executors.MAIN_EXECUTOR.execute {
+ MAIN_EXECUTOR.execute {
controller.get()?.apply {
Log.d(
TAG,
@@ -587,26 +642,46 @@
}
}
- override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {}
-
- override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {}
-
- override fun onCanCreateDesksChanged(canCreateDesks: Boolean) {
- Executors.MAIN_EXECUTOR.execute {
- controller.get()?.onCanCreateDesksChanged(canCreateDesks)
+ override fun onEnterDesktopModeTransitionStarted(transitionDuration: Int) {
+ MAIN_EXECUTOR.execute {
+ Log.d(
+ TAG,
+ ("DesktopTaskListenerImpl: onEnterDesktopModeTransitionStarted with " +
+ "duration= " +
+ transitionDuration),
+ )
+ controller.get()?.isInDesktopMode = true
+ controller.get()?.notifyTaskbarDesktopModeListenersForEntry(transitionDuration)
}
}
+ override fun onExitDesktopModeTransitionStarted(transitionDuration: Int) {
+ MAIN_EXECUTOR.execute {
+ Log.d(
+ TAG,
+ ("DesktopTaskListenerImpl: onExitDesktopModeTransitionStarted with " +
+ "duration= " +
+ transitionDuration),
+ )
+ controller.get()?.isInDesktopMode = false
+ controller.get()?.notifyTaskbarDesktopModeListenersForExit(transitionDuration)
+ }
+ }
+
+ override fun onCanCreateDesksChanged(canCreateDesks: Boolean) {
+ MAIN_EXECUTOR.execute { controller.get()?.onCanCreateDesksChanged(canCreateDesks) }
+ }
+
override fun onDeskAdded(displayId: Int, deskId: Int) {
- Executors.MAIN_EXECUTOR.execute { controller.get()?.onDeskAdded(displayId, deskId) }
+ MAIN_EXECUTOR.execute { controller.get()?.onDeskAdded(displayId, deskId) }
}
override fun onDeskRemoved(displayId: Int, deskId: Int) {
- Executors.MAIN_EXECUTOR.execute { controller.get()?.onDeskRemoved(displayId, deskId) }
+ MAIN_EXECUTOR.execute { controller.get()?.onDeskRemoved(displayId, deskId) }
}
override fun onActiveDeskChanged(displayId: Int, newActiveDesk: Int, oldActiveDesk: Int) {
- Executors.MAIN_EXECUTOR.execute {
+ MAIN_EXECUTOR.execute {
controller.get()?.onActiveDeskChanged(displayId, newActiveDesk, oldActiveDesk)
}
}
@@ -619,7 +694,21 @@
*
* @param doesAnyTaskRequireTaskbarRounding whether task requires taskbar corner roundness.
*/
- fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean)
+ fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {}
+
+ /**
+ * Callback for when user is exiting desktop mode.
+ *
+ * @param duration for exit transition
+ */
+ fun onExitDesktopMode(duration: Int) {}
+
+ /**
+ * Callback for when user is entering desktop mode.
+ *
+ * @param duration for enter transition
+ */
+ fun onEnterDesktopMode(duration: Int) {}
}
companion object {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 2e42e45..57bcc14 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -27,6 +27,7 @@
import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
+import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
@@ -449,14 +450,25 @@
mControllers.taskbarViewController.adjustTaskbarForBubbleBar();
}
- public void init(@NonNull TaskbarSharedState sharedState) {
+ /**
+ * Init of taskbar activity context.
+ * @param duration If duration is greater than 0, it will be used to create an animation
+ * for the taskbar create/recreate process.
+ */
+ public void init(@NonNull TaskbarSharedState sharedState, int duration) {
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false);
mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize();
mWindowLayoutParams = createAllWindowParams();
mLastUpdatedLayoutParams = new WindowManager.LayoutParams();
+
+ AnimatorSet recreateAnim = null;
+ if (duration > 0) {
+ recreateAnim = onRecreateAnimation(duration);
+ }
+
// Initialize controllers after all are constructed.
- mControllers.init(sharedState);
+ mControllers.init(sharedState, recreateAnim);
// This may not be necessary and can be reverted once we move towards recreating all
// controllers without re-creating the window
mControllers.rotationButtonController.onNavigationModeChanged(mNavMode.resValue);
@@ -484,6 +496,33 @@
} else {
notifyUpdateLayoutParams();
}
+
+
+ if (recreateAnim != null) {
+ recreateAnim.start();
+ }
+ }
+
+ /**
+ * Create AnimatorSet for taskbar create/recreate animation. Further used in init
+ */
+ public AnimatorSet onRecreateAnimation(int duration) {
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.setDuration(duration);
+ return animatorSet;
+ }
+
+ /**
+ * Called when we want destroy current taskbar with animation as part of recreate process.
+ */
+ public AnimatorSet onDestroyAnimation(int duration) {
+ mIsDestroyed = true;
+ AnimatorSet animatorSet = new AnimatorSet();
+ mControllers.taskbarViewController.onDestroyAnimation(animatorSet);
+ mControllers.taskbarDragLayerController.onDestroyAnimation(animatorSet);
+ animatorSet.setInterpolator(LINEAR);
+ animatorSet.setDuration(duration);
+ return animatorSet;
}
/**
@@ -1983,6 +2022,10 @@
return mControllers.taskbarStashController.isInApp();
}
+ public boolean isInOverview() {
+ return mControllers.taskbarStashController.isInOverview();
+ }
+
public boolean isInStashedLauncherState() {
return mControllers.taskbarStashController.isInStashedLauncherState();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 6d23853..89cc991 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -50,6 +50,8 @@
}
var isAnimatingPinning = false
+ var isAnimatingPersistentTaskbar = false
+ var isAnimatingTransientTaskbar = false
val paint = Paint()
private val strokePaint = Paint()
@@ -144,7 +146,7 @@
/** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
if (isInSetup) return
- val isTransientTaskbar = backgroundProgress == 0f
+ val isTransientTaskbar = DisplayController.isTransientTaskbar(context)
canvas.save()
if (!isTransientTaskbar || transientBackgroundBounds.isEmpty || isAnimatingPinning) {
drawPersistentBackground(canvas)
@@ -158,7 +160,7 @@
}
private fun drawPersistentBackground(canvas: Canvas) {
- if (isAnimatingPinning) {
+ if (isAnimatingPinning || isAnimatingPersistentTaskbar) {
val persistentTaskbarHeight = maxPersistentTaskbarHeight * backgroundProgress
canvas.translate(0f, canvas.height - persistentTaskbarHeight)
// Draw the background behind taskbar content.
@@ -181,12 +183,13 @@
private fun drawTransientBackground(canvas: Canvas) {
val res = context.resources
val transientTaskbarHeight = maxTransientTaskbarHeight * (1f - backgroundProgress)
+ val isAnimating = isAnimatingPinning || isAnimatingTransientTaskbar
val heightProgressWhileAnimating =
- if (isAnimatingPinning) transientTaskbarHeight else backgroundHeight
+ if (isAnimating) transientTaskbarHeight else backgroundHeight
var progress = heightProgressWhileAnimating / maxTransientTaskbarHeight
progress = Math.round(progress * 100f) / 100f
- if (isAnimatingPinning) {
+ if (isAnimating) {
var scale = transientTaskbarHeight / maxTransientTaskbarHeight
scale = Math.round(scale * 100f) / 100f
bottomMargin =
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index b244be9..6ca9385 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import android.animation.AnimatorSet;
import android.content.pm.ActivityInfo.Config;
import androidx.annotation.NonNull;
@@ -149,15 +150,15 @@
* TaskbarControllers instance, but should be careful to only access things that were created
* in constructors for now, as some controllers may still be waiting for init().
*/
- public void init(@NonNull TaskbarSharedState sharedState) {
+ public void init(@NonNull TaskbarSharedState sharedState, AnimatorSet startAnimation) {
mAreAllControllersInitialized = false;
mSharedState = sharedState;
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
rotationButtonController.init();
- taskbarDragLayerController.init(this);
- taskbarViewController.init(this);
+ taskbarDragLayerController.init(this, startAnimation);
+ taskbarViewController.init(this, startAnimation);
taskbarScrimViewController.init(this);
taskbarUnfoldAnimationController.init(this);
taskbarKeyguardController.init(navbarButtonsViewController);
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
index f71dea9..ca8e4ca 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
@@ -30,6 +30,9 @@
private lateinit var taskbarControllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
+ val isInDesktopMode: Boolean
+ get() = desktopVisibilityController.isInDesktopMode
+
fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) {
taskbarControllers = controllers
taskbarSharedState = sharedState
@@ -42,6 +45,7 @@
desktopVisibilityController.isInDesktopModeAndNotInOverview(displayId)
override fun onTaskbarCornerRoundingUpdate(doesAnyTaskRequireTaskbarRounding: Boolean) {
+ if (taskbarControllers.taskbarActivityContext.isDestroyed) return
taskbarSharedState.showCornerRadiusInDesktopMode = doesAnyTaskRequireTaskbarRounding
val cornerRadius = getTaskbarCornerRoundness(doesAnyTaskRequireTaskbarRounding)
taskbarControllers.taskbarCornerRoundness.animateToValue(cornerRadius).start()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 59ef577..4dbad8c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -186,6 +186,7 @@
@Override
protected void dispatchDraw(Canvas canvas) {
+ if (mContainer.isDestroyed()) return;
float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
* (1f - mTaskbarBackgroundOffset);
mBackgroundRenderer.setBackgroundHeight(backgroundHeight);
@@ -286,6 +287,21 @@
}
/**
+ * Sets animation boolean when only animating persistent taskbar.
+ */
+ public void setIsAnimatingPersistentTaskbarBackground(boolean animatingPersistentTaskbarBg) {
+ mBackgroundRenderer.setAnimatingPersistentTaskbar(animatingPersistentTaskbarBg);
+ }
+
+ /**
+ * Sets animation boolean when only animating transient taskbar.
+ */
+ public void setIsAnimatingTransientTaskbarBackground(boolean animatingTransientTaskbarBg) {
+ mBackgroundRenderer.setAnimatingTransientTaskbar(animatingTransientTaskbarBg);
+ }
+
+
+ /**
* Sets the width percentage to inset the transient taskbar's background from the left and from
* the right.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 68c252a..55ecc37 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -15,9 +15,12 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -29,6 +32,7 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.util.DimensionUtils;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
@@ -58,6 +62,8 @@
private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mAssistantBgTaskbar = new AnimatedFloat(
this::updateBackgroundAlpha);
+ private final AnimatedFloat mBgTaskbarRecreate = new AnimatedFloat(
+ this::updateBackgroundAlpha);
// Used to hide our background color when someone else (e.g. ScrimView) is handling it.
private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
@@ -88,7 +94,10 @@
mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin);
}
- public void init(TaskbarControllers controllers) {
+ /**
+ * Init of taskbar drag layer controller
+ */
+ public void init(TaskbarControllers controllers, AnimatorSet startAnimation) {
mControllers = controllers;
mTaskbarStashViaTouchController = new TaskbarStashViaTouchController(mControllers);
mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks());
@@ -96,15 +105,45 @@
mOnBackgroundNavButtonColorIntensity = mControllers.navbarButtonsViewController
.getOnTaskbarBackgroundNavButtonColorOverride();
- mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity)
- ? PINNING_TRANSIENT
- : PINNING_PERSISTENT);
+
+ if (startAnimation != null) {
+ // set taskbar background render animation boolean
+ if (DisplayController.isTransientTaskbar(mActivity)) {
+ mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(true);
+ } else {
+ mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(true);
+ }
+
+ float desiredValue = DisplayController.isTransientTaskbar(mActivity)
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT;
+
+ float nonDesiredvalue = !DisplayController.isTransientTaskbar(mActivity)
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT;
+
+ ObjectAnimator objectAnimator = mTaskbarBackgroundProgress.animateToValue(
+ nonDesiredvalue, desiredValue);
+ objectAnimator.setInterpolator(EMPHASIZED);
+ startAnimation.play(objectAnimator);
+ startAnimation.addListener(AnimatorListeners.forEndCallback(()-> {
+ // reset taskbar background render animation boolean
+ mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(false);
+ mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(false);
+ }));
+
+ } else {
+ mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity)
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT);
+ }
mBgTaskbar.value = 1;
mKeyguardBgTaskbar.value = 1;
mNotificationShadeBgTaskbar.value = 1;
mImeBgTaskbar.value = 1;
mAssistantBgTaskbar.value = 1;
+ mBgTaskbarRecreate.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
@@ -112,6 +151,13 @@
updateTaskbarAlpha();
}
+ /**
+ * Called when destroying Taskbar with animation.
+ */
+ public void onDestroyAnimation(AnimatorSet animatorSet) {
+ animatorSet.play(mBgTaskbarRecreate.animateToValue(0f));
+ }
+
public void onDestroy() {
mTaskbarDragLayer.onDestroy();
}
@@ -172,14 +218,14 @@
}
private void updateBackgroundAlpha() {
- if (mActivity.isPhoneMode()) {
+ if (mActivity.isPhoneMode() || mActivity.isDestroyed()) {
return;
}
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
* mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
- * mAssistantBgTaskbar.value;
+ * mAssistantBgTaskbar.value * mBgTaskbarRecreate.value;
mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
mBackgroundRendererAlpha.setValue(mLastSetBackgroundAlpha);
@@ -266,6 +312,7 @@
pw.println(prefix + "\t\tmNotificationShadeBgTaskbar=" + mNotificationShadeBgTaskbar.value);
pw.println(prefix + "\t\tmImeBgTaskbar=" + mImeBgTaskbar.value);
pw.println(prefix + "\t\tmAssistantBgTaskbar=" + mAssistantBgTaskbar.value);
+ pw.println(prefix + "\t\tmBgTaskbarRecreate=" + mBgTaskbarRecreate.value);
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index b4ffb74..5d1288c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -39,6 +39,7 @@
import com.airbnb.lottie.LottieAnimationView
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.R
+import com.android.launcher3.RemoveAnimationSettingsTracker
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
@@ -128,6 +129,26 @@
activityContext.dragLayer.post { maybeShowSearchEdu() }
}
+ /**
+ * Turns off auto play of lottie animations if user has opted to remove animation else attaches
+ * click listener to allow user to play or pause animations.
+ */
+ fun handleEduAnimations(animationViews: List<LottieAnimationView>) {
+ for (animationView in animationViews) {
+ if (
+ RemoveAnimationSettingsTracker.INSTANCE.get(animationView.context)
+ .isRemoveAnimationEnabled()
+ ) {
+ animationView.pauseAnimation()
+ } else {
+ animationView.setOnClickListener {
+ if (animationView.isAnimating) animationView.pauseAnimation()
+ else animationView.playAnimation()
+ }
+ }
+ }
+ }
+
/** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
fun maybeShowSwipeEdu() {
if (
@@ -145,7 +166,9 @@
requireViewById(R.id.taskbar_edu_title),
TypefaceUtils.FONT_FAMILY_HEADLINE_SMALL_EMPHASIZED,
)
- requireViewById<LottieAnimationView>(R.id.swipe_animation).supportLightTheme()
+ val swipeAnimation = requireViewById<LottieAnimationView>(R.id.swipe_animation)
+ swipeAnimation.supportLightTheme()
+ handleEduAnimations(listOf(swipeAnimation))
show()
}
}
@@ -174,6 +197,7 @@
splitscreenAnim.supportLightTheme()
suggestionsAnim.supportLightTheme()
pinningAnim.supportLightTheme()
+ handleEduAnimations(listOf(splitscreenAnim, suggestionsAnim, pinningAnim))
if (DisplayController.isTransientTaskbar(activityContext)) {
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
@@ -249,9 +273,6 @@
tooltip?.run {
allowTouchDismissal = true
- requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
- .supportLightTheme()
-
TypefaceUtils.setTypeface(
requireViewById(R.id.taskbar_edu_title),
TypefaceUtils.FONT_FAMILY_HEADLINE_SMALL_EMPHASIZED,
@@ -261,6 +282,10 @@
TypefaceUtils.FONT_FAMILY_BODY_MEDIUM_BASELINE,
)
+ val pinningAnim =
+ requireViewById<LottieAnimationView>(R.id.standalone_pinning_animation)
+ pinningAnim.supportLightTheme()
+ handleEduAnimations(listOf(pinningAnim))
updateLayoutParams<BaseDragLayer.LayoutParams> {
if (DisplayController.isTransientTaskbar(activityContext)) {
bottomMargin += activityContext.deviceProfile.taskbarHeight
@@ -304,7 +329,9 @@
inflateTooltip(R.layout.taskbar_edu_search)
tooltip?.run {
allowTouchDismissal = true
- requireViewById<LottieAnimationView>(R.id.search_edu_animation).supportLightTheme()
+ val searchEdu = requireViewById<LottieAnimationView>(R.id.search_edu_animation)
+ searchEdu.supportLightTheme()
+ handleEduAnimations(listOf(searchEdu))
val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
TypefaceUtils.setTypeface(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index dd9f61e..10eb64a 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -223,9 +223,13 @@
updateStateForFlag(FLAG_LAUNCHER_IN_STATE_TRANSITION, true);
if (!mShouldDelayLauncherStateAnim) {
if (toState == LauncherState.NORMAL) {
- applyState(QuickstepTransitionManager.getTaskbarToHomeDuration(
+ boolean isPinnedTaskbarAndNotInDesktopMode =
DisplayController.isPinnedTaskbar(
- mControllers.taskbarActivityContext)));
+ mControllers.taskbarActivityContext)
+ && !DisplayController.isInDesktopMode(
+ mControllers.taskbarActivityContext);
+ applyState(QuickstepTransitionManager.getTaskbarToHomeDuration(
+ isPinnedTaskbarAndNotInDesktopMode));
} else {
applyState();
}
@@ -680,8 +684,11 @@
} else if (mIconAlignment.isAnimatingToValue(toAlignment)
|| mIconAlignment.isSettledOnValue(toAlignment)) {
// Already at desired value, but make sure we run the callback at the end.
- animatorSet.addListener(AnimatorListeners.forEndCallback(
- this::onIconAlignmentRatioChanged));
+ animatorSet.addListener(AnimatorListeners.forEndCallback(() -> {
+ if (!mIconAlignment.isAnimating()) {
+ onIconAlignmentRatioChanged();
+ }
+ }));
} else {
mIconAlignment.cancelAnimation();
ObjectAnimator iconAlignAnim = mIconAlignment
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 34bb6e0..5155ffc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -26,6 +26,7 @@
import static com.android.launcher3.util.DisplayController.CHANGE_DENSITY;
import static com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
+import static com.android.launcher3.util.DisplayController.CHANGE_SHOW_LOCKED_TASKBAR;
import static com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
@@ -33,6 +34,7 @@
import static com.android.quickstep.util.SystemActionConstants.ACTION_SHOW_TASKBAR;
import static com.android.quickstep.util.SystemActionConstants.SYSTEM_ACTION_ID_TASKBAR;
+import android.animation.AnimatorSet;
import android.annotation.SuppressLint;
import android.app.PendingIntent;
import android.content.ComponentCallbacks;
@@ -62,7 +64,9 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherAppState;
+import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.AnimatorPlaybackController;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarNavButtonCallbacks;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
@@ -101,6 +105,7 @@
// TODO(b/382378283) remove all logs with this tag
public static final String NULL_TASKBAR_ROOT_LAYOUT_TAG = "b/382378283";
public static final String ILLEGAL_ARGUMENT_WM_ADD_VIEW = "b/391653300";
+ private static final int TASKBAR_DESTROY_DURATION = 100;
/**
* All the configurations which do not initiate taskbar recreation.
@@ -189,13 +194,28 @@
}
if ((flags & (CHANGE_DENSITY | CHANGE_NAVIGATION_MODE | CHANGE_DESKTOP_MODE
- | CHANGE_TASKBAR_PINNING)) != 0) {
+ | CHANGE_TASKBAR_PINNING | CHANGE_SHOW_LOCKED_TASKBAR)) != 0) {
debugTaskbarManager("onDisplayInfoChanged - Recreating Taskbar!",
context.getDisplayId());
- recreateTaskbar();
+ TaskbarActivityContext taskbarActivityContext = getCurrentActivityContext();
+ if ((flags & CHANGE_SHOW_LOCKED_TASKBAR) != 0) {
+ recreateTaskbar();
+ } else if ((flags & CHANGE_DESKTOP_MODE) != 0) {
+ // Only Handles Special Exit Cases for Desktop Mode Taskbar Recreation.
+ if (taskbarActivityContext != null
+ && !DesktopVisibilityController.INSTANCE.get(taskbarActivityContext)
+ .isInDesktopMode()
+ && !DisplayController.showLockedTaskbarOnHome(context)) {
+ recreateTaskbar();
+ }
+ } else {
+ recreateTaskbar();
+ }
+
}
}
}
+
private final SettingsCache.OnChangeListener mOnSettingsChangeListener = c -> {
debugTaskbarManager("Settings changed! Recreating Taskbar!");
recreateTaskbar();
@@ -258,7 +278,52 @@
public void onTaskRemoved(int taskId) {
mPerceptibleTasks.remove(taskId);
}
- };
+ }
+
+ ;
+
+ private final DesktopVisibilityController.TaskbarDesktopModeListener
+ mTaskbarDesktopModeListener =
+ new DesktopVisibilityController.TaskbarDesktopModeListener() {
+ @Override
+ public void onExitDesktopMode(int duration) {
+ for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) {
+ int displayId = mTaskbars.keyAt(taskbarIndex);
+ TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay(
+ displayId);
+ if (taskbarActivityContext != null
+ && !taskbarActivityContext.isInOverview()) {
+ AnimatorSet animatorSet = taskbarActivityContext.onDestroyAnimation(
+ TASKBAR_DESTROY_DURATION);
+ animatorSet.addListener(AnimatorListeners.forEndCallback(
+ () -> recreateTaskbarForDisplay(getDefaultDisplayId(),
+ duration)));
+ animatorSet.start();
+ }
+ }
+ }
+
+ @Override
+ public void onEnterDesktopMode(int duration) {
+ for (int taskbarIndex = 0; taskbarIndex < mTaskbars.size(); taskbarIndex++) {
+ int displayId = mTaskbars.keyAt(taskbarIndex);
+ TaskbarActivityContext taskbarActivityContext = getTaskbarForDisplay(
+ displayId);
+ AnimatorSet animatorSet = taskbarActivityContext.onDestroyAnimation(
+ TASKBAR_DESTROY_DURATION);
+ animatorSet.addListener(AnimatorListeners.forEndCallback(
+ () -> recreateTaskbarForDisplay(getDefaultDisplayId(), duration)));
+ animatorSet.start();
+ }
+ }
+
+ @Override
+ public void onTaskbarCornerRoundingUpdate(
+ boolean doesAnyTaskRequireTaskbarRounding) {
+ //NO-OP
+ }
+ };
+
private boolean mUserUnlocked = false;
@@ -337,6 +402,9 @@
debugTaskbarManager("TaskbarManager constructor", primaryDisplayId);
mPrimaryWindowContext = createWindowContext(primaryDisplayId);
mPrimaryWindowManager = mPrimaryWindowContext.getSystemService(WindowManager.class);
+ DesktopVisibilityController.INSTANCE.get(
+ mPrimaryWindowContext).registerTaskbarDesktopModeListener(
+ mTaskbarDesktopModeListener);
createTaskbarRootLayout(primaryDisplayId);
createNavButtonController(primaryDisplayId);
createAndRegisterComponentCallbacks(primaryDisplayId);
@@ -550,13 +618,13 @@
public synchronized void recreateTaskbar() {
// Handles initial creation case.
if (mTaskbars.size() == 0) {
- recreateTaskbarForDisplay(getDefaultDisplayId());
+ recreateTaskbarForDisplay(getDefaultDisplayId(), 0);
return;
}
for (int i = 0; i < mTaskbars.size(); i++) {
int displayId = mTaskbars.keyAt(i);
- recreateTaskbarForDisplay(displayId);
+ recreateTaskbarForDisplay(displayId, 0);
}
}
@@ -565,7 +633,7 @@
* we fully want to destroy an existing taskbar for a specified display and create a new one.
* In other case (folding/unfolding) we don't need to remove and add window.
*/
- private void recreateTaskbarForDisplay(int displayId) {
+ private void recreateTaskbarForDisplay(int displayId, int duration) {
Trace.beginSection("recreateTaskbarForDisplay");
try {
Log.d(ILLEGAL_ARGUMENT_WM_ADD_VIEW, "recreateTaskbarForDisplay: " + displayId);
@@ -582,13 +650,13 @@
boolean displayExists = getDisplay(displayId) != null;
boolean isTaskbarEnabled = dp != null && isTaskbarEnabled(dp);
debugTaskbarManager("recreateTaskbarForDisplay: isTaskbarEnabled=" + isTaskbarEnabled
- + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
- + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ + " [dp != null (i.e. mUserUnlocked)]=" + (dp != null)
+ + " FLAG_HIDE_NAVBAR_WINDOW=" + ENABLE_TASKBAR_NAVBAR_UNIFICATION
+ " dp.isTaskbarPresent=" + (dp == null ? "null" : dp.isTaskbarPresent)
+ " displayExists=" + displayExists);
if (!isTaskbarEnabled || !isLargeScreenTaskbar || !displayExists) {
SystemUiProxy.INSTANCE.get(mBaseContext)
- .notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
+ .notifyTaskbarStatus(/* visible */ false, /* stashed */ false);
if (!isTaskbarEnabled || !displayExists) {
return;
}
@@ -608,7 +676,7 @@
mSharedState.startTaskbarVariantIsTransient =
DisplayController.isTransientTaskbar(taskbar);
mSharedState.allAppsVisible = mSharedState.allAppsVisible && isLargeScreenTaskbar;
- taskbar.init(mSharedState);
+ taskbar.init(mSharedState, duration);
// Non default displays should not use LauncherTaskbarUIController as they shouldn't
// have access to the Launcher activity.
@@ -792,7 +860,7 @@
createTaskbarRootLayout(displayId);
createNavButtonController(displayId);
createAndRegisterComponentCallbacks(displayId);
- recreateTaskbarForDisplay(displayId);
+ recreateTaskbarForDisplay(displayId, 0);
}
}
@@ -845,6 +913,9 @@
public void destroy() {
mRecentsViewContainer = null;
debugTaskbarManager("TaskbarManager#destroy()");
+ DesktopVisibilityController.INSTANCE.get(
+ mPrimaryWindowContext).unregisterTaskbarDesktopModeListener(
+ mTaskbarDesktopModeListener);
removeActivityCallbacksAndListeners();
mTaskbarBroadcastReceiver.unregisterReceiverSafely();
@@ -860,7 +931,7 @@
removeAndUnregisterComponentCallbacks(getDefaultDisplayId());
mShutdownReceiver.unregisterReceiverSafely();
if (ActivityManagerWrapper.usePerceptibleTasks(getPrimaryWindowContext())) {
- for (Integer taskId: mTaskStackListener.mPerceptibleTasks) {
+ for (Integer taskId : mTaskStackListener.mPerceptibleTasks) {
ActivityManagerWrapper.getInstance().setTaskIsPerceptible(taskId, false);
}
}
@@ -940,7 +1011,7 @@
*
* @param displayId The ID of the display to retrieve the taskbar for.
* @return The {@link TaskbarUIController} for the specified display, or
- * {@code null} if no taskbar is associated with that display.
+ * {@code null} if no taskbar is associated with that display.
*/
@Nullable
public TaskbarUIController getUIControllerForDisplay(int displayId) {
@@ -967,7 +1038,7 @@
*
* @param displayId The ID of the display to retrieve the taskbar for.
* @return The {@link TaskbarActivityContext} for the specified display, or
- * {@code null} if no taskbar is associated with that display.
+ * {@code null} if no taskbar is associated with that display.
*/
private TaskbarActivityContext getTaskbarForDisplay(int displayId) {
return mTaskbars.get(displayId);
@@ -976,7 +1047,8 @@
/**
* Creates a {@link TaskbarActivityContext} for the given display and adds it to the map.
- * @param dp The {@link DeviceProfile} for the display.
+ *
+ * @param dp The {@link DeviceProfile} for the display.
* @param displayId The ID of the display.
*/
private @Nullable TaskbarActivityContext createTaskbarActivityContext(DeviceProfile dp,
@@ -1008,6 +1080,7 @@
/**
* Create {@link ComponentCallbacks} for the given display and register it to the relevant
* WindowContext. For external displays, populate maps.
+ *
* @param displayId The ID of the display.
*/
private void createAndRegisterComponentCallbacks(int displayId) {
@@ -1065,7 +1138,8 @@
}
@Override
- public void onLowMemory() { }
+ public void onLowMemory() {
+ }
};
if (isDefaultDisplay(displayId)
|| !DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()) {
@@ -1080,6 +1154,7 @@
/**
* Unregister {@link ComponentCallbacks} for the given display from its WindowContext. For
* external displays, remove from the map.
+ *
* @param displayId The ID of the display.
*/
private void removeAndUnregisterComponentCallbacks(int displayId) {
@@ -1096,6 +1171,7 @@
/**
* Creates a {@link TaskbarNavButtonController} for the given display and adds it to the map
* if it doesn't already exist.
+ *
* @param displayId The ID of the display
*/
private void createNavButtonController(int displayId) {
@@ -1137,7 +1213,7 @@
* Adds the {@link TaskbarActivityContext} associated with the given display ID to taskbar
* map if there is not already a taskbar mapped to that displayId.
*
- * @param displayId The ID of the display to retrieve the taskbar for.
+ * @param displayId The ID of the display to retrieve the taskbar for.
* @param newTaskbar The new {@link TaskbarActivityContext} to add to the map.
*/
private void addTaskbarToMap(int displayId, TaskbarActivityContext newTaskbar) {
@@ -1157,6 +1233,7 @@
/**
* Creates {@link FrameLayout} for the taskbar on the specified display and adds it to map.
+ *
* @param displayId The ID of the display for which to create the taskbar root layout.
*/
private void createTaskbarRootLayout(int displayId) {
@@ -1206,7 +1283,7 @@
/**
* Adds the taskbar root layout {@link FrameLayout} to taskbar map, mapped to display ID.
*
- * @param displayId The ID of the display to associate with the taskbar root layout.
+ * @param displayId The ID of the display to associate with the taskbar root layout.
* @param rootLayout The taskbar root layout {@link FrameLayout} to add to the map.
*/
private void addTaskbarRootLayoutToMap(int displayId, FrameLayout rootLayout) {
@@ -1233,6 +1310,7 @@
/**
* Creates {@link Context} for the taskbar on the specified display.
+ *
* @param displayId The ID of the display for which to create the window context.
*/
private @Nullable Context createWindowContext(int displayId) {
@@ -1312,7 +1390,7 @@
/**
* Adds the window context {@link Context} to taskbar map, mapped to display ID.
*
- * @param displayId The ID of the display to associate with the taskbar root layout.
+ * @param displayId The ID of the display to associate with the taskbar root layout.
* @param windowContext The window context {@link Context} to add to the map.
*/
private void addWindowContextToMap(int displayId, @NonNull Context windowContext) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index a59c9e3..c92f20b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -392,6 +392,7 @@
/** Inflates/binds the hotseat items and recent tasks to the view. */
protected void updateItems(ItemInfo[] hotseatItemInfos, List<GroupTask> recentTasks) {
+ if (mActivityContext.isDestroyed()) return;
// Filter out unsupported items.
hotseatItemInfos = Arrays.stream(hotseatItemInfos)
.filter(Objects::nonNull)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index cbc5d3d..384468c 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -121,9 +121,10 @@
public static final int ALPHA_INDEX_NOTIFICATION_EXPANDED = 4;
public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 5;
public static final int ALPHA_INDEX_SMALL_SCREEN = 6;
-
public static final int ALPHA_INDEX_BUBBLE_BAR = 7;
- private static final int NUM_ALPHA_CHANNELS = 8;
+ public static final int ALPHA_INDEX_RECREATE = 8;
+
+ private static final int NUM_ALPHA_CHANNELS = 9;
/** Only used for animation purposes, to position the divider between two item indices. */
public static final float DIVIDER_VIEW_POSITION_OFFSET = 0.5f;
@@ -238,9 +239,22 @@
R.dimen.transient_taskbar_padding);
}
- public void init(TaskbarControllers controllers) {
+ /**
+ * Init of taskbar view controller.
+ */
+ public void init(TaskbarControllers controllers, AnimatorSet startAnimation) {
mControllers = controllers;
controllers.bubbleControllers.ifPresent(bc -> mBubbleControllers = bc);
+
+ if (startAnimation != null) {
+ MultiPropertyFactory<View>.MultiProperty multiProperty =
+ mTaskbarIconAlpha.get(ALPHA_INDEX_RECREATE);
+ multiProperty.setValue(0f);
+ Animator animator = multiProperty.animateToValue(1f);
+ animator.setInterpolator(EMPHASIZED);
+ startAnimation.play(animator);
+ }
+
mTaskbarView.init(TaskbarViewCallbacksFactory.newInstance(mActivity).create(
mActivity, mControllers, mTaskbarView));
mTaskbarView.getLayoutParams().height = mActivity.isPhoneMode()
@@ -362,6 +376,15 @@
mTaskbarView.announceAccessibilityChanges();
}
+ /**
+ * Called with destroying Taskbar with animation.
+ */
+ public void onDestroyAnimation(AnimatorSet animatorSet) {
+ animatorSet.play(
+ mTaskbarIconAlpha.get(TaskbarViewController.ALPHA_INDEX_RECREATE).animateToValue(
+ 0f));
+ }
+
public void onDestroy() {
if (enableTaskbarPinning()) {
mTaskbarView.removeOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
@@ -1299,7 +1322,7 @@
ObjectAnimator animator = mIconsTranslationXForNavbar.animateToValue(translationX);
animator.setStartDelay(FADE_OUT_ANIM_POSITION_DURATION_MS);
animator.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS);
- animator.setInterpolator(Interpolators.EMPHASIZED);
+ animator.setInterpolator(EMPHASIZED);
return animator;
}
}
diff --git a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
index 1907b4e..44f8bf1 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/states/QuickstepAtomicAnimationFactory.java
@@ -109,8 +109,11 @@
// We sync the scrim fade with the taskbar animation duration to avoid any flickers for
// taskbar icons disappearing before hotseat icons show up.
+ boolean isPinnedTaskbarAndNotInDesktopMode =
+ isPinnedTaskbar && !DisplayController.isInDesktopMode(mContainer);
float scrimUpperBoundFromSplit =
- QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)
+ QuickstepTransitionManager.getTaskbarToHomeDuration(
+ isPinnedTaskbarAndNotInDesktopMode)
/ (float) config.duration;
scrimUpperBoundFromSplit = Math.min(scrimUpperBoundFromSplit, 1f);
config.setInterpolator(ANIM_OVERVIEW_ACTIONS_FADE, clampToProgress(LINEAR, 0, 0.25f));
@@ -142,7 +145,8 @@
if (mContainer.getDeviceProfile().isTaskbarPresent) {
config.duration = Math.min(
config.duration,
- QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar));
+ QuickstepTransitionManager.getTaskbarToHomeDuration(
+ isPinnedTaskbarAndNotInDesktopMode));
}
overview.snapToPage(DEFAULT_PAGE, Math.toIntExact(config.duration));
} else {
diff --git a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
index 67a54e6..c51f659 100644
--- a/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
+++ b/quickstep/src/com/android/quickstep/AbsSwipeUpHandler.java
@@ -120,6 +120,7 @@
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.logging.StatsLogManager;
import com.android.launcher3.logging.StatsLogManager.StatsLogger;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.statemanager.BaseState;
import com.android.launcher3.statemanager.StatefulContainer;
import com.android.launcher3.taskbar.TaskbarThresholdUtils;
@@ -1421,8 +1422,10 @@
}
if (endTarget == HOME) {
boolean isPinnedTaskbar = DisplayController.isPinnedTaskbar(mContext);
+ boolean isNotInDesktop = !DisplayController.isInDesktopMode(mContext);
duration = mContainer != null && mContainer.getDeviceProfile().isTaskbarPresent
- ? QuickstepTransitionManager.getTaskbarToHomeDuration(isPinnedTaskbar)
+ ? QuickstepTransitionManager.getTaskbarToHomeDuration(
+ isPinnedTaskbar && isNotInDesktop)
: StaggeredWorkspaceAnim.DURATION_MS;
SystemUiProxy.INSTANCE.get(mContext).updateContextualEduStats(
mGestureState.isTrackpadGesture(), GestureType.HOME);
@@ -1602,9 +1605,27 @@
if (mParallelRunningAnim != null) {
mParallelRunningAnim.addListener(new AnimatorListenerAdapter() {
@Override
+ public void onAnimationStart(Animator animation) {
+ if (DisplayController.isInDesktopMode(mContext)
+ && mGestureState.getEndTarget() == HOME) {
+ // Set launcher animation started, so we don't notify from
+ // desktop visibility controller
+ DesktopVisibilityController.INSTANCE.get(
+ mContext).setLauncherAnimationRunning(true);
+ }
+ }
+
+ @Override
public void onAnimationEnd(Animator animation) {
mParallelRunningAnim = null;
mStateCallback.setStateOnUiThread(STATE_PARALLEL_ANIM_FINISHED);
+ // Swipe to home animation finished, notify DesktopVisibilityController
+ // to recreate Taskbar
+ if (DisplayController.isInDesktopMode(mContext)
+ && mGestureState.getEndTarget() == HOME) {
+ DesktopVisibilityController.INSTANCE.get(
+ mContext).onLauncherAnimationFromDesktopEnd();
+ }
}
});
mParallelRunningAnim.start();
@@ -1691,7 +1712,6 @@
if (mHandOffAnimationToHome) {
handOffAnimation(velocityPxPerMs);
}
-
windowAnim[0].addAnimatorListener(new AnimationSuccessListener() {
@Override
public void onAnimationSuccess(Animator animator) {
diff --git a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
index 953b0c5..c1bb250 100644
--- a/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
+++ b/quickstep/src/com/android/quickstep/interaction/AllSetActivity.java
@@ -64,6 +64,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
+import com.android.launcher3.RemoveAnimationSettingsTracker;
import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.AnimatorPlaybackController;
@@ -107,6 +108,9 @@
private static final float ANIMATION_PAUSE_ALPHA_THRESHOLD = 0.1f;
+ private static final String KEY_BACKGROUND_ANIMATION_TOGGLED_ON =
+ "background_animation_toggled_on";
+
private final AnimatedFloat mSwipeProgress = new AnimatedFloat(this::onSwipeProgressUpdate);
private final InvariantDeviceProfile.OnIDPChangeListener mOnIDPChangeListener =
@@ -124,6 +128,9 @@
private AnimatorPlaybackController mLauncherStartAnim = null;
+ // Auto play background animation by default
+ private boolean mBackgroundAnimationToggledOn = true;
+
private TextView mHintView;
private final OverviewChangeListener mOverviewChangeListener = this::onOverviewTargetChange;
@@ -200,6 +207,15 @@
LOTTIE_TERTIARY_COLOR_TOKEN, R.color.all_set_bg_tertiary),
getTheme());
+ mBackgroundAnimationToggledOn = savedInstanceState == null
+ || savedInstanceState.getBoolean(KEY_BACKGROUND_ANIMATION_TOGGLED_ON, true);
+ // The animated background is behind a scroll view, which intercepts all input.
+ // However, the content view also covers the full screen
+ requireViewById(R.id.content).setOnClickListener(v -> {
+ mBackgroundAnimationToggledOn = !mBackgroundAnimationToggledOn;
+ maybeResumeOrPauseBackgroundAnimation();
+ });
+
setUpBackgroundAnimation(getDP().isTablet);
getIDP().addOnChangeListener(mOnIDPChangeListener);
@@ -208,6 +224,12 @@
ActivityPreloadUtil.preloadOverviewForSUWAllSet(this);
}
+ @Override
+ protected void onSaveInstanceState(Bundle outState) {
+ super.onSaveInstanceState(outState);
+ outState.putBoolean(KEY_BACKGROUND_ANIMATION_TOGGLED_ON, mBackgroundAnimationToggledOn);
+ }
+
private InvariantDeviceProfile getIDP() {
return LauncherAppState.getInstance(this).getInvariantDeviceProfile();
}
@@ -368,8 +390,10 @@
private void maybeResumeOrPauseBackgroundAnimation() {
boolean shouldPlayAnimation =
- getContentViewAlphaForSwipeProgress() > ANIMATION_PAUSE_ALPHA_THRESHOLD
- && isResumed();
+ !RemoveAnimationSettingsTracker.INSTANCE.get(this).isRemoveAnimationEnabled()
+ && getContentViewAlphaForSwipeProgress() > ANIMATION_PAUSE_ALPHA_THRESHOLD
+ && isResumed()
+ && mBackgroundAnimationToggledOn;
if (mAnimatedBackground.isAnimating() && !shouldPlayAnimation) {
mAnimatedBackground.pauseAnimation();
} else if (!mAnimatedBackground.isAnimating() && shouldPlayAnimation) {
diff --git a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
index 12ca257..a2856a6 100644
--- a/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
+++ b/quickstep/src/com/android/quickstep/util/StaggeredWorkspaceAnim.java
@@ -81,8 +81,10 @@
public StaggeredWorkspaceAnim(QuickstepLauncher launcher, float velocity,
boolean animateOverviewScrim, @Nullable View ignoredView, boolean staggerWorkspace) {
+ boolean isPinnedTaskbarAndNotInDesktopMode = DisplayController.isPinnedTaskbar(launcher)
+ && !DisplayController.isInDesktopMode(launcher);
mTaskbarDurationInMs = QuickstepTransitionManager.getTaskbarToHomeDuration(
- DisplayController.isPinnedTaskbar(launcher));
+ isPinnedTaskbarAndNotInDesktopMode);
prepareToAnimate(launcher, animateOverviewScrim);
mIgnoredView = ignoredView;
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
index 2cd09cc..3a27bb1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarOverflowTest.kt
@@ -333,10 +333,12 @@
Task(Task.TaskKey(it, 0, Intent(), ComponentName("", ""), 0, 2000))
}
recentsModel.updateRecentTasks(listOf(DesktopTask(deskId = 0, tasks)))
- desktopTaskListener?.onTasksVisibilityChanged(
- context.virtualDisplay.display.displayId,
- tasksToAdd,
- )
+ for (task in 1..tasksToAdd) {
+ desktopTaskListener?.onTasksVisibilityChanged(
+ context.virtualDisplay.display.displayId,
+ task,
+ )
+ }
runOnMainSync { recentsModel.resolvePendingTaskRequests() }
}
diff --git a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
index 002c988..8376bc1 100644
--- a/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
+++ b/quickstep/tests/multivalentTests/src/com/android/launcher3/taskbar/TaskbarRecentAppsControllerTest.kt
@@ -959,6 +959,8 @@
private fun setInDesktopMode(inDesktopMode: Boolean) {
whenever(taskbarControllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar())
.thenReturn(inDesktopMode)
+ whenever(taskbarControllers.taskbarDesktopModeController.isInDesktopMode)
+ .thenReturn(inDesktopMode)
}
private fun createItemInfo(
diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java
index 5072e37..d6abb56 100644
--- a/src/com/android/launcher3/PagedView.java
+++ b/src/com/android/launcher3/PagedView.java
@@ -17,6 +17,7 @@
package com.android.launcher3;
import static com.android.app.animation.Interpolators.SCROLL;
+import static com.android.launcher3.RemoveAnimationSettingsTracker.WINDOW_ANIMATION_SCALE_URI;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isAccessibilityEnabled;
import static com.android.launcher3.compat.AccessibilityManagerCompat.isObservedEventType;
import static com.android.launcher3.testing.shared.TestProtocol.SCROLL_FINISHED_MESSAGE;
@@ -33,7 +34,6 @@
import android.graphics.Canvas;
import android.graphics.Rect;
import android.os.Bundle;
-import android.provider.Settings;
import android.util.AttributeSet;
import android.util.Log;
import android.view.InputDevice;
@@ -1756,8 +1756,8 @@
}
if (FeatureFlags.IS_STUDIO_BUILD && !Utilities.isRunningInTestHarness()) {
- duration *= Settings.Global.getFloat(getContext().getContentResolver(),
- Settings.Global.WINDOW_ANIMATION_SCALE, 1);
+ duration *= RemoveAnimationSettingsTracker.INSTANCE.get(getContext()).getValue(
+ WINDOW_ANIMATION_SCALE_URI);
}
whichPage = validateNewPage(whichPage);
diff --git a/src/com/android/launcher3/RemoveAnimationSettingsTracker.kt b/src/com/android/launcher3/RemoveAnimationSettingsTracker.kt
new file mode 100644
index 0000000..dbc04f1
--- /dev/null
+++ b/src/com/android/launcher3/RemoveAnimationSettingsTracker.kt
@@ -0,0 +1,110 @@
+/*
+ * Copyright (C) 2025 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
+
+import android.content.Context
+import android.database.ContentObserver
+import android.net.Uri
+import android.os.Handler
+import android.os.Looper
+import android.provider.Settings
+import android.provider.Settings.Global.ANIMATOR_DURATION_SCALE
+import android.provider.Settings.Global.TRANSITION_ANIMATION_SCALE
+import android.provider.Settings.Global.WINDOW_ANIMATION_SCALE
+import com.android.launcher3.dagger.ApplicationContext
+import com.android.launcher3.dagger.LauncherAppComponent
+import com.android.launcher3.dagger.LauncherAppSingleton
+import com.android.launcher3.util.DaggerSingletonObject
+import com.android.launcher3.util.DaggerSingletonTracker
+import com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR
+import java.util.concurrent.ConcurrentHashMap
+import javax.inject.Inject
+
+/** Tracker Class for when user turns on/off remove animation setting. */
+@LauncherAppSingleton
+class RemoveAnimationSettingsTracker
+@Inject
+constructor(@ApplicationContext val context: Context, tracker: DaggerSingletonTracker) :
+ ContentObserver(Handler(Looper.getMainLooper())) {
+
+ private val contentResolver = context.contentResolver
+
+ /** Caches the last seen value for registered keys. */
+ private val cache: MutableMap<Uri, Float> = ConcurrentHashMap()
+
+ init {
+ UI_HELPER_EXECUTOR.execute {
+ contentResolver.registerContentObserver(WINDOW_ANIMATION_SCALE_URI, false, this)
+ contentResolver.registerContentObserver(TRANSITION_ANIMATION_SCALE_URI, false, this)
+ contentResolver.registerContentObserver(ANIMATOR_DURATION_SCALE_URI, false, this)
+ }
+
+ tracker.addCloseable {
+ UI_HELPER_EXECUTOR.execute { contentResolver.unregisterContentObserver(this) }
+ }
+ }
+
+ /**
+ * Returns the value for this classes key from the cache. If not in cache, will call
+ * [updateValue] to fetch.
+ */
+ fun getValue(uri: Uri): Float {
+ return getValue(uri, 1f)
+ }
+
+ /**
+ * Returns the value for this classes key from the cache. If not in cache, will call
+ * [getValueFromSettingsGlobal] to fetch.
+ */
+ private fun getValue(uri: Uri, defaultValue: Float): Float {
+ return cache.computeIfAbsent(uri) { getValueFromSettingsGlobal(uri, defaultValue) }
+ }
+
+ /** Returns if user has opted into having no animation on their device. */
+ fun isRemoveAnimationEnabled(): Boolean {
+ return getValue(WINDOW_ANIMATION_SCALE_URI) == 0f &&
+ getValue(TRANSITION_ANIMATION_SCALE_URI) == 0f &&
+ getValue(ANIMATOR_DURATION_SCALE_URI) == 0f
+ }
+
+ override fun onChange(selfChange: Boolean, uri: Uri?) {
+ if (uri == null) return
+ updateValue(uri)
+ }
+
+ private fun getValueFromSettingsGlobal(uri: Uri, defaultValue: Float = 1f): Float {
+ return Settings.Global.getFloat(contentResolver, uri.lastPathSegment, defaultValue)
+ }
+
+ private fun updateValue(uri: Uri, defaultValue: Float = 1f) {
+ val newValue = getValueFromSettingsGlobal(uri, defaultValue)
+ cache[uri] = newValue
+ }
+
+ companion object {
+ @JvmField
+ val INSTANCE =
+ DaggerSingletonObject(LauncherAppComponent::getRemoveAnimationSettingsTracker)
+ @JvmField
+ val WINDOW_ANIMATION_SCALE_URI: Uri = Settings.Global.getUriFor(WINDOW_ANIMATION_SCALE)
+ @JvmField
+ val TRANSITION_ANIMATION_SCALE_URI: Uri =
+ Settings.Global.getUriFor(TRANSITION_ANIMATION_SCALE)
+ @JvmField
+ val ANIMATOR_DURATION_SCALE_URI: Uri = Settings.Global.getUriFor(ANIMATOR_DURATION_SCALE)
+ }
+}
diff --git a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
index 249a214..150761f 100644
--- a/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
+++ b/src/com/android/launcher3/dagger/LauncherBaseAppComponent.java
@@ -23,6 +23,7 @@
import com.android.launcher3.InvariantDeviceProfile;
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.RemoveAnimationSettingsTracker;
import com.android.launcher3.graphics.GridCustomizationsProxy;
import com.android.launcher3.graphics.ThemeManager;
import com.android.launcher3.icons.LauncherIcons.IconPool;
@@ -80,8 +81,8 @@
LockedUserState getLockedUserState();
InvariantDeviceProfile getIDP();
IconPool getIconPool();
+ RemoveAnimationSettingsTracker getRemoveAnimationSettingsTracker();
LauncherAppState getLauncherAppState();
-
GridCustomizationsProxy getGridCustomizationsProxy();
/** Builder for LauncherBaseAppComponent. */
diff --git a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
index 062c753..40863c4 100644
--- a/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
+++ b/src/com/android/launcher3/graphics/GridCustomizationsProxy.java
@@ -24,11 +24,9 @@
import android.content.ContentValues;
import android.content.Context;
-import android.content.pm.PackageManager;
import android.database.Cursor;
import android.database.MatrixCursor;
import android.net.Uri;
-import android.os.Binder;
import android.os.Bundle;
import android.os.Handler;
import android.os.IBinder.DeathRecipient;
@@ -297,12 +295,6 @@
@Override
public Bundle call(@NonNull String method, String arg, Bundle extras) {
- if (mContext.checkPermission("android.permission.BIND_WALLPAPER",
- Binder.getCallingPid(), Binder.getCallingUid())
- != PackageManager.PERMISSION_GRANTED) {
- return null;
- }
-
if (METHOD_GET_PREVIEW.equals(method)) {
return getPreview(extras);
} else {
diff --git a/src/com/android/launcher3/util/DisplayController.java b/src/com/android/launcher3/util/DisplayController.java
index 376a61e..ceece4d 100644
--- a/src/com/android/launcher3/util/DisplayController.java
+++ b/src/com/android/launcher3/util/DisplayController.java
@@ -99,10 +99,11 @@
public static final int CHANGE_NAVIGATION_MODE = 1 << 4;
public static final int CHANGE_TASKBAR_PINNING = 1 << 5;
public static final int CHANGE_DESKTOP_MODE = 1 << 6;
+ public static final int CHANGE_SHOW_LOCKED_TASKBAR = 1 << 7;
public static final int CHANGE_ALL = CHANGE_ACTIVE_SCREEN | CHANGE_ROTATION
| CHANGE_DENSITY | CHANGE_SUPPORTED_BOUNDS | CHANGE_NAVIGATION_MODE
- | CHANGE_TASKBAR_PINNING | CHANGE_DESKTOP_MODE;
+ | CHANGE_TASKBAR_PINNING | CHANGE_DESKTOP_MODE | CHANGE_SHOW_LOCKED_TASKBAR;
private static final String ACTION_OVERLAY_CHANGED = "android.intent.action.OVERLAY_CHANGED";
private static final String TARGET_OVERLAY_PACKAGE = "android";
@@ -212,6 +213,13 @@
}
/**
+ * Returns whether the taskbar is pinned in gesture navigation mode.
+ */
+ public static boolean isInDesktopMode(Context context) {
+ return INSTANCE.get(context).getInfo().isInDesktopMode();
+ }
+
+ /**
* Returns whether the taskbar is forced to be pinned when home is visible.
*/
public static boolean showLockedTaskbarOnHome(Context context) {
@@ -335,6 +343,9 @@
if (newInfo.mIsInDesktopMode != oldInfo.mIsInDesktopMode) {
change |= CHANGE_DESKTOP_MODE;
}
+ if (newInfo.mShowLockedTaskbarOnHome != oldInfo.mShowLockedTaskbarOnHome) {
+ change |= CHANGE_SHOW_LOCKED_TASKBAR;
+ }
if (DEBUG) {
Log.d(TAG, "handleInfoChange - change: " + getChangeFlagsString(change));
@@ -494,6 +505,13 @@
}
/**
+ * Returns whether the taskbar is in desktop mode.
+ */
+ public boolean isInDesktopMode() {
+ return mIsInDesktopMode;
+ }
+
+ /**
* Returns {@code true} if the bounds represent a tablet.
*/
public boolean isTablet(WindowBounds bounds) {
@@ -575,6 +593,7 @@
appendFlag(result, change, CHANGE_NAVIGATION_MODE, "CHANGE_NAVIGATION_MODE");
appendFlag(result, change, CHANGE_TASKBAR_PINNING, "CHANGE_TASKBAR_VARIANT");
appendFlag(result, change, CHANGE_DESKTOP_MODE, "CHANGE_DESKTOP_MODE");
+ appendFlag(result, change, CHANGE_SHOW_LOCKED_TASKBAR, "CHANGE_SHOW_LOCKED_TASKBAR");
return result.toString();
}
@@ -592,6 +611,7 @@
pw.println(" isTaskbarPinned=" + info.mIsTaskbarPinned);
pw.println(" isTaskbarPinnedInDesktopMode=" + info.mIsTaskbarPinnedInDesktopMode);
pw.println(" isInDesktopMode=" + info.mIsInDesktopMode);
+ pw.println(" showLockedTaskbarOnHome=" + info.showLockedTaskbarOnHome());
pw.println(" currentSize=" + info.currentSize);
info.mPerDisplayBounds.forEach((key, value) -> pw.println(
" perDisplayBounds - " + key + ": " + value));
diff --git a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
index aa1451b..0ecb38e 100644
--- a/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
+++ b/tests/multivalentTests/src/com/android/launcher3/util/DisplayControllerTest.kt
@@ -34,6 +34,7 @@
import com.android.launcher3.util.DisplayController.CHANGE_DENSITY
import com.android.launcher3.util.DisplayController.CHANGE_DESKTOP_MODE
import com.android.launcher3.util.DisplayController.CHANGE_ROTATION
+import com.android.launcher3.util.DisplayController.CHANGE_SHOW_LOCKED_TASKBAR
import com.android.launcher3.util.DisplayController.CHANGE_TASKBAR_PINNING
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener
import com.android.launcher3.util.LauncherModelHelper.SandboxModelContext
@@ -209,8 +210,13 @@
assertTrue(displayController.getInfo().isTransientTaskbar())
displayController.notifyConfigChange()
+
verify(displayInfoChangeListener)
- .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
+ .onDisplayInfoChanged(
+ any(),
+ any(),
+ eq(CHANGE_TASKBAR_PINNING or CHANGE_SHOW_LOCKED_TASKBAR),
+ )
assertFalse(displayController.getInfo().isTransientTaskbar())
}
@@ -227,7 +233,11 @@
displayController.onConfigurationChanged(configuration)
verify(displayInfoChangeListener)
- .onDisplayInfoChanged(any(), any(), eq(CHANGE_TASKBAR_PINNING))
+ .onDisplayInfoChanged(
+ any(),
+ any(),
+ eq(CHANGE_TASKBAR_PINNING or CHANGE_SHOW_LOCKED_TASKBAR),
+ )
assertFalse(displayController.getInfo().isTransientTaskbar())
}
diff --git a/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java b/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java
index 1e21ee5..44df5b8 100644
--- a/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java
+++ b/tests/src/com/android/launcher3/allapps/KeyboardFocusTest.java
@@ -23,7 +23,6 @@
import com.android.launcher3.Launcher;
import com.android.launcher3.LauncherState;
import com.android.launcher3.util.BaseLauncherActivityTest;
-import com.android.launcher3.util.rule.ScreenRecordRule.ScreenRecord;
import com.android.launcher3.views.ActivityContext;
import org.junit.Test;
@@ -64,7 +63,6 @@
}
@Test
- @ScreenRecord //b/378167329
public void testAllAppsExitSearchAndFocusSearchResults() {
loadLauncherSync();
goToState(LauncherState.ALL_APPS);
diff --git a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
index a123170..38970fe 100644
--- a/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
+++ b/tests/src/com/android/launcher3/ui/workspace/ThemeIconsTest.java
@@ -23,7 +23,6 @@
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
-import android.content.ContentProviderClient;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.net.Uri;
@@ -37,6 +36,7 @@
import com.android.launcher3.LauncherState;
import com.android.launcher3.allapps.AllAppsRecyclerView;
import com.android.launcher3.celllayout.FavoriteItemsTransaction;
+import com.android.launcher3.dagger.LauncherComponentProvider;
import com.android.launcher3.icons.mono.ThemedIconDrawable;
import com.android.launcher3.popup.ArrowPopup;
import com.android.launcher3.util.BaseLauncherActivityTest;
@@ -139,7 +139,7 @@
return icon;
}
- private void setThemeEnabled(boolean isEnabled) throws Exception {
+ private void setThemeEnabled(boolean isEnabled) {
Uri uri = new Uri.Builder()
.scheme(ContentResolver.SCHEME_CONTENT)
.authority(targetContext().getPackageName() + ".grid_control")
@@ -147,11 +147,10 @@
.build();
ContentValues values = new ContentValues();
values.put("boolean_value", isEnabled);
- try (ContentProviderClient client = targetContext().getContentResolver()
- .acquireContentProviderClient(uri)) {
- int result = client.update(uri, values, null);
- assertTrue(result > 0);
- }
+
+ int result = LauncherComponentProvider.get(targetContext()).getGridCustomizationsProxy()
+ .update(uri, values, null, null);
+ assertTrue(result > 0);
}
private void switchToAllApps() {