From dfb48214ea3fe54af38b568d471ff43c0e668be2 Mon Sep 17 00:00:00 2001 From: mpodolian Date: Fri, 13 Sep 2024 17:43:11 -0700 Subject: [PATCH] Update placement of the hotseat according to the bubble bar location. Update the hotseat and Qsb placement according to the 3 nav buttons bar. Test: Manual. Set navigation mode to 3 buttons. On launcher home screen move the bubble bar from one side to another. Observe that the Hotseat and Qsb moving together with the navigation bar. Once moved the bubble bar, expand the bubble bar and collapse it. Observe how the Hotseat is stashing and un-stashing. After bubble bar changes position hit the recent apps button, observe the transition. On launcher home screen start application with the hotseat icon and exit opened application. Observe that flying icon comes back to the correct position in the hotseat. Video with the above scenarios: http://recall/-/gx8ASgewUeUS3QYohfrd1J/blTYrKopTyufOcRoPuVpYK Bug: 346381754 Flag: com.android.wm.shell.enable_bubble_bar_in_persistent_task_bar Change-Id: Ic8c6acdffbbb111cbe4f3fd6bc60195578d7035d --- .../launcher3/QuickstepTransitionManager.java | 9 ++- .../taskbar/LauncherTaskbarUIController.java | 13 +++ .../taskbar/NavbarButtonsViewController.java | 13 ++- .../launcher3/taskbar/TaskbarControllers.java | 7 +- .../TaskbarLauncherStateController.java | 79 +++++++++++++++++++ .../taskbar/TaskbarStashController.java | 5 ++ .../taskbar/TaskbarUIController.java | 12 ++- .../taskbar/TaskbarViewController.java | 23 ++++-- .../taskbar/bubbles/BubbleBarController.java | 3 +- .../taskbar/bubbles/BubbleControllers.java | 5 +- .../BubbleBarLocationOnDemandListener.kt | 34 ++++++++ .../uioverrides/QuickstepLauncher.java | 35 +++++++- src/com/android/launcher3/DeviceProfile.java | 43 +++++++--- src/com/android/launcher3/Hotseat.java | 31 ++++++++ 14 files changed, 284 insertions(+), 28 deletions(-) create mode 100644 quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleBarLocationOnDemandListener.kt diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index a64936d287..4b43bd2c4d 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -1353,8 +1353,13 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener ? null : mLauncher.getTaskbarUIController().findMatchingView(launcherView), true /* hideOriginal */, targetRect, false /* isOpening */); - isInHotseat = launcherView.getTag() instanceof ItemInfo - && ((ItemInfo) launcherView.getTag()).isInHotseat(); + if (launcherView.getTag() instanceof ItemInfo itemInfo) { + isInHotseat = itemInfo.isInHotseat(); + if (isInHotseat) { + int dx = mLauncher.getHotseatItemTranslationX(itemInfo); + targetRect.offset(dx, 0); + } + } } else { targetRect.set(getDefaultWindowTargetRect()); } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 1bebfbdb9c..de7a2d8f9e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -51,6 +51,7 @@ import com.android.quickstep.util.GroupTask; import com.android.quickstep.util.TISBindHelper; import com.android.quickstep.views.RecentsView; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import java.io.PrintWriter; @@ -487,6 +488,18 @@ public class LauncherTaskbarUIController extends TaskbarUIController { return "LauncherTaskbarUIController"; } + @Override + public void onBubbleBarLocationAnimated(BubbleBarLocation location) { + mTaskbarLauncherStateController.onBubbleBarLocationChanged(location, /* animate = */ true); + mLauncher.setBubbleBarLocation(location); + } + + @Override + public void onBubbleBarLocationUpdated(BubbleBarLocation location) { + mTaskbarLauncherStateController.onBubbleBarLocationChanged(location, /* animate = */ false); + mLauncher.setBubbleBarLocation(location); + } + @Override public void onSwipeToUnstashTaskbar() { // Once taskbar is unstashed, the user cannot return back to the overlay. We can diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java index 2ac579361e..a4a93f7d56 100644 --- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java @@ -201,6 +201,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT private final Rect mFloatingRotationButtonBounds = new Rect(); + private @Nullable BubbleBarLocation mBubbleBarLocation; + // Initialized in init. private TaskbarControllers mControllers; private boolean mIsImeRenderingNavButtons; @@ -1174,6 +1176,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT /** Adjusts navigation buttons layout accordingly to the bubble bar position. */ @Override public void onBubbleBarLocationUpdated(BubbleBarLocation location) { + mBubbleBarLocation = location; mNavButtonContainer.setTranslationX(getNavBarTranslationX(location)); } @@ -1181,6 +1184,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT @Override public void onBubbleBarLocationAnimated(BubbleBarLocation location) { // TODO(b/346381754) add the teleport animation similarly to the bubble bar + mBubbleBarLocation = location; mNavButtonContainer.setTranslationX(getNavBarTranslationX(location)); } @@ -1221,9 +1225,12 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT public void onTaskbarLayoutChange() { if (com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar() && mControllers.bubbleControllers.isPresent()) { - BubbleBarLocation bubblesLocation = mControllers.bubbleControllers.get() - .bubbleBarViewController.getBubbleBarLocation(); - onBubbleBarLocationUpdated(bubblesLocation); + if (mBubbleBarLocation == null) { + // only set bubble bar location if it was not set before, e.g. at device boot + mBubbleBarLocation = mControllers.bubbleControllers.get() + .bubbleBarViewController.getBubbleBarLocation(); + } + onBubbleBarLocationUpdated(mBubbleBarLocation); } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java index 56fd2bb66d..59746751a5 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java @@ -26,6 +26,7 @@ import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController; import com.android.launcher3.taskbar.bubbles.BubbleControllers; import com.android.launcher3.taskbar.overlay.TaskbarOverlayController; import com.android.systemui.shared.rotation.RotationButtonController; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import java.io.PrintWriter; import java.util.ArrayList; @@ -219,7 +220,11 @@ public class TaskbarControllers { uiController = newUiController; uiController.init(this); uiController.updateStateForSysuiFlags(mSharedState.sysuiStateFlags); - + bubbleControllers.ifPresent(bubbleControllers -> { + BubbleBarLocation location = + bubbleControllers.bubbleBarViewController.getBubbleBarLocation(); + uiController.onBubbleBarLocationUpdated(location); + }); // Notify that the ui controller has changed navbarButtonsViewController.onUiControllerChanged(); } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index 876221b1d7..065646ad39 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -19,11 +19,14 @@ import static com.android.app.animation.Interpolators.EMPHASIZED; import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_ALIGNMENT; import static com.android.launcher3.Hotseat.ALPHA_CHANNEL_TASKBAR_STASH; import static com.android.launcher3.LauncherState.HOTSEAT_ICONS; +import static com.android.launcher3.Utilities.isRtl; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_APP; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_OVERVIEW; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_IN_STASHED_LAUNCHER_STATE; import static com.android.launcher3.taskbar.TaskbarStashController.FLAG_STASHED_FOR_BUBBLES; import static com.android.launcher3.taskbar.TaskbarViewController.ALPHA_INDEX_HOME; +import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_IN_ANIM_ALPHA_DURATION_MS; +import static com.android.launcher3.taskbar.bubbles.BubbleBarView.FADE_OUT_ANIM_POSITION_DURATION_MS; import static com.android.launcher3.util.FlagDebugUtils.appendFlag; import static com.android.launcher3.util.FlagDebugUtils.formatFlagChange; import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_AWAKE; @@ -42,8 +45,10 @@ import android.util.Log; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import com.android.app.animation.Interpolators; import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Hotseat; import com.android.launcher3.Hotseat.HotseatQsbAlphaId; import com.android.launcher3.LauncherState; import com.android.launcher3.QuickstepTransitionManager; @@ -62,6 +67,7 @@ import com.android.quickstep.views.RecentsView; import com.android.systemui.animation.ViewRootSync; import com.android.systemui.shared.recents.model.ThumbnailData; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import java.io.PrintWriter; import java.util.HashMap; @@ -151,6 +157,7 @@ public class TaskbarLauncherStateController { private AnimatedFloat mTaskbarAlpha; private AnimatedFloat mTaskbarCornerRoundness; private MultiProperty mTaskbarAlphaForHome; + private @Nullable Animator mHotseatTranslationXAnimation; private QuickstepLauncher mLauncher; private boolean mIsDestroyed = false; @@ -168,6 +175,8 @@ public class TaskbarLauncherStateController { private boolean mShouldDelayLauncherStateAnim; + private @Nullable BubbleBarLocation mBubbleBarLocation; + // We skip any view synchronizations during init/destroy. private boolean mCanSyncViews; @@ -185,6 +194,8 @@ public class TaskbarLauncherStateController { mIsQsbInline = dp.isQsbInline; TaskbarLauncherStateController.this.updateIconAlphaForHome( mTaskbarAlphaForHome.getValue(), ALPHA_CHANNEL_TASKBAR_ALIGNMENT); + TaskbarLauncherStateController.this.onBubbleBarLocationChanged( + mBubbleBarLocation, /* animate = */ false); } }; @@ -833,6 +844,74 @@ public class TaskbarLauncherStateController { } } + /** Updates launcher home screen appearance accordingly to the bubble bar location. */ + public void onBubbleBarLocationChanged(BubbleBarLocation location, boolean animate) { + DeviceProfile deviceProfile = mLauncher.getDeviceProfile(); + if (mBubbleBarLocation == location) return; + mBubbleBarLocation = location; + if (!deviceProfile.shouldAdjustHotseatOnBubblesLocationUpdate( + mControllers.taskbarActivityContext)) { + return; + } + int targetX = 0; + if (mBubbleBarLocation != null) { + boolean isBubblesOnLeft = location.isOnLeft(isRtl(mLauncher.getResources())); + targetX = deviceProfile.getHotseatTranslationXForBubbleBar(/* isNavbarOnRight= */ + isBubblesOnLeft); + } + updateHotseatAndQsbTranslationX(targetX, animate); + } + + private void updateHotseatAndQsbTranslationX(float targetValue, boolean animate) { + // cancel existing animation + if (mHotseatTranslationXAnimation != null) { + mHotseatTranslationXAnimation.cancel(); + } + Runnable alignTaskbar = new Runnable() { + @Override + public void run() { + // We only need to align the task bar when on launcher home screen + if (mControllers.taskbarStashController.isOnHome()) { + DeviceProfile dp = mLauncher.getDeviceProfile(); + mControllers.taskbarViewController + .setLauncherIconAlignment(/* alignmentRatio = */ 1, dp); + } + } + }; + Hotseat hotseat = mLauncher.getHotseat(); + AnimatorSet translationXAnimation = new AnimatorSet(); + MultiProperty iconsTranslationX = hotseat.getIconsTranslationX( + Hotseat.ICONS_TRANSLATION_X_NAV_BAR_ALIGNMENT); + if (animate) { + translationXAnimation.playTogether(iconsTranslationX.animateToValue(targetValue)); + } else { + iconsTranslationX.setValue(targetValue); + } + float qsbTargetX = 0; + if (mIsQsbInline) { + qsbTargetX = targetValue; + } + MultiProperty qsbTranslationX = hotseat.getQsbTranslationX(); + if (qsbTranslationX != null) { + if (animate) { + translationXAnimation.playTogether(qsbTranslationX.animateToValue(qsbTargetX)); + } else { + qsbTranslationX.setValue(qsbTargetX); + } + } + if (!animate) { + alignTaskbar.run(); + return; + } + mHotseatTranslationXAnimation = translationXAnimation; + translationXAnimation.setStartDelay(FADE_OUT_ANIM_POSITION_DURATION_MS); + translationXAnimation.setDuration(FADE_IN_ANIM_ALPHA_DURATION_MS); + translationXAnimation.setInterpolator(Interpolators.EMPHASIZED); + translationXAnimation.addListener(AnimatorListeners.forEndCallback(alignTaskbar)); + translationXAnimation.start(); + } + + private final class TaskBarRecentsAnimationListener implements RecentsAnimationCallbacks.RecentsAnimationListener { private final RecentsAnimationCallbacks mCallbacks; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 7624afb440..532ee1e5ca 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -446,6 +446,11 @@ public class TaskbarStashController implements TaskbarControllers.LoggableTaskba return hasAnyFlag(FLAG_IN_OVERVIEW); } + /** Returns whether the taskbar is currently on launcher home screen. */ + public boolean isOnHome() { + return !isInOverview() && !isInApp(); + } + /** Returns whether taskbar is hidden for bubbles. */ public boolean isHiddenForBubbles() { return hasAnyFlag(FLAG_STASHED_FOR_BUBBLES); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 9c8c2a9fda..b80aaf8840 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -36,6 +36,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.model.data.ItemInfo; import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.popup.SystemShortcut; +import com.android.launcher3.taskbar.bubbles.BubbleBarController; import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.SplitConfigurationOptions; import com.android.quickstep.OverviewCommandHelper; @@ -47,6 +48,7 @@ import com.android.quickstep.views.TaskContainer; import com.android.quickstep.views.TaskView; import com.android.systemui.shared.recents.model.Task; import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import java.io.PrintWriter; import java.util.Collections; @@ -55,7 +57,7 @@ import java.util.stream.Stream; /** * Base class for providing different taskbar UI */ -public class TaskbarUIController { +public class TaskbarUIController implements BubbleBarController.BubbleBarLocationListener { public static final TaskbarUIController DEFAULT = new TaskbarUIController(); // Initialized in init. @@ -433,6 +435,14 @@ public class TaskbarUIController { public void stashHotseat(boolean stash) { } + @Override + public void onBubbleBarLocationAnimated(BubbleBarLocation location) { + } + + @Override + public void onBubbleBarLocationUpdated(BubbleBarLocation location) { + } + /** Un-stash the hotseat instantly */ public void unStashHotseatInstantly() { } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index 0a67ac2f1d..1f3fdeb737 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -827,6 +827,14 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar : mPersistentTaskbarDp.taskbarBottomMargin; int firstRecentTaskIndex = -1; + int hotseatNavBarTranslationX = 0; + if (mCurrentBubbleBarLocation != null + && taskbarDp.shouldAdjustHotseatOnBubblesLocationUpdate(mActivity)) { + boolean isBubblesOnLeft = mCurrentBubbleBarLocation.isOnLeft( + mTaskbarView.isLayoutRtl()); + hotseatNavBarTranslationX = taskbarDp + .getHotseatTranslationXForBubbleBar(/* isNavbarOnRight = */ isBubblesOnLeft); + } for (int i = 0; i < mTaskbarView.getChildCount(); i++) { View child = mTaskbarView.getChildAt(i); boolean isAllAppsButton = child == mTaskbarView.getAllAppsButtonContainer(); @@ -860,16 +868,20 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar : Interpolators.clampToProgress(LINEAR, 0.72f, 0.84f)); } } - if (child == mTaskbarView.getQsb()) { boolean isRtl = Utilities.isRtl(child.getResources()); float hotseatIconCenter = isRtl ? launcherDp.widthPx - hotseatPadding.right + borderSpacing + launcherDp.hotseatQsbWidth / 2f : hotseatPadding.left - borderSpacing - launcherDp.hotseatQsbWidth / 2f; + if (taskbarDp.isQsbInline) { + hotseatIconCenter += hotseatNavBarTranslationX; + } float childCenter = (child.getLeft() + child.getRight()) / 2f; - childCenter += ((Reorderable) child).getTranslateDelegate().getTranslationX( - INDEX_TASKBAR_PINNING_ANIM).getValue(); + if (child instanceof Reorderable reorderableChild) { + childCenter += reorderableChild.getTranslateDelegate().getTranslationX( + INDEX_TASKBAR_PINNING_ANIM).getValue(); + } float halfQsbIconWidthDiff = (launcherDp.hotseatQsbWidth - taskbarDp.taskbarIconSize) / 2f; float scale = ((float) taskbarDp.taskbarIconSize) @@ -878,8 +890,8 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar float fromX = isRtl ? -halfQsbIconWidthDiff : halfQsbIconWidthDiff; float toX = hotseatIconCenter - childCenter; - if (child instanceof Reorderable) { - MultiTranslateDelegate mtd = ((Reorderable) child).getTranslateDelegate(); + if (child instanceof Reorderable reorderableChild) { + MultiTranslateDelegate mtd = reorderableChild.getTranslateDelegate(); setter.addFloat(mtd.getTranslationX(INDEX_TASKBAR_ALIGNMENT_ANIM), MULTI_PROPERTY_VALUE, fromX, toX, interpolator); @@ -926,6 +938,7 @@ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbar + (hotseatCellSize + borderSpacing) * positionInHotseat + hotseatCellSize / 2f; } + hotseatIconCenter += hotseatNavBarTranslationX; float childCenter = (child.getLeft() + child.getRight()) / 2f; childCenter += ((Reorderable) child).getTranslateDelegate().getTranslationX( INDEX_TASKBAR_PINNING_ANIM).getValue(); diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index 6860004133..51e09abc65 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -196,7 +196,8 @@ public class BubbleBarController extends IBubblesListener.Stub { mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse( key -> setSelectedBubbleInternal(mBubbles.get(key))); mBubbleBarViewController.setBoundsChangeListener(this::onBubbleBarBoundsChanged); - + mBubbleBarLocationListener.onBubbleBarLocationUpdated( + mBubbleBarViewController.getBubbleBarLocation()); if (sBubbleBarEnabled) { mSystemUiProxy.setBubblesListener(this); } diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java index a66df4c357..d3ac324ac6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleControllers.java @@ -22,6 +22,7 @@ import android.view.View; import com.android.launcher3.taskbar.TaskbarControllers; import com.android.launcher3.taskbar.bubbles.BubbleBarViewController.TaskbarViewPropertiesProvider; +import com.android.launcher3.taskbar.bubbles.stashing.BubbleBarLocationOnDemandListener; import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController; import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.RunnableList; @@ -76,11 +77,11 @@ public class BubbleControllers { * in constructors for now, as some controllers may still be waiting for init(). */ public void init(TaskbarControllers taskbarControllers) { - // TODO(b/346381754) add TaskbarLauncherStateController implementation to adjust the hotseat BubbleBarLocationCompositeListener bubbleBarLocationListeners = new BubbleBarLocationCompositeListener( taskbarControllers.navbarButtonsViewController, - taskbarControllers.taskbarViewController + taskbarControllers.taskbarViewController, + new BubbleBarLocationOnDemandListener(() -> taskbarControllers.uiController) ); bubbleBarController.init(this, bubbleBarLocationListeners, diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleBarLocationOnDemandListener.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleBarLocationOnDemandListener.kt new file mode 100644 index 0000000000..ffe7c4473b --- /dev/null +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/stashing/BubbleBarLocationOnDemandListener.kt @@ -0,0 +1,34 @@ +/* + * Copyright (C) 2024 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.bubbles.stashing + +import com.android.launcher3.taskbar.bubbles.BubbleBarController.BubbleBarLocationListener +import com.android.wm.shell.shared.bubbles.BubbleBarLocation + +/** On demand implementation of [BubbleBarLocationListener]. */ +class BubbleBarLocationOnDemandListener( + private val listenerProvider: () -> BubbleBarLocationListener +) : BubbleBarLocationListener { + + override fun onBubbleBarLocationAnimated(location: BubbleBarLocation) { + listenerProvider().onBubbleBarLocationAnimated(location) + } + + override fun onBubbleBarLocationUpdated(location: BubbleBarLocation) { + listenerProvider().onBubbleBarLocationUpdated(location) + } +} diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index e80e838e90..3a34f4e7a3 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -37,6 +37,7 @@ import static com.android.launcher3.LauncherState.NO_OFFSET; import static com.android.launcher3.LauncherState.OVERVIEW; import static com.android.launcher3.LauncherState.OVERVIEW_MODAL_TASK; import static com.android.launcher3.LauncherState.OVERVIEW_SPLIT_SELECT; +import static com.android.launcher3.Utilities.isRtl; import static com.android.launcher3.compat.AccessibilityManagerCompat.sendCustomAccessibilityEvent; import static com.android.launcher3.config.FeatureFlags.enableSplitContextually; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_LAUNCH_TAP; @@ -65,6 +66,8 @@ import static com.android.quickstep.util.ActiveGestureErrorDetector.GestureEvent import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback; import static com.android.quickstep.util.SplitAnimationTimings.TABLET_HOME_TO_SPLIT; import static com.android.systemui.shared.system.ActivityManagerWrapper.CLOSE_SYSTEM_WINDOWS_REASON_HOME_KEY; +import static com.android.wm.shell.Flags.enableBubbleAnything; +import static com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar; import static com.android.wm.shell.shared.split.SplitScreenConstants.SNAP_TO_50_50; import android.animation.Animator; @@ -198,6 +201,7 @@ import com.android.systemui.unfold.config.UnfoldTransitionConfig; import com.android.systemui.unfold.dagger.UnfoldMain; import com.android.systemui.unfold.progress.RemoteUnfoldTransitionReceiver; import com.android.systemui.unfold.updates.RotationChangeProvider; +import com.android.wm.shell.shared.bubbles.BubbleBarLocation; import com.android.wm.shell.shared.desktopmode.DesktopModeStatus; import kotlin.Unit; @@ -239,6 +243,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, private SplitSelectStateController mSplitSelectStateController; private SplitWithKeyboardShortcutController mSplitWithKeyboardShortcutController; private SplitToWorkspaceController mSplitToWorkspaceController; + private BubbleBarLocation mBubbleBarLocation; /** * If Launcher restarted while in the middle of an Overview split select, it needs this data to @@ -463,7 +468,7 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, if (Flags.enablePrivateSpace()) { shortcuts.add(UNINSTALL_APP); } - if (com.android.wm.shell.Flags.enableBubbleAnything()) { + if (enableBubbleAnything()) { shortcuts.add(BUBBLE_SHORTCUT); } return shortcuts.stream(); @@ -1105,6 +1110,29 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, return mTaskbarUIController; } + /** Provides the translation X for the hotseat item. */ + public int getHotseatItemTranslationX(ItemInfo itemInfo) { + int translationX = 0; + if (isBubbleBarEnabled() + && enableBubbleBarInPersistentTaskBar() + && mBubbleBarLocation != null) { + boolean isBubblesOnLeft = mBubbleBarLocation.isOnLeft(isRtl(getResources())); + translationX += mDeviceProfile + .getHotseatTranslationXForBubbleBar(/* isNavbarOnRight = */ isBubblesOnLeft); + } + if (isBubbleBarEnabled() && hasBubbles()) { + // TODO(368379159) : create a class to reuse computation logic + float adjustedBorderSpace = + mDeviceProfile.getHotseatAdjustedBorderSpaceForBubbleBar(this); + if (Float.compare(adjustedBorderSpace, 0f) != 0) { + float borderSpaceDelta = adjustedBorderSpace - mDeviceProfile.hotseatBorderSpace; + translationX += + (int) (mDeviceProfile.iconSizePx + itemInfo.cellX * borderSpaceDelta); + } + } + return translationX; + } + public SplitToWorkspaceController getSplitToWorkspaceController() { return mSplitToWorkspaceController; } @@ -1410,6 +1438,11 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer, SystemUiProxy.INSTANCE.get(this).showAppBubble(intent); } + /** Sets the location of the bubble bar */ + public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) { + mBubbleBarLocation = bubbleBarLocation; + } + private static final class LauncherTaskViewController extends TaskViewTouchController { diff --git a/src/com/android/launcher3/DeviceProfile.java b/src/com/android/launcher3/DeviceProfile.java index cc5baea07e..b7fcd980b2 100644 --- a/src/com/android/launcher3/DeviceProfile.java +++ b/src/com/android/launcher3/DeviceProfile.java @@ -31,6 +31,8 @@ import static com.android.launcher3.icons.IconNormalizer.ICON_VISIBLE_AREA_FACTO import static com.android.launcher3.testing.shared.ResourceUtils.INVALID_RESOURCE_HANDLE; import static com.android.launcher3.testing.shared.ResourceUtils.pxFromDp; import static com.android.launcher3.testing.shared.ResourceUtils.roundPxValueFromFloat; +import static com.android.wm.shell.Flags.enableBubbleBar; +import static com.android.wm.shell.Flags.enableBubbleBarInPersistentTaskBar; import static com.android.wm.shell.Flags.enableTinyTaskbar; import android.annotation.SuppressLint; @@ -64,8 +66,10 @@ import com.android.launcher3.responsive.ResponsiveSpec.Companion.ResponsiveSpecT import com.android.launcher3.responsive.ResponsiveSpec.DimensionType; import com.android.launcher3.responsive.ResponsiveSpecsProvider; 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; +import com.android.launcher3.util.NavigationMode; import com.android.launcher3.util.ResourceHelper; import com.android.launcher3.util.WindowBounds; import com.android.launcher3.util.window.WindowManagerProxy; @@ -219,6 +223,8 @@ public class DeviceProfile { public int hotseatBarBottomSpacePx; public int hotseatBarEndOffset; public int hotseatQsbSpace; + public int inlineNavButtonsEndSpacingPx; + public int navButtonsLayoutWidthPx; public int springLoadedHotseatBarTopMarginPx; // These 2 values are only used for isVerticalBar // Padding between edge of screen and hotseat @@ -233,7 +239,6 @@ public class DeviceProfile { private final int mMinHotseatIconSpacePx; private final int mMinHotseatQsbWidthPx; private final int mMaxHotseatIconSpacePx; - public final int inlineNavButtonsEndSpacingPx; // Space required for the bubble bar between the hotseat and the edge of the screen. If there's // not enough space, the hotseat will adjust itself for the bubble bar. private final int mBubbleBarSpaceThresholdPx; @@ -692,17 +697,12 @@ public class DeviceProfile { if (areNavButtonsInline && !isPhone) { inlineNavButtonsEndSpacingPx = res.getDimensionPixelSize(inv.inlineNavButtonsEndSpacing); - /* - * 3 nav buttons + - * Spacing between nav buttons + - * Space at the end for contextual buttons - */ - hotseatBarEndOffset = 3 * res.getDimensionPixelSize(R.dimen.taskbar_nav_buttons_size) - + 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween) - + inlineNavButtonsEndSpacingPx; - } else { - inlineNavButtonsEndSpacingPx = 0; - hotseatBarEndOffset = 0; + /* 3 nav buttons + Spacing between nav buttons */ + navButtonsLayoutWidthPx = 3 * res.getDimensionPixelSize( + R.dimen.taskbar_nav_buttons_size) + + 2 * res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween); + /* nav buttons layout width + Space at the end for contextual buttons */ + hotseatBarEndOffset = navButtonsLayoutWidthPx + inlineNavButtonsEndSpacingPx; } mBubbleBarSpaceThresholdPx = @@ -2326,6 +2326,25 @@ public class DeviceProfile { return c.createConfigurationContext(config); } + /** + * Returns whether Taskbar and Hotseat should adjust horizontally on bubble bar location update. + */ + public boolean shouldAdjustHotseatOnBubblesLocationUpdate(Context context) { + return enableBubbleBar() + && enableBubbleBarInPersistentTaskBar() + && DisplayController.getNavigationMode(context) + == NavigationMode.THREE_BUTTONS; + } + + /** Returns hotseat translation X for the bubble bar position. */ + public int getHotseatTranslationXForBubbleBar(boolean isNavbarOnRight) { + if (isNavbarOnRight) { + return 0; + } else { + return navButtonsLayoutWidthPx; + } + } + /** * Callback when a component changes the DeviceProfile associated with it, as a result of * configuration change diff --git a/src/com/android/launcher3/Hotseat.java b/src/com/android/launcher3/Hotseat.java index 024dde477f..ae4c122703 100644 --- a/src/com/android/launcher3/Hotseat.java +++ b/src/com/android/launcher3/Hotseat.java @@ -34,8 +34,10 @@ import android.view.ViewGroup; import android.widget.FrameLayout; import androidx.annotation.IntDef; +import androidx.annotation.Nullable; import com.android.launcher3.util.HorizontalInsettableView; +import com.android.launcher3.util.MultiPropertyFactory; import com.android.launcher3.util.MultiPropertyFactory.MultiProperty; import com.android.launcher3.util.MultiTranslateDelegate; import com.android.launcher3.util.MultiValueAlpha; @@ -61,6 +63,14 @@ public class Hotseat extends CellLayout implements Insettable { public @interface HotseatQsbAlphaId { } + public static final int ICONS_TRANSLATION_X_NAV_BAR_ALIGNMENT = 0; + public static final int ICONS_TRANSLATION_X_CHANNELS_COUNT = 1; + + @Retention(RetentionPolicy.RUNTIME) + @IntDef({ICONS_TRANSLATION_X_NAV_BAR_ALIGNMENT}) + public @interface IconsTranslationX { + } + // Ratio of empty space, qsb should take up to appear visually centered. public static final float QSB_CENTER_FACTOR = .325f; private static final int BUBBLE_BAR_ADJUSTMENT_ANIMATION_DURATION_MS = 250; @@ -72,6 +82,10 @@ public class Hotseat extends CellLayout implements Insettable { private final MultiValueAlpha mIconsAlphaChannels; private final MultiValueAlpha mQsbAlphaChannels; + private @Nullable MultiProperty mQsbTranslationX; + + private final MultiPropertyFactory mIconsTranslationXFactory; + private final View mQsb; public Hotseat(Context context) { @@ -88,9 +102,26 @@ public class Hotseat extends CellLayout implements Insettable { addView(mQsb); mIconsAlphaChannels = new MultiValueAlpha(getShortcutsAndWidgets(), ALPHA_CHANNEL_CHANNELS_COUNT); + if (mQsb instanceof Reorderable qsbReorderable) { + mQsbTranslationX = qsbReorderable.getTranslateDelegate() + .getTranslationX(MultiTranslateDelegate.INDEX_NAV_BAR_ANIM); + } + mIconsTranslationXFactory = new MultiPropertyFactory<>(getShortcutsAndWidgets(), + VIEW_TRANSLATE_X, ICONS_TRANSLATION_X_CHANNELS_COUNT, Float::sum); mQsbAlphaChannels = new MultiValueAlpha(mQsb, ALPHA_CHANNEL_CHANNELS_COUNT); } + /** Provides translation X for hotseat icons for the channel. */ + public MultiProperty getIconsTranslationX(@IconsTranslationX int channelId) { + return mIconsTranslationXFactory.get(channelId); + } + + /** Provides translation X for hotseat Qsb. */ + @Nullable + public MultiProperty getQsbTranslationX() { + return mQsbTranslationX; + } + /** * Returns orientation specific cell X given invariant order in the hotseat */