Merge "Fix failing DeleteDropTargetTest" into main
diff --git a/aconfig/launcher.aconfig b/aconfig/launcher.aconfig
index 874f862..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 {
@@ -41,3 +41,10 @@
description: "Enable updated overview icon and menu within task."
bug: "257950105"
}
+
+flag {
+ name: "enable_taskbar_no_recreate"
+ namespace: "launcher"
+ description: "Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext."
+ bug: "299193589"
+}
diff --git a/quickstep/AndroidManifest.xml b/quickstep/AndroidManifest.xml
index 6d958ed..82f8ebe 100644
--- a/quickstep/AndroidManifest.xml
+++ b/quickstep/AndroidManifest.xml
@@ -30,7 +30,9 @@
<uses-permission android:name="android.permission.REMOVE_TASKS"/>
<uses-permission android:name="android.permission.WRITE_SECURE_SETTINGS"/>
<uses-permission android:name="android.permission.MANAGE_ACTIVITY_TASKS"/>
+ <uses-permission android:name="android.permission.INTERNAL_SYSTEM_WINDOW"/>
<uses-permission android:name="android.permission.STATUS_BAR"/>
+ <uses-permission android:name="android.permission.STATUS_BAR_SERVICE"/>
<uses-permission android:name="android.permission.STOP_APP_SWITCHES"/>
<uses-permission android:name="android.permission.SET_ORIENTATION"/>
<uses-permission android:name="android.permission.READ_FRAME_BUFFER"/>
diff --git a/quickstep/res/values-land/dimens.xml b/quickstep/res/values-land/dimens.xml
index ee594c8..2b17b93 100644
--- a/quickstep/res/values-land/dimens.xml
+++ b/quickstep/res/values-land/dimens.xml
@@ -84,4 +84,5 @@
<dimen name="keyboard_quick_switch_taskview_width">205dp</dimen>
<dimen name="keyboard_quick_switch_taskview_height">119dp</dimen>
+
</resources>
diff --git a/quickstep/res/values-sw600dp-land/dimens.xml b/quickstep/res/values-sw600dp-land/dimens.xml
index 9cb3fec..5e9a177 100644
--- a/quickstep/res/values-sw600dp-land/dimens.xml
+++ b/quickstep/res/values-sw600dp-land/dimens.xml
@@ -27,4 +27,10 @@
<dimen name="gesture_tutorial_menu_done_button_top_spacing">40dp</dimen>
<dimen name="gesture_tutorial_menu_back_shape_bottom_margin">49dp</dimen>
+ <!-- Grid Only Overview -->
+ <!-- The top margin above the top row of tasks in grid only overview -->
+ <dimen name="overview_top_margin_grid_only">24dp</dimen>
+ <!-- The bottom margin above the bottom row of tasks in grid only overview -->
+ <dimen name="overview_bottom_margin_grid_only">40dp</dimen>
+
</resources>
diff --git a/quickstep/res/values-sw600dp/dimens.xml b/quickstep/res/values-sw600dp/dimens.xml
index daf1f63..f9528b3 100644
--- a/quickstep/res/values-sw600dp/dimens.xml
+++ b/quickstep/res/values-sw600dp/dimens.xml
@@ -33,6 +33,10 @@
<dimen name="overview_page_spacing">36dp</dimen>
<!-- The space to the left and to the right of the "Clear all" button -->
<dimen name="overview_grid_side_margin">64dp</dimen>
+ <!-- The top margin above the top row of tasks in grid only overview -->
+ <dimen name="overview_top_margin_grid_only">80dp</dimen>
+ <!-- The bottom margin above the bottom row of tasks in grid only overview -->
+ <dimen name="overview_bottom_margin_grid_only">80dp</dimen>
<!-- Overview actions -->
<dimen name="overview_actions_top_margin">24dp</dimen>
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index d4d6b26..6ee151b 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -20,6 +20,7 @@
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
import static android.view.WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
+import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR;
import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static android.window.SplashScreen.SPLASH_SCREEN_STYLE_UNDEFINED;
@@ -29,8 +30,8 @@
import static com.android.launcher3.Flags.enableCursorHoverStates;
import static com.android.launcher3.Utilities.calculateTextHeight;
import static com.android.launcher3.Utilities.isRunningInTestHarness;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NO_RECREATION;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_PINNING;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_FOLDER_OPEN;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_FULLSCREEN;
@@ -128,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
@@ -173,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);
@@ -254,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),
@@ -274,7 +279,7 @@
: TaskbarRecentAppsController.DEFAULT,
new TaskbarEduTooltipController(this),
new KeyboardQuickSwitchController(),
- new TaskbarDividerPopupController(this),
+ new TaskbarPinningController(this),
bubbleControllersOptional);
}
@@ -295,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);
}
@@ -339,7 +361,7 @@
mIsDestroyed = false;
}
- if (!ENABLE_TASKBAR_NO_RECREATION.get() && !mAddedWindow) {
+ if (!enableTaskbarNoRecreate() && !mAddedWindow) {
mWindowManager.addView(mDragLayer, mWindowLayoutParams);
mAddedWindow = true;
} else {
@@ -391,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) {
@@ -430,9 +453,10 @@
* for taskbar showing as navigation bar
*/
private WindowManager.LayoutParams createAllWindowParams() {
+ final int windowType =
+ FLAG_HIDE_NAVBAR_WINDOW ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
WindowManager.LayoutParams windowLayoutParams =
- createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL,
- TaskbarActivityContext.WINDOW_TITLE);
+ createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
boolean isPhoneNavMode = TaskbarManager.isPhoneButtonNavMode(this);
if (!isPhoneNavMode) {
return windowLayoutParams;
@@ -445,7 +469,7 @@
windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
WindowManager.LayoutParams lp =
- createDefaultWindowLayoutParams(TYPE_NAVIGATION_BAR_PANEL,
+ createDefaultWindowLayoutParams(windowType,
TaskbarActivityContext.WINDOW_TITLE);
switch (rot) {
case Surface.ROTATION_0, Surface.ROTATION_180 -> {
@@ -695,7 +719,7 @@
mIsDestroyed = true;
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
- if (!ENABLE_TASKBAR_NO_RECREATION.get() && !FLAG_HIDE_NAVBAR_WINDOW) {
+ if (!enableTaskbarNoRecreate() && !FLAG_HIDE_NAVBAR_WINDOW) {
mWindowManager.removeViewImmediate(mDragLayer);
mAddedWindow = false;
}
@@ -794,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);
}
@@ -853,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
@@ -865,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));
}
@@ -878,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.
@@ -1290,7 +1322,7 @@
void notifyUpdateLayoutParams() {
if (mDragLayer.isAttachedToWindow()) {
- if (ENABLE_TASKBAR_NO_RECREATION.get()) {
+ if (enableTaskbarNoRecreate()) {
mWindowManager.updateViewLayout(mDragLayer.getRootView(), mWindowLayoutParams);
} else {
mWindowManager.updateViewLayout(mDragLayer, mWindowLayoutParams);
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/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
index 56ba460..d4f42d8 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java
@@ -211,7 +211,7 @@
}
applyState();
boolean disallowLongClick =
- FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
+ FeatureFlags.enableSplitContextually()
? mLauncher.isSplitSelectionEnabled()
: finalState == LauncherState.OVERVIEW_SPLIT_SELECT;
com.android.launcher3.taskbar.Utilities.setOverviewDragState(
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
index 6dfd243..b500c3e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarManager.java
@@ -18,12 +18,11 @@
import static android.content.Context.RECEIVER_NOT_EXPORTED;
import static android.content.pm.PackageManager.FEATURE_PC;
import static android.view.Display.DEFAULT_DISPLAY;
+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.ENABLE_TASKBAR_NO_RECREATION;
+import static com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate;
import static com.android.launcher3.util.DisplayController.TASKBAR_NOT_DESTROYED_TAG;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange;
@@ -37,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;
@@ -59,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;
@@ -147,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
@@ -209,8 +200,9 @@
public TaskbarManager(TouchInteractionService service) {
Display display =
service.getSystemService(DisplayManager.class).getDisplay(DEFAULT_DISPLAY);
- mContext = service.createWindowContext(display, TYPE_NAVIGATION_BAR_PANEL, null);
- if (ENABLE_TASKBAR_NO_RECREATION.get()) {
+ mContext = service.createWindowContext(display,
+ FLAG_HIDE_NAVBAR_WINDOW ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL, null);
+ if (enableTaskbarNoRecreate()) {
mWindowManager = mContext.getSystemService(WindowManager.class);
mTaskbarRootLayout = new FrameLayout(mContext) {
@Override
@@ -305,10 +297,8 @@
private void destroyExistingTaskbar() {
debugWhyTaskbarNotDestroyed("destroyExistingTaskbar: " + mTaskbarActivityContext);
if (mTaskbarActivityContext != null) {
- LauncherPrefs.get(mContext).removeListener(mTaskbarPinningPreferenceChangeListener,
- TASKBAR_PINNING);
mTaskbarActivityContext.onDestroy();
- if (!FLAG_HIDE_NAVBAR_WINDOW || ENABLE_TASKBAR_NO_RECREATION.get()) {
+ if (!FLAG_HIDE_NAVBAR_WINDOW || enableTaskbarNoRecreate()) {
mTaskbarActivityContext = null;
}
}
@@ -448,12 +438,14 @@
return;
}
- if (ENABLE_TASKBAR_NO_RECREATION.get() || mTaskbarActivityContext == null) {
+ if (enableTaskbarNoRecreate() || mTaskbarActivityContext == null) {
mTaskbarActivityContext = new TaskbarActivityContext(mContext, dp,
mNavButtonController, mUnfoldProgressProvider);
} else {
mTaskbarActivityContext.updateDeviceProfile(dp);
}
+ mSharedState.startTaskbarVariantIsTransient =
+ DisplayController.isTransientTaskbar(mTaskbarActivityContext);
mTaskbarActivityContext.init(mSharedState);
if (mActivity != null) {
@@ -461,16 +453,12 @@
createTaskbarUIControllerForActivity(mActivity));
}
- if (ENABLE_TASKBAR_NO_RECREATION.get()) {
+ if (enableTaskbarNoRecreate()) {
addTaskbarRootViewToWindow();
mTaskbarRootLayout.removeAllViews();
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();
}
@@ -603,8 +591,7 @@
}
private void addTaskbarRootViewToWindow() {
- if (ENABLE_TASKBAR_NO_RECREATION.get() && !mAddedWindow
- && mTaskbarActivityContext != null) {
+ if (enableTaskbarNoRecreate() && !mAddedWindow && mTaskbarActivityContext != null) {
mWindowManager.addView(mTaskbarRootLayout,
mTaskbarActivityContext.getWindowLayoutParams());
mAddedWindow = true;
@@ -612,7 +599,7 @@
}
private void removeTaskbarRootViewFromWindow() {
- if (ENABLE_TASKBAR_NO_RECREATION.get() && mAddedWindow) {
+ if (enableTaskbarNoRecreate() && mAddedWindow) {
mWindowManager.removeViewImmediate(mTaskbarRootLayout);
mAddedWindow = false;
}
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/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
index d78ca88..e2f4f32 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/BaseRecentsViewStateController.java
@@ -107,8 +107,7 @@
setter.setFloat(mRecentsView, TASK_SECONDARY_TRANSLATION, 0f,
config.getInterpolator(ANIM_OVERVIEW_TRANSLATE_Y, LINEAR));
- boolean exitingOverview = !FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
- && !toState.overviewUi;
+ boolean exitingOverview = !FeatureFlags.enableSplitContextually() && !toState.overviewUi;
if (mRecentsView.isSplitSelectionActive() && exitingOverview) {
setter.add(mRecentsView.getSplitSelectController().getSplitAnimationController()
.createPlaceholderDismissAnim(mLauncher));
diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
index 4c739fa..009b1bd 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java
@@ -34,7 +34,6 @@
import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT;
import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent;
import static com.android.launcher3.config.FeatureFlags.ENABLE_HOME_TRANSITION_LISTENER;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP;
import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID;
import static com.android.launcher3.popup.QuickstepSystemShortcut.getSplitSelectShortcutByPosition;
@@ -644,7 +643,7 @@
splitSelectSource.alreadyRunningTaskId = taskWasFound
? foundTask.key.id
: INVALID_TASK_ID;
- if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
startSplitToHome(splitSelectSource);
} else {
recentsView.initiateSplitSelect(splitSelectSource);
@@ -718,7 +717,7 @@
super.onPause();
- if (ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
// If Launcher pauses before both split apps are selected, exit split screen.
if (!mSplitSelectStateController.isBothSplitAppsConfirmed() &&
!mSplitSelectStateController.isLaunchingFirstAppFullscreen()) {
diff --git a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
index b266bcd..f6cd30a 100644
--- a/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
+++ b/quickstep/src/com/android/launcher3/uioverrides/touchcontrollers/NavBarToHomeTouchController.java
@@ -195,7 +195,7 @@
() -> recentsView.finishRecentsAnimation(true /* toRecents */, null));
if (mStartState.overviewUi) {
new OverviewToHomeAnim(mLauncher, () -> onSwipeInteractionCompleted(mEndState),
- FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
+ FeatureFlags.enableSplitContextually()
? mCancelSplitRunnable
: null)
.animateWithVelocity(velocity);
diff --git a/quickstep/src/com/android/quickstep/BaseActivityInterface.java b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
index 25389c5..88933f4 100644
--- a/quickstep/src/com/android/quickstep/BaseActivityInterface.java
+++ b/quickstep/src/com/android/quickstep/BaseActivityInterface.java
@@ -267,7 +267,7 @@
Resources res = context.getResources();
float maxScale = res.getFloat(R.dimen.overview_max_scale);
Rect gridRect = new Rect();
- calculateGridSize(dp, gridRect);
+ calculateGridSize(dp, context, gridRect);
calculateTaskSizeInternal(context, dp, gridRect, maxScale, Gravity.CENTER, outRect);
}
@@ -321,10 +321,16 @@
/**
* Calculates the overview grid size for the provided device configuration.
*/
- public final void calculateGridSize(DeviceProfile dp, Rect outRect) {
+ public final void calculateGridSize(DeviceProfile dp, Context context, Rect outRect) {
Rect insets = dp.getInsets();
int topMargin = dp.overviewTaskThumbnailTopMarginPx;
int bottomMargin = dp.getOverviewActionsClaimedSpace();
+ if (dp.isTaskbarPresent && Flags.enableGridOnlyOverview()) {
+ topMargin += context.getResources().getDimensionPixelSize(
+ R.dimen.overview_top_margin_grid_only);
+ bottomMargin += context.getResources().getDimensionPixelSize(
+ R.dimen.overview_bottom_margin_grid_only);
+ }
int sideMargin = dp.overviewGridSideMargin;
outRect.set(0, 0, dp.widthPx, dp.heightPx);
@@ -340,7 +346,7 @@
Resources res = context.getResources();
Rect potentialTaskRect = new Rect();
if (Flags.enableGridOnlyOverview()) {
- calculateGridSize(dp, potentialTaskRect);
+ calculateGridSize(dp, context, potentialTaskRect);
} else {
calculateFocusTaskSize(context, dp, potentialTaskRect);
}
diff --git a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
index 3fdc7ba..8d26fd4 100644
--- a/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
+++ b/quickstep/src/com/android/quickstep/RecentsAnimationDeviceState.java
@@ -19,6 +19,7 @@
import static android.app.WindowConfiguration.WINDOWING_MODE_PINNED;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
import static com.android.launcher3.util.DisplayController.CHANGE_ALL;
import static com.android.launcher3.util.DisplayController.CHANGE_NAVIGATION_MODE;
import static com.android.launcher3.util.DisplayController.CHANGE_ROTATION;
@@ -60,6 +61,8 @@
import androidx.annotation.BinderThread;
import androidx.annotation.NonNull;
+import com.android.launcher3.LauncherPrefs;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.DisplayInfoChangeListener;
import com.android.launcher3.util.DisplayController.Info;
@@ -86,8 +89,8 @@
static final String SUPPORT_ONE_HANDED_MODE = "ro.support_one_handed_mode";
// TODO: Move to quickstep contract
- private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 9;
- private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 2;
+ private static final float QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON = 3f;
+ private static final float QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL = 1.414f;
private final Context mContext;
private final DisplayController mDisplayController;
@@ -546,15 +549,31 @@
/**
* Returns the touch slop for {@link InputConsumer}s to compare against before pilfering
- * pointers. Note that this is squared because it expects to be compared against
- * {@link com.android.launcher3.Utilities#squaredHypot} (to avoid square root on each event).
+ * pointers.
*/
- public float getSquaredTouchSlop() {
+ public float getTouchSlop() {
float slopMultiplier = isFullyGesturalNavMode()
? QUICKSTEP_TOUCH_SLOP_RATIO_GESTURAL
: QUICKSTEP_TOUCH_SLOP_RATIO_TWO_BUTTON;
float touchSlop = ViewConfiguration.get(mContext).getScaledTouchSlop();
- return slopMultiplier * touchSlop * touchSlop;
+
+ if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
+ float customSlopMultiplier =
+ LauncherPrefs.get(mContext).get(LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE) / 100f;
+ return customSlopMultiplier * slopMultiplier * touchSlop;
+ } else {
+ return slopMultiplier * touchSlop;
+ }
+ }
+
+ /**
+ * Returns the squared touch slop for {@link InputConsumer}s to compare against before pilfering
+ * pointers. Note that this is squared because it expects to be compared against
+ * {@link com.android.launcher3.Utilities#squaredHypot} (to avoid square root on each event).
+ */
+ public float getSquaredTouchSlop() {
+ float touchSlop = getTouchSlop();
+ return touchSlop * touchSlop;
}
public String getSystemUiStateString() {
diff --git a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
index cf74b7d..312cdc9 100644
--- a/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
+++ b/quickstep/src/com/android/quickstep/TaskOverlayFactory.java
@@ -190,11 +190,11 @@
*/
public void endLiveTileMode(@NonNull Runnable callback) {
RecentsView recentsView = mThumbnailView.getTaskView().getRecentsView();
- if (recentsView != null) {
- recentsView.switchToScreenshot(
- () -> recentsView.finishRecentsAnimation(true /* toRecents */,
- false /* shouldPip */, callback));
- }
+ // Task has already been dismissed
+ if (recentsView == null) return;
+ recentsView.switchToScreenshot(
+ () -> recentsView.finishRecentsAnimation(true /* toRecents */,
+ false /* shouldPip */, callback));
}
/**
@@ -212,6 +212,8 @@
private void enterSplitSelect() {
RecentsView overviewPanel = mThumbnailView.getTaskView().getRecentsView();
+ // Task has already been dismissed
+ if (overviewPanel == null) return;
overviewPanel.initiateSplitSelect(mThumbnailView.getTaskView());
}
diff --git a/quickstep/src/com/android/quickstep/TouchInteractionService.java b/quickstep/src/com/android/quickstep/TouchInteractionService.java
index b2f04b8..98a9938 100644
--- a/quickstep/src/com/android/quickstep/TouchInteractionService.java
+++ b/quickstep/src/com/android/quickstep/TouchInteractionService.java
@@ -963,7 +963,8 @@
.append(SUBSTRING_PREFIX)
.append("Long press nav handle enabled, ")
.append("using NavHandleLongPressInputConsumer");
- base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat);
+ base = new NavHandleLongPressInputConsumer(this, base, mInputMonitorCompat,
+ mDeviceState);
}
if (mDeviceState.isBubblesExpanded()) {
diff --git a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
index 059b0ce..95ce406 100644
--- a/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
+++ b/quickstep/src/com/android/quickstep/fallback/FallbackRecentsView.java
@@ -254,7 +254,7 @@
setOverviewSelectEnabled(false);
}
if (finalState != OVERVIEW_SPLIT_SELECT) {
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.resetState();
} else {
resetFromSplitSelectionState();
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
index f11e537..32f7bd5 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/NavHandleLongPressInputConsumer.java
@@ -15,7 +15,6 @@
*/
package com.android.quickstep.inputconsumers;
-import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE;
import static com.android.launcher3.LauncherPrefs.LONG_PRESS_NAV_HANDLE_TIMEOUT_MS;
import static com.android.launcher3.util.Executors.MAIN_EXECUTOR;
@@ -28,6 +27,7 @@
import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.util.DisplayController;
import com.android.quickstep.InputConsumer;
+import com.android.quickstep.RecentsAnimationDeviceState;
import com.android.systemui.shared.system.InputMonitorCompat;
/**
@@ -47,23 +47,18 @@
private MotionEvent mCurrentDownEvent;
public NavHandleLongPressInputConsumer(Context context, InputConsumer delegate,
- InputMonitorCompat inputMonitor) {
+ InputMonitorCompat inputMonitor, RecentsAnimationDeviceState deviceState) {
super(delegate, inputMonitor);
mViewConfiguration = ViewConfiguration.get(context);
mNavHandleWidth = context.getResources().getDimensionPixelSize(
R.dimen.navigation_home_handle_width);
mScreenWidth = DisplayController.INSTANCE.get(context).getInfo().currentSize.x;
- float touchSlop;
if (FeatureFlags.CUSTOM_LPNH_THRESHOLDS.get()) {
- float customSlopMultiplier =
- LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE) / 100f;
- touchSlop = mViewConfiguration.getScaledEdgeSlop() * customSlopMultiplier;
mLongPressTimeout = LauncherPrefs.get(context).get(LONG_PRESS_NAV_HANDLE_TIMEOUT_MS);
} else {
- touchSlop = mViewConfiguration.getScaledTouchSlop();
mLongPressTimeout = ViewConfiguration.getLongPressTimeout();
}
- mTouchSlopSquared = touchSlop * touchSlop;
+ mTouchSlopSquared = deviceState.getSquaredTouchSlop();
mNavHandleLongPressHandler = NavHandleLongPressHandler.newInstance(context);
}
@@ -87,17 +82,14 @@
}
}
case MotionEvent.ACTION_MOVE -> {
+ if (!MAIN_EXECUTOR.getHandler().hasCallbacks(mTriggerLongPress)) {
+ break;
+ }
+
float touchSlopSquared = mTouchSlopSquared;
float dx = ev.getX() - mCurrentDownEvent.getX();
float dy = ev.getY() - mCurrentDownEvent.getY();
double distanceSquared = (dx * dx) + (dy * dy);
- // If the gesture is ambiguous then require more movement before classifying this
- // as a NON long press gesture.
- if (ev.getClassification() == MotionEvent.CLASSIFICATION_AMBIGUOUS_GESTURE) {
- float ambiguousGestureMultiplier =
- mViewConfiguration.getScaledAmbiguousGestureMultiplier();
- touchSlopSquared *= ambiguousGestureMultiplier * ambiguousGestureMultiplier;
- }
if (distanceSquared > touchSlopSquared) {
cancelLongPress();
}
diff --git a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
index 28c00eb..e724547 100644
--- a/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
+++ b/quickstep/src/com/android/quickstep/inputconsumers/OtherActivityInputConsumer.java
@@ -40,7 +40,6 @@
import android.util.Log;
import android.view.MotionEvent;
import android.view.VelocityTracker;
-import android.view.ViewConfiguration;
import androidx.annotation.UiThread;
@@ -154,7 +153,7 @@
boolean continuingPreviousGesture = mTaskAnimationManager.isRecentsAnimationRunning();
mIsDeferredDownTarget = !continuingPreviousGesture && isDeferredDownTarget;
- mTouchSlop = ViewConfiguration.get(this).getScaledTouchSlop();
+ mTouchSlop = mDeviceState.getTouchSlop();
mSquaredTouchSlop = mDeviceState.getSquaredTouchSlop();
mPassedPilferInputSlop = mPassedWindowMoveSlop = continuingPreviousGesture;
diff --git a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
index ae497f0..6ee65d4 100644
--- a/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
+++ b/quickstep/src/com/android/quickstep/util/SplitAnimationController.kt
@@ -300,7 +300,7 @@
pendingAnimation.addEndListener {
splitSelectStateController.launchInitialAppFullscreen {
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
splitSelectStateController.resetState()
} else if (resetCallback.isPresent) {
resetCallback.get().run()
diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
index 8e3b5ec..c873152 100644
--- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java
@@ -152,8 +152,7 @@
private final BackPressHandler mSplitBackHandler = new BackPressHandler() {
@Override
public boolean canHandleBack() {
- return FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() &&
- isSplitSelectActive();
+ return FeatureFlags.enableSplitContextually() && isSplitSelectActive();
}
@Override
@@ -711,7 +710,7 @@
/**
* To be called whenever we exit split selection state. If
- * {@link FeatureFlags#ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE} is set, this should be the
+ * {@link FeatureFlags#enableSplitContextually()} is set, this should be the
* central way split is getting reset, which should then go through the callbacks to reset
* other state.
*/
diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
index 00b5621..1b80388 100644
--- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
+++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java
@@ -17,7 +17,6 @@
package com.android.quickstep.util;
import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS;
-import static com.android.launcher3.config.FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import android.animation.Animator;
@@ -40,6 +39,7 @@
import com.android.launcher3.LauncherAppState;
import com.android.launcher3.R;
import com.android.launcher3.anim.PendingAnimation;
+import com.android.launcher3.config.FeatureFlags;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.IconCache;
import com.android.launcher3.model.data.PackageItemInfo;
@@ -192,7 +192,7 @@
private boolean shouldIgnoreSecondSplitLaunch() {
return (!ENABLE_SPLIT_FROM_FULLSCREEN_WITH_KEYBOARD_SHORTCUTS.get()
- && !ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()
+ && !FeatureFlags.enableSplitContextually()
&& !DesktopTaskView.DESKTOP_MODE_SUPPORTED)
|| !mController.isSplitSelectActive();
}
diff --git a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
index fb9e640..7ff2de9 100644
--- a/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/LauncherRecentsView.java
@@ -87,7 +87,7 @@
StateManager stateManager = mActivity.getStateManager();
animated &= stateManager.shouldAnimateStateChange();
stateManager.goToState(NORMAL, animated);
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.getSplitAnimationController()
.playPlaceholderDismissAnim(mActivity);
}
@@ -232,7 +232,7 @@
@Override
protected boolean canLaunchFullscreenTask() {
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
return !mSplitSelectStateController.isSplitSelectActive();
} else {
return !mActivity.isInState(OVERVIEW_SPLIT_SELECT);
diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java
index 0a195c3..b3d8da7 100644
--- a/quickstep/src/com/android/quickstep/views/RecentsView.java
+++ b/quickstep/src/com/android/quickstep/views/RecentsView.java
@@ -1087,7 +1087,7 @@
mIPipAnimationListener);
mOrientationState.initListeners();
mTaskOverlayFactory.initListeners();
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.registerSplitListener(mSplitSelectionListener);
}
}
@@ -1108,7 +1108,7 @@
mIPipAnimationListener.setActivityAndRecentsView(null, null);
mOrientationState.destroyListeners();
mTaskOverlayFactory.removeListeners();
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.unregisterSplitListener(mSplitSelectionListener);
}
}
@@ -2064,7 +2064,7 @@
dp.widthPx - mInsets.right - mTempRect.right,
dp.heightPx - mInsets.bottom - mTempRect.bottom);
- mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(),
+ mSizeStrategy.calculateGridSize(mActivity.getDeviceProfile(), mActivity,
mLastComputedGridSize);
mSizeStrategy.calculateGridTaskSize(mActivity, mActivity.getDeviceProfile(),
mLastComputedGridTaskSize, mOrientationHandler);
@@ -2418,7 +2418,7 @@
remoteTargetHandle.getTransformParams().setTargetSet(null);
remoteTargetHandle.getTaskViewSimulator().setDrawsBelowRecents(false);
});
- if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (!FeatureFlags.enableSplitContextually()) {
resetFromSplitSelectionState();
}
@@ -3307,7 +3307,7 @@
InteractionJankMonitorWrapper.CUJ_SPLIT_SCREEN_ENTER);
} else {
// If transition to split select was interrupted, clean up to prevent glitches
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.resetState();
} else {
resetFromSplitSelectionState();
@@ -4760,7 +4760,7 @@
pendingAnimation.addEndListener(aBoolean -> {
mSplitSelectStateController.launchSplitTasks(
aBoolean1 -> {
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
mSplitSelectStateController.resetState();
} else {
resetFromSplitSelectionState();
@@ -4789,7 +4789,7 @@
@SuppressLint("WrongCall")
protected void resetFromSplitSelectionState() {
if (mSplitSelectSource != null || mSplitHiddenTaskViewIndex != -1 ||
- FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ FeatureFlags.enableSplitContextually()) {
safeRemoveDragLayerView(mSplitSelectStateController.getFirstFloatingTaskView());
safeRemoveDragLayerView(mSecondFloatingTaskView);
safeRemoveDragLayerView(mSplitSelectStateController.getSplitInstructionsView());
@@ -4809,7 +4809,7 @@
setTaskViewsPrimarySplitTranslation(0);
setTaskViewsSecondarySplitTranslation(0);
- if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (!FeatureFlags.enableSplitContextually()) {
// When flag is on, this method gets called from resetState() call below, let's avoid
// infinite recursion today
mSplitSelectStateController.resetState();
diff --git a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
index 4ca02e0..e8f06ee 100644
--- a/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
+++ b/quickstep/src/com/android/quickstep/views/SplitInstructionsView.java
@@ -99,7 +99,7 @@
private void init() {
mTextView = findViewById(R.id.split_instructions_text);
- if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (!FeatureFlags.enableSplitContextually()) {
mTextView.setCompoundDrawables(null, null, null, null);
return;
}
@@ -138,7 +138,7 @@
@Override
public void onInitializeAccessibilityNodeInfo(AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(info);
- if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (!FeatureFlags.enableSplitContextually()) {
return;
}
@@ -150,7 +150,7 @@
@Override
public boolean performAccessibilityAction(int action, Bundle arguments) {
- if (!FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (!FeatureFlags.enableSplitContextually()) {
return super.performAccessibilityAction(action, arguments);
}
diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java
index beb10ef..fec17b4 100644
--- a/quickstep/src/com/android/quickstep/views/TaskView.java
+++ b/quickstep/src/com/android/quickstep/views/TaskView.java
@@ -1677,6 +1677,7 @@
return super.performAccessibilityAction(action, arguments);
}
+ @Nullable
public RecentsView getRecentsView() {
return (RecentsView) getParent();
}
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/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
index eba3252..f6368b0 100644
--- a/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
+++ b/quickstep/tests/src/com/android/quickstep/TaplOverviewIconTest.java
@@ -82,7 +82,7 @@
taskMenu.touchOutsideTaskMenuToDismiss();
OverviewTaskMenu splitMenu =
- mLauncher.getOverview().getCurrentTask().tapSplitTaskMenu();
+ mLauncher.goHome().switchToOverview().getCurrentTask().tapSplitTaskMenu();
assertTrue("App info item not appearing in expanded split task's menu.",
splitMenu.hasMenuItem("App info"));
splitMenu.touchOutsideTaskMenuToDismiss();
diff --git a/res/values/config.xml b/res/values/config.xml
index cd9c9de..4b15a6b 100644
--- a/res/values/config.xml
+++ b/res/values/config.xml
@@ -242,6 +242,8 @@
<item>@dimen/iconSize72dp</item>
</integer-array>
+ <dimen name="minimum_icon_label_size">8sp</dimen>
+
<!-- Used for custom widgets -->
<array name="custom_widget_providers"/>
</resources>
diff --git a/res/values/dimens.xml b/res/values/dimens.xml
index e532dad..81c2337 100644
--- a/res/values/dimens.xml
+++ b/res/values/dimens.xml
@@ -412,6 +412,9 @@
<dimen name="overview_grid_side_margin">0dp</dimen>
<dimen name="overview_grid_row_spacing">0dp</dimen>
<dimen name="overview_page_spacing">0dp</dimen>
+ <dimen name="overview_top_margin_grid_only">0dp</dimen>
+ <dimen name="overview_bottom_margin_grid_only">0dp</dimen>
+
<dimen name="split_placeholder_size">72dp</dimen>
<dimen name="split_placeholder_inset">16dp</dimen>
<dimen name="split_placeholder_icon_size">44dp</dimen>
@@ -423,7 +426,7 @@
<dimen name="split_instructions_drawable_padding">10dp</dimen>
<dimen name="split_instructions_bottom_margin_phone_landscape">24dp</dimen>
<dimen name="split_instructions_bottom_margin_phone_portrait">60dp</dimen>
-
+
<!-- Workspace grid visualization parameters -->
<dimen name="grid_visualization_rounding_radius">28dp</dimen>
<dimen name="grid_visualization_horizontal_cell_spacing">6dp</dimen>
diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java
index 2ac6098..bdffe46 100644
--- a/src/com/android/launcher3/DeviceProfile.java
+++ b/src/com/android/launcher3/DeviceProfile.java
@@ -63,6 +63,7 @@
import com.android.launcher3.responsive.HotseatSpecs;
import com.android.launcher3.responsive.WorkspaceSpecs;
import com.android.launcher3.uioverrides.ApiWrapper;
+import com.android.launcher3.util.CellContentDimensions;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.DisplayController.Info;
import com.android.launcher3.util.IconSizeSteps;
@@ -299,6 +300,7 @@
public final int stashedTaskbarHeight;
public final int taskbarBottomMargin;
public final int taskbarIconSize;
+ private final int mTransientTaskbarClaimedSpace;
// If true, used to layout taskbar in 3 button navigation mode.
public final boolean startAlignTaskbar;
public final boolean isTransientTaskbar;
@@ -370,18 +372,23 @@
}
this.isTransientTaskbar = isTransientTaskbar;
+ int transientTaskbarIconSize = pxFromDp(inv.transientTaskbarIconSize[mTypeIndex], mMetrics);
+ int transientTaskbarBottomMargin =
+ res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
+ int transientTaskbarHeight =
+ Math.round((transientTaskbarIconSize * ICON_VISIBLE_AREA_FACTOR)
+ + (2 * res.getDimensionPixelSize(R.dimen.transient_taskbar_padding)));
+ mTransientTaskbarClaimedSpace = transientTaskbarHeight + 2 * transientTaskbarBottomMargin;
+
if (!isTaskbarPresent) {
taskbarIconSize = taskbarHeight = stashedTaskbarHeight = taskbarBottomMargin = 0;
startAlignTaskbar = false;
} else if (isTransientTaskbar) {
- float invTransientIconSizeDp = inv.transientTaskbarIconSize[mTypeIndex];
- taskbarIconSize = pxFromDp(invTransientIconSizeDp, mMetrics);
- taskbarHeight = Math.round((taskbarIconSize * ICON_VISIBLE_AREA_FACTOR)
- + (2 * res.getDimensionPixelSize(R.dimen.transient_taskbar_padding)));
+ taskbarIconSize = transientTaskbarIconSize;
+ taskbarHeight = transientTaskbarHeight;
stashedTaskbarHeight =
res.getDimensionPixelSize(R.dimen.transient_taskbar_stashed_height);
- taskbarBottomMargin =
- res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin);
+ taskbarBottomMargin = transientTaskbarBottomMargin;
startAlignTaskbar = false;
} else {
taskbarIconSize = pxFromDp(ResourcesCompat.getFloat(res, R.dimen.taskbar_icon_size),
@@ -924,14 +931,11 @@
- iconTextHeight;
if (mIsResponsiveGrid) {
- // Hide text only if doesn't fit inside the cell for responsive grid
- if (workspaceCellPaddingY < 0) {
- iconTextSizePx = 0;
- iconDrawablePaddingPx = 0;
- int iconSizeWithOverlap = getIconSizeWithOverlap(iconSizePx);
- cellYPaddingPx = Math.max(0, getCellSize().y - iconSizeWithOverlap) / 2;
- autoResizeAllAppsCells();
- }
+ iconTextSizePx = 0;
+ iconDrawablePaddingPx = 0;
+ int iconSizeWithOverlap = getIconSizeWithOverlap(iconSizePx);
+ cellYPaddingPx = Math.max(0, getCellSize().y - iconSizeWithOverlap) / 2;
+ autoResizeAllAppsCells();
return;
}
@@ -1047,22 +1051,23 @@
iconSizePx = mIconSizeSteps.getIconSmallerThan(cellWidthPx);
}
- // TODO(b/296400197): isVerticalBar shouldn't show labels anymore
iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
- int iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx);
- int cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
- while (iconSizePx > mIconSizeSteps.minimumIconSize()
- && cellContentHeight > cellHeightPx) {
- iconDrawablePaddingPx -= cellContentHeight - cellHeightPx;
- if (iconDrawablePaddingPx < 0) {
- // get a smaller icon size
- iconSizePx = mIconSizeSteps.getNextLowerIconSize(iconSizePx);
- iconDrawablePaddingPx = getNormalizedIconDrawablePadding();
+ CellContentDimensions cellContentDimensions = new CellContentDimensions(iconSizePx,
+ iconDrawablePaddingPx,
+ iconTextSizePx);
+ if (isVerticalLayout) {
+ if (cellHeightPx < iconSizePx) {
+ cellContentDimensions.setIconSizePx(
+ mIconSizeSteps.getIconSmallerThan(cellHeightPx));
}
- // calculate new cellContentHeight
- cellContentHeight = iconSizePx + iconDrawablePaddingPx + iconTextHeight;
+ } else {
+ cellContentDimensions.resizeToFitCellHeight(cellHeightPx, mIconSizeSteps);
}
+ iconSizePx = cellContentDimensions.getIconSizePx();
+ iconDrawablePaddingPx = cellContentDimensions.getIconDrawablePaddingPx();
+ iconTextSizePx = cellContentDimensions.getIconTextSizePx();
+ int cellContentHeight = cellContentDimensions.getCellContentHeight();
cellYPaddingPx = Math.max(0, cellHeightPx - cellContentHeight) / 2;
} else if (mIsScalableGrid) {
@@ -1760,14 +1765,9 @@
return getHotseatBarBottomPadding() + launcherIconBottomSpace - taskbarIconBottomSpace;
}
- /**
- * Returns the number of pixels required below OverviewActions excluding insets.
- */
+ /** Returns the number of pixels required below OverviewActions. */
public int getOverviewActionsClaimedSpaceBelow() {
- if (isTaskbarPresent) {
- return taskbarHeight + taskbarBottomMargin * 2;
- }
- return mInsets.bottom;
+ return isTaskbarPresent ? mTransientTaskbarClaimedSpace : mInsets.bottom;
}
/** Gets the space that the overview actions will take, including bottom margin. */
diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java
index c0520c1..9255ff4 100644
--- a/src/com/android/launcher3/Launcher.java
+++ b/src/com/android/launcher3/Launcher.java
@@ -1578,7 +1578,7 @@
}
}
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get()) {
+ if (FeatureFlags.enableSplitContextually()) {
handleSplitAnimationGoingToHome();
}
mOverlayManager.hideOverlay(isStarted() && !isForceInvisible());
diff --git a/src/com/android/launcher3/LauncherPrefs.kt b/src/com/android/launcher3/LauncherPrefs.kt
index c6a9283..4f8caab 100644
--- a/src/com/android/launcher3/LauncherPrefs.kt
+++ b/src/com/android/launcher3/LauncherPrefs.kt
@@ -20,11 +20,12 @@
import android.content.SharedPreferences
import android.content.SharedPreferences.OnSharedPreferenceChangeListener
import android.util.Log
-import android.view.ViewConfiguration
import androidx.annotation.VisibleForTesting
import com.android.launcher3.BuildConfig.WIDGET_ON_FIRST_SCREEN
import com.android.launcher3.LauncherFiles.DEVICE_PREFERENCES_KEY
import com.android.launcher3.LauncherFiles.SHARED_PREFERENCES_KEY
+import com.android.launcher3.config.FeatureFlags.LPNH_SLOP_PERCENTAGE
+import com.android.launcher3.config.FeatureFlags.LPNH_TIMEOUT_MS
import com.android.launcher3.model.DeviceGridState
import com.android.launcher3.pm.InstallSessionHelper
import com.android.launcher3.provider.RestoreDbTask
@@ -310,16 +311,16 @@
)
@JvmField
val LONG_PRESS_NAV_HANDLE_SLOP_PERCENTAGE =
- nonRestorableItem(
- "pref_long_press_nav_handle_slop_multiplier",
- 100,
+ nonRestorableItem(
+ "pref_long_press_nav_handle_slop_percentage",
+ LPNH_SLOP_PERCENTAGE.get(),
EncryptionType.MOVE_TO_DEVICE_PROTECTED
- )
+ )
@JvmField
val LONG_PRESS_NAV_HANDLE_TIMEOUT_MS =
nonRestorableItem(
"pref_long_press_nav_handle_timeout_ms",
- ViewConfiguration.getLongPressTimeout(),
+ LPNH_TIMEOUT_MS.get(),
EncryptionType.MOVE_TO_DEVICE_PROTECTED
)
@JvmField
diff --git a/src/com/android/launcher3/config/FeatureFlags.java b/src/com/android/launcher3/config/FeatureFlags.java
index 9c0a508..c0d0662 100644
--- a/src/com/android/launcher3/config/FeatureFlags.java
+++ b/src/com/android/launcher3/config/FeatureFlags.java
@@ -21,8 +21,11 @@
import static com.android.launcher3.config.FeatureFlags.FlagState.ENABLED;
import static com.android.launcher3.config.FeatureFlags.FlagState.TEAMFOOD;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getDebugFlag;
+import static com.android.launcher3.uioverrides.flags.FlagsFactory.getIntFlag;
import static com.android.launcher3.uioverrides.flags.FlagsFactory.getReleaseFlag;
+import android.view.ViewConfiguration;
+
import androidx.annotation.VisibleForTesting;
import com.android.launcher3.BuildConfig;
@@ -113,9 +116,17 @@
"Allow entering All Apps from Overview (e.g. long swipe up from app)");
public static final BooleanFlag CUSTOM_LPNH_THRESHOLDS =
- getDebugFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
+ getReleaseFlag(301680992, "CUSTOM_LPNH_THRESHOLDS", DISABLED,
"Add dev options to customize the LPNH trigger slop and milliseconds");
+ public static final IntFlag LPNH_SLOP_PERCENTAGE =
+ getIntFlag(301680992, "LPNH_SLOP_PERCENTAGE", 100,
+ "Controls touch slop percentage for lpnh");
+
+ public static final IntFlag LPNH_TIMEOUT_MS =
+ getIntFlag(301680992, "LPNH_TIMEOUT_MS", ViewConfiguration.getLongPressTimeout(),
+ "Controls lpnh timeout in milliseconds");
+
public static final BooleanFlag ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS = getReleaseFlag(
270394468, "ENABLE_SHOW_KEYBOARD_OPTION_IN_ALL_APPS", ENABLED,
"Enable option to show keyboard when going to all-apps");
@@ -202,9 +213,13 @@
public static final BooleanFlag ENABLE_TRANSIENT_TASKBAR = getDebugFlag(270395798,
"ENABLE_TRANSIENT_TASKBAR", ENABLED, "Enables transient taskbar.");
+ // Aconfig migration complete for ENABLE_TASKBAR_NO_RECREATION.
public static final BooleanFlag ENABLE_TASKBAR_NO_RECREATION = getDebugFlag(299193589,
"ENABLE_TASKBAR_NO_RECREATION", DISABLED,
"Enables taskbar with no recreation from lifecycle changes of TaskbarActivityContext.");
+ public static boolean enableTaskbarNoRecreate() {
+ return ENABLE_TASKBAR_NO_RECREATION.get() || Flags.enableTaskbarNoRecreate();
+ }
// TODO(Block 16): Clean up flags
// When enabled the promise icon is visible in all apps while installation an app.
@@ -379,6 +394,10 @@
public static final BooleanFlag ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE = getDebugFlag(
270393453, "ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE", DISABLED,
"Enable initiating split screen from workspace to workspace.");
+ public static boolean enableSplitContextually() {
+ return ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() ||
+ com.android.wm.shell.Flags.enableSplitContextual();
+ }
public static final BooleanFlag ENABLE_TRACKPAD_GESTURE = getDebugFlag(271010401,
"ENABLE_TRACKPAD_GESTURE", ENABLED, "Enables trackpad gesture.");
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/touch/ItemLongClickListener.java b/src/com/android/launcher3/touch/ItemLongClickListener.java
index a09e5a4..0c322cc 100644
--- a/src/com/android/launcher3/touch/ItemLongClickListener.java
+++ b/src/com/android/launcher3/touch/ItemLongClickListener.java
@@ -138,8 +138,9 @@
// Return early if an item is already being dragged (e.g. when long-pressing two shortcuts)
if (launcher.getDragController().isDragging()) return false;
// Return early if user is in the middle of selecting split-screen apps
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() &&
- launcher.isSplitSelectionEnabled()) return false;
+ if (FeatureFlags.enableSplitContextually() && launcher.isSplitSelectionEnabled()) {
+ return false;
+ }
return true;
}
diff --git a/src/com/android/launcher3/touch/WorkspaceTouchListener.java b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
index 1232069..5b6c9e0 100644
--- a/src/com/android/launcher3/touch/WorkspaceTouchListener.java
+++ b/src/com/android/launcher3/touch/WorkspaceTouchListener.java
@@ -206,8 +206,7 @@
HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
mLauncher.getStatsLogManager().logger().log(LAUNCHER_WORKSPACE_LONGPRESS);
mLauncher.showDefaultOptions(mTouchDownPoint.x, mTouchDownPoint.y);
- if (FeatureFlags.ENABLE_SPLIT_FROM_WORKSPACE_TO_WORKSPACE.get() &&
- mLauncher.isSplitSelectionEnabled()) {
+ if (FeatureFlags.enableSplitContextually() && mLauncher.isSplitSelectionEnabled()) {
mLauncher.dismissSplitSelection();
}
} else {
diff --git a/src/com/android/launcher3/util/CellContentDimensions.kt b/src/com/android/launcher3/util/CellContentDimensions.kt
new file mode 100644
index 0000000..3c8e0c4
--- /dev/null
+++ b/src/com/android/launcher3/util/CellContentDimensions.kt
@@ -0,0 +1,69 @@
+/*
+ * 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.util
+
+import com.android.launcher3.Utilities
+import kotlin.math.max
+
+class CellContentDimensions(
+ var iconSizePx: Int,
+ var iconDrawablePaddingPx: Int,
+ var iconTextSizePx: Int
+) {
+ /**
+ * This method goes through some steps to reduce the padding between icon and label, icon size
+ * and then label size, until it can fit in the [cellHeightPx].
+ *
+ * @return the height of the content after being sized down.
+ */
+ fun resizeToFitCellHeight(cellHeightPx: Int, iconSizeSteps: IconSizeSteps): Int {
+ var cellContentHeight = getCellContentHeight()
+
+ // Step 1. Decrease drawable padding
+ if (cellContentHeight > cellHeightPx) {
+ val diff = cellContentHeight - cellHeightPx
+ iconDrawablePaddingPx = max(0, iconDrawablePaddingPx - diff)
+ cellContentHeight = getCellContentHeight()
+ }
+
+ while (
+ (iconTextSizePx > iconSizeSteps.minimumIconLabelSize ||
+ iconSizePx > iconSizeSteps.minimumIconSize()) && cellContentHeight > cellHeightPx
+ ) {
+ // Step 2. Decrease icon size
+ iconSizePx = iconSizeSteps.getNextLowerIconSize(iconSizePx)
+ cellContentHeight = getCellContentHeight()
+
+ // Step 3. Decrease label size
+ if (cellContentHeight > cellHeightPx) {
+ iconTextSizePx =
+ max(
+ iconSizeSteps.minimumIconLabelSize,
+ iconTextSizePx - IconSizeSteps.TEXT_STEP
+ )
+ cellContentHeight = getCellContentHeight()
+ }
+ }
+
+ return cellContentHeight
+ }
+
+ /** Calculate new cellContentHeight */
+ fun getCellContentHeight(): Int {
+ val iconTextHeight = Utilities.calculateTextHeight(iconTextSizePx.toFloat())
+ return iconSizePx + iconDrawablePaddingPx + iconTextHeight
+ }
+}
diff --git a/src/com/android/launcher3/util/IconSizeSteps.kt b/src/com/android/launcher3/util/IconSizeSteps.kt
index 2a5afe0..aa644b0 100644
--- a/src/com/android/launcher3/util/IconSizeSteps.kt
+++ b/src/com/android/launcher3/util/IconSizeSteps.kt
@@ -23,12 +23,14 @@
class IconSizeSteps(res: Resources) {
private val steps: List<Int>
+ val minimumIconLabelSize: Int
init {
steps =
res.obtainTypedArray(R.array.icon_size_steps).use {
(0 until it.length()).map { step -> it.getDimensionOrThrow(step).toInt() }.sorted()
}
+ minimumIconLabelSize = res.getDimensionPixelSize(R.dimen.minimum_icon_label_size)
}
fun minimumIconSize(): Int = steps[0]
@@ -44,4 +46,8 @@
private fun getIndexForIconSize(iconSizePx: Int): Int {
return max(0, steps.indexOfFirst { iconSizePx <= it })
}
+
+ companion object {
+ internal const val TEXT_STEP = 1
+ }
}
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;
diff --git a/tests/Android.bp b/tests/Android.bp
index a3d05bb..8725b46 100644
--- a/tests/Android.bp
+++ b/tests/Android.bp
@@ -40,19 +40,14 @@
"src/com/android/launcher3/ui/PortraitLandscapeRunner.java",
"src/com/android/launcher3/ui/TestViewHelpers.java",
"src/com/android/launcher3/util/LauncherLayoutBuilder.java",
+ "src/com/android/launcher3/util/ModelTestExtensions.kt",
"src/com/android/launcher3/util/TestConstants.java",
"src/com/android/launcher3/util/TestUtil.java",
"src/com/android/launcher3/util/Wait.java",
"src/com/android/launcher3/util/WidgetUtils.java",
- "src/com/android/launcher3/util/rule/FailureWatcher.java",
- "src/com/android/launcher3/util/rule/ViewCaptureRule.kt",
+ "src/com/android/launcher3/util/rule/*.java",
+ "src/com/android/launcher3/util/rule/*.kt",
"src/com/android/launcher3/util/viewcapture_analysis/*.java",
- "src/com/android/launcher3/util/rule/SamplerRule.java",
- "src/com/android/launcher3/util/rule/ScreenRecordRule.java",
- "src/com/android/launcher3/util/rule/ShellCommandRule.java",
- "src/com/android/launcher3/util/rule/TestIsolationRule.java",
- "src/com/android/launcher3/util/rule/TestStabilityRule.java",
- "src/com/android/launcher3/util/ModelTestExtensions.kt",
"src/com/android/launcher3/testcomponent/*.java",
"src/com/android/launcher3/testcomponent/*.kt",
],
diff --git a/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt b/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
new file mode 100644
index 0000000..4770546
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/CellContentDimensionsTest.kt
@@ -0,0 +1,148 @@
+/*
+ * 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.util
+
+import android.content.Context
+import android.content.res.Configuration
+import android.util.DisplayMetrics
+import androidx.test.core.app.ApplicationProvider
+import androidx.test.ext.junit.runners.AndroidJUnit4
+import androidx.test.filters.SmallTest
+import com.google.common.truth.Truth.assertThat
+import org.junit.Before
+import org.junit.Test
+import org.junit.runner.RunWith
+
+@SmallTest
+@RunWith(AndroidJUnit4::class)
+class CellContentDimensionsTest {
+ private var context: Context? = null
+ private val runningContext: Context = ApplicationProvider.getApplicationContext()
+ private lateinit var iconSizeSteps: IconSizeSteps
+
+ @Before
+ fun setup() {
+ // 160dp makes 1px = 1dp
+ val config =
+ Configuration(runningContext.resources.configuration).apply {
+ this.densityDpi = DisplayMetrics.DENSITY_DEFAULT
+ }
+ context = runningContext.createConfigurationContext(config)
+ iconSizeSteps = IconSizeSteps(context!!.resources)
+ }
+
+ @Test
+ fun dimensionsFitTheCell() {
+ val cellSize = Pair(80, 104)
+ val cellContentDimensions =
+ CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+ val contentHeight =
+ cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+ assertThat(contentHeight).isEqualTo(93)
+ cellContentDimensions.run {
+ assertThat(iconSizePx).isEqualTo(66)
+ assertThat(iconDrawablePaddingPx).isEqualTo(8)
+ assertThat(iconTextSizePx).isEqualTo(14)
+ }
+ }
+
+ @Test
+ fun decreasePadding() {
+ val cellSize = Pair(67, 87)
+ val cellContentDimensions =
+ CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+ val contentHeight =
+ cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+ assertThat(contentHeight).isEqualTo(87)
+ cellContentDimensions.run {
+ assertThat(iconSizePx).isEqualTo(66)
+ assertThat(iconDrawablePaddingPx).isEqualTo(2)
+ assertThat(iconTextSizePx).isEqualTo(14)
+ }
+ }
+
+ @Test
+ fun decreaseIcon() {
+ val cellSize = Pair(65, 84)
+ val cellContentDimensions =
+ CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+ val contentHeight =
+ cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+ assertThat(contentHeight).isEqualTo(82)
+ cellContentDimensions.run {
+ assertThat(iconSizePx).isEqualTo(63)
+ assertThat(iconDrawablePaddingPx).isEqualTo(0)
+ assertThat(iconTextSizePx).isEqualTo(14)
+ }
+ }
+
+ @Test
+ fun decreaseText() {
+ val cellSize = Pair(63, 81)
+ val cellContentDimensions =
+ CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+ val contentHeight =
+ cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+ assertThat(contentHeight).isEqualTo(81)
+ cellContentDimensions.run {
+ assertThat(iconSizePx).isEqualTo(63)
+ assertThat(iconDrawablePaddingPx).isEqualTo(0)
+ assertThat(iconTextSizePx).isEqualTo(13)
+ }
+ }
+
+ @Test
+ fun decreaseIconAndTextTwoSteps() {
+ val cellSize = Pair(60, 78)
+ val cellContentDimensions =
+ CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+ val contentHeight =
+ cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+ assertThat(contentHeight).isEqualTo(77)
+ cellContentDimensions.run {
+ assertThat(iconSizePx).isEqualTo(61)
+ assertThat(iconDrawablePaddingPx).isEqualTo(0)
+ assertThat(iconTextSizePx).isEqualTo(12)
+ }
+ }
+
+ @Test
+ fun decreaseIconAndTextToMinimum() {
+ val cellSize = Pair(52, 63)
+ val cellContentDimensions =
+ CellContentDimensions(iconSizePx = 66, iconDrawablePaddingPx = 8, iconTextSizePx = 14)
+
+ val contentHeight =
+ cellContentDimensions.resizeToFitCellHeight(cellSize.second, iconSizeSteps)
+
+ assertThat(contentHeight).isEqualTo(63)
+ cellContentDimensions.run {
+ assertThat(iconSizePx).isEqualTo(52)
+ assertThat(iconDrawablePaddingPx).isEqualTo(0)
+ assertThat(iconTextSizePx).isEqualTo(8)
+ }
+ }
+}
diff --git a/tests/src/com/android/launcher3/util/rule/SetFlagsRuleExt.kt b/tests/src/com/android/launcher3/util/rule/SetFlagsRuleExt.kt
new file mode 100644
index 0000000..d682456
--- /dev/null
+++ b/tests/src/com/android/launcher3/util/rule/SetFlagsRuleExt.kt
@@ -0,0 +1,23 @@
+/*
+ * Copyright (C) 2008 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.util.rule
+
+import android.platform.test.flag.junit.SetFlagsRule
+
+fun SetFlagsRule.setFlags(enabled: Boolean, vararg flagName: String) {
+ if (enabled) enableFlags(*flagName) else disableFlags(*flagName)
+}
diff --git a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
index 25c73de..38cc321 100644
--- a/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
+++ b/tests/tapl/com/android/launcher3/tapl/OverviewTaskMenu.java
@@ -16,8 +16,6 @@
package com.android.launcher3.tapl;
-import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED;
-
import androidx.annotation.NonNull;
import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiObject2;
@@ -61,14 +59,8 @@
try (LauncherInstrumentation.Closable e = mLauncher.eventsCheck();
LauncherInstrumentation.Closable c = mLauncher.addContextLayer(
"before tapping the app info menu item")) {
-
- mLauncher.executeAndWaitForLauncherEvent(
- () -> mLauncher.clickLauncherObject(
- mLauncher.findObjectInContainer(mMenu, By.text("App info"))),
- accessibilityEvent ->
- accessibilityEvent.getEventType() == TYPE_WINDOW_STATE_CHANGED,
- () -> "Unable to start Settings by clicking App Info",
- "Tap the app info menu item");
+ mLauncher.clickLauncherObject(
+ mLauncher.findObjectInContainer(mMenu, By.text("App info")));
try (LauncherInstrumentation.Closable c1 = mLauncher.addContextLayer(
"tapped app info menu item")) {