Merge "Read LPNH touch slop percentage and timeout ms from DeviceConfig." into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 5f4e1b6..7c6d7a8 100644
--- a/aconfig/launcher.aconfig
+++ b/aconfig/launcher.aconfig
@@ -32,7 +32,7 @@
name: "enable_responsive_workspace"
namespace: "launcher"
description: "Enables new workspace grid calculations method."
- bug: "241386436"
+ bug: "302189128"
}
flag {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 76b9aa9..6ee151b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -129,6 +129,7 @@
import java.io.PrintWriter;
import java.util.Collections;
import java.util.Optional;
+import java.util.function.Consumer;
/**
* The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
@@ -174,13 +175,16 @@
private final TaskbarShortcutMenuAccessibilityDelegate mAccessibilityDelegate;
+ private DeviceProfile mTransientTaskbarDeviceProfile;
+
+ private DeviceProfile mPersistentTaskbarDeviceProfile;
+
public TaskbarActivityContext(Context windowContext, DeviceProfile launcherDp,
TaskbarNavButtonController buttonController, ScopedUnfoldTransitionProgressProvider
unfoldTransitionProgressProvider) {
super(windowContext);
applyDeviceProfile(launcherDp);
-
final Resources resources = getResources();
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
@@ -255,9 +259,9 @@
new TaskbarViewController(this, taskbarView),
new TaskbarScrimViewController(this, taskbarScrimView),
new TaskbarUnfoldAnimationController(this, unfoldTransitionProgressProvider,
- mWindowManager,
- new RotationChangeProvider(c.getSystemService(DisplayManager.class), this,
- getMainThreadHandler())),
+ mWindowManager,
+ new RotationChangeProvider(c.getSystemService(DisplayManager.class), this,
+ getMainThreadHandler())),
new TaskbarKeyguardController(this),
new StashedHandleViewController(this, stashedHandleView),
new TaskbarStashController(this),
@@ -275,7 +279,7 @@
: TaskbarRecentAppsController.DEFAULT,
new TaskbarEduTooltipController(this),
new KeyboardQuickSwitchController(),
- new TaskbarDividerPopupController(this),
+ new TaskbarPinningController(this),
bubbleControllersOptional);
}
@@ -296,17 +300,34 @@
* the icon size
*/
private void applyDeviceProfile(DeviceProfile originDeviceProfile) {
- mDeviceProfile = originDeviceProfile.toBuilder(this)
- .withDimensionsOverride(deviceProfile -> {
- // Taskbar should match the number of icons of hotseat
- deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
- // Same QSB width to have a smooth animation
- deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
+ Consumer<DeviceProfile> overrideProvider = deviceProfile -> {
+ // Taskbar should match the number of icons of hotseat
+ deviceProfile.numShownHotseatIcons = originDeviceProfile.numShownHotseatIcons;
+ // Same QSB width to have a smooth animation
+ deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
- // Update icon size
- deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
- deviceProfile.updateIconSize(1f, getResources());
- }).build();
+ // Update icon size
+ deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
+ deviceProfile.updateIconSize(1f, getResources());
+ };
+ mDeviceProfile = originDeviceProfile.toBuilder(this)
+ .withDimensionsOverride(overrideProvider).build();
+
+ if (DisplayController.isTransientTaskbar(this)) {
+ mTransientTaskbarDeviceProfile = mDeviceProfile;
+ mPersistentTaskbarDeviceProfile = mDeviceProfile
+ .toBuilder(this)
+ .withDimensionsOverride(overrideProvider)
+ .setIsTransientTaskbar(false)
+ .build();
+ } else {
+ mPersistentTaskbarDeviceProfile = mDeviceProfile;
+ mTransientTaskbarDeviceProfile = mDeviceProfile
+ .toBuilder(this)
+ .withDimensionsOverride(overrideProvider)
+ .setIsTransientTaskbar(true)
+ .build();
+ }
mNavMode = DisplayController.getNavigationMode(this);
}
@@ -392,7 +413,8 @@
/**
* Creates LayoutParams for adding a view directly to WindowManager as a new window.
- * @param type The window type to pass to the created WindowManager.LayoutParams.
+ *
+ * @param type The window type to pass to the created WindowManager.LayoutParams.
* @param title The window title to pass to the created WindowManager.LayoutParams.
*/
public WindowManager.LayoutParams createDefaultWindowLayoutParams(int type, String title) {
@@ -796,7 +818,7 @@
// Overlay AFVs are in a separate window and do not require Taskbar to be fullscreen.
if (!isDragInProgress
&& !AbstractFloatingView.hasOpenView(
- this, TYPE_ALL & ~TYPE_TASKBAR_OVERLAY_PROXY)) {
+ this, TYPE_ALL & ~TYPE_TASKBAR_OVERLAY_PROXY)) {
// Reverts Taskbar window to its original size
setTaskbarWindowFullscreen(false);
}
@@ -855,7 +877,7 @@
? resources.getDimensionPixelSize(R.dimen.arrow_toast_arrow_height)
+ (resources.getDimensionPixelSize(R.dimen.taskbar_tooltip_vertical_padding) * 2)
+ calculateTextHeight(
- resources.getDimensionPixelSize(R.dimen.arrow_toast_text_size))
+ resources.getDimensionPixelSize(R.dimen.arrow_toast_text_size))
: 0;
// Return transient taskbar window height when pinning feature is enabled, so taskbar view
@@ -867,7 +889,7 @@
return transientTaskbarDp.taskbarHeight
+ (2 * transientTaskbarDp.taskbarBottomMargin)
+ Math.max(extraHeightForTaskbarTooltips, resources.getDimensionPixelSize(
- R.dimen.transient_taskbar_shadow_blur));
+ R.dimen.transient_taskbar_shadow_blur));
}
@@ -880,6 +902,14 @@
return getResources().getDimensionPixelSize(R.dimen.taskbar_suw_frame);
}
+ public DeviceProfile getTransientTaskbarDeviceProfile() {
+ return mTransientTaskbarDeviceProfile;
+ }
+
+ public DeviceProfile getPersistentTaskbarDeviceProfile() {
+ return mPersistentTaskbarDeviceProfile;
+ }
+
/**
* Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE} on the taskbar
* window.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index d237c1f..e4ebf65 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -29,26 +29,38 @@
import com.android.launcher3.Utilities.mapRange
import com.android.launcher3.Utilities.mapToRange
import com.android.launcher3.icons.GraphicsUtils.setColorAlphaBound
+import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_PERSISTENT
+import com.android.launcher3.taskbar.TaskbarPinningController.Companion.PINNING_TRANSIENT
import com.android.launcher3.util.DisplayController
/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
-class TaskbarBackgroundRenderer(context: TaskbarActivityContext) {
+class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
private val isInSetup: Boolean = !context.isUserSetupComplete
private val DARK_THEME_SHADOW_ALPHA = 51f
private val LIGHT_THEME_SHADOW_ALPHA = 25f
+ private val maxTransientTaskbarHeight =
+ context.transientTaskbarDeviceProfile.taskbarHeight.toFloat()
+ private val maxPersistentTaskbarHeight =
+ context.persistentTaskbarDeviceProfile.taskbarHeight.toFloat()
+ var backgroundProgress =
+ if (DisplayController.isTransientTaskbar(context)) {
+ PINNING_TRANSIENT
+ } else {
+ PINNING_PERSISTENT
+ }
+
+ var isAnimatingPinning = false
+
val paint = Paint()
val lastDrawnTransientRect = RectF()
var backgroundHeight = context.deviceProfile.taskbarHeight.toFloat()
var translationYForSwipe = 0f
var translationYForStash = 0f
- private var maxBackgroundHeight = context.deviceProfile.taskbarHeight.toFloat()
private val transientBackgroundBounds = context.transientTaskbarBounds
- private val isTransientTaskbar = DisplayController.isTransientTaskbar(context)
-
private val shadowAlpha: Float
private var shadowBlur = 0f
private var keyShadowDistance = 0f
@@ -75,13 +87,6 @@
paint.flags = Paint.ANTI_ALIAS_FLAG
paint.style = Paint.Style.FILL
- if (isTransientTaskbar) {
- val res = context.resources
- bottomMargin = res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
- shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
- keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
- }
-
shadowAlpha =
if (Utilities.isDarkTheme(context)) DARK_THEME_SHADOW_ALPHA
else LIGHT_THEME_SHADOW_ALPHA
@@ -90,10 +95,11 @@
}
fun updateStashedHandleWidth(dp: DeviceProfile, res: Resources) {
- stashedHandleWidth = res.getDimensionPixelSize(
+ stashedHandleWidth =
+ res.getDimensionPixelSize(
if (TaskbarManager.isPhoneMode(dp)) R.dimen.taskbar_stashed_small_screen
else R.dimen.taskbar_stashed_handle_width
- )
+ )
}
/**
@@ -102,7 +108,7 @@
* @param cornerRoundness 0 has no round corner, 1 has complete round corner.
*/
fun setCornerRoundness(cornerRoundness: Float) {
- if (isTransientTaskbar && !transientBackgroundBounds.isEmpty) {
+ if (DisplayController.isTransientTaskbar(context) && !transientBackgroundBounds.isEmpty) {
return
}
@@ -126,63 +132,122 @@
/** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
+ if (isInSetup) return
+ val isTransientTaskbar = backgroundProgress == 0f
canvas.save()
- if (!isTransientTaskbar || transientBackgroundBounds.isEmpty) {
- canvas.translate(0f, canvas.height - backgroundHeight - bottomMargin)
- // Draw the background behind taskbar content.
- canvas.drawRect(0f, 0f, canvas.width.toFloat(), backgroundHeight, paint)
-
- // Draw the inverted rounded corners above the taskbar.
- canvas.translate(0f, -leftCornerRadius)
- canvas.drawPath(invertedLeftCornerPath, paint)
- canvas.translate(0f, leftCornerRadius)
- canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
- canvas.drawPath(invertedRightCornerPath, paint)
- } else if (!isInSetup) {
- // backgroundHeight is a value from [0...maxBackgroundHeight], so we can use it as a
- // proxy to figure out the animation progress of the stash/unstash animation.
- val progress = backgroundHeight / maxBackgroundHeight
-
- // At progress 0, we draw the background as the stashed handle.
- // At progress 1, we draw the background as the full taskbar.
- val newBackgroundHeight =
- mapRange(progress, stashedHandleHeight.toFloat(), maxBackgroundHeight)
- val fullWidth = transientBackgroundBounds.width()
- val newWidth = mapRange(progress, stashedHandleWidth.toFloat(), fullWidth.toFloat())
- val halfWidthDelta = (fullWidth - newWidth) / 2f
- val radius = newBackgroundHeight / 2f
- val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
-
- // Aligns the bottom with the bottom of the stashed handle.
- val bottom =
- canvas.height - bottomMargin +
- bottomMarginProgress +
- translationYForSwipe +
- translationYForStash +
- -mapRange(1f - progress, 0f, stashedHandleHeight / 2f)
-
- // Draw shadow.
- val newShadowAlpha =
- mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, shadowAlpha, Interpolators.LINEAR)
- paint.setShadowLayer(
- shadowBlur,
- 0f,
- keyShadowDistance,
- setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
- )
-
- lastDrawnTransientRect.set(
- transientBackgroundBounds.left + halfWidthDelta,
- bottom - newBackgroundHeight,
- transientBackgroundBounds.right - halfWidthDelta,
- bottom
- )
- val horizontalInset = fullWidth * widthInsetPercentage
- lastDrawnTransientRect.inset(horizontalInset, 0f)
-
- canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, paint)
+ if (!isTransientTaskbar || transientBackgroundBounds.isEmpty || isAnimatingPinning) {
+ drawPersistentBackground(canvas)
}
canvas.restore()
+ canvas.save()
+ if (isAnimatingPinning || isTransientTaskbar) {
+ drawTransientBackground(canvas)
+ }
+ canvas.restore()
+ }
+
+ private fun drawPersistentBackground(canvas: Canvas) {
+ if (isAnimatingPinning) {
+ val persistentTaskbarHeight = maxPersistentTaskbarHeight * backgroundProgress
+ canvas.translate(0f, canvas.height - persistentTaskbarHeight)
+ // Draw the background behind taskbar content.
+ canvas.drawRect(0f, 0f, canvas.width.toFloat(), persistentTaskbarHeight, paint)
+ } else {
+ canvas.translate(0f, canvas.height - maxPersistentTaskbarHeight)
+ // Draw the background behind taskbar content.
+ canvas.drawRect(0f, 0f, canvas.width.toFloat(), maxPersistentTaskbarHeight, paint)
+ }
+
+ // Draw the inverted rounded corners above the taskbar.
+ canvas.translate(0f, -leftCornerRadius)
+ canvas.drawPath(invertedLeftCornerPath, paint)
+ canvas.translate(0f, leftCornerRadius)
+ canvas.translate(canvas.width - rightCornerRadius, -rightCornerRadius)
+ canvas.drawPath(invertedRightCornerPath, paint)
+ }
+
+ private fun drawTransientBackground(canvas: Canvas) {
+ val res = context.resources
+ val transientTaskbarHeight = maxTransientTaskbarHeight * (1f - backgroundProgress)
+ val heightProgressWhileAnimating =
+ if (isAnimatingPinning) transientTaskbarHeight else backgroundHeight
+
+ var progress = heightProgressWhileAnimating / maxTransientTaskbarHeight
+ progress = Math.round(progress * 100f) / 100f
+ if (isAnimatingPinning) {
+ var scale = transientTaskbarHeight / maxTransientTaskbarHeight
+ scale = Math.round(scale * 100f) / 100f
+ bottomMargin =
+ mapRange(
+ scale,
+ 0f,
+ res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat()
+ )
+ .toInt()
+ shadowBlur =
+ mapRange(scale, 0f, res.getDimension(R.dimen.transient_taskbar_shadow_blur))
+ keyShadowDistance =
+ mapRange(scale, 0f, res.getDimension(R.dimen.transient_taskbar_key_shadow_distance))
+ } else {
+ bottomMargin = res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin)
+ shadowBlur = res.getDimension(R.dimen.transient_taskbar_shadow_blur)
+ keyShadowDistance = res.getDimension(R.dimen.transient_taskbar_key_shadow_distance)
+ }
+
+ // At progress 0, we draw the background as the stashed handle.
+ // At progress 1, we draw the background as the full taskbar.
+ // Min height capped to max persistent taskbar height for animation
+ val backgroundHeightWhileAnimating =
+ if (isAnimatingPinning) maxPersistentTaskbarHeight else stashedHandleHeight.toFloat()
+ val newBackgroundHeight =
+ mapRange(progress, backgroundHeightWhileAnimating, maxTransientTaskbarHeight)
+ val fullWidth = transientBackgroundBounds.width()
+
+ // .9f is here to restrict min width of the background while animating, so transient
+ // background keeps it pill shape until animation end.
+ val animationWidth =
+ if (DisplayController.isTransientTaskbar(context)) fullWidth.toFloat() * .9f
+ else fullWidth.toFloat()
+ val backgroundWidthWhileAnimating =
+ if (isAnimatingPinning) animationWidth else stashedHandleWidth.toFloat()
+
+ val newWidth = mapRange(progress, backgroundWidthWhileAnimating, fullWidth.toFloat())
+ val halfWidthDelta = (fullWidth - newWidth) / 2f
+ val radius = newBackgroundHeight / 2f
+ val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
+
+ // Aligns the bottom with the bottom of the stashed handle.
+ val bottom =
+ canvas.height - bottomMargin +
+ bottomMarginProgress +
+ translationYForSwipe +
+ translationYForStash +
+ -mapRange(
+ 1f - progress,
+ 0f,
+ if (isAnimatingPinning) 0f else stashedHandleHeight / 2f
+ )
+
+ // Draw shadow.
+ val newShadowAlpha =
+ mapToRange(paint.alpha.toFloat(), 0f, 255f, 0f, shadowAlpha, Interpolators.LINEAR)
+ paint.setShadowLayer(
+ shadowBlur,
+ 0f,
+ keyShadowDistance,
+ setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
+ )
+
+ lastDrawnTransientRect.set(
+ transientBackgroundBounds.left + halfWidthDelta,
+ bottom - newBackgroundHeight,
+ transientBackgroundBounds.right - halfWidthDelta,
+ bottom
+ )
+ val horizontalInset = fullWidth * widthInsetPercentage
+ lastDrawnTransientRect.inset(horizontalInset, 0f)
+
+ canvas.drawRoundRect(lastDrawnTransientRect, radius, radius, paint)
}
/**
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index d82f501..f9ddc3d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -62,7 +62,7 @@
public final TaskbarOverlayController taskbarOverlayController;
public final TaskbarEduTooltipController taskbarEduTooltipController;
public final KeyboardQuickSwitchController keyboardQuickSwitchController;
- public final TaskbarDividerPopupController taskbarPinningController;
+ public final TaskbarPinningController taskbarPinningController;
public final Optional<BubbleControllers> bubbleControllers;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@@ -110,7 +110,7 @@
TaskbarRecentAppsController taskbarRecentAppsController,
TaskbarEduTooltipController taskbarEduTooltipController,
KeyboardQuickSwitchController keyboardQuickSwitchController,
- TaskbarDividerPopupController taskbarPinningController,
+ TaskbarPinningController taskbarPinningController,
Optional<BubbleControllers> bubbleControllers) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
@@ -171,7 +171,7 @@
taskbarTranslationController.init(this);
taskbarEduTooltipController.init(this);
keyboardQuickSwitchController.init(this);
- taskbarPinningController.init(this);
+ taskbarPinningController.init(this, mSharedState);
bubbleControllers.ifPresent(controllers -> controllers.init(this));
mControllersToLog = new LoggableTaskbarController[] {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupController.kt
deleted file mode 100644
index a2c61ce..0000000
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupController.kt
+++ /dev/null
@@ -1,82 +0,0 @@
-/*
- * Copyright (C) 2023 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 com.android.launcher3.LauncherPrefs
-import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
-import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
-import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
-import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_PINNED
-import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_UNPINNED
-import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAndPopulate
-import java.io.PrintWriter
-
-/** Controls taskbar pinning through a popup view. */
-class TaskbarDividerPopupController(private val context: TaskbarActivityContext) :
- TaskbarControllers.LoggableTaskbarController {
-
- private lateinit var controllers: TaskbarControllers
- private val launcherPrefs = LauncherPrefs.get(context)
- private val statsLogManager = context.statsLogManager
-
- fun init(taskbarControllers: TaskbarControllers) {
- controllers = taskbarControllers
- }
-
- fun showPinningView(view: View) {
- context.isTaskbarWindowFullscreen = true
-
- view.post {
- val popupView = createAndPopulate(view, context)
- popupView.requestFocus()
-
- popupView.onCloseCallback =
- callback@{ didPreferenceChange ->
- statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
- context.dragLayer.post { context.onPopupVisibilityChanged(false) }
-
- if (!didPreferenceChange) {
- return@callback
- }
-
- if (launcherPrefs.get(TASKBAR_PINNING)) {
- animateTransientToPersistentTaskbar()
- statsLogManager.logger().log(LAUNCHER_TASKBAR_PINNED)
- } else {
- animatePersistentToTransientTaskbar()
- statsLogManager.logger().log(LAUNCHER_TASKBAR_UNPINNED)
- }
- }
- popupView.changePreference = {
- launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
- }
- context.onPopupVisibilityChanged(true)
- popupView.show()
- statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
- }
- }
-
- // TODO(b/265436799): provide animation/transition from transient taskbar to persistent one
- private fun animateTransientToPersistentTaskbar() {}
-
- // TODO(b/265436799): provide animation/transition from persistent taskbar to transient one
- private fun animatePersistentToTransientTaskbar() {}
-
- override fun dumpLogs(prefix: String, pw: PrintWriter) {
- pw.println(prefix + "TaskbarPinningController:")
- }
-}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index b200858..d13b53f 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -75,12 +75,6 @@
/** Callback invoked when the pinning popup view is closing. */
var onCloseCallback: (preferenceChanged: Boolean) -> Unit = {}
- /**
- * Callback invoked when the user preference changes in popup view. Preference change will be
- * based upon current value stored in [LauncherPrefs] for `TASKBAR_PINNING`
- */
- var changePreference: () -> Unit = {}
-
init {
// This synchronizes the arrow and menu to open at the same time
mOpenChildFadeStartDelay = mOpenFadeStartDelay
@@ -185,8 +179,6 @@
private fun onClickAlwaysShowTaskbarSwitchOption() {
didPreferenceChange = true
- changePreference()
- changePreference = {}
// Allow switch animation to finish and then close the popup.
postDelayed(DIVIDER_POPUP_CLOSING_DELAY) {
if (isOpen) {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index e521154..1eb8d53 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -73,6 +73,8 @@
private SafeCloseable mViewCaptureCloseable;
private float mTaskbarBackgroundOffset;
+ private float mTaskbarBackgroundProgress;
+ private boolean mIsAnimatingTaskbarPinning = false;
private final MultiPropertyFactory<TaskbarDragLayer> mTaskbarBackgroundAlpha;
@@ -162,10 +164,19 @@
float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
* (1f - mTaskbarBackgroundOffset);
mBackgroundRenderer.setBackgroundHeight(backgroundHeight);
+ mBackgroundRenderer.setBackgroundProgress(mTaskbarBackgroundProgress);
mBackgroundRenderer.draw(canvas);
super.dispatchDraw(canvas);
}
+ /**
+ * Sets animation boolean when taskbar pinning animation starts or stops.
+ */
+ public void setAnimatingTaskbarPinning(boolean animatingTaskbarPinning) {
+ mIsAnimatingTaskbarPinning = animatingTaskbarPinning;
+ mBackgroundRenderer.setAnimatingPinning(mIsAnimatingTaskbarPinning);
+ }
+
protected MultiProperty getBackgroundRendererAlpha() {
return mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES);
}
@@ -175,6 +186,15 @@
}
/**
+ * Sets the value for taskbar background switching between persistent and transient backgrounds.
+ * @param progress 0 is transient background, 1 is persistent background.
+ */
+ protected void setTaskbarBackgroundProgress(float progress) {
+ mTaskbarBackgroundProgress = progress;
+ invalidate();
+ }
+
+ /**
* Sets the translation of the background color behind all the Taskbar contents.
* @param offset 0 is fully onscreen, 1 is fully offscreen.
*/
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index 867b062..73e32ab 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -15,6 +15,9 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
+import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
+
import android.content.res.Resources;
import android.graphics.Point;
import android.graphics.Rect;
@@ -24,6 +27,7 @@
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.util.DimensionUtils;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.TouchController;
@@ -58,6 +62,9 @@
// changes the inset visibility.
private final AnimatedFloat mTaskbarAlpha = new AnimatedFloat(this::updateTaskbarAlpha);
+ private final AnimatedFloat mTaskbarBackgroundProgress = new AnimatedFloat(
+ this::updateTaskbarBackgroundProgress);
+
// Initialized in init.
private TaskbarControllers mControllers;
private TaskbarStashViaTouchController mTaskbarStashViaTouchController;
@@ -83,6 +90,10 @@
mOnBackgroundNavButtonColorIntensity = mControllers.navbarButtonsViewController
.getOnTaskbarBackgroundNavButtonColorOverride();
+ mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity)
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT);
+
mBgTaskbar.value = 1;
mKeyguardBgTaskbar.value = 1;
mNotificationShadeBgTaskbar.value = 1;
@@ -138,6 +149,11 @@
return mBgOffset;
}
+ // AnimatedFloat is for animating between pinned and transient taskbar
+ public AnimatedFloat getTaskbarBackgroundProgress() {
+ return mTaskbarBackgroundProgress;
+ }
+
public AnimatedFloat getTaskbarAlpha() {
return mTaskbarAlpha;
}
@@ -180,10 +196,13 @@
private void updateBackgroundOffset() {
mTaskbarDragLayer.setTaskbarBackgroundOffset(mBgOffset.value);
-
updateOnBackgroundNavButtonColorIntensity();
}
+ private void updateTaskbarBackgroundProgress() {
+ mTaskbarDragLayer.setTaskbarBackgroundProgress(mTaskbarBackgroundProgress.value);
+ }
+
private void updateTaskbarAlpha() {
mTaskbarDragLayer.setAlpha(mTaskbarAlpha.value);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index fa5d1fc..b500c3e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -21,8 +21,6 @@
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
-import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
-import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
import static com.android.launcher3.LauncherState.OVERVIEW;
import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
@@ -38,7 +36,6 @@
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
-import android.content.SharedPreferences;
import android.content.pm.ActivityInfo;
import android.content.res.Configuration;
import android.hardware.display.DisplayManager;
@@ -60,12 +57,12 @@
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.InvariantDeviceProfile.OnIDPChangeListener;
import com.android.launcher3.LauncherAppState;
-import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.statemanager.StatefulActivity;
import com.android.launcher3.taskbar.unfold.NonDestroyableScopedUnfoldTransitionProgressProvider;
import com.android.launcher3.uioverrides.QuickstepLauncher;
import com.android.launcher3.util.ActivityLifecycleCallbacksAdapter;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SimpleBroadcastReceiver;
import com.android.quickstep.RecentsActivity;
@@ -148,13 +145,6 @@
private final SimpleBroadcastReceiver mTaskbarBroadcastReceiver =
new SimpleBroadcastReceiver(this::showTaskbarFromBroadcast);
- private final SharedPreferences.OnSharedPreferenceChangeListener
- mTaskbarPinningPreferenceChangeListener = (sharedPreferences, key) -> {
- if (TASKBAR_PINNING_KEY.equals(key)) {
- recreateTaskbar();
- }
- };
-
private final ActivityLifecycleCallbacksAdapter mLifecycleCallbacks =
new ActivityLifecycleCallbacksAdapter() {
@Override
@@ -307,8 +297,6 @@
private void destroyExistingTaskbar() {
debugWhyTaskbarNotDestroyed("destroyExistingTaskbar: " + mTaskbarActivityContext);
if (mTaskbarActivityContext != null) {
- LauncherPrefs.get(mContext).removeListener(mTaskbarPinningPreferenceChangeListener,
- TASKBAR_PINNING);
mTaskbarActivityContext.onDestroy();
if (!FLAG_HIDE_NAVBAR_WINDOW || enableTaskbarNoRecreate()) {
mTaskbarActivityContext = null;
@@ -456,6 +444,8 @@
} else {
mTaskbarActivityContext.updateDeviceProfile(dp);
}
+ mSharedState.startTaskbarVariantIsTransient =
+ DisplayController.isTransientTaskbar(mTaskbarActivityContext);
mTaskbarActivityContext.init(mSharedState);
if (mActivity != null) {
@@ -469,10 +459,6 @@
mTaskbarRootLayout.addView(mTaskbarActivityContext.getDragLayer());
mTaskbarActivityContext.notifyUpdateLayoutParams();
}
-
- // We to wait until user unlocks the device to attach listener.
- LauncherPrefs.get(mContext).addListener(mTaskbarPinningPreferenceChangeListener,
- TASKBAR_PINNING);
} finally {
Trace.endSection();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
new file mode 100644
index 0000000..d1bed3e
--- /dev/null
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarPinningController.kt
@@ -0,0 +1,112 @@
+/*
+ * Copyright (C) 2023 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.animation.AnimatorSet
+import android.view.View
+import androidx.core.animation.doOnEnd
+import com.android.launcher3.LauncherPrefs
+import com.android.launcher3.LauncherPrefs.Companion.TASKBAR_PINNING
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE
+import com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN
+import com.android.launcher3.taskbar.TaskbarDividerPopupView.Companion.createAndPopulate
+import java.io.PrintWriter
+
+/** Controls taskbar pinning through a popup view. */
+class TaskbarPinningController(private val context: TaskbarActivityContext) :
+ TaskbarControllers.LoggableTaskbarController {
+
+ private lateinit var controllers: TaskbarControllers
+ private lateinit var taskbarSharedState: TaskbarSharedState
+ private val launcherPrefs = LauncherPrefs.get(context)
+ private val statsLogManager = context.statsLogManager
+ private var isAnimatingTaskbarPinning = false
+
+ fun init(taskbarControllers: TaskbarControllers, sharedState: TaskbarSharedState) {
+ controllers = taskbarControllers
+ taskbarSharedState = sharedState
+ }
+
+ fun showPinningView(view: View) {
+ context.isTaskbarWindowFullscreen = true
+
+ view.post {
+ val popupView = createAndPopulate(view, context)
+ popupView.requestFocus()
+
+ popupView.onCloseCallback =
+ callback@{ didPreferenceChange ->
+ statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_CLOSE)
+ context.dragLayer.post { context.onPopupVisibilityChanged(false) }
+
+ if (!didPreferenceChange) {
+ return@callback
+ }
+ val animateToValue =
+ if (!launcherPrefs.get(TASKBAR_PINNING)) {
+ PINNING_PERSISTENT
+ } else {
+ PINNING_TRANSIENT
+ }
+ taskbarSharedState.taskbarWasPinned = animateToValue == PINNING_TRANSIENT
+ animateTaskbarPinning(animateToValue)
+ }
+ context.onPopupVisibilityChanged(true)
+ popupView.show()
+ statsLogManager.logger().log(LAUNCHER_TASKBAR_DIVIDER_MENU_OPEN)
+ }
+ }
+
+ private fun animateTaskbarPinning(animateToValue: Float) {
+ val animatorSet = AnimatorSet()
+ val taskbarViewController = controllers.taskbarViewController
+ val dragLayerController = controllers.taskbarDragLayerController
+
+ animatorSet.playTogether(
+ dragLayerController.taskbarBackgroundProgress.animateToValue(animateToValue),
+ taskbarViewController.taskbarIconTranslationYForPinning.animateToValue(animateToValue),
+ taskbarViewController.taskbarIconScaleForPinning.animateToValue(animateToValue),
+ taskbarViewController.taskbarIconTranslationXForPinning.animateToValue(animateToValue)
+ )
+
+ animatorSet.doOnEnd { recreateTaskbarAndUpdatePinningValue() }
+ animatorSet.duration = PINNING_ANIMATION_DURATION
+ updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(true)
+ animatorSet.start()
+ }
+
+ private fun updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(isAnimating: Boolean) {
+ isAnimatingTaskbarPinning = isAnimating
+ context.dragLayer.setAnimatingTaskbarPinning(isAnimating)
+ }
+
+ private fun recreateTaskbarAndUpdatePinningValue() {
+ updateIsAnimatingTaskbarPinningAndNotifyTaskbarDragLayer(false)
+ launcherPrefs.put(TASKBAR_PINNING, !launcherPrefs.get(TASKBAR_PINNING))
+ }
+
+ override fun dumpLogs(prefix: String, pw: PrintWriter) {
+ pw.println(prefix + "TaskbarPinningController:")
+ pw.println("$prefix\tisAnimatingTaskbarPinning=$isAnimatingTaskbarPinning")
+ pw.println("$prefix\tTASKBAR_PINNING shared pref =" + launcherPrefs.get(TASKBAR_PINNING))
+ }
+
+ companion object {
+ const val PINNING_PERSISTENT = 1f
+ const val PINNING_TRANSIENT = 0f
+ const val PINNING_ANIMATION_DURATION = 500L
+ }
+}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
index abbd18b..176a8c5 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarSharedState.java
@@ -71,4 +71,11 @@
new InsetsFrameProvider(mInsetsOwner, INDEX_RIGHT, systemGestures())
.setSource(SOURCE_DISPLAY)
};
+
+ // Allows us to shift translation logic when doing taskbar pinning animation.
+ public Boolean startTaskbarVariantIsTransient = true;
+
+ // To track if taskbar was pinned using taskbar pinning feature at the time of recreate,
+ // so we can unstash transient taskbar when we un-pinning taskbar.
+ public Boolean taskbarWasPinned = false;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
index e67a6d5..5be74be 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java
@@ -22,7 +22,7 @@
import static com.android.app.animation.Interpolators.FINAL_FRAME;
import static com.android.app.animation.Interpolators.INSTANT;
import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING_KEY;
+import static com.android.launcher3.LauncherPrefs.TASKBAR_PINNING;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_HIDE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_LONGPRESS_SHOW;
@@ -337,7 +337,8 @@
&& mPrefs.getBoolean(SHARED_PREFS_STASHED_KEY, DEFAULT_STASHED_PREF);
boolean isInSetup = !mActivity.isUserSetupComplete() || setupUIVisible;
updateStateForFlag(FLAG_STASHED_IN_APP_MANUAL, isManuallyStashedInApp);
- updateStateForFlag(FLAG_STASHED_IN_APP_AUTO, isTransientTaskbar);
+ updateStateForFlag(FLAG_STASHED_IN_APP_AUTO,
+ isTransientTaskbar && !mTaskbarSharedState.taskbarWasPinned);
updateStateForFlag(FLAG_STASHED_IN_APP_SETUP, isInSetup);
updateStateForFlag(FLAG_IN_SETUP, isInSetup);
updateStateForFlag(FLAG_STASHED_SMALL_SCREEN, isPhoneMode()
@@ -346,6 +347,9 @@
// us that we're paused until a bit later. This avoids flickering upon recreating taskbar.
updateStateForFlag(FLAG_IN_APP, true);
applyState(/* duration = */ 0);
+ if (mTaskbarSharedState.taskbarWasPinned) {
+ tryStartTaskbarTimeout();
+ }
notifyStashChange(/* visible */ false, /* stashed */ isStashedInApp());
}
@@ -361,7 +365,7 @@
* Returns whether the user can manually stash the taskbar based on the current device state.
*/
protected boolean supportsManualStashing() {
- if (ENABLE_TASKBAR_PINNING.get() && mPrefs.getBoolean(TASKBAR_PINNING_KEY, false)) {
+ if (ENABLE_TASKBAR_PINNING.get() && LauncherPrefs.get(mActivity).get(TASKBAR_PINNING)) {
return false;
}
return supportsVisualStashing()
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
index 5f58de5..a7461b7 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java
@@ -20,7 +20,6 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.config.FeatureFlags.ENABLE_ALL_APPS_SEARCH_IN_TASKBAR;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTOR;
import android.content.Context;
@@ -98,8 +97,6 @@
private final float mTransientTaskbarMinWidth;
- private final float mTaskbarAllAppsButtonTranslationXOffset;
-
private boolean mShouldTryStartAlign;
public TaskbarView(@NonNull Context context) {
@@ -125,13 +122,16 @@
&& !TaskbarManager.isPhoneMode(mActivityContext.getDeviceProfile());
mIsRtl = Utilities.isRtl(resources);
mTransientTaskbarMinWidth = resources.getDimension(R.dimen.transient_taskbar_min_width);
- mTaskbarAllAppsButtonTranslationXOffset =
- resources.getDimension(getAllAppsButtonTranslationXOffset(isTransientTaskbar));
+
onDeviceProfileChanged(mActivityContext.getDeviceProfile());
int actualMargin = resources.getDimensionPixelSize(R.dimen.taskbar_icon_spacing);
int actualIconSize = mActivityContext.getDeviceProfile().taskbarIconSize;
+ if (FeatureFlags.ENABLE_TASKBAR_PINNING.get()) {
+ DeviceProfile deviceProfile = mActivityContext.getTransientTaskbarDeviceProfile();
+ actualIconSize = deviceProfile.taskbarIconSize;
+ }
int visualIconSize = (int) (actualIconSize * ICON_VISIBLE_AREA_FACTOR);
mIconTouchSize = Math.max(actualIconSize,
@@ -139,8 +139,11 @@
// We layout the icons to be of mIconTouchSize in width and height
mItemMarginLeftRight = actualMargin - (mIconTouchSize - visualIconSize) / 2;
- mItemPadding = (mIconTouchSize - actualIconSize) / 2;
+ // We always layout taskbar as a transient taskbar when we have taskbar pinning feature on,
+ // then we scale and translate the icons to match persistent taskbar designs, so we use
+ // taskbar icon size from current device profile to calculate correct item padding.
+ mItemPadding = (mIconTouchSize - mActivityContext.getDeviceProfile().taskbarIconSize) / 2;
mFolderLeaveBehindColor = Themes.getAttrColor(mActivityContext,
android.R.attr.textColorTertiary);
@@ -173,7 +176,8 @@
@DrawableRes
private int getAllAppsButton(boolean isTransientTaskbar) {
- boolean shouldSelectTransientIcon = (isTransientTaskbar || ENABLE_TASKBAR_PINNING.get())
+ boolean shouldSelectTransientIcon =
+ (isTransientTaskbar || FeatureFlags.ENABLE_TASKBAR_PINNING.get())
&& !mActivityContext.isThreeButtonNav();
if (ENABLE_ALL_APPS_SEARCH_IN_TASKBAR.get()) {
return shouldSelectTransientIcon
@@ -187,7 +191,7 @@
}
@DimenRes
- private int getAllAppsButtonTranslationXOffset(boolean isTransientTaskbar) {
+ public int getAllAppsButtonTranslationXOffset(boolean isTransientTaskbar) {
if (isTransientTaskbar) {
return R.dimen.transient_taskbar_all_apps_button_translation_x_offset;
} else {
@@ -370,8 +374,6 @@
}
if (mAllAppsButton != null) {
- mAllAppsButton.setTranslationXForTaskbarAllAppsIcon(getChildCount() > 0
- ? mTaskbarAllAppsButtonTranslationXOffset : 0f);
addView(mAllAppsButton, mIsRtl ? getChildCount() : 0);
// if only all apps button present, don't include divider view.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
index 8a8c3bc..0d06088 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java
@@ -21,14 +21,19 @@
import static com.android.launcher3.LauncherAnimUtils.VIEW_ALPHA;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_Y;
+import static com.android.launcher3.Utilities.mapRange;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.anim.AnimatedFloat.VALUE;
import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
+import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_TASKBAR_ALLAPPS_BUTTON_TAP;
+import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
+import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneButtonNavMode;
import static com.android.launcher3.taskbar.TaskbarManager.isPhoneMode;
import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_ALIGNMENT_ANIM;
+import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_PINNING_ANIM;
import static com.android.launcher3.util.MultiTranslateDelegate.INDEX_TASKBAR_REVEAL_ANIM;
import android.animation.Animator;
@@ -61,11 +66,13 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.ThemedIconDrawable;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.util.LauncherBindableItemsContainer;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiTranslateDelegate;
import com.android.launcher3.util.MultiValueAlpha;
+import com.android.launcher3.views.IconButtonView;
import java.io.PrintWriter;
import java.util.function.Predicate;
@@ -98,12 +105,27 @@
this::updateTranslationY);
private final AnimatedFloat mTaskbarIconTranslationYForStash = new AnimatedFloat(
this::updateTranslationY);
+
+ private final AnimatedFloat mTaskbarIconScaleForPinning = new AnimatedFloat(
+ this::updateTaskbarIconsScale);
+
+ private final AnimatedFloat mTaskbarIconTranslationXForPinning = new AnimatedFloat(
+ this::updateTaskbarIconTranslationXForPinning);
+
+ private final AnimatedFloat mTaskbarIconTranslationYForPinning = new AnimatedFloat(
+ this::updateTranslationY);
+
+ private final View.OnLayoutChangeListener mTaskbarViewLayoutChangeListener =
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom)
+ -> updateTaskbarIconTranslationXForPinning();
+
+
private AnimatedFloat mTaskbarNavButtonTranslationY;
private AnimatedFloat mTaskbarNavButtonTranslationYForInAppDisplay;
private float mTaskbarIconTranslationYForSwipe;
private float mTaskbarIconTranslationYForSpringOnStash;
- private final int mTaskbarBottomMargin;
+ private int mTaskbarBottomMargin;
private final int mStashedHandleHeight;
private final int mLauncherThemedIconsBackgroundColor;
private final int mTaskbarThemedIconsBackgroundColor;
@@ -131,8 +153,18 @@
private final boolean mIsRtl;
+ private final DeviceProfile mTransientTaskbarDp;
+ private final DeviceProfile mPersistentTaskbarDp;
+
+ private final int mTransientIconSize;
+ private final int mPersistentIconSize;
+
public TaskbarViewController(TaskbarActivityContext activity, TaskbarView taskbarView) {
mActivity = activity;
+ mTransientTaskbarDp = mActivity.getTransientTaskbarDeviceProfile();
+ mPersistentTaskbarDp = mActivity.getPersistentTaskbarDeviceProfile();
+ mTransientIconSize = mTransientTaskbarDp.taskbarIconSize;
+ mPersistentIconSize = mPersistentTaskbarDp.taskbarIconSize;
mTaskbarView = taskbarView;
mTaskbarIconAlpha = new MultiValueAlpha(mTaskbarView, NUM_ALPHA_CHANNELS);
mTaskbarIconAlpha.setUpdateVisibility(true);
@@ -162,6 +194,12 @@
: mActivity.getDeviceProfile().taskbarHeight;
mTaskbarIconScaleForStash.updateValue(1f);
+ float pinningValue = DisplayController.isTransientTaskbar(mActivity)
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT;
+ mTaskbarIconScaleForPinning.updateValue(pinningValue);
+ mTaskbarIconTranslationYForPinning.updateValue(pinningValue);
+ mTaskbarIconTranslationXForPinning.updateValue(pinningValue);
mModelCallbacks.init(controllers);
if (mActivity.isUserSetupComplete()) {
@@ -181,6 +219,9 @@
mTaskbarIconAlpha.get(ALPHA_INDEX_SMALL_SCREEN)
.animateToValue(isPhoneButtonNavMode(mActivity) ? 0 : 1).start();
}
+ if (ENABLE_TASKBAR_PINNING.get()) {
+ mTaskbarView.addOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
+ }
}
/**
@@ -191,6 +232,9 @@
}
public void onDestroy() {
+ if (ENABLE_TASKBAR_PINNING.get()) {
+ mTaskbarView.removeOnLayoutChangeListener(mTaskbarViewLayoutChangeListener);
+ }
LauncherAppState.getInstance(mActivity).getModel().removeCallbacks(mModelCallbacks);
mActivity.removeOnDeviceProfileChangeListener(mDeviceProfileChangeListener);
mModelCallbacks.unregisterListeners();
@@ -253,6 +297,18 @@
return mTaskbarIconTranslationYForStash;
}
+ public AnimatedFloat getTaskbarIconScaleForPinning() {
+ return mTaskbarIconScaleForPinning;
+ }
+
+ public AnimatedFloat getTaskbarIconTranslationXForPinning() {
+ return mTaskbarIconTranslationXForPinning;
+ }
+
+ public AnimatedFloat getTaskbarIconTranslationYForPinning() {
+ return mTaskbarIconTranslationYForPinning;
+ }
+
/**
* Applies scale properties for the entire TaskbarView (rather than individual icons).
*/
@@ -263,6 +319,65 @@
}
/**
+ * Applies scale properties for the taskbar icons
+ */
+ private void updateTaskbarIconsScale() {
+ float scale = mTaskbarIconScaleForPinning.value;
+ View[] iconViews = mTaskbarView.getIconViews();
+
+ float finalScale;
+ if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
+ finalScale = mapRange(scale, 1f, ((float) mPersistentIconSize / mTransientIconSize));
+ } else {
+ finalScale = mapRange(scale, ((float) mTransientIconSize / mPersistentIconSize), 1f);
+ }
+
+ for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
+ iconViews[iconIndex].setScaleX(finalScale);
+ iconViews[iconIndex].setScaleY(finalScale);
+ }
+ }
+
+ private void updateTaskbarIconTranslationXForPinning() {
+ View[] iconViews = mTaskbarView.getIconViews();
+ float scale = mTaskbarIconTranslationXForPinning.value;
+ float taskbarCenterX =
+ mTaskbarView.getLeft() + (mTaskbarView.getRight() - mTaskbarView.getLeft()) / 2.0f;
+
+ float finalMarginScale = mapRange(scale, 0f, mTransientIconSize - mPersistentIconSize);
+
+ float transientTaskbarAllAppsOffset = mActivity.getResources().getDimension(
+ mTaskbarView.getAllAppsButtonTranslationXOffset(true));
+ float persistentTaskbarAllAppsOffset = mActivity.getResources().getDimension(
+ mTaskbarView.getAllAppsButtonTranslationXOffset(false));
+
+ float allAppIconTranslateRange = mapRange(scale, transientTaskbarAllAppsOffset,
+ persistentTaskbarAllAppsOffset);
+
+ float halfIconCount = iconViews.length / 2.0f;
+ for (int iconIndex = 0; iconIndex < iconViews.length; iconIndex++) {
+ View iconView = iconViews[iconIndex];
+ MultiTranslateDelegate translateDelegate =
+ ((Reorderable) iconView).getTranslateDelegate();
+ float iconCenterX =
+ iconView.getLeft() + (iconView.getRight() - iconView.getLeft()) / 2.0f;
+ if (iconCenterX <= taskbarCenterX) {
+ translateDelegate.getTranslationX(INDEX_TASKBAR_PINNING_ANIM).setValue(
+ finalMarginScale * (halfIconCount - iconIndex));
+ } else {
+ translateDelegate.getTranslationX(INDEX_TASKBAR_PINNING_ANIM).setValue(
+ -finalMarginScale * (iconIndex - halfIconCount));
+ }
+
+ if (iconView.equals(mTaskbarView.getAllAppsButtonView()) && iconViews.length > 1) {
+ ((IconButtonView) iconView).setTranslationXForTaskbarAllAppsIcon(
+ allAppIconTranslateRange);
+ }
+ }
+ }
+
+
+ /**
* Sets the translation of the TaskbarView during the swipe up gesture.
*/
public void setTranslationYForSwipe(float transY) {
@@ -282,10 +397,41 @@
mTaskbarView.setTranslationY(mTaskbarIconTranslationYForHome.value
+ mTaskbarIconTranslationYForStash.value
+ mTaskbarIconTranslationYForSwipe
+ + getTaskbarIconTranslationYForPinningValue()
+ mTaskbarIconTranslationYForSpringOnStash);
}
/**
+ * Computes translation y for taskbar pinning.
+ */
+ private float getTaskbarIconTranslationYForPinningValue() {
+ if (mControllers.getSharedState() == null) return 0f;
+
+ float scale = mTaskbarIconTranslationYForPinning.value;
+ float taskbarIconTranslationYForPinningValue;
+
+ // transY is calculated here by adding/subtracting the taskbar bottom margin
+ // aligning the icon bound to be at bottom of current taskbar view and then
+ // finally placing the icon in the middle of new taskbar background height.
+ if (mControllers.getSharedState().startTaskbarVariantIsTransient) {
+ float transY =
+ mTransientTaskbarDp.taskbarBottomMargin + (mTransientTaskbarDp.taskbarHeight
+ - mTaskbarView.getIconLayoutBounds().bottom)
+ - (mPersistentTaskbarDp.taskbarHeight
+ - mTransientTaskbarDp.taskbarIconSize) / 2f;
+ taskbarIconTranslationYForPinningValue = mapRange(scale, 0f, transY);
+ } else {
+ float transY =
+ -mTransientTaskbarDp.taskbarBottomMargin + (mPersistentTaskbarDp.taskbarHeight
+ - mTaskbarView.getIconLayoutBounds().bottom)
+ - (mTransientTaskbarDp.taskbarHeight
+ - mTransientTaskbarDp.taskbarIconSize) / 2f;
+ taskbarIconTranslationYForPinningValue = mapRange(scale, transY, 0f);
+ }
+ return taskbarIconTranslationYForPinningValue;
+ }
+
+ /**
* Updates the Taskbar's themed icons background according to the progress between in-app/home.
*/
protected void updateIconsBackground() {
@@ -471,6 +617,8 @@
mOnControllerPreCreateCallback.run();
DeviceProfile taskbarDp = mActivity.getDeviceProfile();
Rect hotseatPadding = launcherDp.getHotseatLayoutPadding(mActivity);
+ boolean isTransientTaskbar = DisplayController.isTransientTaskbar(mActivity);
+
float scaleUp = ((float) launcherDp.iconSizePx) / taskbarDp.taskbarIconSize;
int borderSpacing = launcherDp.hotseatBorderSpace;
int hotseatCellSize = DeviceProfile.calculateCellWidth(
@@ -497,6 +645,10 @@
setter.addOnFrameListener(anim -> mActivity.setTaskbarWindowHeight(
anim.getAnimatedFraction() > 0 ? expandedHeight : collapsedHeight));
+ mTaskbarBottomMargin = isTransientTaskbar
+ ? mTransientTaskbarDp.taskbarBottomMargin
+ : mPersistentTaskbarDp.taskbarBottomMargin;
+
for (int i = 0; i < mTaskbarView.getChildCount(); i++) {
View child = mTaskbarView.getChildAt(i);
boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonView();
@@ -507,7 +659,7 @@
// to avoid icons disappearing rather than fading out visually.
setter.setViewAlpha(child, 0, Interpolators.clampToProgress(LINEAR, 0.8f, 1f));
} else if ((isAllAppsButton && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get())
- || (isTaskbarDividerView && FeatureFlags.ENABLE_TASKBAR_PINNING.get())) {
+ || (isTaskbarDividerView && ENABLE_TASKBAR_PINNING.get())) {
if (!isToHome
&& mIsHotseatIconOnTopWhenAligned
&& mIsStashed) {
@@ -528,6 +680,8 @@
+ launcherDp.hotseatQsbWidth / 2f
: hotseatPadding.left - borderSpacing - launcherDp.hotseatQsbWidth / 2f;
float childCenter = (child.getLeft() + child.getRight()) / 2f;
+ childCenter += ((Reorderable) child).getTranslateDelegate().getTranslationX(
+ INDEX_TASKBAR_PINNING_ANIM).getValue();
float halfQsbIconWidthDiff =
(launcherDp.hotseatQsbWidth - taskbarDp.taskbarIconSize) / 2f;
float scale = ((float) taskbarDp.taskbarIconSize)
@@ -561,9 +715,9 @@
}
int positionInHotseat;
- if (isAllAppsButton) {
- // Note that there is no All Apps button in the hotseat, this position is only used
- // as its convenient for animation purposes.
+ if (isAllAppsButton || isTaskbarDividerView) {
+ // Note that there is no All Apps button or taskbar divider view in the hotseat,
+ // this position is only used as its convenient for animation purposes.
positionInHotseat = Utilities.isRtl(child.getResources())
? taskbarDp.numShownHotseatIcons
: -1;
@@ -587,10 +741,11 @@
+ hotseatCellSize / 2f;
}
float childCenter = (child.getLeft() + child.getRight()) / 2f;
+ childCenter += ((Reorderable) child).getTranslateDelegate().getTranslationX(
+ INDEX_TASKBAR_PINNING_ANIM).getValue();
float toX = hotseatIconCenter - childCenter;
if (child instanceof Reorderable) {
MultiTranslateDelegate mtd = ((Reorderable) child).getTranslateDelegate();
-
setter.setFloat(mtd.getTranslationX(INDEX_TASKBAR_ALIGNMENT_ANIM),
MULTI_PROPERTY_VALUE, toX, interpolator);
setter.setFloat(mtd.getTranslationY(INDEX_TASKBAR_ALIGNMENT_ANIM),
diff --git a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
index 2c16c15..15b1e53 100644
--- a/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
+++ b/quickstep/tests/src/com/android/launcher3/taskbar/TaskbarBaseTestCase.kt
@@ -55,7 +55,7 @@
@Mock lateinit var taskbarOverlayController: TaskbarOverlayController
@Mock lateinit var taskbarEduTooltipController: TaskbarEduTooltipController
@Mock lateinit var keyboardQuickSwitchController: KeyboardQuickSwitchController
- @Mock lateinit var taskbarPinningController: TaskbarDividerPopupController
+ @Mock lateinit var taskbarPinningController: TaskbarPinningController
@Mock lateinit var optionalBubbleControllers: Optional<BubbleControllers>
lateinit var taskbarControllers: TaskbarControllers
diff --git a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconAppChipMenuTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconAppChipMenuTest.java
index 15952c1..969da68 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconAppChipMenuTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconAppChipMenuTest.java
@@ -18,6 +18,7 @@
import com.android.launcher3.Flags;
import com.android.launcher3.InvariantDeviceProfile;
+import org.junit.After;
import org.junit.Before;
/**
@@ -35,4 +36,11 @@
executeOnLauncher(launcher -> InvariantDeviceProfile.INSTANCE.get(launcher).onConfigChanged(
launcher));
}
+
+ @After
+ public void tearDown() {
+ mSetFlagsRule.disableFlags(Flags.FLAG_ENABLE_OVERVIEW_ICON_MENU);
+ executeOnLauncher(launcher -> InvariantDeviceProfile.INSTANCE.get(launcher).onConfigChanged(
+ launcher));
+ }
}
diff --git a/src/com/android/launcher3/model/DatabaseHelper.java b/src/com/android/launcher3/model/DatabaseHelper.java
index 8167b97..1360510 100644
--- a/src/com/android/launcher3/model/DatabaseHelper.java
+++ b/src/com/android/launcher3/model/DatabaseHelper.java
@@ -269,7 +269,6 @@
Favorites.CONTAINER, Favorites.CONTAINER_DESKTOP,
Favorites.CELLY, 0), null);
}
- return;
}
case 31: {
LauncherDbUtils.migrateLegacyShortcuts(mContext, db);
diff --git a/src/com/android/launcher3/util/MultiTranslateDelegate.java b/src/com/android/launcher3/util/MultiTranslateDelegate.java
index 6f6392f..84ef445 100644
--- a/src/com/android/launcher3/util/MultiTranslateDelegate.java
+++ b/src/com/android/launcher3/util/MultiTranslateDelegate.java
@@ -36,6 +36,7 @@
// Specific for items in taskbar (icons, folders, qsb)
public static final int INDEX_TASKBAR_ALIGNMENT_ANIM = 3;
public static final int INDEX_TASKBAR_REVEAL_ANIM = 4;
+ public static final int INDEX_TASKBAR_PINNING_ANIM = 5;
// Affect all items inside of a MultipageCellLayout
public static final int INDEX_CELLAYOUT_MULTIPAGE_SPACING = 3;
@@ -46,7 +47,7 @@
// Specific for hotseat items when adjusting for bubbles
public static final int INDEX_BUBBLE_ADJUSTMENT_ANIM = 3;
- public static final int COUNT = 5;
+ public static final int COUNT = 6;
private final MultiPropertyFactory<View> mTranslationX;
private final MultiPropertyFactory<View> mTranslationY;