mTaskbarInAppDisplayProgressMultiProp =
+ new MultiPropertyFactory<>(mTaskbarInAppDisplayProgress,
+ AnimatedFloat.VALUE, DISPLAY_PROGRESS_COUNT, Float::max);
+ private final AnimatedFloat mLauncherPauseProgress = new AnimatedFloat(
+ this::onLauncherPauseProgressUpdate);
private final QuickstepLauncher mLauncher;
private final HomeVisibilityState mHomeState;
- private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener = dp -> {
- onStashedInAppChanged(dp);
- if (mControllers != null && mControllers.taskbarViewController != null) {
- mControllers.taskbarViewController.onRotationChanged(dp);
- }
- };
- private final HomeVisibilityState.VisibilityChangeListener mVisibilityChangeListener = this::onLauncherVisibilityChanged;
+ private final DeviceProfile.OnDeviceProfileChangeListener mOnDeviceProfileChangeListener =
+ dp -> {
+ onStashedInAppChanged(dp);
+ postAdjustHotseatForBubbleBar();
+ if (mControllers != null && mControllers.taskbarViewController != null) {
+ mControllers.taskbarViewController.onRotationChanged(dp);
+ }
+ };
+ private final HomeVisibilityState.VisibilityChangeListener mVisibilityChangeListener =
+ this::onLauncherVisibilityChanged;
// Initialized in init.
- private final TaskbarLauncherStateController mTaskbarLauncherStateController = new TaskbarLauncherStateController();
+ private final TaskbarLauncherStateController
+ mTaskbarLauncherStateController = new TaskbarLauncherStateController();
+ // When overview-in-a-window is enabled, that window is the container, else it is mLauncher.
+ private RecentsViewContainer mRecentsViewContainer;
public LauncherTaskbarUIController(QuickstepLauncher launcher) {
mLauncher = launcher;
- mHomeState = SystemUiProxy.INSTANCE.get(mLauncher).getHomeVisibilityState();
+ mHomeState = SystemUiProxy.INSTANCE.get(mLauncher).getHomeVisibilityState();
}
@Override
@@ -101,24 +119,30 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mTaskbarLauncherStateController.init(mControllers, mLauncher,
mControllers.getSharedState().sysuiStateFlags);
-
+ final TaskbarActivityContext taskbarContext = mControllers.taskbarActivityContext;
+ int displayId = taskbarContext.getDisplayId();
+ BaseContainerInterface, ?> containerInterface = OverviewComponentObserver.INSTANCE.get(
+ taskbarContext).getContainerInterface(displayId);
+ if (containerInterface != null
+ && containerInterface.getCreatedContainer()
+ instanceof RecentsWindowManager recentsWindowManager) {
+ mRecentsViewContainer = recentsWindowManager;
+ mRecentsViewContainer.setTaskbarUIController(this);
+ } else {
+ mRecentsViewContainer = mLauncher;
+ }
mLauncher.setTaskbarUIController(this);
+
mHomeState.addListener(mVisibilityChangeListener);
- onLauncherVisibilityChanged(
- Flags.useActivityOverlay()
- ? mHomeState.isHomeVisible()
- : mLauncher.hasBeenResumed(),
- true /* fromInit */);
+ onLauncherVisibilityChanged(mHomeState.isHomeVisible(), true /* fromInit */);
onStashedInAppChanged(mLauncher.getDeviceProfile());
mLauncher.addOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
// Restore the in-app display progress from before Taskbar was recreated.
float[] prevProgresses = mControllers.getSharedState().inAppDisplayProgressMultiPropValues;
- // Make a copy of the previous progress to set since updating the multiprop will
- // update
- // the property which also calls onInAppDisplayProgressChanged() which writes
- // the current
+ // Make a copy of the previous progress to set since updating the multiprop will update
+ // the property which also calls onInAppDisplayProgressChanged() which writes the current
// values into the shared state
prevProgresses = Arrays.copyOf(prevProgresses, prevProgresses.length);
for (int i = 0; i < prevProgresses.length; i++) {
@@ -128,12 +152,15 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
@Override
protected void onDestroy() {
+ onLauncherVisibilityChanged(false /* isVisible */, true /* fromInitOrDestroy */);
+ mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
super.onDestroy();
- onLauncherVisibilityChanged(false);
mTaskbarLauncherStateController.onDestroy();
mLauncher.setTaskbarUIController(null);
- mLauncher.removeOnDeviceProfileChangeListener(mOnDeviceProfileChangeListener);
+ if (mRecentsViewContainer != mLauncher) {
+ mRecentsViewContainer.setTaskbarUIController(null);
+ }
mHomeState.removeListener(mVisibilityChangeListener);
}
@@ -141,9 +168,8 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
if (mControllers != null) {
// Update our shared state so we can restore it if taskbar gets recreated.
for (int i = 0; i < DISPLAY_PROGRESS_COUNT; i++) {
- mControllers
- .getSharedState().inAppDisplayProgressMultiPropValues[i] = mTaskbarInAppDisplayProgressMultiProp
- .get(i).getValue();
+ mControllers.getSharedState().inAppDisplayProgressMultiPropValues[i] =
+ mTaskbarInAppDisplayProgressMultiProp.get(i).getValue();
}
// Ensure nav buttons react to our latest state if necessary.
mControllers.navbarButtonsViewController.updateNavButtonTranslationY();
@@ -152,8 +178,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
@Override
protected boolean isTaskbarTouchable() {
- return !(mTaskbarLauncherStateController.isAnimatingToLauncher()
- && mTaskbarLauncherStateController.isTaskbarAlignedWithHotseat());
+ // Touching down during animation to Hotseat will end the transition and allow the touch to
+ // go through to the Hotseat directly.
+ return !isAnimatingToHotseat();
}
public void setShouldDelayLauncherStateAnim(boolean shouldDelayLauncherStateAnim) {
@@ -161,19 +188,25 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
shouldDelayLauncherStateAnim);
}
+ @Override
+ public void stashHotseat(boolean stash) {
+ mTaskbarLauncherStateController.stashHotseat(stash);
+ }
+
+ @Override
+ public void unStashHotseatInstantly() {
+ mTaskbarLauncherStateController.unStashHotseatInstantly();
+ }
+
/**
* Adds the Launcher resume animator to the given animator set.
*
- * This should be used to run a Launcher resume animation whose progress matches
- * a
+ * This should be used to run a Launcher resume animation whose progress matches a
* swipe progress.
*
- * @param placeholderDuration a placeholder duration to be used to ensure all
- * full-length
- * sub-animations are properly coordinated. This
- * duration should not
- * actually be used since this animation tracks a
- * swipe progress.
+ * @param placeholderDuration a placeholder duration to be used to ensure all full-length
+ * sub-animations are properly coordinated. This duration should not
+ * actually be used since this animation tracks a swipe progress.
*/
protected void addLauncherVisibilityChangedAnimation(AnimatorSet animation,
int placeholderDuration) {
@@ -185,51 +218,69 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
/**
- * Should be called from onResume() and onPause(), and animates the Taskbar
- * accordingly.
+ * Should be called from onResume() and onPause(), and animates the Taskbar accordingly.
*/
@Override
public void onLauncherVisibilityChanged(boolean isVisible) {
+ final TaskbarActivityContext taskbarContext = mControllers.taskbarActivityContext;
+ if (taskbarContext.showLockedTaskbarOnHome()
+ && !taskbarContext.showDesktopTaskbarForFreeformDisplay()
+ && taskbarContext.isPrimaryDisplay()) {
+ DisplayController.INSTANCE.get(mLauncher).notifyConfigChange();
+ }
+
onLauncherVisibilityChanged(isVisible, false /* fromInit */);
}
- private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInit) {
+ private void onLauncherVisibilityChanged(boolean isVisible, boolean fromInitOrDestroy) {
+ if (mControllers == null) {
+ return;
+ }
onLauncherVisibilityChanged(
isVisible,
- fromInit,
+ fromInitOrDestroy,
/* startAnimation= */ true,
- DisplayController.isTransientTaskbar(mLauncher)
- ? TRANSIENT_TASKBAR_TRANSITION_DURATION
- : (!isVisible
- ? QuickstepTransitionManager.TASKBAR_TO_APP_DURATION
- : QuickstepTransitionManager.getTaskbarToHomeDuration()));
+ getTaskbarAnimationDuration(isVisible));
+ }
+
+ private int getTaskbarAnimationDuration(boolean isVisible) {
+ // fast animation duration since we will not be playing workspace reveal animation.
+ boolean shouldOverrideToFastAnimation = !isHotseatIconOnTopWhenAligned();
+ if (!Flags.predictiveBackToHomePolish()) {
+ shouldOverrideToFastAnimation |= mLauncher.getPredictiveBackToHomeInProgress();
+ }
+
+ boolean isPinned = mControllers.taskbarActivityContext.isPinnedTaskbar();
+ if (isVisible || isPinned) {
+ return getTaskbarToHomeDuration(shouldOverrideToFastAnimation, isPinned);
+ } else {
+ return (mControllers.taskbarActivityContext.isTransientTaskbar())
+ ? TRANSIENT_TASKBAR_TRANSITION_DURATION : TASKBAR_TO_APP_DURATION;
+ }
}
@Nullable
private Animator onLauncherVisibilityChanged(
- boolean isVisible, boolean fromInit, boolean startAnimation, int duration) {
- // Launcher is resumed during the swipe-to-overview gesture under
- // shell-transitions, so
- // avoid updating taskbar state in that situation (when it's non-interactive --
- // or
+ boolean isVisible, boolean fromInitOrDestroy, boolean startAnimation, int duration) {
+ // Launcher is resumed during the swipe-to-overview gesture under shell-transitions, so
+ // avoid updating taskbar state in that situation (when it's non-interactive -- or
// "background") to avoid premature animations.
- if (ENABLE_SHELL_TRANSITIONS && isVisible
- && mLauncher.getStateManager().getState().hasFlag(FLAG_NON_INTERACTIVE)
- && !mLauncher.getStateManager().getState().isTaskbarAlignedWithHotseat(mLauncher)) {
+ LauncherState state = mTaskbarLauncherStateController.getLauncherState();
+ boolean nonInteractiveState = state.hasFlag(FLAG_NON_INTERACTIVE)
+ && !state.isTaskbarAlignedWithHotseat(mLauncher);
+ if (isVisible && (nonInteractiveState || mSkipLauncherVisibilityChange)) {
return null;
}
- DesktopVisibilityController desktopController = LauncherActivityInterface.INSTANCE
- .getDesktopVisibilityController();
- if (!enableDesktopWindowingWallpaperActivity()
- && desktopController != null
- && desktopController.areDesktopTasksVisible()) {
+ if (!ENABLE_DESKTOP_WINDOWING_WALLPAPER_ACTIVITY.isTrue()
+ && mControllers.taskbarDesktopModeController.isInDesktopModeAndNotInOverview(
+ mControllers.taskbarActivityContext.getDisplayId())) {
// TODO: b/333533253 - Remove after flag rollout
isVisible = false;
}
mTaskbarLauncherStateController.updateStateForFlag(FLAG_VISIBLE, isVisible);
- if (fromInit) {
+ if (fromInitOrDestroy) {
duration = 0;
}
return mTaskbarLauncherStateController.applyState(duration, startAnimation);
@@ -242,9 +293,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
@Override
public void refreshResumedState() {
- onLauncherVisibilityChanged(Flags.useActivityOverlay()
- ? mHomeState.isHomeVisible()
- : mLauncher.hasBeenResumed());
+ onLauncherVisibilityChanged(mHomeState.isHomeVisible());
}
@Override
@@ -254,19 +303,58 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
}
+ private void postAdjustHotseatForBubbleBar() {
+ Hotseat hotseat = mLauncher.getHotseat();
+ if (hotseat == null || !isBubbleBarVisible()) return;
+ hotseat.post(() -> {
+ if (mControllers == null) return;
+ adjustHotseatForBubbleBar(isBubbleBarVisible());
+ });
+ }
+
+ private boolean isBubbleBarVisible() {
+ BubbleControllers bubbleControllers = mControllers.bubbleControllers.orElse(null);
+ return bubbleControllers != null
+ && bubbleControllers.bubbleBarViewController.isBubbleBarVisible();
+ }
+
/**
- * Create Taskbar animation when going from an app to Launcher as part of
- * recents transition.
- *
- * @param toState If known, the state we will end up in when reaching
- * Launcher.
- * @param callbacks callbacks to track the recents animation lifecycle. The
- * state change is
- * automatically reset once the recents animation finishes
+ * Create Taskbar animation when going from an app to Launcher as part of recents transition.
+ * {@inheritDoc}
*/
- public Animator createAnimToLauncher(@NonNull LauncherState toState,
- @NonNull RecentsAnimationCallbacks callbacks, long duration) {
- return mTaskbarLauncherStateController.createAnimToLauncher(toState, callbacks, duration);
+ @Override
+ public Animator getParallelAnimationToGestureEndTarget(
+ GestureState.GestureEndTarget gestureEndTarget, long duration,
+ RecentsAnimationCallbacks callbacks) {
+ return mTaskbarLauncherStateController.createAnimToLauncher(
+ LauncherActivityInterface.INSTANCE.stateFromGestureEndTarget(gestureEndTarget),
+ callbacks,
+ duration);
+ }
+
+ /**
+ * Create Taskbar animation to be played alongside the Launcher app launch animation.
+ */
+ public @Nullable Animator createAnimToApp() {
+ if (!syncAppLaunchWithTaskbarStash()) {
+ return null;
+ }
+ TaskbarStashController stashController = mControllers.taskbarStashController;
+ stashController.updateStateForFlag(TaskbarStashController.FLAG_IN_APP, true);
+ return stashController.createApplyStateAnimator(stashController.getStashDuration());
+ }
+
+ /**
+ * Temporarily ignore FLAG_IN_APP for app launches to prevent premature taskbar stashing.
+ * This is needed because taskbar gets a signal to stash before we actually start the
+ * app launch animation.
+ */
+ public void setIgnoreInAppFlagForSync(boolean enabled) {
+ if (syncAppLaunchWithTaskbarStash()
+ && mControllers != null
+ && mControllers.taskbarStashController != null) {
+ mControllers.taskbarStashController.updateStateForFlag(FLAG_IGNORE_IN_APP, enabled);
+ }
}
public void updateTaskbarLauncherStateGoingHome() {
@@ -274,10 +362,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mTaskbarLauncherStateController.applyState();
}
- public boolean isDraggingItem() {
- return mControllers.taskbarDragController.isDragging();
- }
-
@Override
protected void onStashedInAppChanged() {
onStashedInAppChanged(mLauncher.getDeviceProfile());
@@ -289,8 +373,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
/**
- * Starts a Taskbar EDU flow, if the user should see one upon launching an
- * application.
+ * Starts a Taskbar EDU flow, if the user should see one upon launching an application.
*/
public void showEduOnAppLaunch() {
if (!shouldShowEduOnAppLaunch()) {
@@ -300,7 +383,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
// Persistent features EDU tooltip.
- if (!DisplayController.isTransientTaskbar(mLauncher)) {
+ if (!mControllers.taskbarActivityContext.isTransientTaskbar()) {
mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
return;
}
@@ -315,8 +398,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
/**
- * Returns {@code true} if a Taskbar education should be shown on application
- * launch.
+ * Returns {@code true} if a Taskbar education should be shown on application launch.
*/
public boolean shouldShowEduOnAppLaunch() {
if (Utilities.isRunningInTestHarness()) {
@@ -324,7 +406,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
// Persistent features EDU tooltip.
- if (!DisplayController.isTransientTaskbar(mLauncher)) {
+ if (!mControllers.taskbarActivityContext.isTransientTaskbar()) {
return !OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP.hasReachedMax(mLauncher);
}
@@ -341,8 +423,7 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
/**
- * Animates Taskbar elements during a transition to a Launcher state that should
- * use in-app
+ * Animates Taskbar elements during a transition to a Launcher state that should use in-app
* layouts.
*
* @param progress [0, 1]
@@ -355,16 +436,22 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
// This method can be called before init() is called.
return;
}
- if (mControllers.uiController.isIconAlignedWithHotseat()
- && !mTaskbarLauncherStateController.isAnimatingToLauncher()) {
- // Only animate the nav buttons while home and not animating home, otherwise let
- // the TaskbarViewController handle it.
- mControllers.navbarButtonsViewController
- .getTaskbarNavButtonTranslationYForInAppDisplay()
- .updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
- * mTaskbarInAppDisplayProgress.value);
- mControllers.navbarButtonsViewController
- .getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
+ if (mControllers.uiController.isIconAlignedWithHotseat()) {
+ if (!mTaskbarLauncherStateController.isAnimatingToLauncher()) {
+ // Only animate the nav buttons while home and not animating home, otherwise let
+ // the TaskbarViewController handle it.
+ mControllers.navbarButtonsViewController
+ .getTaskbarNavButtonTranslationYForInAppDisplay()
+ .updateValue(mLauncher.getDeviceProfile().getTaskbarOffsetY()
+ * mTaskbarInAppDisplayProgress.value);
+ mControllers.navbarButtonsViewController
+ .getOnTaskbarBackgroundNavButtonColorOverride().updateValue(progress);
+ }
+ if (isBubbleBarEnabled()) {
+ mControllers.bubbleControllers.ifPresent(
+ c -> c.bubbleStashController.setInAppDisplayOverrideProgress(
+ mTaskbarInAppDisplayProgress.value));
+ }
}
}
@@ -409,7 +496,18 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
public boolean isHotseatIconOnTopWhenAligned() {
return mTaskbarLauncherStateController.isInHotseatOnTopStates()
&& mTaskbarInAppDisplayProgressMultiProp.get(MINUS_ONE_PAGE_PROGRESS_INDEX)
- .getValue() == 0;
+ .getValue() == 0;
+ }
+
+ @Override
+ public boolean isAnimatingToHotseat() {
+ return mTaskbarLauncherStateController.isAnimatingToLauncher()
+ && isIconAlignedWithHotseat();
+ }
+
+ @Override
+ public void endAnimationToHotseat() {
+ mTaskbarLauncherStateController.resetIconAlignment();
}
@Override
@@ -418,21 +516,26 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
}
@Override
- protected boolean canToggleHomeAllApps() {
- return mLauncher.isResumed()
+ protected void toggleAllApps(boolean focusSearch) {
+ boolean canToggleHomeAllApps = mLauncher.isResumed()
&& !mTaskbarLauncherStateController.isInOverviewUi()
&& !mLauncher.areDesktopTasksVisible();
+ if (canToggleHomeAllApps) {
+ mLauncher.toggleAllApps(focusSearch);
+ return;
+ }
+ super.toggleAllApps(focusSearch);
}
@Override
public RecentsView getRecentsView() {
- return mLauncher.getOverviewPanel();
+ return mRecentsViewContainer.getOverviewPanel();
}
@Override
public void launchSplitTasks(
- @NonNull GroupTask groupTask, @Nullable RemoteTransition remoteTransition) {
- mLauncher.launchSplitTasks(groupTask, remoteTransition);
+ @NonNull SplitTask splitTask, @Nullable RemoteTransition remoteTransition) {
+ mLauncher.launchSplitTasks(splitTask, remoteTransition);
}
@Override
@@ -440,12 +543,6 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
mTaskbarLauncherStateController.resetIconAlignment();
}
- @Nullable
- @Override
- protected TISBindHelper getTISBindHelper() {
- return mLauncher.getTISBindHelper();
- }
-
@Override
public void dumpLogs(String prefix, PrintWriter pw) {
super.dumpLogs(prefix, pw);
@@ -459,7 +556,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
"MINUS_ONE_PAGE_PROGRESS_INDEX",
"ALL_APPS_PAGE_PROGRESS_INDEX",
"WIDGETS_PAGE_PROGRESS_INDEX",
- "SYSUI_SURFACE_PROGRESS_INDEX");
+ "SYSUI_SURFACE_PROGRESS_INDEX",
+ "LAUNCHER_PAUSE_PROGRESS_INDEX");
+ pw.println(String.format("%s\tmRecentsWindowContainer=%s", prefix, mRecentsViewContainer));
mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw);
}
@@ -468,4 +567,60 @@ public class LauncherTaskbarUIController extends TaskbarUIController {
protected String getTaskbarUIControllerName() {
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
+ // clear it here to set the expected state once the user goes home.
+ if (mLauncher.getWorkspace().isOverlayShown()) {
+ mLauncher.getWorkspace().onOverlayScrollChanged(0);
+ }
+ }
+
+ /**
+ * Called when Launcher Activity resumed while staying at home.
+ *
+ * Shift nav buttons up to at-home position.
+ */
+ public void onLauncherResume() {
+ mLauncherPauseProgress.animateToValue(0.0f).start();
+ }
+
+ /**
+ * Called when Launcher Activity paused while staying at home.
+ *
+ * To avoid UI clash between taskbar & bottom sheet, shift nav buttons down to in-app position.
+ */
+ public void onLauncherPause() {
+ mLauncherPauseProgress.animateToValue(1.0f).start();
+ }
+
+ /**
+ * On launcher stop, avoid animating taskbar & overriding pre-existing animations.
+ */
+ public void onLauncherStop() {
+ mLauncherPauseProgress.cancelAnimation();
+ mLauncherPauseProgress.updateValue(0.0f);
+ }
+
+ private void onLauncherPauseProgressUpdate() {
+ // If we are not aligned with hotseat, setting this will clobber the 3 button nav position.
+ // So in that case, treat the progress as 0 instead.
+ float pauseProgress = isIconAlignedWithHotseat() ? mLauncherPauseProgress.value : 0;
+ onTaskbarInAppDisplayProgressUpdate(pauseProgress, LAUNCHER_PAUSE_PROGRESS_INDEX);
+ }
+
+
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
index bfd93dda31..2d6f1ee5be 100644
--- a/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/ManageWindowsTaskbarShortcut.kt
@@ -225,7 +225,7 @@ class ManageWindowsTaskbarShortcut(
// Calculate the Y position to place the carousel above the taskbar
menuView.rootView.y =
- deviceProfile.availableHeightPx -
+ deviceProfile.deviceProperties.availableHeightPx -
menuView.menuHeight -
controllers.taskbarStashController.touchableHeight -
margin
@@ -234,9 +234,12 @@ class ManageWindowsTaskbarShortcut(
// but avoid clashing with the screen edge
menuView.rootView.translationX =
if (Utilities.isRtl(context.resources)) {
- -(deviceProfile.availableWidthPx - menuView.menuWidth) / 2f
+ -(deviceProfile.deviceProperties.availableWidthPx - menuView.menuWidth) / 2f
} else {
- val maxX = deviceProfile.availableWidthPx - menuView.menuWidth - margin
+ val maxX =
+ deviceProfile.deviceProperties.availableWidthPx -
+ menuView.menuWidth -
+ margin
minOf(originalView.x, maxX)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
index 293c2b2a65..323372be9d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/NavbarButtonsViewController.java
@@ -23,6 +23,7 @@ import static android.view.WindowManager.LayoutParams.TYPE_NAVIGATION_BAR_PANEL;
import static com.android.launcher3.LauncherAnimUtils.ROTATION_DRAWABLE_PERCENT;
import static com.android.launcher3.LauncherAnimUtils.VIEW_TRANSLATE_X;
import static com.android.launcher3.Utilities.getDescendantCoordRelativeToAncestor;
+import static com.android.launcher3.anim.AnimatorListeners.forEndCallback;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import static com.android.launcher3.taskbar.LauncherTaskbarUIController.SYSUI_SURFACE_PROGRESS_INDEX;
import static com.android.launcher3.taskbar.TaskbarNavButtonController.BUTTON_A11Y;
@@ -38,21 +39,27 @@ import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VAL
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISABLED;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_BACK_DISMISS_IME;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_HOME_DISABLED;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SHOWING;
-import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_SHOWING;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_IME_VISIBLE;
+import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_OVERVIEW_DISABLED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SCREEN_PINNING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_SHORTCUT_HELPER_SHOWING;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
+import static com.android.window.flags2.Flags.predictiveBackThreeButtonNav;
+import android.animation.Animator;
import android.animation.ArgbEvaluator;
import android.animation.ObjectAnimator;
import android.annotation.DrawableRes;
import android.annotation.IdRes;
import android.annotation.LayoutRes;
+import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.ActivityInfo.Config;
import android.content.res.ColorStateList;
@@ -60,24 +67,27 @@ import android.content.res.Resources;
import android.graphics.Color;
import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.RectF;
import android.graphics.Region;
import android.graphics.Region.Op;
-import android.graphics.drawable.AnimatedVectorDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.PaintDrawable;
import android.graphics.drawable.RotateDrawable;
-import android.inputmethodservice.InputMethodService;
+import android.os.Bundle;
import android.os.Handler;
+import android.os.SystemProperties;
import android.util.Property;
import android.view.Gravity;
+import android.view.HapticFeedbackConstants;
+import android.view.KeyEvent;
import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnAttachStateChangeListener;
-import android.view.View.OnClickListener;
-import android.view.View.OnHoverListener;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.WindowManager;
+import android.view.accessibility.AccessibilityNodeInfo;
+import android.view.inputmethod.Flags;
import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
@@ -92,11 +102,11 @@ import com.android.launcher3.Utilities;
import com.android.launcher3.anim.AlphaUpdateListener;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.TaskbarNavButtonController.TaskbarButton;
+import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory;
import com.android.launcher3.taskbar.navbutton.NavButtonLayoutFactory.NavButtonLayoutter;
import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
import com.android.launcher3.util.DimensionUtils;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.launcher3.util.TouchController;
@@ -105,25 +115,37 @@ import com.android.launcher3.views.BaseDragLayer;
import com.android.systemui.shared.navigationbar.KeyButtonRipple;
import com.android.systemui.shared.rotation.FloatingRotationButton;
import com.android.systemui.shared.rotation.RotationButton;
-import com.android.systemui.shared.rotation.RotationButtonController;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.QuickStepContract;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.StringJoiner;
+import java.util.concurrent.atomic.AtomicBoolean;
import java.util.function.IntPredicate;
/**
* Controller for managing nav bar buttons in taskbar
*/
-public class NavbarButtonsViewController implements TaskbarControllers.LoggableTaskbarController {
+public class NavbarButtonsViewController implements TaskbarControllers.LoggableTaskbarController,
+ BubbleBarController.BubbleBarLocationListener {
private final Rect mTempRect = new Rect();
- private static final int FLAG_SWITCHER_SHOWING = 1 << 0;
+ /** Whether the IME Switcher button is visible. */
+ private static final int FLAG_IME_SWITCHER_BUTTON_VISIBLE = 1 << 0;
+ /** Whether the IME is visible. */
private static final int FLAG_IME_VISIBLE = 1 << 1;
- private static final int FLAG_ROTATION_BUTTON_VISIBLE = 1 << 2;
+ /**
+ * The back button is visually adjusted to indicate that it will dismiss the IME when pressed.
+ * This only takes effect while the IME is visible. By default, it is set while the IME is
+ * visible, but may be overridden by the
+ * {@link android.inputmethodservice.InputMethodService.BackDispositionMode backDispositionMode}
+ * set by the IME.
+ */
+ private static final int FLAG_BACK_DISMISS_IME = 1 << 2;
private static final int FLAG_A11Y_VISIBLE = 1 << 3;
private static final int FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE = 1 << 4;
private static final int FLAG_KEYGUARD_VISIBLE = 1 << 5;
@@ -139,13 +161,15 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
private static final int FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING = 1 << 15;
/**
- * Flags where a UI could be over Taskbar surfaces, so the color override should
- * be disabled.
+ * Flags where a UI could be over Taskbar surfaces, so the color override should be disabled.
*/
- private static final int FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED = FLAG_NOTIFICATION_SHADE_EXPANDED
- | FLAG_VOICE_INTERACTION_WINDOW_SHOWING;
+ private static final int FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED =
+ FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_VOICE_INTERACTION_WINDOW_SHOWING;
private static final String NAV_BUTTONS_SEPARATE_WINDOW_TITLE = "Taskbar Nav Buttons";
+ private static final String SUW_THEME_SYSTEM_PROPERTY = "setupwizard.theme";
+ private static final String GLIF_EXPRESSIVE_THEME = "glif_expressive";
+ private static final String GLIF_EXPRESSIVE_LIGHT_THEME = "glif_expressive_light";
private static final double SQUARE_ASPECT_RATIO_BOTTOM_BOUND = 0.95;
private static final double SQUARE_ASPECT_RATIO_UPPER_BOUND = 1.05;
@@ -155,6 +179,9 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
public static final int ALPHA_INDEX_SUW = 2;
private static final int NUM_ALPHA_CHANNELS = 3;
+ private static final long AUTODIM_TIMEOUT_MS = 2250;
+ private static final long PREDICTIVE_BACK_TIMEOUT_MS = 200;
+
private final ArrayList mPropertyHolders = new ArrayList<>();
private final ArrayList mAllButtons = new ArrayList<>();
private int mState;
@@ -163,17 +190,19 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
private final @Nullable Context mNavigationBarPanelContext;
private final WindowManagerProxy mWindowManagerProxy;
private final NearestTouchFrame mNavButtonsView;
+ private final Handler mHandler;
private final LinearLayout mNavButtonContainer;
// Used for IME+A11Y buttons
private final ViewGroup mEndContextualContainer;
private final ViewGroup mStartContextualContainer;
- private final int mLightIconColorOnHome;
- private final int mDarkIconColorOnHome;
- /**
- * Color to use for navigation bar buttons, if they are on on a Taskbar surface
- * background.
- */
+ private final int mLightIconColorOnWorkspace;
+ private final int mDarkIconColorOnWorkspace;
+ /** Color to use for navbar buttons, if they are on on a Taskbar surface background. */
private final int mOnBackgroundIconColor;
+ private final boolean mIsExpressiveThemeEnabled;
+
+ private @Nullable Animator mNavBarLocationAnimator;
+ private @Nullable BubbleBarLocation mBubbleBarTargetLocation;
private final AnimatedFloat mTaskbarNavButtonTranslationY = new AnimatedFloat(
this::updateNavButtonTranslationY);
@@ -182,13 +211,15 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
private final AnimatedFloat mTaskbarNavButtonTranslationYForIme = new AnimatedFloat(
this::updateNavButtonTranslationY);
private float mLastSetNavButtonTranslationY;
- // Used for System UI state updates that should translate the nav button for
- // in-app display.
+ // Used for System UI state updates that should translate the nav button for in-app display.
private final AnimatedFloat mNavButtonInAppDisplayProgressForSysui = new AnimatedFloat(
this::updateNavButtonInAppDisplayProgressForSysui);
- /** Expected nav button dark intensity communicated via the framework. */
+ /**
+ * Expected nav button dark intensity piped down from {@code LightBarController} in framework
+ * via {@code TaskbarDelegate}.
+ */
private final AnimatedFloat mTaskbarNavButtonDarkIntensity = new AnimatedFloat(
- this::updateNavButtonColor);
+ this::onDarkIntensityChanged);
/** {@code 1} if the Taskbar background color is fully opaque. */
private final AnimatedFloat mOnTaskbarBackgroundNavButtonColorOverride = new AnimatedFloat(
this::updateNavButtonColor);
@@ -218,26 +249,41 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
// Variables for moving nav buttons to a separate window above IME
private boolean mAreNavButtonsInSeparateWindow = false;
private BaseDragLayer mSeparateWindowParent; // Initialized in init.
- private final ViewTreeObserver.OnComputeInternalInsetsListener mSeparateWindowInsetsComputer = this::onComputeInsetsForSeparateWindow;
+ private final ViewTreeObserver.OnComputeInternalInsetsListener mSeparateWindowInsetsComputer =
+ this::onComputeInsetsForSeparateWindow;
private final RecentsHitboxExtender mHitboxExtender = new RecentsHitboxExtender();
private ImageView mRecentsButton;
private Space mSpace;
+ private TaskbarTransitions mTaskbarTransitions;
+ private @BarTransitions.TransitionMode int mTransitionMode;
+
+ private final Runnable mAutoDim = () -> mTaskbarTransitions.setAutoDim(true);
+
public NavbarButtonsViewController(TaskbarActivityContext context,
- @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView) {
+ @Nullable Context navigationBarPanelContext, NearestTouchFrame navButtonsView,
+ Handler handler) {
mContext = context;
mNavigationBarPanelContext = navigationBarPanelContext;
mWindowManagerProxy = WindowManagerProxy.INSTANCE.get(mContext);
mNavButtonsView = navButtonsView;
+ mHandler = handler;
mNavButtonContainer = mNavButtonsView.findViewById(R.id.end_nav_buttons);
mEndContextualContainer = mNavButtonsView.findViewById(R.id.end_contextual_buttons);
mStartContextualContainer = mNavButtonsView.findViewById(R.id.start_contextual_buttons);
- mLightIconColorOnHome = context.getColor(R.color.taskbar_nav_icon_light_color_on_home);
- mDarkIconColorOnHome = context.getColor(R.color.taskbar_nav_icon_dark_color_on_home);
+ mLightIconColorOnWorkspace = context.getColor(R.color.taskbar_nav_icon_light_color_on_home);
+ mDarkIconColorOnWorkspace = context.getColor(R.color.taskbar_nav_icon_dark_color_on_home);
mOnBackgroundIconColor = Utilities.isDarkTheme(context)
? context.getColor(R.color.taskbar_nav_icon_light_color)
: context.getColor(R.color.taskbar_nav_icon_dark_color);
+
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions = new TaskbarTransitions(mContext, mNavButtonsView);
+ }
+ String SUWTheme = SystemProperties.get(SUW_THEME_SYSTEM_PROPERTY, "");
+ mIsExpressiveThemeEnabled = SUWTheme.equals(GLIF_EXPRESSIVE_THEME)
+ || SUWTheme.equals(GLIF_EXPRESSIVE_LIGHT_THEME);
}
/**
@@ -249,26 +295,37 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
protected void setupController() {
- boolean isThreeButtonNav = mContext.isThreeButtonNav();
+ final boolean isThreeButtonNav = mContext.isThreeButtonNav();
+ final boolean isPhoneMode = mContext.isPhoneMode();
DeviceProfile deviceProfile = mContext.getDeviceProfile();
Resources resources = mContext.getResources();
- Point p = !mContext.isUserSetupComplete()
- ? new Point(0, mControllers.taskbarActivityContext.getSetupWindowSize())
- : DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources,
- mContext.isPhoneMode());
- mNavButtonsView.getLayoutParams().height = p.y;
+
+ int setupSize = mControllers.taskbarActivityContext.getSetupWindowSize();
+ Point p = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile, resources, isPhoneMode,
+ mContext.isGestureNav());
+ ViewGroup.LayoutParams navButtonsViewLayoutParams = mNavButtonsView.getLayoutParams();
+ navButtonsViewLayoutParams.width = p.x;
+ if (!mContext.isUserSetupComplete()) {
+ // Setup mode in phone mode uses gesture nav.
+ navButtonsViewLayoutParams.height = setupSize;
+ } else {
+ navButtonsViewLayoutParams.height = p.y;
+ }
+ mNavButtonsView.setLayoutParams(navButtonsViewLayoutParams);
mIsImeRenderingNavButtons = mContext.imeDrawsImeNavBar();
-// mDisplayController = DisplayController.INSTANCE.get(mContext);
-
if (!mIsImeRenderingNavButtons) {
// IME switcher
- mImeSwitcherButton = addButton(R.drawable.ic_ime_switcher, BUTTON_IME_SWITCH,
+ final int switcherResId = Flags.imeSwitcherRevamp()
+ ? com.android.internal.R.drawable.ic_ime_switcher_new
+ : R.drawable.ic_ime_switcher;
+ mImeSwitcherButton = addButton(switcherResId, BUTTON_IME_SWITCH,
isThreeButtonNav ? mStartContextualContainer : mEndContextualContainer,
mControllers.navButtonController, R.id.ime_switcher);
+ // A11y and IME Switcher buttons overlap on phone mode, show only a11y if both visible.
mPropertyHolders.add(new StatePropertyHolder(mImeSwitcherButton,
- flags -> ((flags & FLAG_SWITCHER_SHOWING) != 0)
- && ((flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0)));
+ flags -> (flags & FLAG_IME_SWITCHER_BUTTON_VISIBLE) != 0
+ && !(isPhoneMode && (flags & FLAG_A11Y_VISIBLE) != 0)));
}
mPropertyHolders.add(new StatePropertyHolder(
@@ -282,62 +339,61 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
.get(ALPHA_INDEX_SMALL_SCREEN),
flags -> (flags & FLAG_SMALL_SCREEN) == 0));
- mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
- .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
-
- // Force nav buttons (specifically back button) to be visible during setup
- // wizard.
- boolean isInSetup = !mContext.isUserSetupComplete();
- boolean isInKidsMode = mContext.isNavBarKidsModeActive();
- boolean alwaysShowButtons = isThreeButtonNav || isInSetup;
-
- // Make sure to remove nav bar buttons translation when any of the following
- // occur:
- // - Notification shade is expanded
- // - IME is showing (add separate translation for IME)
- // - VoiceInteractionWindow (assistant) is showing
- // - Keyboard shortcuts helper is showing
- int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
- | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
- mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
- flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
- 1, 0));
- // Center nav buttons in new height for IME.
- float transForIme = (mContext.getDeviceProfile().taskbarHeight
- - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
- // For gesture nav, nav buttons only show for IME anyway so keep them translated
- // down.
- float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
- mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
- flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
- transForIme, defaultButtonTransY));
+ if (!isPhoneMode) {
+ mPropertyHolders.add(new StatePropertyHolder(mControllers.taskbarDragLayerController
+ .getKeyguardBgTaskbar(), flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0));
+ }
// Start at 1 because relevant flags are unset at init.
mOnBackgroundNavButtonColorOverrideMultiplier.value = 1;
- mPropertyHolders.add(new StatePropertyHolder(
- mOnBackgroundNavButtonColorOverrideMultiplier,
- flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
- mPropertyHolders.add(new StatePropertyHolder(
- mSlideInViewVisibleNavButtonColorOverride,
- flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+ // Potentially force the back button to be visible during setup wizard. The back button
+ // won't show up if the expressive theme is enabled and simple view is disabled
+ boolean shouldShowInSetup = !mContext.isUserSetupComplete()
+ && (!mIsExpressiveThemeEnabled || mContext.isSimpleViewEnabled());
+ boolean isInKidsMode = mContext.isNavBarKidsModeActive();
+ boolean alwaysShowButtons = isThreeButtonNav || shouldShowInSetup;
+
+ // Make sure to remove nav bar buttons translation when any of the following occur:
+ // - Notification shade is expanded
+ // - IME is visible (add separate translation for IME)
+ // - VoiceInteractionWindow (assistant) is showing
+ // - Keyboard shortcuts helper is showing
+ if (!isPhoneMode) {
+ int flagsToRemoveTranslation = FLAG_NOTIFICATION_SHADE_EXPANDED | FLAG_IME_VISIBLE
+ | FLAG_VOICE_INTERACTION_WINDOW_SHOWING | FLAG_KEYBOARD_SHORTCUT_HELPER_SHOWING;
+ mPropertyHolders.add(new StatePropertyHolder(mNavButtonInAppDisplayProgressForSysui,
+ flags -> (flags & flagsToRemoveTranslation) != 0, AnimatedFloat.VALUE,
+ 1, 0));
+ // Center nav buttons in new height for IME.
+ float transForIme = (mContext.getDeviceProfile().getTaskbarProfile().getHeight()
+ - mControllers.taskbarInsetsController.getTaskbarHeightForIme()) / 2f;
+ // For gesture nav, nav buttons only show for IME anyway so keep them translated down.
+ float defaultButtonTransY = alwaysShowButtons ? 0 : transForIme;
+ mPropertyHolders.add(new StatePropertyHolder(mTaskbarNavButtonTranslationYForIme,
+ flags -> (flags & FLAG_IME_VISIBLE) != 0 && !isInKidsMode, AnimatedFloat.VALUE,
+ transForIme, defaultButtonTransY));
+
+ mPropertyHolders.add(new StatePropertyHolder(
+ mOnBackgroundNavButtonColorOverrideMultiplier,
+ flags -> (flags & FLAGS_ON_BACKGROUND_COLOR_OVERRIDE_DISABLED) == 0));
+
+ mPropertyHolders.add(new StatePropertyHolder(
+ mSlideInViewVisibleNavButtonColorOverride,
+ flags -> (flags & FLAG_SLIDE_IN_VIEW_VISIBLE) != 0));
+ }
if (alwaysShowButtons) {
initButtons(mNavButtonContainer, mEndContextualContainer,
mControllers.navButtonController);
updateButtonLayoutSpacing();
- updateStateForFlag(FLAG_SMALL_SCREEN, mContext.isPhoneButtonNavMode());
+ updateStateForFlag(FLAG_SMALL_SCREEN, isPhoneMode);
- mPropertyHolders.add(new StatePropertyHolder(
- mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
- flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
- } else if (!mIsImeRenderingNavButtons) {
- View imeDownButton = addButton(R.drawable.ic_sysbar_back, BUTTON_BACK,
- mStartContextualContainer, mControllers.navButtonController, R.id.back);
- imeDownButton.setRotation(Utilities.isRtl(resources) ? 90 : -90);
- // Only show when IME is visible.
- mPropertyHolders.add(new StatePropertyHolder(imeDownButton,
- flags -> (flags & FLAG_IME_VISIBLE) != 0));
+ if (!isPhoneMode) {
+ mPropertyHolders.add(new StatePropertyHolder(
+ mControllers.taskbarDragLayerController.getNavbarBackgroundAlpha(),
+ flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0));
+ }
}
mFloatingRotationButton = new FloatingRotationButton(
ENABLE_TASKBAR_NAVBAR_UNIFICATION ? mNavigationBarPanelContext : mContext,
@@ -353,14 +409,18 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
R.bool.floating_rotation_button_position_left);
mControllers.rotationButtonController.setRotationButton(mFloatingRotationButton,
mRotationButtonListener);
+ if (isPhoneMode) {
+ mTaskbarTransitions.init();
+ }
applyState();
mPropertyHolders.forEach(StatePropertyHolder::endAnimation);
// Initialize things needed to move nav buttons to separate window.
- mSeparateWindowParent = new BaseDragLayer(mContext, null, 0) {
+ mSeparateWindowParent = new BaseDragLayer<>(mContext, null, 0) {
@Override
public void recreateControllers() {
+ super.recreateControllers();
mControllers = new TouchController[0];
}
@@ -372,6 +432,12 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
};
mSeparateWindowParent.recreateControllers();
+ if (BubbleBarController.isBubbleBarEnabled()) {
+ mNavButtonsView.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) ->
+ onLayoutsUpdated()
+ );
+ }
}
private void initButtons(ViewGroup navContainer, ViewGroup endContainer,
@@ -400,16 +466,19 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
flags -> (flags & FLAG_IME_VISIBLE) == 0));
}
mPropertyHolders.add(new StatePropertyHolder(mBackButton,
- flags -> (flags & FLAG_IME_VISIBLE) != 0,
+ flags -> (flags & FLAG_BACK_DISMISS_IME) != 0,
ROTATION_DRAWABLE_PERCENT, 1f, 0f));
- // Translate back button to be at end/start of other buttons for keyguard
+ // Translate back button to be at end/start of other buttons for keyguard (only after SUW
+ // since it is laid to align with SUW actions while in that state)
int navButtonSize = mContext.getResources().getDimensionPixelSize(
R.dimen.taskbar_nav_buttons_size);
boolean isRtl = Utilities.isRtl(mContext.getResources());
if (!mContext.isPhoneMode()) {
mPropertyHolders.add(new StatePropertyHolder(
- mBackButton, flags -> (flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
- || (flags & FLAG_KEYGUARD_VISIBLE) != 0,
+ mBackButton, flags -> mContext.isUserSetupComplete()
+ && ((flags & FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE) != 0
+ || (flags & FLAG_KEYGUARD_VISIBLE) != 0)
+ && (!shouldShowHomeButtonInLockscreen(flags)),
VIEW_TRANSLATE_X, navButtonSize * (isRtl ? -2 : 2), 0));
}
@@ -419,10 +488,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
mHomeButtonAlpha = new MultiValueAlpha(mHomeButton, NUM_ALPHA_CHANNELS);
mHomeButtonAlpha.setUpdateVisibility(true);
mPropertyHolders.add(
- new StatePropertyHolder(mHomeButtonAlpha.get(
- ALPHA_INDEX_KEYGUARD_OR_DISABLE),
- flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0
- && (flags & FLAG_DISABLE_HOME) == 0 && !mContext.isGestureNav()));
+ new StatePropertyHolder(mHomeButtonAlpha.get(ALPHA_INDEX_KEYGUARD_OR_DISABLE),
+ this::shouldShowHomeButtonInLockscreen));
// Recents button
mRecentsButton = addButton(R.drawable.ic_sysbar_recent, BUTTON_RECENTS,
@@ -438,6 +505,13 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
navButtonController.onButtonClick(BUTTON_RECENTS, v);
mHitboxExtender.onRecentsButtonClicked();
});
+ mRecentsButton.addOnLayoutChangeListener(
+ (v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
+ int[] location = v.getLocationOnScreen();
+ Rect bounds = new Rect(location[0], location[1], location[0] + v.getWidth(),
+ location[1] + v.getHeight());
+ navButtonController.onRecentsButtonLayoutChanged(bounds);
+ });
mPropertyHolders.add(new StatePropertyHolder(mRecentsButton,
flags -> (flags & FLAG_KEYGUARD_VISIBLE) == 0 && (flags & FLAG_DISABLE_RECENTS) == 0
&& !mContext.isNavBarKidsModeActive() && !mContext.isGestureNav()));
@@ -447,32 +521,68 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
endContainer, navButtonController, R.id.accessibility_button,
R.layout.taskbar_contextual_button);
mPropertyHolders.add(new StatePropertyHolder(mA11yButton,
- flags -> (flags & FLAG_A11Y_VISIBLE) != 0
- && (flags & FLAG_ROTATION_BUTTON_VISIBLE) == 0));
+ flags -> (flags & FLAG_A11Y_VISIBLE) != 0));
mSpace = new Space(mNavButtonsView.getContext());
mSpace.setOnClickListener(view -> navButtonController.onButtonClick(BUTTON_SPACE, view));
- mSpace.setOnLongClickListener(view -> navButtonController.onButtonLongClick(BUTTON_SPACE, view));
+ mSpace.setOnLongClickListener(view ->
+ navButtonController.onButtonLongClick(BUTTON_SPACE, view));
+ }
+
+ /**
+ * Method to determine whether the Navigation Bar is viewable in Setup Wizard
+ *
+ * @return {@code true} if the device is in Setup Wizard, the expressive theme is enabled,
+ * and Simple View is NOT enabled
+ */
+ boolean isNavbarHiddenInSUW() {
+ if (mContext == null) {
+ return false;
+ }
+ return !mContext.isUserSetupComplete() && mIsExpressiveThemeEnabled
+ && !mContext.isSimpleViewEnabled();
+ }
+
+ /**
+ * Method to determine whether to show the home button in lockscreen
+ *
+ * When the keyguard is visible hide home button. Anytime we are
+ * occluded we want to show the home button for apps over keyguard.
+ * however we don't want to show when not occluded/visible.
+ * (visible false || occluded true) && disable false && not gnav
+ */
+ private boolean shouldShowHomeButtonInLockscreen(int flags) {
+ return ((flags & FLAG_KEYGUARD_VISIBLE) == 0
+ || (flags & FLAG_KEYGUARD_OCCLUDED) != 0)
+ && (flags & FLAG_DISABLE_HOME) == 0
+ && !mContext.isGestureNav();
}
private void parseSystemUiFlags(@SystemUiStateFlags long sysUiStateFlags) {
mSysuiStateFlags = sysUiStateFlags;
- boolean isImeVisible = (sysUiStateFlags & SYSUI_STATE_IME_SHOWING) != 0;
- boolean isImeSwitcherShowing = (sysUiStateFlags & SYSUI_STATE_IME_SWITCHER_SHOWING) != 0;
+ boolean isImeSwitcherButtonVisible =
+ (sysUiStateFlags & SYSUI_STATE_IME_SWITCHER_BUTTON_VISIBLE) != 0;
+ boolean isImeVisible = (sysUiStateFlags & SYSUI_STATE_IME_VISIBLE) != 0;
+ boolean isBackDismissIme = (sysUiStateFlags & SYSUI_STATE_BACK_DISMISS_IME) != 0;
boolean a11yVisible = (sysUiStateFlags & SYSUI_STATE_A11Y_BUTTON_CLICKABLE) != 0;
boolean isHomeDisabled = (sysUiStateFlags & SYSUI_STATE_HOME_DISABLED) != 0;
- boolean isRecentsDisabled = (sysUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
+ // TODO: b/409075366 - ensure this signal is correctly set for external displays.
+ boolean isRecentsDisabled = mContext.isPrimaryDisplay()
+ && (sysUiStateFlags & SYSUI_STATE_OVERVIEW_DISABLED) != 0;
boolean isBackDisabled = (sysUiStateFlags & SYSUI_STATE_BACK_DISABLED) != 0;
long shadeExpandedFlags = SYSUI_STATE_NOTIFICATION_PANEL_EXPANDED
| SYSUI_STATE_QUICK_SETTINGS_EXPANDED;
boolean isNotificationShadeExpanded = (sysUiStateFlags & shadeExpandedFlags) != 0;
boolean isScreenPinningActive = (sysUiStateFlags & SYSUI_STATE_SCREEN_PINNING) != 0;
- boolean isVoiceInteractionWindowShowing = (sysUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0;
- boolean isKeyboardShortcutHelperShowing = (sysUiStateFlags & SYSUI_STATE_SHORTCUT_HELPER_SHOWING) != 0;
-
- // TODO(b/202218289) we're getting IME as not visible on lockscreen from system
+ boolean isVoiceInteractionWindowShowing =
+ (sysUiStateFlags & SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING) != 0;
+ boolean isKeyboardShortcutHelperShowing =
+ (sysUiStateFlags & SYSUI_STATE_SHORTCUT_HELPER_SHOWING) != 0;
+ boolean splitAnimationRunning =
+ (sysUiStateFlags & SYSUI_STATE_DISABLE_GESTURE_SPLIT_INVOCATION) != 0;
+ updateStateForFlag(FLAG_IME_SWITCHER_BUTTON_VISIBLE, isImeSwitcherButtonVisible);
updateStateForFlag(FLAG_IME_VISIBLE, isImeVisible);
- updateStateForFlag(FLAG_SWITCHER_SHOWING, isImeSwitcherShowing);
+ updateStateForFlag(FLAG_BACK_DISMISS_IME, isBackDismissIme);
updateStateForFlag(FLAG_A11Y_VISIBLE, a11yVisible);
updateStateForFlag(FLAG_DISABLE_HOME, isHomeDisabled);
updateStateForFlag(FLAG_DISABLE_RECENTS, isRecentsDisabled);
@@ -484,10 +594,17 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
if (mA11yButton != null) {
// Only used in 3 button
- boolean a11yLongClickable = (sysUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
+ boolean a11yLongClickable =
+ (sysUiStateFlags & SYSUI_STATE_A11Y_BUTTON_LONG_CLICKABLE) != 0;
mA11yButton.setLongClickable(a11yLongClickable);
updateButtonLayoutSpacing();
}
+
+ if (mNavButtonContainer.getChildCount() > 0) {
+ for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) {
+ mNavButtonContainer.getChildAt(i).setEnabled(!splitAnimationRunning);
+ }
+ }
}
public void updateStateForSysuiFlags(@SystemUiStateFlags long systemUiStateFlags,
@@ -519,8 +636,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
/**
* Slightly misnamed, but should be called when keyguard OR AOD is showing.
- * We consider keyguardVisible when it's showing bouncer OR is occlucded by
- * another app
+ * We consider keyguardVisible when it's showing bouncer OR is occlucded by another app
*/
public void setKeyguardVisible(boolean isKeyguardVisible, boolean isKeyguardOccluded) {
updateStateForFlag(FLAG_KEYGUARD_VISIBLE, isKeyguardVisible || isKeyguardOccluded);
@@ -556,7 +672,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
* Returns true if the recents (overview) button is disabled
*/
public boolean isRecentsDisabled() {
- return (mState & FLAG_DISABLE_RECENTS) != 0;
+ // TODO: b/409075366 - ensure this signal is correctly set for external displays.
+ return (mState & FLAG_DISABLE_RECENTS) != 0 && mContext.isPrimaryDisplay();
}
/**
@@ -602,12 +719,68 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
/**
* Sets the AccessibilityDelegate for the back button.
+ *
+ * When setting a back button accessibility delegate, make sure to not dispatch any duplicate
+ * click events. Click events get injected in the internal accessibility delegate in
+ * {@link #setupBackButtonAccessibility(View, AccessibilityDelegate)}.
*/
public void setBackButtonAccessibilityDelegate(AccessibilityDelegate accessibilityDelegate) {
if (mBackButton == null) {
return;
}
- mBackButton.setAccessibilityDelegate(accessibilityDelegate);
+ boolean predictiveBackThreeButtonNav;
+ try {
+ predictiveBackThreeButtonNav = predictiveBackThreeButtonNav();
+ } catch (Throwable t) {
+ predictiveBackThreeButtonNav = false;
+ }
+ if (predictiveBackThreeButtonNav) {
+ setupBackButtonAccessibility(mBackButton, accessibilityDelegate);
+ } else {
+ mBackButton.setAccessibilityDelegate(accessibilityDelegate);
+ }
+ }
+
+ public void setWallpaperVisible(boolean isVisible) {
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions.setWallpaperVisibility(isVisible);
+ }
+ }
+
+ public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
+ mTransitionMode = barMode;
+ if (checkBarModes) {
+ checkNavBarModes();
+ }
+ }
+
+ public void checkNavBarModes() {
+ if (mContext.isPhoneMode()) {
+ boolean isBarHidden = (mSysuiStateFlags & SYSUI_STATE_NAV_BAR_HIDDEN) != 0;
+ mTaskbarTransitions.transitionTo(mTransitionMode, !isBarHidden);
+ }
+ }
+
+ public void finishBarAnimations() {
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions.finishAnimations();
+ }
+ }
+
+ public void touchAutoDim(boolean reset) {
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions.setAutoDim(false);
+ mHandler.removeCallbacks(mAutoDim);
+ if (reset) {
+ mHandler.postDelayed(mAutoDim, AUTODIM_TIMEOUT_MS);
+ }
+ }
+ }
+
+ public void transitionTo(@BarTransitions.TransitionMode int barMode, boolean animate) {
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions.transitionTo(barMode, animate);
+ }
}
/** Use to set the translationY for the all nav+contextual buttons */
@@ -615,10 +788,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
return mTaskbarNavButtonTranslationY;
}
- /**
- * Use to set the translationY for the all nav+contextual buttons when in
- * Launcher
- */
+ /** Use to set the translationY for the all nav+contextual buttons when in Launcher */
public AnimatedFloat getTaskbarNavButtonTranslationYForInAppDisplay() {
return mTaskbarNavButtonTranslationYForInAppDisplay;
}
@@ -628,9 +798,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
return mTaskbarNavButtonDarkIntensity;
}
- /**
- * Use to override the nav button color with {@link #mOnBackgroundIconColor}.
- */
+ /** Use to override the nav button color with {@link #mOnBackgroundIconColor}. */
public AnimatedFloat getOnTaskbarBackgroundNavButtonColorOverride() {
return mOnTaskbarBackgroundNavButtonColorOverride;
}
@@ -649,7 +817,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
private void applyState() {
int count = mPropertyHolders.size();
for (int i = 0; i < count; i++) {
- mPropertyHolders.get(i).setState(mState);
+ mPropertyHolders.get(i).setState(mState, mContext.isGestureNav());
}
}
@@ -671,10 +839,10 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
final float normalTranslationY = mTaskbarNavButtonTranslationY.value;
final float imeAdjustmentTranslationY = mTaskbarNavButtonTranslationYForIme.value;
TaskbarUIController uiController = mControllers.uiController;
- final float inAppDisplayAdjustmentTranslationY = (uiController instanceof LauncherTaskbarUIController
- && ((LauncherTaskbarUIController) uiController).shouldUseInAppLayout())
- ? mTaskbarNavButtonTranslationYForInAppDisplay.value
- : 0;
+ final float inAppDisplayAdjustmentTranslationY =
+ (uiController instanceof LauncherTaskbarUIController
+ && ((LauncherTaskbarUIController) uiController).shouldUseInAppLayout())
+ ? mTaskbarNavButtonTranslationYForInAppDisplay.value : 0;
mLastSetNavButtonTranslationY = normalTranslationY
+ imeAdjustmentTranslationY
@@ -682,39 +850,78 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
mNavButtonsView.setTranslationY(mLastSetNavButtonTranslationY);
}
+ /**
+ * Sets Taskbar 3-button mode icon colors based on the
+ * {@link #mTaskbarNavButtonDarkIntensity} value piped in from Framework. For certain cases
+ * in large screen taskbar where there may be opaque surfaces, the selected SystemUI button
+ * colors are intentionally overridden.
+ *
+ * This method is also called when any of the AnimatedFloat instances change.
+ */
private void updateNavButtonColor() {
final ArgbEvaluator argbEvaluator = ArgbEvaluator.getInstance();
- final int sysUiNavButtonIconColorOnHome = (int) argbEvaluator.evaluate(
- mTaskbarNavButtonDarkIntensity.value,
- mLightIconColorOnHome,
- mDarkIconColorOnHome);
+ int taskbarNavButtonColor = getSysUiIconColorOnHome(argbEvaluator);
+ // Only phone mode foldable button colors should be identical to SysUI navbar colors.
+ if (!(ENABLE_TASKBAR_NAVBAR_UNIFICATION && mContext.isPhoneMode())) {
+ taskbarNavButtonColor = getTaskbarButtonColor(argbEvaluator, taskbarNavButtonColor);
+ }
+ applyButtonColors(taskbarNavButtonColor);
+ }
- // Override the color from framework if nav buttons are over an opaque Taskbar
- // surface.
- final int iconColor = (int) argbEvaluator.evaluate(
- mOnBackgroundNavButtonColorOverrideMultiplier.value
- * Math.max(
- mOnTaskbarBackgroundNavButtonColorOverride.value,
- mSlideInViewVisibleNavButtonColorOverride.value),
- sysUiNavButtonIconColorOnHome,
+ /**
+ * Taskbar 3-button mode icon colors based on the
+ * {@link #mTaskbarNavButtonDarkIntensity} value piped in from Framework.
+ */
+ private int getSysUiIconColorOnHome(ArgbEvaluator argbEvaluator) {
+ return (int) argbEvaluator.evaluate(getTaskbarNavButtonDarkIntensity().value,
+ mLightIconColorOnWorkspace, mDarkIconColorOnWorkspace);
+ }
+
+ /**
+ * If Taskbar background is opaque or slide in overlay is visible, the selected SystemUI button
+ * colors are intentionally overridden. The override can be disabled when
+ * {@link #mOnBackgroundNavButtonColorOverrideMultiplier} is {@code 0}.
+ */
+ private int getTaskbarButtonColor(ArgbEvaluator argbEvaluator, int sysUiIconColorOnHome) {
+ final float sysUIColorOverride =
+ mOnBackgroundNavButtonColorOverrideMultiplier.value * Math.max(
+ mOnTaskbarBackgroundNavButtonColorOverride.value,
+ mSlideInViewVisibleNavButtonColorOverride.value);
+ return (int) argbEvaluator.evaluate(sysUIColorOverride, sysUiIconColorOnHome,
mOnBackgroundIconColor);
+ }
+ /**
+ * Iteratively sets button colors for each button in {@link #mAllButtons}.
+ */
+ private void applyButtonColors(int iconColor) {
for (ImageView button : mAllButtons) {
button.setImageTintList(ColorStateList.valueOf(iconColor));
Drawable background = button.getBackground();
if (background instanceof KeyButtonRipple) {
((KeyButtonRipple) background).setDarkIntensity(
- mTaskbarNavButtonDarkIntensity.value);
+ getTaskbarNavButtonDarkIntensity().value);
}
}
}
+ /**
+ * Updates Taskbar 3-Button icon colors as {@link #mTaskbarNavButtonDarkIntensity} changes.
+ */
+ private void onDarkIntensityChanged() {
+ updateNavButtonColor();
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions.onDarkIntensityChanged(getTaskbarNavButtonDarkIntensity().value);
+ }
+ }
+
protected ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
ViewGroup parent, TaskbarNavButtonController navButtonController, @IdRes int id) {
return addButton(drawableId, buttonType, parent, navButtonController, id,
R.layout.taskbar_nav_button);
}
+ @SuppressLint("ClickableViewAccessibility")
private ImageView addButton(@DrawableRes int drawableId, @TaskbarButton int buttonType,
ViewGroup parent, TaskbarNavButtonController navButtonController, @IdRes int id,
@LayoutRes int layoutId) {
@@ -722,11 +929,103 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
buttonView.setImageResource(drawableId);
buttonView.setContentDescription(parent.getContext().getString(
navButtonController.getButtonContentDescription(buttonType)));
- buttonView.setOnClickListener(view -> navButtonController.onButtonClick(buttonType, view));
- buttonView.setOnLongClickListener(view -> navButtonController.onButtonLongClick(buttonType, view));
+ boolean predictiveBackThreeButtonNav;
+ try {
+ predictiveBackThreeButtonNav = predictiveBackThreeButtonNav();
+ } catch (Throwable t) {
+ predictiveBackThreeButtonNav = false;
+ }
+ if (predictiveBackThreeButtonNav && buttonType == BUTTON_BACK) {
+ // set up special touch listener for back button to support predictive back
+ setupBackButtonAccessibility(buttonView, null);
+ setBackButtonTouchListener(buttonView, navButtonController);
+ // Set this View clickable, so that NearestTouchFrame.java forwards closeby touches to
+ // this View
+ buttonView.setClickable(true);
+ } else {
+ buttonView.setOnClickListener(view ->
+ navButtonController.onButtonClick(buttonType, view));
+ buttonView.setOnLongClickListener(view ->
+ navButtonController.onButtonLongClick(buttonType, view));
+ buttonView.setOnTouchListener((v, event) -> {
+ if (event.getAction() == MotionEvent.ACTION_DOWN) {
+ buttonView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
+ return false;
+ });
+ }
return buttonView;
}
+ private void setupBackButtonAccessibility(View backButton,
+ AccessibilityDelegate accessibilityDelegate) {
+ View.AccessibilityDelegate backButtonAccessibilityDelegate =
+ new View.AccessibilityDelegate() {
+ @Override
+ public boolean performAccessibilityAction(View host, int action, Bundle args) {
+ if (accessibilityDelegate != null) {
+ accessibilityDelegate.performAccessibilityAction(host, action, args);
+ }
+ if (action == AccessibilityNodeInfo.ACTION_CLICK) {
+ mControllers.navButtonController.sendBackKeyEvent(KeyEvent.ACTION_DOWN,
+ /*cancelled*/ false);
+ mControllers.navButtonController.sendBackKeyEvent(KeyEvent.ACTION_UP,
+ /*cancelled*/ false);
+ return true;
+ }
+ return super.performAccessibilityAction(host, action, args);
+ }
+ };
+ backButton.setAccessibilityDelegate(backButtonAccessibilityDelegate);
+ }
+
+ private void setBackButtonTouchListener(View buttonView,
+ TaskbarNavButtonController navButtonController) {
+ final RectF rect = new RectF();
+ final AtomicBoolean hasSentDownEvent = new AtomicBoolean(false);
+ final Runnable longPressTimeout = () -> {
+ navButtonController.sendBackKeyEvent(KeyEvent.ACTION_DOWN, /*cancelled*/ false);
+ hasSentDownEvent.set(true);
+ };
+ buttonView.setOnTouchListener((v, event) -> {
+ int motionEventAction = event.getAction();
+ if (motionEventAction == MotionEvent.ACTION_DOWN) {
+ hasSentDownEvent.set(false);
+ mHandler.postDelayed(longPressTimeout, PREDICTIVE_BACK_TIMEOUT_MS);
+ rect.set(0, 0, v.getWidth(), v.getHeight());
+ buttonView.performHapticFeedback(HapticFeedbackConstants.VIRTUAL_KEY,
+ HapticFeedbackConstants.FLAG_IGNORE_VIEW_SETTING);
+ }
+ boolean isCancelled = motionEventAction == MotionEvent.ACTION_CANCEL
+ || (!rect.contains(event.getX(), event.getY())
+ && (motionEventAction == MotionEvent.ACTION_MOVE
+ || motionEventAction == MotionEvent.ACTION_UP));
+ if (motionEventAction != MotionEvent.ACTION_UP && !isCancelled) {
+ // return early. we don't care about any other cases than UP or CANCEL from here on
+ return false;
+ }
+ mHandler.removeCallbacks(longPressTimeout);
+ if (!hasSentDownEvent.get()) {
+ if (isCancelled) {
+ // if it is cancelled and ACTION_DOWN has not been sent yet, return early and
+ // don't send anything to sysui.
+ return false;
+ }
+ navButtonController.sendBackKeyEvent(KeyEvent.ACTION_DOWN, isCancelled);
+ }
+ navButtonController.sendBackKeyEvent(KeyEvent.ACTION_UP, isCancelled);
+ if (motionEventAction == MotionEvent.ACTION_UP && !isCancelled) {
+ buttonView.performClick();
+ }
+ return false;
+ });
+ buttonView.setOnLongClickListener((view) -> {
+ navButtonController.onButtonLongClick(BUTTON_BACK, view);
+ return false;
+ });
+ }
+
private ImageView addButton(ViewGroup parent, @IdRes int id, @LayoutRes int layoutId) {
ImageView buttonView = (ImageView) mContext.getLayoutInflater()
.inflate(layoutId, parent, false);
@@ -744,19 +1043,23 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
if (mFloatingRotationButton != null) {
mFloatingRotationButton.onConfigurationChanged(configChanges);
}
- if (!mContext.isUserSetupComplete()) {
+ if (!mContext.isUserSetupComplete() && !ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
handleSetupUi();
}
updateButtonLayoutSpacing();
}
private void handleSetupUi() {
+ // Setup wizard handles the UI when the expressive theme is enabled and Simple View isn't.
+ if (mIsExpressiveThemeEnabled && !mContext.isSimpleViewEnabled()) {
+ return;
+ }
// Since setup wizard only has back button enabled, it looks strange to be
// end-aligned, so start-align instead.
- FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams) mNavButtonContainer
- .getLayoutParams();
- FrameLayout.LayoutParams navButtonsViewLayoutParams = (FrameLayout.LayoutParams) mNavButtonsView
- .getLayoutParams();
+ FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams)
+ mNavButtonContainer.getLayoutParams();
+ FrameLayout.LayoutParams navButtonsViewLayoutParams = (FrameLayout.LayoutParams)
+ mNavButtonsView.getLayoutParams();
Resources resources = mContext.getResources();
DeviceProfile deviceProfile = mContext.getDeviceProfile();
@@ -767,9 +1070,9 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
// If SUW is on a large screen device that is landscape (or has a square aspect
// ratio) the back button has to be placed accordingly
- if ((deviceProfile.isTablet && deviceProfile.isLandscape)
- || (deviceProfile.aspectRatio > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
- && deviceProfile.aspectRatio < SQUARE_ASPECT_RATIO_UPPER_BOUND)) {
+ if ((deviceProfile.getDeviceProperties().isTablet() && deviceProfile.getDeviceProperties().isLandscape())
+ || (deviceProfile.getDeviceProperties().getAspectRatio() > SQUARE_ASPECT_RATIO_BOTTOM_BOUND
+ && deviceProfile.getDeviceProperties().getAspectRatio() < SQUARE_ASPECT_RATIO_UPPER_BOUND)) {
navButtonsLayoutParams.setMarginStart(
resources.getDimensionPixelSize(R.dimen.taskbar_back_button_suw_start_margin));
navButtonsViewLayoutParams.bottomMargin = resources.getDimensionPixelSize(
@@ -780,7 +1083,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
int phoneOrPortraitSetupMargin = resources.getDimensionPixelSize(
R.dimen.taskbar_contextual_button_suw_margin);
navButtonsLayoutParams.setMarginStart(phoneOrPortraitSetupMargin);
- navButtonsLayoutParams.bottomMargin = !deviceProfile.isLandscape
+ navButtonsLayoutParams.bottomMargin = !deviceProfile.getDeviceProperties().isLandscape()
? 0
: phoneOrPortraitSetupMargin - (resources.getDimensionPixelSize(
R.dimen.taskbar_nav_buttons_size) / 2);
@@ -792,8 +1095,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
/**
- * Adds the correct spacing to 3 button nav container depending on if device is
- * in kids mode,
+ * Adds the correct spacing to 3 button nav container depending on if device is in kids mode,
* setup wizard, or normal 3 button nav.
*/
private void updateButtonLayoutSpacing() {
@@ -806,10 +1108,11 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
boolean isInKidsMode = mContext.isNavBarKidsModeActive();
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
- NavButtonLayoutter navButtonLayoutter = NavButtonLayoutFactory.Companion.getUiLayoutter(
- dp, mNavButtonsView, mImeSwitcherButton,
- mA11yButton, mSpace, res, isInKidsMode, isInSetup, isThreeButtonNav,
- mContext.isPhoneMode(), mWindowManagerProxy.getRotation(mContext));
+ NavButtonLayoutter navButtonLayoutter =
+ NavButtonLayoutFactory.Companion.getUiLayoutter(
+ dp, mNavButtonsView, mImeSwitcherButton,
+ mA11yButton, mSpace, res, isInKidsMode, isInSetup, isThreeButtonNav,
+ mContext.isPhoneMode(), mWindowManagerProxy.getRotation(mContext));
navButtonLayoutter.layoutButtons(mContext, isA11yButtonPersistent());
updateButtonsBackground();
updateNavButtonColor();
@@ -849,7 +1152,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
// Home button layout
LinearLayout.LayoutParams homeLayoutparams = new LinearLayout.LayoutParams(
buttonWidth,
- buttonHeight);
+ buttonHeight
+ );
int homeButtonLeftMargin = res.getDimensionPixelSize(
R.dimen.taskbar_home_button_left_margin_kids);
homeLayoutparams.setMargins(homeButtonLeftMargin, 0, 0, 0);
@@ -858,7 +1162,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
// Back button layout
LinearLayout.LayoutParams backLayoutParams = new LinearLayout.LayoutParams(
buttonWidth,
- buttonHeight);
+ buttonHeight
+ );
int backButtonLeftMargin = res.getDimensionPixelSize(
R.dimen.taskbar_back_button_left_margin_kids);
backLayoutParams.setMargins(backButtonLeftMargin, 0, 0, 0);
@@ -872,8 +1177,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
mBackButton.setBackground(buttonBackground);
// Update alignment within taskbar
- FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams) mNavButtonContainer
- .getLayoutParams();
+ FrameLayout.LayoutParams navButtonsLayoutParams = (FrameLayout.LayoutParams)
+ mNavButtonContainer.getLayoutParams();
navButtonsLayoutParams.setMarginStart(
navButtonsLayoutParams.getMarginEnd() / 2);
navButtonsLayoutParams.setMarginEnd(navButtonsLayoutParams.getMarginStart());
@@ -890,15 +1195,15 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
// Setup normal 3 button
// Add spacing after the end of the last nav button
- FrameLayout.LayoutParams navButtonParams = (FrameLayout.LayoutParams) mNavButtonContainer.getLayoutParams();
+ FrameLayout.LayoutParams navButtonParams =
+ (FrameLayout.LayoutParams) mNavButtonContainer.getLayoutParams();
navButtonParams.gravity = Gravity.END;
navButtonParams.width = FrameLayout.LayoutParams.WRAP_CONTENT;
navButtonParams.height = MATCH_PARENT;
int navMarginEnd = (int) res.getDimension(dp.inv.inlineNavButtonsEndSpacing);
int contextualWidth = mEndContextualContainer.getWidth();
- // If contextual buttons are showing, we check if the end margin is enough for
- // the
+ // If contextual buttons are showing, we check if the end margin is enough for the
// contextual button to be showing - if not, move the nav buttons over a smidge
if (isA11yButtonPersistent() && navMarginEnd < contextualWidth) {
// Additional spacing, eat up half of space between last icon and nav button
@@ -911,7 +1216,8 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
int spaceInBetween = res.getDimensionPixelSize(R.dimen.taskbar_button_space_inbetween);
for (int i = 0; i < mNavButtonContainer.getChildCount(); i++) {
View navButton = mNavButtonContainer.getChildAt(i);
- LinearLayout.LayoutParams buttonLayoutParams = (LinearLayout.LayoutParams) navButton.getLayoutParams();
+ LinearLayout.LayoutParams buttonLayoutParams =
+ (LinearLayout.LayoutParams) navButton.getLayoutParams();
buttonLayoutParams.weight = 0;
if (i == 0) {
buttonLayoutParams.setMarginEnd(spaceInBetween / 2);
@@ -948,9 +1254,9 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
public void onDestroy() {
mPropertyHolders.clear();
- mControllers.rotationButtonController.unregisterListeners();
if (mFloatingRotationButton != null) {
mFloatingRotationButton.hide();
+ mFloatingRotationButton = null;
}
moveNavButtonsBackToTaskbarWindow();
@@ -961,8 +1267,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
/**
- * Moves mNavButtonsView from TaskbarDragLayer to a placeholder BaseDragLayer on
- * a new window.
+ * Moves mNavButtonsView from TaskbarDragLayer to a placeholder BaseDragLayer on a new window.
*/
public void moveNavButtonsToNewWindow() {
if (mAreNavButtonsInSeparateWindow) {
@@ -970,8 +1275,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
if (mIsImeRenderingNavButtons) {
- // IME is rendering the nav buttons, so we don't need to create a new layer for
- // them.
+ // IME is rendering the nav buttons, so we don't need to create a new layer for them.
return;
}
@@ -1000,8 +1304,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
/**
- * Moves mNavButtonsView from its temporary window and reattaches it to
- * TaskbarDragLayer.
+ * Moves mNavButtonsView from its temporary window and reattaches it to TaskbarDragLayer.
*/
public void moveNavButtonsBackToTaskbarWindow() {
if (!mAreNavButtonsInSeparateWindow) {
@@ -1020,8 +1323,7 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
/**
- * Called whenever a new ui controller is set, and should update anything that
- * depends on the
+ * Called whenever a new ui controller is set, and should update anything that depends on the
* ui controller.
*/
public void onUiControllerChanged() {
@@ -1054,13 +1356,17 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
+ mOnBackgroundNavButtonColorOverrideMultiplier.value);
mNavButtonsView.dumpLogs(prefix + "\t", pw);
+ if (mContext.isPhoneMode()) {
+ mTaskbarTransitions.dumpLogs(prefix + "\t", pw);
+ }
}
private static String getStateString(int flags) {
StringJoiner str = new StringJoiner("|");
- appendFlag(str, flags, FLAG_SWITCHER_SHOWING, "FLAG_SWITCHER_SHOWING");
+ appendFlag(str, flags, FLAG_IME_SWITCHER_BUTTON_VISIBLE,
+ "FLAG_IME_SWITCHER_BUTTON_VISIBLE");
appendFlag(str, flags, FLAG_IME_VISIBLE, "FLAG_IME_VISIBLE");
- appendFlag(str, flags, FLAG_ROTATION_BUTTON_VISIBLE, "FLAG_ROTATION_BUTTON_VISIBLE");
+ appendFlag(str, flags, FLAG_BACK_DISMISS_IME, "FLAG_BACK_DISMISS_IME");
appendFlag(str, flags, FLAG_A11Y_VISIBLE, "FLAG_A11Y_VISIBLE");
appendFlag(str, flags, FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE,
"FLAG_ONLY_BACK_FOR_BOUNCER_VISIBLE");
@@ -1090,6 +1396,105 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
mHitboxExtender.onAnimationProgressToOverview(alignment);
}
+ /** Adjusts navigation buttons layout accordingly to the bubble bar position. */
+ @Override
+ public void onBubbleBarLocationUpdated(BubbleBarLocation location) {
+ boolean locationUpdated = location != mBubbleBarTargetLocation;
+ if (locationUpdated) {
+ cancelExistingNavBarAnimation();
+ } else {
+ endExistingAnimation();
+ }
+ mNavButtonContainer.setTranslationX(getNavBarTranslationX(location));
+ mBubbleBarTargetLocation = location;
+ }
+
+ /** Animates navigation buttons accordingly to the bubble bar position. */
+ @Override
+ public void onBubbleBarLocationAnimated(BubbleBarLocation location) {
+ if (location == mBubbleBarTargetLocation) return;
+ cancelExistingNavBarAnimation();
+ mBubbleBarTargetLocation = location;
+ int finalX = getNavBarTranslationX(location);
+ Animator teleportAnimator = BarsLocationAnimatorHelper
+ .getTeleportAnimatorForNavButtons(location, mNavButtonContainer, finalX);
+ teleportAnimator.addListener(forEndCallback(() -> mNavBarLocationAnimator = null));
+ mNavBarLocationAnimator = teleportAnimator;
+ mNavBarLocationAnimator.start();
+ }
+
+ private void endExistingAnimation() {
+ if (mNavBarLocationAnimator != null) {
+ mNavBarLocationAnimator.end();
+ mNavBarLocationAnimator = null;
+ }
+ }
+
+ private void cancelExistingNavBarAnimation() {
+ if (mNavBarLocationAnimator != null) {
+ mNavBarLocationAnimator.cancel();
+ mNavBarLocationAnimator = null;
+ }
+ }
+
+ private int getNavBarTranslationX(BubbleBarLocation location) {
+ boolean isNavbarOnRight = location.isOnLeft(mNavButtonsView.isLayoutRtl());
+ DeviceProfile dp = mContext.getDeviceProfile();
+ float navBarTargetStartX;
+ if (!mContext.isUserSetupComplete()) {
+ // Skip additional translations on the nav bar container while in SUW layout
+ return 0;
+ } else if (mContext.shouldStartAlignTaskbar()) {
+ int navBarSpacing = dp.getHotseatProfile().getInlineNavButtonsEndSpacingPx();
+ // If the taskbar is start aligned the navigation bar is aligned to the start or end of
+ // the container, depending on the bubble bar location
+ if (isNavbarOnRight) {
+ navBarTargetStartX = dp.getDeviceProperties().getWidthPx() - navBarSpacing - mNavButtonContainer.getWidth();
+ } else {
+ navBarTargetStartX = navBarSpacing;
+ }
+ } else {
+ // If the task bar is not start aligned, the navigation bar is located in the center
+ // between the taskbar and screen edges, depending on the bubble bar location.
+ float navbarWidth = mNavButtonContainer.getWidth();
+ Rect taskbarBounds = mControllers.taskbarViewController
+ .getTransientTaskbarIconLayoutBoundsInParent();
+ if (isNavbarOnRight) {
+ if (mNavButtonsView.isLayoutRtl()) {
+ float taskBarEnd = taskbarBounds.right;
+ navBarTargetStartX = (dp.getDeviceProperties().getWidthPx() + taskBarEnd - navbarWidth) / 2;
+ } else {
+ navBarTargetStartX = mNavButtonContainer.getLeft();
+ }
+ } else {
+ float taskBarStart = taskbarBounds.left;
+ navBarTargetStartX = (taskBarStart - navbarWidth) / 2;
+ }
+ }
+ return (int) navBarTargetStartX - mNavButtonContainer.getLeft();
+ }
+
+ /** Adjusts the navigation buttons layout position according to the bubble bar location. */
+ public void onLayoutsUpdated() {
+ // no need to do anything if on phone, or if taskbar or navbar views were not placed on
+ // screen.
+ Rect transientTaskbarIconLayoutBoundsInParent = mControllers.taskbarViewController
+ .getTransientTaskbarIconLayoutBoundsInParent();
+ if (mContext.getDeviceProfile().getDeviceProperties().isPhone()
+ || transientTaskbarIconLayoutBoundsInParent.isEmpty()
+ || mNavButtonsView.getWidth() == 0) {
+ return;
+ }
+ if (mControllers.bubbleControllers.isPresent()) {
+ if (mBubbleBarTargetLocation == null) {
+ // only set bubble bar location if it was not set before
+ mBubbleBarTargetLocation = mControllers.bubbleControllers.get()
+ .bubbleBarViewController.getBubbleBarLocation();
+ }
+ onBubbleBarLocationUpdated(mBubbleBarTargetLocation);
+ }
+ }
+
private class RotationButtonListener implements RotationButton.RotationButtonUpdatesCallback {
@Override
public void onVisibilityChanged(boolean isVisible) {
@@ -1102,83 +1507,6 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
}
}
- private class RotationButtonImpl implements RotationButton {
-
- private final ImageView mButton;
- private AnimatedVectorDrawable mImageDrawable;
-
- RotationButtonImpl(ImageView button) {
- mButton = button;
- }
-
- @Override
- public void setRotationButtonController(RotationButtonController rotationButtonController) {
- // TODO(b/187754252) UI polish, different icons based on light/dark context, etc
- mImageDrawable = (AnimatedVectorDrawable) mButton.getContext()
- .getDrawable(rotationButtonController.getIconResId());
- mButton.setImageDrawable(mImageDrawable);
- mButton.setContentDescription(mButton.getResources()
- .getString(R.string.accessibility_rotate_button));
- mImageDrawable.setCallback(mButton);
- }
-
- @Override
- public View getCurrentView() {
- return mButton;
- }
-
- @Override
- public boolean show() {
- mButton.setVisibility(View.VISIBLE);
- mState |= FLAG_ROTATION_BUTTON_VISIBLE;
- applyState();
- return true;
- }
-
- @Override
- public boolean hide() {
- mButton.setVisibility(View.GONE);
- mState &= ~FLAG_ROTATION_BUTTON_VISIBLE;
- applyState();
- return true;
- }
-
- @Override
- public boolean isVisible() {
- return mButton.getVisibility() == View.VISIBLE;
- }
-
- @Override
- public void updateIcon(int lightIconColor, int darkIconColor) {
- // TODO(b/187754252): UI Polish
- }
-
- @Override
- public void setOnClickListener(OnClickListener onClickListener) {
- mButton.setOnClickListener(onClickListener);
- }
-
- @Override
- public void setOnHoverListener(OnHoverListener onHoverListener) {
- mButton.setOnHoverListener(onHoverListener);
- }
-
- @Override
- public AnimatedVectorDrawable getImageDrawable() {
- return mImageDrawable;
- }
-
- @Override
- public void setDarkIntensity(float darkIntensity) {
- // TODO(b/187754252) UI polish
- }
-
- @Override
- public boolean acceptRotationProposal() {
- return mButton.isAttachedToWindow();
- }
- }
-
private static class StatePropertyHolder {
private final float mEnabledValue, mDisabledValue;
@@ -1209,13 +1537,16 @@ public class NavbarButtonsViewController implements TaskbarControllers.LoggableT
mAnimator = ObjectAnimator.ofFloat(target, property, enabledValue, disabledValue);
}
- public void setState(int flags) {
+ public void setState(int flags, boolean skipAnimation) {
boolean isEnabled = mEnableCondition.test(flags);
if (mIsEnabled != isEnabled) {
mIsEnabled = isEnabled;
mAnimator.cancel();
mAnimator.setFloatValues(mIsEnabled ? mEnabledValue : mDisabledValue);
mAnimator.start();
+ if (skipAnimation) {
+ mAnimator.end();
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt b/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt
index da6932fc16..0dce63a838 100644
--- a/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/PinToTaskbarShortcut.kt
@@ -19,8 +19,11 @@ package com.android.launcher3.taskbar
import android.content.Context
import android.util.SparseArray
import android.view.View
+import android.window.DesktopExperienceFlags
+import androidx.annotation.VisibleForTesting
import com.android.launcher3.DeviceProfile
import com.android.launcher3.LauncherAppState
+import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS
import com.android.launcher3.LauncherSettings.Favorites.CONTAINER_HOTSEAT
import com.android.launcher3.R
import com.android.launcher3.model.BgDataModel
@@ -37,7 +40,7 @@ class PinToTaskbarShortcut(
target: T,
itemInfo: ItemInfo?,
originalView: View,
- private val mIsPin: Boolean,
+ @get:VisibleForTesting val mIsPin: Boolean,
private val mPinnedInfoList: SparseArray,
) :
SystemShortcut(
@@ -60,7 +63,18 @@ class PinToTaskbarShortcut(
.getWriter(true, mTarget!!.cellPosMapper, callbacks)
if (!mIsPin) {
- writer.deleteItemFromDatabase(mItemInfo, "item unpinned through long-press menu")
+ var infoToUnpin = mItemInfo
+ if (mItemInfo.container == CONTAINER_ALL_APPS) {
+ for (i in 0..(
writer.addItemToDatabase(newInfo, CONTAINER_HOTSEAT, mItemInfo.screenId, cellX, cellY)
}
+
+ companion object {
+ fun isPinningAppWithContextMenuEnabled(context: TaskbarActivityContext): Boolean =
+ DesktopExperienceFlags.ENABLE_PINNING_APP_WITH_CONTEXT_MENU.isTrue &&
+ context.isTaskbarShowingDesktopTasks
+ }
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
index 94e2244172..caf3320ea6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleView.java
@@ -47,6 +47,7 @@ public class StashedHandleView extends View {
private final int[] mTmpArr = new int[2];
private @Nullable ObjectAnimator mColorChangeAnim;
+ private Boolean mIsRegionDark;
public StashedHandleView(Context context) {
this(context, null);
@@ -95,7 +96,11 @@ public class StashedHandleView extends View {
* @param animate Whether to animate the change, or apply it immediately.
*/
public void updateHandleColor(boolean isRegionDark, boolean animate) {
+ if (mIsRegionDark != null && mIsRegionDark == isRegionDark) {
+ return;
+ }
int newColor = isRegionDark ? mStashedHandleLightColor : mStashedHandleDarkColor;
+ mIsRegionDark = isRegionDark;
if (mColorChangeAnim != null) {
mColorChangeAnim.cancel();
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
index 252f2a81f0..c19d883e96 100644
--- a/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/StashedHandleViewController.java
@@ -17,32 +17,34 @@ package com.android.launcher3.taskbar;
import static android.view.Display.DEFAULT_DISPLAY;
+import static com.android.launcher3.EncryptionType.ENCRYPTED;
+import static com.android.launcher3.LauncherPrefs.nonRestorableItem;
+import static com.android.launcher3.taskbar.Utilities.getShapedTaskbarRadius;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NAV_BAR_HIDDEN;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.ValueAnimator;
import android.content.Context;
-import android.content.SharedPreferences;
import android.content.res.Resources;
import android.graphics.Outline;
import android.graphics.Rect;
import android.view.View;
import android.view.ViewOutlineProvider;
+import com.android.launcher3.ConstantItem;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
-import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.NavHandle;
-import com.android.systemui.shared.navigationbar.RegionSamplingHelper;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
+import com.android.wm.shell.shared.handles.RegionSamplingHelper;
import java.io.PrintWriter;
@@ -56,7 +58,8 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
public static final int ALPHA_INDEX_HOME_DISABLED = 1;
public static final int ALPHA_INDEX_ASSISTANT_INVOKED = 2;
public static final int ALPHA_INDEX_HIDDEN_WHILE_DREAMING = 3;
- private static final int NUM_ALPHA_CHANNELS = 4;
+ public static final int ALPHA_INDEX_NUDGED = 4;
+ private static final int NUM_ALPHA_CHANNELS = 5;
// Values for long press animations, picked to most closely match navbar spec.
private static final float SCALE_TOUCH_ANIMATION_SHRINK = 0.85f;
@@ -68,8 +71,11 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
private static final String SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY =
"stashed_handle_region_is_dark";
+ private static final ConstantItem STASHED_HANDLE_REGION_IS_DARK =
+ nonRestorableItem(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY, false, ENCRYPTED);
+
private final TaskbarActivityContext mActivity;
- private final SharedPreferences mPrefs;
+ private final LauncherPrefs mPrefs;
private final StashedHandleView mStashedHandleView;
private int mStashedHandleWidth;
private final int mStashedHandleHeight;
@@ -94,6 +100,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
// States that affect whether region sampling is enabled or not
private boolean mIsStashed;
private boolean mIsLumaSamplingEnabled;
+ private boolean mIsAppTransitionPending;
private boolean mTaskbarHidden;
private float mTranslationYForSwipe;
@@ -102,13 +109,12 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
public StashedHandleViewController(TaskbarActivityContext activity,
StashedHandleView stashedHandleView) {
mActivity = activity;
- mPrefs = LauncherPrefs.getPrefs(mActivity);
+ mPrefs = LauncherPrefs.get(mActivity);
mStashedHandleView = stashedHandleView;
mTaskbarStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, NUM_ALPHA_CHANNELS);
mTaskbarStashedHandleAlpha.setUpdateVisibility(true);
mStashedHandleView.updateHandleColor(
- mPrefs.getBoolean(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY, false),
- false /* animate */);
+ mPrefs.get(STASHED_HANDLE_REGION_IS_DARK), false /* animate */);
final Resources resources = mActivity.getResources();
mStashedHandleHeight = resources.getDimensionPixelSize(
R.dimen.taskbar_stashed_handle_height);
@@ -118,16 +124,17 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
mControllers = controllers;
DeviceProfile deviceProfile = mActivity.getDeviceProfile();
Resources resources = mActivity.getResources();
- if (mActivity.isPhoneGestureNavMode() || mActivity.isTinyTaskbar()) {
+ if (mActivity.isPhoneGestureNavMode() || mActivity.isTinyTaskbar()
+ || mActivity.isBubbleBarOnPhone()) {
mTaskbarSize = resources.getDimensionPixelSize(R.dimen.taskbar_phone_size);
mStashedHandleWidth =
resources.getDimensionPixelSize(R.dimen.taskbar_stashed_small_screen);
} else {
- mTaskbarSize = deviceProfile.taskbarHeight;
+ mTaskbarSize = deviceProfile.getTaskbarProfile().getHeight();
mStashedHandleWidth = resources
.getDimensionPixelSize(R.dimen.taskbar_stashed_handle_width);
}
- int taskbarBottomMargin = deviceProfile.taskbarBottomMargin;
+ int taskbarBottomMargin = deviceProfile.getTaskbarProfile().getBottomMargin();
mStashedHandleView.getLayoutParams().height = mTaskbarSize + taskbarBottomMargin;
mTaskbarStashedHandleAlpha.get(ALPHA_INDEX_STASHED).setValue(
@@ -146,7 +153,9 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
stashedCenterX + mStashedHandleWidth / 2,
stashedCenterY + mStashedHandleHeight / 2);
mStashedHandleView.updateSampledRegion(mStashedHandleBounds);
- mStashedHandleRadius = view.getHeight() / 2f;
+ mStashedHandleRadius = Flags.enableLauncherIconShapes()
+ ? getShapedTaskbarRadius(mActivity)
+ : view.getHeight() / 2f;
outline.setRoundRect(mStashedHandleBounds, mStashedHandleRadius);
}
});
@@ -166,6 +175,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
/**
* Returns the stashed handle bounds.
+ *
* @param out The destination rect.
*/
public void getStashedHandleBounds(Rect out) {
@@ -178,8 +188,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
@Override
public void onRegionDarknessChanged(boolean isRegionDark) {
mStashedHandleView.updateHandleColor(isRegionDark, true /* animate */);
- mPrefs.edit().putBoolean(SHARED_PREFS_STASHED_HANDLE_REGION_DARK_KEY,
- isRegionDark).apply();
+ mPrefs.put(STASHED_HANDLE_REGION_IS_DARK, isRegionDark);
}
@Override
@@ -191,11 +200,13 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
public void onDestroy() {
- mRegionSamplingHelper.stopAndDestroy();
+ if (mRegionSamplingHelper != null) {
+ mRegionSamplingHelper.stopAndDestroy();
+ }
mRegionSamplingHelper = null;
}
- public MultiPropertyFactory getStashedHandleAlpha() {
+ public MultiValueAlpha getStashedHandleAlpha() {
return mTaskbarStashedHandleAlpha;
}
@@ -209,16 +220,18 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
* morphs into the size of where the taskbar icons will be.
*/
public Animator createRevealAnimToIsStashed(boolean isStashed) {
- Rect visualBounds = new Rect(mControllers.taskbarViewController.getIconLayoutBounds());
+ Rect visualBounds = mControllers.taskbarViewController
+ .getTransientTaskbarIconLayoutBounds();
float startRadius = mStashedHandleRadius;
- if (DisplayController.isTransientTaskbar(mActivity)) {
+ if (mActivity.isTransientTaskbar()) {
// Account for the full visual height of the transient taskbar.
int heightDiff = (mTaskbarSize - visualBounds.height()) / 2;
visualBounds.top -= heightDiff;
visualBounds.bottom += heightDiff;
-
- startRadius = visualBounds.height() / 2f;
+ startRadius = Flags.enableLauncherIconShapes()
+ ? getShapedTaskbarRadius(mActivity)
+ : visualBounds.height() / 2f;
}
final RevealOutlineAnimation handleRevealProvider = new RoundedRectRevealOutlineProvider(
@@ -257,6 +270,11 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
updateSamplingState();
}
+ public void setIsAppTransitionPending(boolean pending) {
+ mIsAppTransitionPending = pending;
+ updateSamplingState();
+ }
+
private void updateSamplingState() {
updateRegionSamplingWindowVisibility();
if (shouldSample()) {
@@ -268,7 +286,7 @@ public class StashedHandleViewController implements TaskbarControllers.LoggableT
}
private boolean shouldSample() {
- return mIsStashed && mIsLumaSamplingEnabled;
+ return mIsStashed && mIsLumaSamplingEnabled && !mIsAppTransitionPending;
}
protected void updateStashedHandleHintScale() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
index 4e8034da63..f7e760d44e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java
@@ -16,15 +16,19 @@
package com.android.launcher3.taskbar;
import static android.os.Trace.TRACE_TAG_APP;
-import static android.view.Display.DEFAULT_DISPLAY;
import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
+import static android.view.WindowManager.LayoutParams.FLAG_ALT_FOCUSABLE_IM;
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;
+import static androidx.annotation.VisibleForTesting.PACKAGE_PRIVATE;
+
+import static com.android.app.animation.Interpolators.LINEAR;
import static com.android.launcher3.AbstractFloatingView.TYPE_ALL;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ON_BOARD_POPUP;
import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_OVERLAY_PROXY;
import static com.android.launcher3.Flags.enableCursorHoverStates;
@@ -36,14 +40,18 @@ import static com.android.launcher3.config.FeatureFlags.enableTaskbarPinning;
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;
+import static com.android.launcher3.taskbar.TaskbarStashController.SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE;
import static com.android.launcher3.testing.shared.ResourceUtils.getBoolByName;
import static com.android.launcher3.util.Executors.UI_HELPER_EXECUTOR;
import static com.android.quickstep.util.AnimUtils.completeRunnableListCallback;
+import static com.android.quickstep.util.ExternalDisplaysKt.isExternalDisplay;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE;
import static com.android.systemui.shared.system.QuickStepContract.SYSUI_STATE_VOICE_INTERACTION_WINDOW_SHOWING;
+import static com.android.wm.shell.Flags.enableBubbleBar;
+import static com.android.wm.shell.Flags.enableBubbleBarOnPhones;
import static com.android.wm.shell.Flags.enableTinyTaskbar;
-import static java.util.stream.Collectors.toList;
+import static java.lang.invoke.MethodHandles.Lookup.PROTECTED;
import android.animation.AnimatorSet;
import android.animation.ValueAnimator;
@@ -55,20 +63,26 @@ import android.content.pm.ActivityInfo.Config;
import android.content.pm.LauncherApps;
import android.content.res.Resources;
import android.graphics.PixelFormat;
+import android.graphics.Point;
import android.graphics.Rect;
+import android.graphics.drawable.Drawable;
import android.hardware.display.DisplayManager;
import android.os.IRemoteCallback;
import android.os.Process;
import android.os.Trace;
import android.provider.Settings;
import android.util.Log;
-import android.view.Display;
import android.view.Gravity;
import android.view.Surface;
import android.view.View;
import android.view.WindowInsets;
import android.view.WindowManager;
+import android.widget.FrameLayout;
import android.widget.Toast;
+import android.window.DesktopExperienceFlags;
+import android.window.DesktopModeFlags;
+import android.window.DesktopModeFlags.DesktopModeFlag;
+import android.window.RemoteTransition;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
@@ -76,42 +90,64 @@ import androidx.annotation.VisibleForTesting;
import androidx.core.graphics.Insets;
import androidx.core.view.WindowInsetsCompat;
+import com.android.internal.jank.Cuj;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
+import com.android.launcher3.BubbleTextView.RunningAppState;
import com.android.launcher3.DeviceProfile;
+import com.android.launcher3.Flags;
import com.android.launcher3.LauncherPrefs;
import com.android.launcher3.LauncherSettings.Favorites;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
+import com.android.launcher3.allapps.ActivityAllAppsContainerView;
+import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.anim.AnimatorPlaybackController;
import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.config.FeatureFlags;
-import com.android.launcher3.dot.DotInfo;
+import com.android.launcher3.desktop.DesktopAppLaunchTransition;
+import com.android.launcher3.desktop.DesktopAppLaunchTransition.AppLaunchType;
import com.android.launcher3.folder.Folder;
import com.android.launcher3.folder.FolderIcon;
+import com.android.launcher3.icons.BitmapRenderer;
+import com.android.launcher3.icons.FastBitmapDrawable;
import com.android.launcher3.logger.LauncherAtom;
import com.android.launcher3.logging.StatsLogManager;
+import com.android.launcher3.model.ModelWriter;
import com.android.launcher3.model.data.AppInfo;
import com.android.launcher3.model.data.AppPairInfo;
import com.android.launcher3.model.data.FolderInfo;
import com.android.launcher3.model.data.ItemInfo;
+import com.android.launcher3.model.data.TaskItemInfo;
import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.popup.PopupDataProvider;
+import com.android.launcher3.statehandlers.DesktopVisibilityController;
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.AutohideSuspendFlag;
import com.android.launcher3.taskbar.TaskbarTranslationController.TransitionCallback;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.bubbles.BubbleBarController;
import com.android.launcher3.taskbar.bubbles.BubbleBarPinController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarSwipeController;
import com.android.launcher3.taskbar.bubbles.BubbleBarView;
import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.bubbles.BubbleCreator;
import com.android.launcher3.taskbar.bubbles.BubbleDismissController;
import com.android.launcher3.taskbar.bubbles.BubbleDragController;
import com.android.launcher3.taskbar.bubbles.BubblePinController;
-import com.android.launcher3.taskbar.bubbles.BubbleStashController;
import com.android.launcher3.taskbar.bubbles.BubbleStashedHandleViewController;
+import com.android.launcher3.taskbar.bubbles.DragToBubbleController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
+import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider;
+import com.android.launcher3.taskbar.bubbles.stashing.DeviceProfileDimensionsProviderAdapter;
+import com.android.launcher3.taskbar.bubbles.stashing.PersistentBubbleStashController;
+import com.android.launcher3.taskbar.bubbles.stashing.TransientBubbleStashController;
+import com.android.launcher3.taskbar.customization.TaskbarFeatureEvaluator;
+import com.android.launcher3.taskbar.customization.TaskbarSpecsEvaluator;
+import com.android.launcher3.taskbar.growth.NudgeController;
import com.android.launcher3.taskbar.navbutton.NearestTouchFrame;
+import com.android.launcher3.taskbar.overlay.TaskbarOverlayContext;
import com.android.launcher3.taskbar.overlay.TaskbarOverlayController;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
@@ -119,29 +155,39 @@ import com.android.launcher3.touch.ItemClickHandler;
import com.android.launcher3.touch.ItemClickHandler.ItemClickProxy;
import com.android.launcher3.util.ActivityOptionsWrapper;
import com.android.launcher3.util.ApiWrapper;
+import com.android.launcher3.util.ApplicationInfoWrapper;
import com.android.launcher3.util.ComponentKey;
import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.Executors;
+import com.android.launcher3.util.LauncherBindableItemsContainer;
+import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.NavigationMode;
-import com.android.launcher3.util.PackageManagerHelper;
import com.android.launcher3.util.RunnableList;
import com.android.launcher3.util.SettingsCache;
import com.android.launcher3.util.SplitConfigurationOptions.SplitSelectSource;
import com.android.launcher3.util.TraceHelper;
import com.android.launcher3.util.VibratorWrapper;
-import com.android.launcher3.util.ViewCache;
import com.android.launcher3.views.ActivityContext;
-import com.android.quickstep.LauncherActivityInterface;
+import com.android.launcher3.views.BaseDragLayer;
import com.android.quickstep.NavHandle;
import com.android.quickstep.RecentsModel;
+import com.android.quickstep.SystemUiProxy;
+import com.android.quickstep.util.DesktopTask;
+import com.android.quickstep.util.GroupTask;
+import com.android.quickstep.util.SingleTask;
+import com.android.quickstep.util.SplitTask;
+import com.android.quickstep.views.DesktopTaskView;
import com.android.quickstep.views.RecentsView;
import com.android.quickstep.views.TaskView;
+import com.android.systemui.animation.ViewRootSync;
import com.android.systemui.shared.recents.model.Task;
import com.android.systemui.shared.rotation.RotationButtonController;
+import com.android.systemui.shared.statusbar.phone.BarTransitions;
import com.android.systemui.shared.system.ActivityManagerWrapper;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
import com.android.systemui.unfold.updates.RotationChangeProvider;
import com.android.systemui.unfold.util.ScopedUnfoldTransitionProgressProvider;
+import com.android.wm.shell.shared.desktopmode.DesktopTaskToFrontReason;
import java.io.PrintWriter;
import java.util.Collections;
@@ -150,12 +196,9 @@ import java.util.Optional;
import java.util.function.Consumer;
/**
- * The {@link ActivityContext} with which we inflate Taskbar-related Views. This
- * allows UI elements
- * that are used by both Launcher and Taskbar (such as Folder) to reference a
- * generic
- * ActivityContext and BaseDragLayer instead of the Launcher activity and its
- * DragLayer.
+ * The {@link ActivityContext} with which we inflate Taskbar-related Views. This allows UI elements
+ * that are used by both Launcher and Taskbar (such as Folder) to reference a generic
+ * ActivityContext and BaseDragLayer instead of the Launcher activity and its DragLayer.
*/
public class TaskbarActivityContext extends BaseTaskbarContext {
@@ -165,6 +208,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
private static final String WINDOW_TITLE = "Taskbar";
+ public static final String SIMPLE_VIEW_SETTINGS_KEY = "matcha_enable";
+
+ protected static final DesktopModeFlag ENABLE_TASKBAR_BEHIND_SHADE = new DesktopModeFlag(
+ Flags::enableTaskbarBehindShade, false);
+
private final @Nullable Context mNavigationBarPanelContext;
private final TaskbarDragLayer mDragLayer;
@@ -173,24 +221,27 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
private final WindowManager mWindowManager;
private DeviceProfile mDeviceProfile;
private WindowManager.LayoutParams mWindowLayoutParams;
+ private WindowManager.LayoutParams mLastUpdatedLayoutParams;
private boolean mIsFullscreen;
+ private boolean mIsNotificationShadeExpanded = false;
// The size we should return to when we call setTaskbarWindowFullscreen(false)
private int mLastRequestedNonFullscreenSize;
+ /**
+ * When this is true, the taskbar window size is not updated. Requests to update the window
+ * size are stored in {@link #mLastRequestedNonFullscreenSize} and will take effect after
+ * bubbles no longer animate and {@link #setTaskbarWindowForAnimatingBubble()} is called.
+ */
+ private boolean mIsTaskbarSizeFrozenForAnimatingBubble;
private NavigationMode mNavMode;
private boolean mImeDrawsImeNavBar;
- private final ViewCache mViewCache = new ViewCache();
private final boolean mIsSafeModeEnabled;
- private final boolean mIsUserSetupComplete;
- private final boolean mIsNavBarForceVisible;
- private final boolean mIsNavBarKidsMode;
+ private boolean mIsUserSetupComplete;
+ private boolean mIsNavBarForceVisible;
+ private boolean mIsNavBarKidsMode;
private boolean mIsDestroyed = false;
- // The flag to know if the window is excluded from magnification region
- // computation.
- private boolean mIsExcludeFromMagnificationRegion = false;
- private boolean mBindingItems = false;
private boolean mAddedWindow = false;
// The bounds of the taskbar items relative to TaskbarDragLayer
@@ -203,46 +254,54 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
private DeviceProfile mPersistentTaskbarDeviceProfile;
private final LauncherPrefs mLauncherPrefs;
+ private final int mPrimaryDisplayId;
+ private final SystemUiProxy mSysUiProxy;
- public TaskbarActivityContext(Context windowContext,
+ private TaskbarFeatureEvaluator mTaskbarFeatureEvaluator;
+
+ private TaskbarSpecsEvaluator mTaskbarSpecsEvaluator;
+
+ // Snapshot is used to temporarily draw taskbar behind the shade.
+ private @Nullable View mTaskbarSnapshotView;
+ private @Nullable TaskbarOverlayContext mTaskbarSnapshotOverlay;
+
+ public TaskbarActivityContext(int displayId, Context windowContext,
@Nullable Context navigationBarPanelContext, DeviceProfile launcherDp,
TaskbarNavButtonController buttonController,
- ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider) {
- super(windowContext);
-
+ ScopedUnfoldTransitionProgressProvider unfoldTransitionProgressProvider,
+ boolean isPrimaryDisplay, int primaryDisplayId, SystemUiProxy sysUiProxy) {
+ super(windowContext, displayId, isPrimaryDisplay);
mNavigationBarPanelContext = navigationBarPanelContext;
+ mSysUiProxy = sysUiProxy;
+ mPrimaryDisplayId = primaryDisplayId;
applyDeviceProfile(launcherDp);
final Resources resources = getResources();
+ mTaskbarFeatureEvaluator = TaskbarFeatureEvaluator.getInstance(this);
+ mTaskbarSpecsEvaluator = new TaskbarSpecsEvaluator(
+ this,
+ mTaskbarFeatureEvaluator,
+ mDeviceProfile.inv.numRows,
+ mDeviceProfile.inv.numColumns);
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, resources, false);
mIsSafeModeEnabled = TraceHelper.allowIpcs("isSafeMode",
() -> getPackageManager().isSafeMode());
- // TODO(b/244231596) For shared Taskbar window, update this value in
- // applyDeviceProfile()
- // instead so to get correct value when recreating the taskbar
- SettingsCache settingsCache = SettingsCache.INSTANCE.get(this);
- mIsUserSetupComplete = settingsCache.getValue(
- Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
- mIsNavBarKidsMode = settingsCache.getValue(
- Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
- mIsNavBarForceVisible = mIsNavBarKidsMode;
-
// Get display and corners first, as views might use them in constructor.
- Display display = windowContext.getDisplay();
Context c = getApplicationContext();
mWindowManager = c.getSystemService(WindowManager.class);
// Inflate views.
- int taskbarLayout = DisplayController.isTransientTaskbar(this) && !isPhoneMode()
- ? R.layout.transient_taskbar
- : R.layout.taskbar;
+ boolean isTransientTaskbar = isTransientTaskbar();
+ int taskbarLayout = isTransientTaskbar ? R.layout.transient_taskbar : R.layout.taskbar;
mDragLayer = (TaskbarDragLayer) mLayoutInflater.inflate(taskbarLayout, null, false);
TaskbarView taskbarView = mDragLayer.findViewById(R.id.taskbar_view);
TaskbarScrimView taskbarScrimView = mDragLayer.findViewById(R.id.taskbar_scrim);
NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
StashedHandleView stashedHandleView = mDragLayer.findViewById(R.id.stashed_handle);
+ NudgeView nudgeView = mDragLayer.findViewById(R.id.nudge_icon);
BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
+ FrameLayout bubbleBarContainer = mDragLayer.findViewById(R.id.taskbar_bubbles_container);
StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
@@ -250,18 +309,37 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
// If Bubble bar is present, TaskbarControllers depends on it so build it first.
Optional bubbleControllersOptional = Optional.empty();
BubbleBarController.onTaskbarRecreated();
- if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
+ final boolean deviceBubbleBarEnabled = enableBubbleBarOnPhones()
+ || (!mDeviceProfile.getDeviceProperties().isPhone() && !mDeviceProfile.isVerticalBarLayout());
+ if (BubbleBarController.isBubbleBarEnabled() && deviceBubbleBarEnabled
+ && bubbleBarView != null && isPrimaryDisplay) {
+ Optional bubbleHandleController = Optional.empty();
+ Optional bubbleBarSwipeController = Optional.empty();
+ if (isTransientTaskbar) {
+ bubbleHandleController = Optional.of(
+ new BubbleStashedHandleViewController(this, bubbleHandleView));
+ bubbleBarSwipeController = Optional.of(new BubbleBarSwipeController(this));
+ }
+ TaskbarHotseatDimensionsProvider dimensionsProvider =
+ new DeviceProfileDimensionsProviderAdapter(this);
+ BubbleStashController bubbleStashController = isTransientTaskbar
+ ? new TransientBubbleStashController(dimensionsProvider, this)
+ : new PersistentBubbleStashController(dimensionsProvider);
+ bubbleStashController.setBubbleBarVerticalCenterForHome(
+ launcherDp.getBubbleBarVerticalCenterForHome());
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
- new BubbleBarViewController(this, bubbleBarView),
- new BubbleStashController(this),
- new BubbleStashedHandleViewController(this, bubbleHandleView),
- new BubbleDragController(this),
+ new BubbleBarViewController(this, bubbleBarView, bubbleBarContainer),
+ bubbleStashController,
+ bubbleHandleController,
+ new BubbleDragController(this, mDragLayer),
new BubbleDismissController(this, mDragLayer),
- new BubbleBarPinController(this, mDragLayer,
- () -> DisplayController.INSTANCE.get(this).getInfo().currentSize),
- new BubblePinController(this, mDragLayer,
- () -> DisplayController.INSTANCE.get(this).getInfo().currentSize)));
+ new BubbleBarPinController(this, bubbleBarContainer, this::getScreenSize),
+ new BubblePinController(this, bubbleBarContainer, this::getScreenSize),
+ bubbleBarSwipeController,
+ new DragToBubbleController(this, bubbleBarContainer),
+ new BubbleCreator(this)
+ ));
}
// Construct controllers.
@@ -278,7 +356,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers = new TaskbarControllers(this,
new TaskbarDragController(this),
buttonController,
- new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView),
+ new NavbarButtonsViewController(this, mNavigationBarPanelContext, navButtonsView,
+ getMainThreadHandler()),
rotationButtonController,
new TaskbarDragLayerController(this, mDragLayer),
new TaskbarViewController(this, taskbarView),
@@ -299,23 +378,29 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
new VoiceInteractionWindowController(this),
new TaskbarTranslationController(this),
new TaskbarSpringOnStashController(this),
- new TaskbarRecentAppsController(
- RecentsModel.INSTANCE.get(this),
- LauncherActivityInterface.INSTANCE::getDesktopVisibilityController),
+ new TaskbarRecentAppsController(this, RecentsModel.INSTANCE.get(this)),
TaskbarEduTooltipController.newInstance(this),
new KeyboardQuickSwitchController(),
- new TaskbarPinningController(this,
- () -> DisplayController.INSTANCE.get(this).getInfo().isInDesktopMode()),
- bubbleControllersOptional);
+ new TaskbarPinningController(this),
+ bubbleControllersOptional,
+ new TaskbarDesktopModeController(this,
+ DesktopVisibilityController.INSTANCE.get(this)),
+ new NudgeController(this),
+ new NudgeViewController(this, nudgeView));
mLauncherPrefs = LauncherPrefs.get(this);
+ onViewCreated();
}
- /** Updates {@link DeviceProfile} instances for any Taskbar windows. */
+ /** Updates {@link deviceprofile} instances for any Taskbar windows. */
public void updateDeviceProfile(DeviceProfile launcherDp) {
applyDeviceProfile(launcherDp);
-
mControllers.taskbarOverlayController.updateLauncherDeviceProfile(launcherDp);
+ mControllers.bubbleControllers.ifPresent(bubbleControllers -> {
+ int bubbleBarVerticalCenter = launcherDp.getBubbleBarVerticalCenterForHome();
+ bubbleControllers.bubbleStashController
+ .setBubbleBarVerticalCenterForHome(bubbleBarVerticalCenter);
+ });
AbstractFloatingView.closeAllOpenViewsExcept(this, false, TYPE_REBIND_SAFE);
// Reapply fullscreen to take potential new screen size into account.
setTaskbarWindowFullscreen(mIsFullscreen);
@@ -323,9 +408,66 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
dispatchDeviceProfileChanged();
}
+ public final int getPrimaryDisplayId() {
+ return mPrimaryDisplayId;
+ }
+
+ @Override
+ public boolean isTransientTaskbar() {
+ return DisplayController.isTransientTaskbar(this) && isPrimaryDisplay() && !isPhoneMode();
+ }
+
+ @Override
+ public boolean isPinnedTaskbar() {
+ return DisplayController.isPinnedTaskbar(this);
+ }
+
+ @Override
+ public NavigationMode getNavigationMode() {
+ return isPrimaryDisplay() ? DisplayController.getNavigationMode(this)
+ : NavigationMode.THREE_BUTTONS;
+ }
+
+ @Override
+ public boolean isInDesktopMode() {
+ return mControllers != null
+ && mControllers.taskbarDesktopModeController.isInDesktopMode(getDisplayId());
+ }
+
+ @Override
+ public boolean isTaskbarShowingDesktopTasks() {
+ return mControllers != null
+ && mControllers.taskbarDesktopModeController.shouldShowDesktopTasksInTaskbar(
+ getDisplayId());
+ }
+
+ @Override
+ public boolean showLockedTaskbarOnHome() {
+ return DisplayController.showLockedTaskbarOnHome(this);
+ }
+
+ @Override
+ public boolean showDesktopTaskbarForFreeformDisplay() {
+ return DisplayController.showDesktopTaskbarForFreeformDisplay(this);
+ }
+
+ @Override
+ public Point getScreenSize() {
+ return DisplayController.INSTANCE.get(this).getInfo().currentSize;
+ }
+
+ @Override
+ public int getDisplayHeight() {
+ return DisplayController.INSTANCE.get(this).getInfo().currentSize.y;
+ }
+
+ @Override
+ public void notifyConfigChanged() {
+ DisplayController.INSTANCE.get(this).notifyConfigChange();
+ }
+
/**
- * Copy the original DeviceProfile, match the number of hotseat icons and qsb
- * width and update
+ * Copy the original DeviceProfile, match the number of hotseat icons and qsb width and update
* the icon size
*/
private void applyDeviceProfile(DeviceProfile originDeviceProfile) {
@@ -336,13 +478,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
deviceProfile.hotseatQsbWidth = originDeviceProfile.hotseatQsbWidth;
// Update icon size
- deviceProfile.iconSizePx = deviceProfile.taskbarIconSize;
+ deviceProfile.iconSizePx = deviceProfile.getTaskbarProfile().getIconSize();
deviceProfile.updateIconSize(1f, this);
};
mDeviceProfile = originDeviceProfile.toBuilder(this)
.withDimensionsOverride(overrideProvider).build();
- if (DisplayController.isTransientTaskbar(this)) {
+ if (isTransientTaskbar()) {
mTransientTaskbarDeviceProfile = mDeviceProfile;
mPersistentTaskbarDeviceProfile = mDeviceProfile
.toBuilder(this)
@@ -357,24 +499,42 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
.setIsTransientTaskbar(true)
.build();
}
- mNavMode = DisplayController.getNavigationMode(this);
+ mNavMode = getNavigationMode();
+
+ SettingsCache settingsCache = SettingsCache.INSTANCE.get(this);
+ mIsUserSetupComplete = settingsCache.getValue(
+ Settings.Secure.getUriFor(Settings.Secure.USER_SETUP_COMPLETE), 0);
+ mIsNavBarKidsMode = settingsCache.getValue(
+ Settings.Secure.getUriFor(Settings.Secure.NAV_BAR_KIDS_MODE), 0);
+ mIsNavBarForceVisible = mIsNavBarKidsMode;
}
/** Called when the visibility of the bubble bar changed. */
public void bubbleBarVisibilityChanged(boolean isVisible) {
mControllers.uiController.adjustHotseatForBubbleBar(isVisible);
- mControllers.taskbarViewController.resetIconAlignmentController();
+ mControllers.taskbarViewController.adjustTaskbarForBubbleBar();
}
- public void init(@NonNull TaskbarSharedState sharedState) {
+ /**
+ * Init of taskbar activity context.
+ * @param duration If duration is greater than 0, it will be used to create an animation
+ * for the taskbar create/recreate process.
+ */
+ public void init(@NonNull TaskbarSharedState sharedState, int duration) {
mImeDrawsImeNavBar = getBoolByName(IME_DRAWS_IME_NAV_BAR_RES_NAME, getResources(), false);
mLastRequestedNonFullscreenSize = getDefaultTaskbarWindowSize();
mWindowLayoutParams = createAllWindowParams();
+ mLastUpdatedLayoutParams = new WindowManager.LayoutParams();
+
+
+ AnimatorSet recreateAnim = null;
+ if (duration > 0) {
+ recreateAnim = onRecreateAnimation(duration);
+ }
// Initialize controllers after all are constructed.
- mControllers.init(sharedState);
- // This may not be necessary and can be reverted once we move towards recreating
- // all
+ mControllers.init(sharedState, recreateAnim);
+ // This may not be necessary and can be reverted once we move towards recreating all
// controllers without re-creating the window
mControllers.rotationButtonController.onNavigationModeChanged(mNavMode.resValue);
updateSysuiStateFlags(sharedState.sysuiStateFlags, true /* fromInit */);
@@ -385,12 +545,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
onNavButtonsDarkIntensityChanged(sharedState.navButtonsDarkIntensity);
onNavigationBarLumaSamplingEnabled(sharedState.mLumaSamplingDisplayId,
sharedState.mIsLumaSamplingEnabled);
+ setWallpaperVisible(sharedState.wallpaperVisible);
+ onTransitionModeUpdated(sharedState.barMode, true /* checkBarModes */);
if (ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
- // W/ the flag not set this entire class gets re-created, which resets the value
- // of
- // mIsDestroyed. We re-use the class for small-screen, so we explicitly have to
- // mark
+ // W/ the flag not set this entire class gets re-created, which resets the value of
+ // mIsDestroyed. We re-use the class for small-screen, so we explicitly have to mark
// this class as non-destroyed
mIsDestroyed = false;
}
@@ -401,43 +561,95 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
} else {
notifyUpdateLayoutParams();
}
+
+
+ if (recreateAnim != null) {
+ recreateAnim.start();
+ }
}
/**
- * @return {@code true} if the device profile isn't a large screen profile and
- * we are using a
- * single window for taskbar and navbar.
+ * Create AnimatorSet for taskbar create/recreate animation. Further used in init
+ */
+ public AnimatorSet onRecreateAnimation(int duration) {
+ AnimatorSet animatorSet = new AnimatorSet();
+ animatorSet.setDuration(duration);
+ return animatorSet;
+ }
+
+ /**
+ * Called when we want destroy current taskbar with animation as part of recreate process.
+ */
+ public AnimatorSet onDestroyAnimation(int duration) {
+ mIsDestroyed = true;
+ AnimatorSet animatorSet = new AnimatorSet();
+ mControllers.taskbarViewController.onDestroyAnimation(animatorSet);
+ mControllers.taskbarDragLayerController.onDestroyAnimation(animatorSet);
+ animatorSet.setInterpolator(LINEAR);
+ animatorSet.setDuration(duration);
+ return animatorSet;
+ }
+
+ /**
+ * @return {@code true} if the device profile isn't a large screen profile and we are using a
+ * single window for taskbar and navbar.
*/
public boolean isPhoneMode() {
return ENABLE_TASKBAR_NAVBAR_UNIFICATION
- && mDeviceProfile.isPhone
+ && mDeviceProfile.getDeviceProperties().isPhone()
&& !mDeviceProfile.isTaskbarPresent;
}
+ public boolean isTaskbarInMinimalState() {
+ return mControllers.taskbarViewController.isTaskbarInMinimalState();
+ }
+
/**
- * @return {@code true} if {@link #isPhoneMode()} is true and we're using 3
- * button-nav
+ * @return {@code true} if {@link #isPhoneMode()} is true and we're using 3 button-nav
*/
public boolean isPhoneButtonNavMode() {
return isPhoneMode() && isThreeButtonNav();
}
/**
- * @return {@code true} if {@link #isPhoneMode()} is true and we're using
- * gesture nav
+ * @return {@code true} if {@link #isPhoneMode()} is true and we're using gesture nav
*/
public boolean isPhoneGestureNavMode() {
return isPhoneMode() && !isThreeButtonNav();
}
+ /** Returns whether Taskbar draws its own background, vs being translucent for apps to draw. */
+ public boolean drawsTaskbarBackground() {
+ return !isPhoneMode();
+ }
+
/** Returns {@code true} iff a tiny version of taskbar is shown on phone. */
public boolean isTinyTaskbar() {
- return enableTinyTaskbar() && mDeviceProfile.isPhone && mDeviceProfile.isTaskbarPresent;
+ return enableTinyTaskbar() && mDeviceProfile.getDeviceProperties().isPhone() && mDeviceProfile.isTaskbarPresent;
+ }
+
+ public boolean isBubbleBarOnPhone() {
+ return enableBubbleBarOnPhones() && enableBubbleBar() && mDeviceProfile.getDeviceProperties().isPhone();
}
/**
- * Returns if software keyboard is docked or input toolbar is placed at the
- * taskbar area
+ * Returns {@code true} iff bubble bar is enabled (but not necessarily visible /
+ * containing bubbles).
+ */
+ @Override
+ public boolean isBubbleBarEnabled() {
+ return getBubbleControllers() != null && BubbleBarController.isBubbleBarEnabled();
+ }
+
+ private boolean isBubbleBarAnimating() {
+ return mControllers
+ .bubbleControllers
+ .map(controllers -> controllers.bubbleBarViewController.isAnimatingNewBubble())
+ .orElse(false);
+ }
+
+ /**
+ * Returns if software keyboard is docked or input toolbar is placed at the taskbar area
*/
public boolean isImeDocked() {
View dragLayer = getDragLayer();
@@ -446,7 +658,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return false;
}
- WindowInsetsCompat insetsCompat = WindowInsetsCompat.toWindowInsetsCompat(insets, dragLayer.getRootView());
+ WindowInsetsCompat insetsCompat =
+ WindowInsetsCompat.toWindowInsetsCompat(insets, dragLayer.getRootView());
if (insetsCompat.isVisible(WindowInsetsCompat.Type.ime())) {
Insets imeInsets = insetsCompat.getInsets(WindowInsetsCompat.Type.ime());
@@ -461,17 +674,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
* Show Taskbar upon receiving broadcast
*/
public void showTaskbarFromBroadcast() {
- mControllers.taskbarStashController.showTaskbarFromBroadcast();
- }
-
- /** Toggles Taskbar All Apps overlay. */
- public void toggleAllApps() {
- mControllers.taskbarAllAppsController.toggle();
- }
-
- /** Toggles Taskbar All Apps overlay with keyboard ready for search. */
- public void toggleAllAppsSearch() {
- mControllers.taskbarAllAppsController.toggleSearch();
+ // If user is in middle of taskbar education handle go to next step of education
+ if (mControllers.taskbarEduTooltipController.isBeforeTooltipFeaturesStep()) {
+ mControllers.taskbarEduTooltipController.hide();
+ mControllers.taskbarEduTooltipController.maybeShowFeaturesEdu();
+ }
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
}
@Override
@@ -482,6 +690,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
@Override
public void dispatchDeviceProfileChanged() {
super.dispatchDeviceProfileChanged();
+ Trace.instantForTrack(TRACE_TAG_APP, "TaskbarActivityContext#DeviceProfileChanged",
+ getDeviceProfile().toSmallString());
}
@NonNull
@@ -507,19 +717,16 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Creates LayoutParams for adding a view directly to WindowManager as a new
- * window.
+ * 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 title The window title 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) {
int windowFlags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
- | WindowManager.LayoutParams.FLAG_SLIPPERY
- | WindowManager.LayoutParams.FLAG_SPLIT_TOUCH;
- if (DisplayController.isTransientTaskbar(this) && !isRunningInTestHarness()) {
+ | WindowManager.LayoutParams.FLAG_SLIPPERY;
+ boolean watchOutside = isTransientTaskbar() || isThreeButtonNav();
+ if (watchOutside && !isRunningInTestHarness()) {
windowFlags |= WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL
| WindowManager.LayoutParams.FLAG_WATCH_OUTSIDE_TOUCH;
}
@@ -536,7 +743,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
windowLayoutParams.receiveInsetsIgnoringZOrder = true;
windowLayoutParams.softInputMode = WindowManager.LayoutParams.SOFT_INPUT_ADJUST_NOTHING;
windowLayoutParams.layoutInDisplayCutoutMode = LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
- windowLayoutParams.privateFlags = WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
+ windowLayoutParams.privateFlags =
+ WindowManager.LayoutParams.PRIVATE_FLAG_NO_MOVE_ANIMATION;
windowLayoutParams.accessibilityTitle = getString(
isPhoneMode() ? R.string.taskbar_phone_a11y_title : R.string.taskbar_a11y_title);
@@ -544,19 +752,21 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets
- * LP.paramsForRotation
+ * Creates {@link WindowManager.LayoutParams} for Taskbar, and also sets LP.paramsForRotation
* for taskbar
*/
private WindowManager.LayoutParams createAllWindowParams() {
- final int windowType = ENABLE_TASKBAR_NAVBAR_UNIFICATION ? TYPE_NAVIGATION_BAR : TYPE_NAVIGATION_BAR_PANEL;
- WindowManager.LayoutParams windowLayoutParams = createDefaultWindowLayoutParams(windowType,
- TaskbarActivityContext.WINDOW_TITLE);
+ final int windowType =
+ (ENABLE_TASKBAR_NAVBAR_UNIFICATION && isPrimaryDisplay()) ? TYPE_NAVIGATION_BAR
+ : TYPE_NAVIGATION_BAR_PANEL;
+ WindowManager.LayoutParams windowLayoutParams =
+ createDefaultWindowLayoutParams(windowType, TaskbarActivityContext.WINDOW_TITLE);
windowLayoutParams.paramsForRotation = new WindowManager.LayoutParams[4];
for (int rot = Surface.ROTATION_0; rot <= Surface.ROTATION_270; rot++) {
- WindowManager.LayoutParams lp = createDefaultWindowLayoutParams(windowType,
- TaskbarActivityContext.WINDOW_TITLE);
+ WindowManager.LayoutParams lp =
+ createDefaultWindowLayoutParams(windowType,
+ TaskbarActivityContext.WINDOW_TITLE);
if (isPhoneButtonNavMode()) {
populatePhoneButtonNavModeWindowLayoutParams(rot, lp);
}
@@ -564,7 +774,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
// Override with current layout params
- WindowManager.LayoutParams currentParams = windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
+ WindowManager.LayoutParams currentParams =
+ windowLayoutParams.paramsForRotation[getDisplay().getRotation()];
windowLayoutParams.width = currentParams.width;
windowLayoutParams.height = currentParams.height;
windowLayoutParams.gravity = currentParams.gravity;
@@ -573,8 +784,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Update {@link WindowManager.LayoutParams} with values specific to phone and 3
- * button
+ * Update {@link WindowManager.LayoutParams} with values specific to phone and 3 button
* navigation users
*/
private void populatePhoneButtonNavModeWindowLayoutParams(int rot,
@@ -610,6 +820,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mNavMode == NavigationMode.THREE_BUTTONS;
}
+ /** Returns whether taskbar should start align. */
+ public boolean shouldStartAlignTaskbar() {
+ return isThreeButtonNav() && mDeviceProfile.getTaskbarProfile().isStartAlignTaskbar();
+ }
+
public boolean isGestureNav() {
return mNavMode == NavigationMode.NO_BUTTON;
}
@@ -619,9 +834,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
public int getCornerRadius() {
- return isPhoneMode() ? 0
- : getResources().getDimensionPixelSize(
- R.dimen.persistent_taskbar_corner_radius);
+ return isPhoneMode() ? 0 : getResources().getDimensionPixelSize(
+ R.dimen.persistent_taskbar_corner_radius);
}
public WindowManager.LayoutParams getWindowLayoutParams() {
@@ -643,6 +857,11 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mControllers.taskbarDragController;
}
+ @Override
+ public ModelWriter getModelWriter() {
+ return mControllers.taskbarViewController.getModelWriter();
+ }
+
@Nullable
public BubbleControllers getBubbleControllers() {
return mControllers.bubbleControllers.orElse(null);
@@ -653,11 +872,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mControllers.stashedHandleViewController;
}
- @Override
- public ViewCache getViewCache() {
- return mViewCache;
- }
-
@Override
public View.OnClickListener getItemOnClickListener() {
return this::onTaskbarIconClicked;
@@ -673,14 +887,16 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
LauncherAtom.ContainerInfo oldContainer = itemInfoBuilder.getContainerInfo();
- LauncherAtom.TaskBarContainer.Builder taskbarBuilder = LauncherAtom.TaskBarContainer.newBuilder();
+ LauncherAtom.TaskBarContainer.Builder taskbarBuilder =
+ LauncherAtom.TaskBarContainer.newBuilder();
if (mControllers.uiController.isInOverviewUi()) {
taskbarBuilder.setTaskSwitcherContainer(
LauncherAtom.TaskSwitcherContainer.newBuilder());
}
if (oldContainer.hasPredictedHotseatContainer()) {
- LauncherAtom.PredictedHotseatContainer predictedHotseat = oldContainer.getPredictedHotseatContainer();
+ LauncherAtom.PredictedHotseatContainer predictedHotseat =
+ oldContainer.getPredictedHotseatContainer();
if (predictedHotseat.hasIndex()) {
taskbarBuilder.setIndex(predictedHotseat.getIndex());
@@ -724,31 +940,28 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
}
- @Override
- public DotInfo getDotInfoForItem(ItemInfo info) {
- return getPopupDataProvider().getDotInfoForItem(info);
- }
-
@NonNull
@Override
public PopupDataProvider getPopupDataProvider() {
return mControllers.taskbarPopupController.getPopupDataProvider();
}
+ @NonNull
+ @Override
+ public LauncherBindableItemsContainer getContent() {
+ return mControllers.taskbarViewController.getContent();
+ }
+
+ @Override
+ public ActivityAllAppsContainerView> getAppsView() {
+ return mControllers.taskbarAllAppsController.getAppsView();
+ }
+
@Override
public View.AccessibilityDelegate getAccessibilityDelegate() {
return mAccessibilityDelegate;
}
- @Override
- public boolean isBindingItems() {
- return mBindingItems;
- }
-
- public void setBindingItems(boolean bindingItems) {
- mBindingItems = bindingItems;
- }
-
@Override
public void onDragStart() {
setTaskbarWindowFullscreen(true);
@@ -761,7 +974,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
@Override
public void onPopupVisibilityChanged(boolean isVisible) {
- setTaskbarWindowFocusable(isVisible);
+ setTaskbarWindowFocusable(isVisible /* focusable */, false /* imeFocusable */);
}
@Override
@@ -778,11 +991,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
public ActivityOptionsWrapper makeDefaultActivityOptions(int splashScreenStyle) {
RunnableList callbacks = new RunnableList();
ActivityOptions options = ActivityOptions.makeCustomAnimation(this, 0, 0);
- if (Utilities.ATLEAST_T) {
- options.setSplashScreenStyle(splashScreenStyle);
- }
- Utilities.allowBGLaunch(options);
- IRemoteCallback endCallback = completeRunnableListCallback(callbacks);
+ options.setSplashScreenStyle(splashScreenStyle);
+ options.setPendingIntentBackgroundActivityStartMode(
+ ActivityOptions.MODE_BACKGROUND_ACTIVITY_START_ALLOWED);
+ IRemoteCallback endCallback = completeRunnableListCallback(callbacks, this);
options.setOnAnimationAbortListener(endCallback);
options.setOnAnimationFinishedListener(endCallback);
@@ -794,11 +1006,23 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED);
}
+ private ActivityOptionsWrapper getActivityLaunchDesktopOptions() {
+ ActivityOptions options = ActivityOptions.makeRemoteTransition(
+ createDesktopAppLaunchRemoteTransition(
+ AppLaunchType.LAUNCH, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON));
+ return new ActivityOptionsWrapper(options, new RunnableList());
+ }
+
/**
* Sets a new data-source for this taskbar instance
*/
public void setUIController(@NonNull TaskbarUIController uiController) {
mControllers.setUiController(uiController);
+ if (BubbleBarController.isBubbleBarEnabled() && mControllers.bubbleControllers.isEmpty()) {
+ // if the bubble bar was visible in a previous configuration of taskbar and is being
+ // recreated now without bubbles, clean up any bubble bar adjustments from hotseat
+ bubbleBarVisibilityChanged(/* isVisible= */ false);
+ }
}
/**
@@ -808,11 +1032,39 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.taskbarStashController.setSetupUIVisible(isVisible);
}
+ public void setWallpaperVisible(boolean isVisible) {
+ mControllers.navbarButtonsViewController.setWallpaperVisible(isVisible);
+ }
+
+ public void checkNavBarModes() {
+ mControllers.navbarButtonsViewController.checkNavBarModes();
+ }
+
+ public void finishBarAnimations() {
+ mControllers.navbarButtonsViewController.finishBarAnimations();
+ }
+
+ public void touchAutoDim(boolean reset) {
+ mControllers.navbarButtonsViewController.touchAutoDim(reset);
+ }
+
+ public void transitionTo(@BarTransitions.TransitionMode int barMode,
+ boolean animate) {
+ mControllers.navbarButtonsViewController.transitionTo(barMode, animate);
+ }
+
+ public void appTransitionPending(boolean pending) {
+ mControllers.stashedHandleViewController.setIsAppTransitionPending(pending);
+ }
+
/**
* Called when this instance of taskbar is no longer needed
*/
public void onDestroy() {
+ onViewDestroyed();
+ removeTaskbarSnapshot();
mIsDestroyed = true;
+ mTaskbarFeatureEvaluator.onDestroy();
setUIController(TaskbarUIController.DEFAULT);
mControllers.onDestroy();
if (!enableTaskbarNoRecreate() && !ENABLE_TASKBAR_NAVBAR_UNIFICATION) {
@@ -830,7 +1082,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.navbarButtonsViewController.updateStateForSysuiFlags(systemUiStateFlags,
fromInit);
boolean isShadeVisible = (systemUiStateFlags & SYSUI_STATE_NOTIFICATION_PANEL_VISIBLE) != 0;
- onNotificationShadeExpandChanged(isShadeVisible, fromInit);
+ onNotificationShadeExpandChanged(isShadeVisible, fromInit || isPhoneMode());
mControllers.taskbarViewController.setRecentsButtonDisabled(
mControllers.navbarButtonsViewController.isRecentsDisabled()
|| isNavBarKidsModeActive());
@@ -849,25 +1101,124 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.uiController.updateStateForSysuiFlags(systemUiStateFlags);
mControllers.bubbleControllers.ifPresent(controllers -> {
controllers.bubbleBarController.updateStateForSysuiFlags(systemUiStateFlags);
- controllers.bubbleStashedHandleViewController.setIsHomeButtonDisabled(
- mControllers.navbarButtonsViewController.isHomeDisabled());
+ controllers.bubbleStashedHandleViewController.ifPresent(controller ->
+ controller.setIsHomeButtonDisabled(
+ mControllers.navbarButtonsViewController.isHomeDisabled()));
});
}
/**
- * Hides the taskbar icons and background when the notication shade is expanded.
+ * Hides the taskbar icons and background when the notification shade is expanded.
*/
private void onNotificationShadeExpandChanged(boolean isExpanded, boolean skipAnim) {
+ boolean isExpandedUpdated = isExpanded != mIsNotificationShadeExpanded;
+ mIsNotificationShadeExpanded = isExpanded;
+ // Close all floating views within the Taskbar window to make sure nothing is shown over
+ // the notification shade.
+ if (isExpanded) {
+ AbstractFloatingView.closeAllOpenViewsExcept(this, TYPE_TASKBAR_OVERLAY_PROXY);
+ }
+
float alpha = isExpanded ? 0 : 1;
AnimatorSet anim = new AnimatorSet();
anim.play(mControllers.taskbarViewController.getTaskbarIconAlpha().get(
TaskbarViewController.ALPHA_INDEX_NOTIFICATION_EXPANDED).animateToValue(alpha));
anim.play(mControllers.taskbarDragLayerController.getNotificationShadeBgTaskbar()
.animateToValue(alpha));
+
+ if (isExpandedUpdated) {
+ mControllers.bubbleControllers.ifPresent(controllers -> {
+ BubbleBarViewController bubbleBarViewController =
+ controllers.bubbleBarViewController;
+ anim.play(bubbleBarViewController.getBubbleBarAlpha().get(0).animateToValue(alpha));
+ MultiPropertyFactory.MultiProperty handleAlpha =
+ controllers.bubbleStashController.getHandleViewAlpha();
+ if (handleAlpha != null) {
+ anim.play(handleAlpha.animateToValue(alpha));
+ }
+ });
+ }
anim.start();
if (skipAnim) {
anim.end();
}
+
+ updateTaskbarSnapshot(anim, isExpanded);
+ }
+
+ private void updateTaskbarSnapshot(AnimatorSet anim, boolean isExpanded) {
+ if (!ENABLE_TASKBAR_BEHIND_SHADE.isTrue()
+ || isPhoneMode()) {
+ return;
+ }
+ if (mTaskbarSnapshotView == null) {
+ mTaskbarSnapshotView = new View(this);
+ }
+ if (isExpanded) {
+ if (!mTaskbarSnapshotView.isAttachedToWindow()
+ && mDragLayer.isAttachedToWindow()
+ && mDragLayer.isLaidOut()
+ && mDragLayer.isVisibleToUser()
+ && mTaskbarSnapshotView.getParent() == null) {
+ NearestTouchFrame navButtonsView = mDragLayer.findViewById(R.id.navbuttons_view);
+ int oldNavButtonsVisibility = navButtonsView.getVisibility();
+ navButtonsView.setVisibility(View.INVISIBLE);
+
+ Drawable drawable = new FastBitmapDrawable(BitmapRenderer.createHardwareBitmap(
+ mDragLayer.getWidth(),
+ mDragLayer.getHeight(),
+ mDragLayer::draw));
+
+ navButtonsView.setVisibility(oldNavButtonsVisibility);
+ mTaskbarSnapshotView.setBackground(drawable);
+ mTaskbarSnapshotView.setAlpha(0f);
+
+ mTaskbarSnapshotView.addOnAttachStateChangeListener(
+ new View.OnAttachStateChangeListener() {
+ @Override
+ public void onViewAttachedToWindow(@NonNull View v) {
+ mTaskbarSnapshotView.removeOnAttachStateChangeListener(this);
+ anim.end();
+ mTaskbarSnapshotView.setAlpha(1f);
+ if (!Utilities.isRunningInTestHarness()) {
+ ViewRootSync.synchronizeNextDraw(mDragLayer,
+ mTaskbarSnapshotView,
+ () -> {});
+ }
+ }
+
+ @Override
+ public void onViewDetachedFromWindow(@NonNull View v) {}
+ });
+ BaseDragLayer.LayoutParams layoutParams = new BaseDragLayer.LayoutParams(
+ mDragLayer.getWidth(), mDragLayer.getHeight());
+ layoutParams.gravity = mWindowLayoutParams.gravity;
+ layoutParams.ignoreInsets = true;
+ mTaskbarSnapshotOverlay = mControllers.taskbarOverlayController.requestWindow();
+ mTaskbarSnapshotOverlay.getDragLayer().addView(mTaskbarSnapshotView, layoutParams);
+ }
+ } else {
+ if (mTaskbarSnapshotView.isAttachedToWindow()) {
+ mTaskbarSnapshotView.setAlpha(0f);
+ anim.end();
+ if (Utilities.isRunningInTestHarness()) {
+ removeTaskbarSnapshot();
+ } else {
+ ViewRootSync.synchronizeNextDraw(mDragLayer, mTaskbarSnapshotView,
+ this::removeTaskbarSnapshot);
+ }
+ } else {
+ removeTaskbarSnapshot();
+ }
+ }
+ }
+
+ private void removeTaskbarSnapshot() {
+ if (mTaskbarSnapshotOverlay != null) {
+ mTaskbarSnapshotOverlay.getDragLayer().removeView(mTaskbarSnapshotView);
+ }
+ mTaskbarSnapshotView = null;
+ mTaskbarSnapshotOverlay = null;
}
public void onRotationProposal(int rotation, boolean isValid) {
@@ -885,9 +1236,13 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.rotationButtonController.onBehaviorChanged(displayId, behavior);
}
+ public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
+ mControllers.navbarButtonsViewController.onTransitionModeUpdated(barMode, checkBarModes);
+ }
+
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
- mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
- .updateValue(darkIntensity);
+ mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity().updateValue(
+ darkIntensity);
}
public void onNavigationBarLumaSamplingEnabled(int displayId, boolean enable) {
@@ -911,19 +1266,40 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
setTaskbarWindowSize(fullscreen ? MATCH_PARENT : mLastRequestedNonFullscreenSize);
}
+ /**
+ * Updates the taskbar window size according to whether bubbles are animating.
+ *
+ * This method should be called when bubbles start animating and again after the animation is
+ * complete.
+ */
+ public void setTaskbarWindowForAnimatingBubble() {
+ if (isBubbleBarAnimating()) {
+ // the default window size accounts for the bubble flyout
+ setTaskbarWindowSize(getDefaultTaskbarWindowSize());
+ mIsTaskbarSizeFrozenForAnimatingBubble = true;
+ } else {
+ mIsTaskbarSizeFrozenForAnimatingBubble = false;
+ setTaskbarWindowSize(
+ mLastRequestedNonFullscreenSize != 0
+ ? mLastRequestedNonFullscreenSize : getDefaultTaskbarWindowSize());
+ }
+ }
+
/**
* Called when drag ends or when a view is removed from the DragLayer.
*/
void onDragEndOrViewRemoved() {
boolean isDragInProgress = mControllers.taskbarDragController.isSystemDragInProgress();
- // Overlay AFVs are in a separate window and do not require Taskbar to be
- // fullscreen.
+ // 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);
+ Runnable resetTaskbarFullscreen = () -> setTaskbarWindowFullscreen(false);
+ mControllers.bubbleControllers.ifPresentOrElse(
+ bc -> bc.dragToBubbleController.runAfterDropTargetsHidden(
+ resetTaskbarFullscreen), resetTaskbarFullscreen);
}
setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_DRAGGING, isDragInProgress);
@@ -934,31 +1310,27 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Updates the TaskbarContainer size (pass
- * {@link #getDefaultTaskbarWindowSize()} to reset).
+ * Updates the TaskbarContainer size (pass {@link #getDefaultTaskbarWindowSize()} to reset).
*/
public void setTaskbarWindowSize(int size) {
- // In landscape phone button nav mode, we should set the task bar width instead
- // of height
- // because this is the only case in which the nav bar is not on the display
- // bottom.
- boolean landscapePhoneButtonNav = isPhoneButtonNavMode() && mDeviceProfile.isLandscape;
- if ((landscapePhoneButtonNav ? mWindowLayoutParams.width : mWindowLayoutParams.height) == size
- || mIsDestroyed) {
+ // In landscape phone button nav mode, we should set the task bar width instead of height
+ // because this is the only case in which the nav bar is not on the display bottom.
+ boolean landscapePhoneButtonNav = isPhoneButtonNavMode() && mDeviceProfile.getDeviceProperties().isLandscape();
+ if ((landscapePhoneButtonNav ? mWindowLayoutParams.width : mWindowLayoutParams.height)
+ == size || mIsDestroyed) {
return;
}
if (size == MATCH_PARENT) {
- size = mDeviceProfile.heightPx;
+ size = mDeviceProfile.getDeviceProperties().getHeightPx();
} else {
mLastRequestedNonFullscreenSize = size;
- if (mIsFullscreen) {
- // We still need to be fullscreen, so defer any change to our height until we
- // call
- // setTaskbarWindowFullscreen(false). For example, this could happen when
- // dragging
- // from the gesture region, as the drag will cancel the gesture and reset
- // launcher's
- // state, which in turn normally would reset the taskbar window height as well.
+ if (mIsFullscreen || mIsTaskbarSizeFrozenForAnimatingBubble) {
+ // We either still need to be fullscreen or a bubble is still animating, so defer
+ // any change to our height until setTaskbarWindowFullscreen(false) is called or
+ // setTaskbarWindowForAnimatingBubble() is called after the bubble animation
+ // completed. For example, this could happen when dragging from the gesture region,
+ // as the drag will cancel the gesture and reset launcher's state, which in turn
+ // normally would reset the taskbar window height as well.
return;
}
}
@@ -974,53 +1346,61 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
}
mControllers.runAfterInit(
- mControllers.taskbarInsetsController::onTaskbarOrBubblebarWindowHeightOrInsetsChanged);
+ mControllers.taskbarInsetsController
+ ::onTaskbarOrBubblebarWindowHeightOrInsetsChanged);
notifyUpdateLayoutParams();
}
/**
- * Returns the default size (in most cases height, but in 3-button phone mode,
- * width) of the
+ * Returns the default size (in most cases height, but in 3-button phone mode, width) of the
* window, including the static corner radii above taskbar.
*/
public int getDefaultTaskbarWindowSize() {
Resources resources = getResources();
if (isPhoneMode()) {
- return isThreeButtonNav() ? resources.getDimensionPixelSize(R.dimen.taskbar_phone_size)
- : resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
+ return isThreeButtonNav() ?
+ resources.getDimensionPixelSize(R.dimen.taskbar_phone_size) :
+ resources.getDimensionPixelSize(R.dimen.taskbar_stashed_size);
}
if (!isUserSetupComplete()) {
return getSetupWindowSize();
}
- boolean shouldTreatAsTransient = DisplayController.isTransientTaskbar(this)
- || (enableTaskbarPinning() && !isThreeButtonNav());
+ int bubbleBarTop = mControllers.bubbleControllers.map(bubbleControllers ->
+ bubbleControllers.bubbleBarViewController.getBubbleBarWithFlyoutMaximumHeight()
+ ).orElse(0);
+ int taskbarWindowSize;
+ boolean shouldTreatAsTransient =
+ isTransientTaskbar() || (enableTaskbarPinning()
+ && mTaskbarFeatureEvaluator.getSupportsTransitionToTransientTaskbar());
int extraHeightForTaskbarTooltips = enableCursorHoverStates()
? 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.taskbar_tooltip_vertical_padding) * 2)
+ + calculateTextHeight(
+ resources.getDimensionPixelSize(R.dimen.arrow_toast_text_size))
: 0;
- // Return transient taskbar window height when pinning feature is enabled, so
- // taskbar view
+ // Return transient taskbar window height when pinning feature is enabled, so taskbar view
// does not get cut off during pinning animation.
if (shouldTreatAsTransient) {
DeviceProfile transientTaskbarDp = mDeviceProfile.toBuilder(this)
.setIsTransientTaskbar(true).build();
- return transientTaskbarDp.taskbarHeight
- + (2 * transientTaskbarDp.taskbarBottomMargin)
+ taskbarWindowSize = transientTaskbarDp.getTaskbarProfile().getHeight()
+ + (2 * transientTaskbarDp.getTaskbarProfile().getBottomMargin())
+ Math.max(extraHeightForTaskbarTooltips, resources.getDimensionPixelSize(
- R.dimen.transient_taskbar_shadow_blur));
+ R.dimen.transient_taskbar_shadow_blur));
+ return Math.max(taskbarWindowSize, bubbleBarTop);
}
- return mDeviceProfile.taskbarHeight
+
+ taskbarWindowSize = mDeviceProfile.getTaskbarProfile().getHeight()
+ getCornerRadius()
+ extraHeightForTaskbarTooltips;
+ return Math.max(taskbarWindowSize, bubbleBarTop);
}
public int getSetupWindowSize() {
@@ -1036,35 +1416,55 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE}
- * on the taskbar
- * window.
+ * Sets whether the taskbar window should be focusable and IME focusable. This won't be IME
+ * focusable unless it is also focusable.
+ *
+ * @param focusable whether it should be focusable.
+ * @param imeFocusable whether it should be IME focusable.
+ *
+ * @see WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE
+ * @see WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM
*/
- public void setTaskbarWindowFocusable(boolean focusable) {
- if (focusable) {
- mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
- } else {
- mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
- }
- notifyUpdateLayoutParams();
- }
-
- /**
- * Applies forcibly show flag to taskbar window iff transient taskbar is
- * unstashed.
- */
- public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) {
- if (!DisplayController.isTransientTaskbar(this)) {
+ public void setTaskbarWindowFocusable(boolean focusable, boolean imeFocusable) {
+ if (isPhoneMode()) {
return;
}
+ if (focusable) {
+ mWindowLayoutParams.flags &= ~FLAG_NOT_FOCUSABLE;
+ if (imeFocusable) {
+ mWindowLayoutParams.flags &= ~FLAG_ALT_FOCUSABLE_IM;
+ } else {
+ mWindowLayoutParams.flags |= FLAG_ALT_FOCUSABLE_IM;
+ }
+ } else {
+ mWindowLayoutParams.flags |= FLAG_NOT_FOCUSABLE;
+ mWindowLayoutParams.flags &= ~FLAG_ALT_FOCUSABLE_IM;
+ }
notifyUpdateLayoutParams();
}
/**
- * Either adds or removes {@link WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE}
- * on the taskbar
- * window. If we're now focusable, also move nav buttons to a separate window
- * above IME.
+ * Applies forcibly show flag to taskbar window iff transient taskbar is unstashed.
+ */
+ public void applyForciblyShownFlagWhileTransientTaskbarUnstashed(boolean shouldForceShow) {
+ if (!isTransientTaskbar() || isPhoneMode()) {
+ return;
+ }
+ if (shouldForceShow) {
+ mWindowLayoutParams.forciblyShownTypes |= WindowInsets.Type.navigationBars();
+ } else {
+ mWindowLayoutParams.forciblyShownTypes &= ~WindowInsets.Type.navigationBars();
+ }
+ notifyUpdateLayoutParams();
+ }
+
+ /**
+ * Sets whether the taskbar window should be focusable, as well as IME focusable. If we're now
+ * focusable, also move nav buttons to a separate window above IME.
+ *
+ * @param focusable whether it should be focusable.
+ *
+ * @see WindowManager.LayoutParams#FLAG_NOT_FOCUSABLE
*/
public void setTaskbarWindowFocusableForIme(boolean focusable) {
if (focusable) {
@@ -1072,13 +1472,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
} else {
mControllers.navbarButtonsViewController.moveNavButtonsBackToTaskbarWindow();
}
- setTaskbarWindowFocusable(focusable);
+ setTaskbarWindowFocusable(focusable, true /* imeFocusable */);
}
- /**
- * Adds the given view to WindowManager with the provided LayoutParams (creates
- * new window).
- */
+ /** Adds the given view to WindowManager with the provided LayoutParams (creates new window). */
public void addWindowView(View view, WindowManager.LayoutParams windowLayoutParams) {
if (!view.isAttachedToWindow()) {
mWindowManager.addView(view, windowLayoutParams);
@@ -1097,15 +1494,50 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.uiController.startSplitSelection(splitSelectSource);
}
+ // If in overview, and a desktop task is available, launches the overview desktop task and
+ // schedules the provided runnable.
+ // Returns whether the runnable has been posted.
+ private boolean runAfterLaunchingDesktopTaskIfInOverview(
+ RecentsView recents,
+ Runnable runnableToRun) {
+ if (recents == null || !isTaskbarShowingDesktopTasks()
+ || !mControllers.uiController.isInOverviewUi()) {
+ return false;
+ }
+
+ RunnableList runnableList = recents.launchRunningDesktopTaskView();
+ // Wrapping it in runnable so we post after DW is ready for the app
+ // launch.
+ if (runnableList == null) {
+ return false;
+ }
+
+ runnableList.add(() -> UI_HELPER_EXECUTOR.execute(runnableToRun));
+ return true;
+ }
+
protected void onTaskbarIconClicked(View view) {
TaskbarUIController taskbarUIController = mControllers.uiController;
RecentsView recents = taskbarUIController.getRecentsView();
boolean shouldCloseAllOpenViews = true;
Object tag = view.getTag();
- if (tag instanceof Task) {
- Task task = (Task) tag;
- ActivityManagerWrapper.getInstance().startActivityFromRecents(task.key,
- ActivityOptions.makeBasic());
+
+ mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
+
+ // TODO: b/316004172, b/343289567: Handle `DesktopTask` and `SplitTask`.
+ if (tag instanceof SingleTask singleTask) {
+ RemoteTransition remoteTransition =
+ (isTaskbarShowingDesktopTasks() && canUnminimizeDesktopTask(
+ singleTask.getTask().key.id))
+ ? createDesktopAppLaunchRemoteTransition(AppLaunchType.UNMINIMIZE,
+ Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
+ : null;
+ Runnable launchTask = () -> handleGroupTaskLaunch(singleTask, remoteTransition,
+ isTaskbarShowingDesktopTasks(), DesktopTaskToFrontReason.TASKBAR_TAP);
+ if (!runAfterLaunchingDesktopTaskIfInOverview(recents, launchTask)) {
+ launchTask.run();
+ }
+
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
} else if (tag instanceof FolderInfo) {
// Tapping an expandable folder icon on Taskbar
@@ -1122,6 +1554,22 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.uiController.onTaskbarIconLaunched(api);
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
}
+ } else if (tag instanceof TaskItemInfo info) {
+ RemoteTransition remoteTransition = canUnminimizeDesktopTask(info.getTaskId())
+ ? createDesktopAppLaunchRemoteTransition(
+ AppLaunchType.UNMINIMIZE, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
+ : null;
+
+ Runnable launchTask = () ->
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(
+ info.getTaskId(), remoteTransition,
+ DesktopTaskToFrontReason.TASKBAR_TAP);
+ if (!runAfterLaunchingDesktopTaskIfInOverview(recents, launchTask)) {
+ UI_HELPER_EXECUTOR.execute(launchTask);
+ }
+
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(
+ /* stash= */ true);
} else if (tag instanceof WorkspaceItemInfo) {
// Tapping a launchable icon on Taskbar
WorkspaceItemInfo info = (WorkspaceItemInfo) tag;
@@ -1134,7 +1582,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
Intent intent = new Intent(info.getIntent())
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
- if (mIsSafeModeEnabled && !PackageManagerHelper.isSystemApp(this, intent)) {
+ if (mIsSafeModeEnabled
+ && !new ApplicationInfoWrapper(this, intent).isSystem()) {
Toast.makeText(this, R.string.safemode_shortcut_error,
Toast.LENGTH_SHORT).show();
} else if (info.isPromise()) {
@@ -1156,8 +1605,8 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
} catch (NullPointerException
- | ActivityNotFoundException
- | SecurityException e) {
+ | ActivityNotFoundException
+ | SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
.show();
Log.e(TAG, "Unable to launch. tag=" + info + " intent=" + intent, e);
@@ -1185,8 +1634,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
} else if (tag instanceof AppInfo) {
// Tapping an item in AllApps
AppInfo info = (AppInfo) tag;
- if (recents != null
- && taskbarUIController.getRecentsView().isSplitSelectionActive()) {
+ if (recents != null && recents.isSplitSelectionActive()) {
// If we are selecting a second app for split, launch the split tasks
taskbarUIController.triggerSecondAppForSplit(info, info.intent, view);
} else {
@@ -1200,14 +1648,80 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
Log.e(TAG, "Unknown type clicked: " + tag);
}
+ mControllers.taskbarPopupController.maybeCloseMultiInstanceMenu();
if (shouldCloseAllOpenViews) {
AbstractFloatingView.closeAllOpenViews(this);
}
}
/**
- * Runs when the user taps a Taskbar icon in TaskbarActivityContext (Overview or
- * inside an app),
+ * Launches the given GroupTask with the following behavior:
+ * - If the GroupTask is a DesktopTask, launch the tasks in that Desktop.
+ * - If {@code onDesktop}, bring the given GroupTask to the front.
+ * - If the GroupTask is a single task, launch it via startActivityFromRecents.
+ * - Otherwise, we assume the GroupTask is a Split pair and launch them together.
+ *
+ * Given start and/or finish callbacks, they will be run before an after the app launch
+ * respectively in cases where we can't use the remote transition, otherwise we will assume that
+ * these callbacks are included in the remote transition.
+ */
+ public void handleGroupTaskLaunch(
+ GroupTask task,
+ @Nullable RemoteTransition remoteTransition,
+ boolean onDesktop,
+ DesktopTaskToFrontReason toFrontReason) {
+ if (task instanceof DesktopTask) {
+ UI_HELPER_EXECUTOR.execute(
+ () -> SystemUiProxy.INSTANCE.get(this).showDesktopApps(getDisplayId(),
+ remoteTransition));
+ return;
+ }
+ if (onDesktop && task instanceof SingleTask singleTask) {
+ boolean useRemoteTransition = canUnminimizeDesktopTask(singleTask.getTask().key.id);
+ UI_HELPER_EXECUTOR.execute(() -> {
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(singleTask.getTask().key.id,
+ useRemoteTransition ? remoteTransition : null, toFrontReason);
+ });
+ return;
+ }
+ if (task instanceof SingleTask singleTask) {
+ UI_HELPER_EXECUTOR.execute(() -> {
+ ActivityOptions activityOptions =
+ makeDefaultActivityOptions(SPLASH_SCREEN_STYLE_UNDEFINED).options;
+ activityOptions.setRemoteTransition(remoteTransition);
+
+ ActivityManagerWrapper.getInstance().startActivityFromRecents(
+ singleTask.getTask().key, activityOptions);
+ });
+ return;
+ }
+ assert task instanceof SplitTask;
+ mControllers.uiController.launchSplitTasks((SplitTask) task, remoteTransition);
+ }
+
+ /** Returns whether the given task is minimized and can be unminimized. */
+ public boolean canUnminimizeDesktopTask(int taskId) {
+ BubbleTextView.RunningAppState runningAppState =
+ mControllers.taskbarRecentAppsController.getRunningAppState(taskId);
+ Log.d(TAG, "Task id=" + taskId + ", Running app state=" + runningAppState);
+ return runningAppState == RunningAppState.MINIMIZED
+ && DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_ALTTAB_TRANSITIONS_BUGFIX.isTrue();
+ }
+
+ private RemoteTransition createDesktopAppLaunchRemoteTransition(
+ AppLaunchType appLaunchType, @Cuj.CujType int cujType) {
+ return new RemoteTransition(
+ new DesktopAppLaunchTransition(
+ this,
+ appLaunchType,
+ cujType,
+ getMainExecutor()
+ ),
+ "TaskbarDesktopAppLaunch");
+ }
+
+ /**
+ * Runs when the user taps a Taskbar icon in TaskbarActivityContext (Overview or inside an app),
* and calls the appropriate method to animate and launch.
*/
private void launchFromTaskbar(@Nullable RecentsView recents, @Nullable View launchingIconView,
@@ -1224,7 +1738,10 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
*/
private void launchFromInAppTaskbar(@Nullable RecentsView recents,
@Nullable View launchingIconView, List extends ItemInfo> itemInfos) {
- if (recents == null) {
+ boolean launchedFromExternalDisplay =
+ DesktopExperienceFlags.ENABLE_TASKBAR_CONNECTED_DISPLAYS.isTrue()
+ && !isPrimaryDisplay();
+ if (recents == null && !launchedFromExternalDisplay) {
return;
}
@@ -1232,24 +1749,20 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
if (tappedAppPair) {
// If the icon is an app pair, the logic gets a bit complicated because we play
- // different animations depending on which app (or app pair) is currently
- // running on
+ // different animations depending on which app (or app pair) is currently running on
// screen, so delegate logic to appPairsController.
recents.getSplitSelectController().getAppPairsController()
.handleAppPairLaunchInApp((AppPairIcon) launchingIconView, itemInfos);
} else {
// Tapped a single app, nothing complicated here.
- startItemInfoActivity(itemInfos.get(0), null /* foundTask */);
+ startItemInfoActivity(itemInfos.get(0), null /*foundTask*/);
}
}
/**
- * Run when the user taps a Taskbar icon while in Overview. If the tapped app is
- * currently
- * visible to the user in Overview, or is part of a visible split pair, we
- * expand the TaskView
- * as if the user tapped on it (preserving the split pair). Otherwise, launch it
- * normally
+ * Run when the user taps a Taskbar icon while in Overview. If the tapped app is currently
+ * visible to the user in Overview, or is part of a visible split pair, we expand the TaskView
+ * as if the user tapped on it (preserving the split pair). Otherwise, launch it normally
* (potentially breaking a split pair).
*/
private void launchFromOverviewTaskbar(@Nullable RecentsView recents,
@@ -1260,20 +1773,21 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
boolean isLaunchingAppPair = itemInfos.size() == 2;
// Convert the list of ItemInfo instances to a list of ComponentKeys
- List componentKeys = itemInfos.stream().map(ItemInfo::getComponentKey).collect(toList());
+ List componentKeys =
+ itemInfos.stream().map(ItemInfo::getComponentKey).toList();
recents.getSplitSelectController().findLastActiveTasksAndRunCallback(
componentKeys,
isLaunchingAppPair,
foundTasks -> {
- @Nullable
- Task foundTask = foundTasks[0];
+ @Nullable Task foundTask = foundTasks[0];
if (foundTask != null) {
TaskView foundTaskView = recents.getTaskViewByTaskId(foundTask.key.id);
if (foundTaskView != null
- && foundTaskView.isVisibleToUser()) {
+ && foundTaskView.isVisibleToUser()
+ && !(foundTaskView instanceof DesktopTaskView)) {
TestLogging.recordEvent(
TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
- foundTaskView.launchTasks();
+ foundTaskView.launchWithAnimation();
return;
}
}
@@ -1282,24 +1796,28 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
// Finish recents animation if it's running before launching to ensure
// we get both leashes for the animation
mControllers.uiController.setSkipNextRecentsAnimEnd();
- recents.switchToScreenshot(() -> recents.finishRecentsAnimation(true /* toRecents */,
- false /* shouldPip */,
- () -> recents
- .getSplitSelectController()
- .getAppPairsController()
- .launchAppPair((AppPairIcon) launchingIconView,
- -1 /* cuj */)));
+ recents.switchToScreenshot(() ->
+ recents.finishRecentsAnimation(true /*toRecents*/,
+ false /*shouldPip*/,
+ () -> recents
+ .getSplitSelectController()
+ .getAppPairsController()
+ .launchAppPair((AppPairIcon) launchingIconView,
+ -1 /*cuj*/)));
} else {
- startItemInfoActivity(itemInfos.get(0), foundTask);
+ Runnable launchTask =
+ () -> startItemInfoActivity(itemInfos.get(0), foundTask);
+ if (!runAfterLaunchingDesktopTaskIfInOverview(recents, launchTask)) {
+ launchTask.run();
+ }
}
- });
+ }
+ );
}
/**
- * Starts an activity with the information provided by the "info" param.
- * However, if
- * taskInRecents is present, it will prioritize re-launching an existing
- * instance via
+ * Starts an activity with the information provided by the "info" param. However, if
+ * taskInRecents is present, it will prioritize re-launching an existing instance via
* {@link ActivityManagerWrapper#startActivityFromRecents(int, ActivityOptions)}
*/
private void startItemInfoActivity(ItemInfo info, @Nullable Task taskInRecents) {
@@ -1307,26 +1825,29 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
try {
TestLogging.recordEvent(TestProtocol.SEQUENCE_MAIN, "start: taskbarAppIcon");
- if (info.user.equals(Process.myUserHandle())) {
- // TODO(b/216683257): Use startActivityForResult for search results that require
- // it.
- if (taskInRecents != null) {
- // Re launch instance from recents
- ActivityOptionsWrapper opts = getActivityLaunchOptions(null, info);
- opts.options.setLaunchDisplayId(
- getDisplay() == null ? DEFAULT_DISPLAY : getDisplay().getDisplayId());
- if (ActivityManagerWrapper.getInstance()
- .startActivityFromRecents(taskInRecents.key, opts.options)) {
- mControllers.uiController.getRecentsView()
- .addSideTaskLaunchCallback(opts.onEndCallback);
- return;
- }
- }
-
- startActivity(intent);
- } else {
+ if (!info.user.equals(Process.myUserHandle())) {
+ // TODO b/376819104: support Desktop launch animations for apps in managed profiles
getSystemService(LauncherApps.class).startMainActivity(
intent.getComponent(), info.user, intent.getSourceBounds(), null);
+ return;
+ }
+ int displayId = getDisplayId();
+ // TODO(b/216683257): Use startActivityForResult for search results that require it.
+ if (taskInRecents != null) {
+ // Re launch instance from recents
+ ActivityOptionsWrapper opts = getActivityLaunchOptions(null, info);
+ opts.options.setLaunchDisplayId(displayId);
+ if (ActivityManagerWrapper.getInstance()
+ .startActivityFromRecents(taskInRecents.key, opts.options)) {
+ mControllers.uiController.getRecentsView()
+ .addSideTaskLaunchCallback(opts.onEndCallback);
+ return;
+ }
+ }
+ if (shouldLaunchInDesktop(displayId, info)) {
+ launchDesktopApp(intent, info, displayId);
+ } else {
+ startActivity(intent, null);
}
} catch (NullPointerException | ActivityNotFoundException | SecurityException e) {
Toast.makeText(this, R.string.activity_not_found, Toast.LENGTH_SHORT)
@@ -1335,6 +1856,46 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
}
+ private boolean shouldLaunchInDesktop(int displayId, ItemInfo info) {
+ if (!DesktopModeFlags.ENABLE_DESKTOP_APP_LAUNCH_TRANSITIONS_BUGFIX.isTrue()) {
+ return false;
+ }
+ if (DesktopExperienceFlags.ENABLE_DESKTOP_FIRST_FULLSCREEN_REFOCUS_BUGFIX.isTrue()
+ && DisplayController.isInDesktopFirstMode(this)
+ && mControllers.taskbarRecentAppsController.hasSingleTask(info)) {
+ // Keep the fullscreen mode in desktop-first mode.
+ return false;
+ }
+ // Always launch in freeform if in external display.
+ return (DesktopExperienceFlags.ENABLE_FREEFORM_DISPLAY_LAUNCH_PARAMS.isTrue()
+ && isExternalDisplay(displayId)) || isTaskbarShowingDesktopTasks();
+ }
+
+ private void launchDesktopApp(Intent intent, ItemInfo info, int displayId) {
+ TaskbarRecentAppsController.TaskState taskState =
+ mControllers.taskbarRecentAppsController.getDesktopItemState(info);
+ RunningAppState appState = taskState.getRunningAppState();
+ if (appState == RunningAppState.RUNNING || appState == RunningAppState.MINIMIZED) {
+ // We only need a custom animation (a RemoteTransition) if the task is minimized - if
+ // it's already visible it will just be brought forward.
+ RemoteTransition remoteTransition = (appState == RunningAppState.MINIMIZED)
+ ? createDesktopAppLaunchRemoteTransition(
+ AppLaunchType.UNMINIMIZE, Cuj.CUJ_DESKTOP_MODE_APP_LAUNCH_FROM_ICON)
+ : null;
+ UI_HELPER_EXECUTOR.execute(() ->
+ SystemUiProxy.INSTANCE.get(this).showDesktopApp(taskState.getTaskId(),
+ remoteTransition, DesktopTaskToFrontReason.TASKBAR_TAP));
+ return;
+ }
+ // There is no task associated with this launch - launch a new task through an intent
+ ActivityOptionsWrapper opts = getActivityLaunchDesktopOptions();
+ if (DesktopModeFlags.ENABLE_START_LAUNCH_TRANSITION_FROM_TASKBAR_BUGFIX.isTrue()) {
+ mSysUiProxy.startLaunchIntentTransition(intent, opts.options.toBundle(), displayId);
+ } else {
+ startActivity(intent, opts.options.toBundle());
+ }
+ }
+
/** Expands a folder icon when it is clicked */
private void expandFolder(FolderIcon folderIcon) {
Folder folder = folderIcon.getFolder();
@@ -1360,13 +1921,19 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
folder.animateOpen();
getStatsLogManager().logger().withItemInfo(folder.mInfo).log(LAUNCHER_FOLDER_OPEN);
- folder.iterateOverItems((itemInfo, itemView) -> {
+ folder.mapOverItems((itemInfo, itemView) -> {
mControllers.taskbarViewController
.setClickAndLongClickListenersForIcon(itemView);
// To play haptic when dragging, like other Taskbar items do.
itemView.setHapticFeedbackEnabled(true);
return false;
});
+
+ // Close any open taskbar tooltips.
+ if (AbstractFloatingView.hasOpenView(this, TYPE_ON_BOARD_POPUP)) {
+ AbstractFloatingView.getOpenView(this, TYPE_ON_BOARD_POPUP)
+ .close(/* animate= */ false);
+ }
});
}
@@ -1379,10 +1946,19 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
/**
* Called when we want to unstash taskbar when user performs swipes up gesture.
+ *
+ * @param delayTaskbarBackground whether we will delay the taskbar background animation
*/
- public void onSwipeToUnstashTaskbar() {
+ public void onSwipeToUnstashTaskbar(boolean delayTaskbarBackground) {
+ mControllers.uiController.onSwipeToUnstashTaskbar();
+
boolean wasStashed = mControllers.taskbarStashController.isStashed();
- mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false);
+ if (isTransientTaskbar()) {
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(/* stash= */ false,
+ SHOULD_BUBBLES_FOLLOW_DEFAULT_VALUE, delayTaskbarBackground);
+ } else if (shouldAllowTaskbarToAutoStash()) {
+ mControllers.taskbarStashController.updateAndAnimatePinnedTaskbar(false);
+ }
boolean isStashed = mControllers.taskbarStashController.isStashed();
if (isStashed != wasStashed) {
VibratorWrapper.INSTANCE.get(this).vibrateForTaskbarUnstash();
@@ -1390,15 +1966,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.taskbarEduTooltipController.hide();
}
- /**
- * Called when we want to open bubblebar when user performs swipes up gesture.
- */
- public void onSwipeToOpenBubblebar() {
- mControllers.bubbleControllers.ifPresent(controllers -> {
- controllers.bubbleStashController.showBubbleBar(/* expandBubbles= */ true);
- });
- }
-
/** Returns {@code true} if Taskbar All Apps is open. */
public boolean isTaskbarAllAppsOpen() {
return mControllers.taskbarAllAppsController.isOpen();
@@ -1417,8 +1984,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Called to start the taskbar translation spring to its settled translation
- * (0).
+ * Called to start the taskbar translation spring to its settled translation (0).
*/
public void startTranslationSpring() {
mControllers.taskbarTranslationController.startSpring();
@@ -1439,19 +2005,23 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
}
/**
- * Called when we detect a motion down or up/cancel in the nav region while
- * stashed.
+ * Called when we detect a motion down or up/cancel in the nav region while stashed.
*
- * @param animateForward Whether to animate towards the unstashed hint state or
- * back to stashed.
+ * @param animateForward Whether to animate towards the unstashed hint state or back to stashed.
*/
public void startTaskbarUnstashHint(boolean animateForward) {
mControllers.taskbarStashController.startUnstashHint(animateForward);
}
/**
- * Enables the auto timeout for taskbar stashing. This method should only be
- * used for taskbar
+ * @return if we should allow taskbar to auto stash
+ */
+ public boolean shouldAllowTaskbarToAutoStash() {
+ return mControllers.taskbarStashController.shouldAllowTaskbarToAutoStash();
+ }
+
+ /**
+ * Enables the auto timeout for taskbar stashing. This method should only be used for taskbar
* testing.
*/
@VisibleForTesting
@@ -1464,7 +2034,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
*/
@VisibleForTesting
public void unstashTaskbarIfStashed() {
- if (DisplayController.isTransientTaskbar(this)) {
+ if (isTransientTaskbar()) {
mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(false);
}
}
@@ -1483,32 +2053,40 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mIsUserSetupComplete;
}
+ /**
+ * Checks if the simple view mode is enabled.
+ *
+ * Since Simple View puts the device in 3 button nav mode, we use that as a precursor to
+ * checking the actual value in Settings to avoid extra calls to Settings.
+ */
+ public boolean isSimpleViewEnabled() {
+ return isThreeButtonNav()
+ && Settings.Secure.getInt(getContentResolver(), SIMPLE_VIEW_SETTINGS_KEY, 0)
+ > 0;
+ }
+
public boolean isNavBarKidsModeActive() {
return mIsNavBarKidsMode && isThreeButtonNav();
}
- protected boolean isNavBarForceVisible() {
+ @VisibleForTesting(otherwise = PROTECTED)
+ public boolean isNavBarForceVisible() {
return mIsNavBarForceVisible;
}
/**
* Displays a single frame of the Launcher start from SUW animation.
*
- * This animation is a combination of the Launcher resume animation, which
- * animates the hotseat
- * icons into position, the Taskbar unstash to hotseat animation, which animates
- * the Taskbar
- * stash bar into the hotseat icons, and an override to prevent showing the
- * Taskbar all apps
+ * This animation is a combination of the Launcher resume animation, which animates the hotseat
+ * icons into position, the Taskbar unstash to hotseat animation, which animates the Taskbar
+ * stash bar into the hotseat icons, and an override to prevent showing the Taskbar all apps
* button.
*
- * This should be used to run a Taskbar unstash to hotseat animation whose
- * progress matches a
+ * This should be used to run a Taskbar unstash to hotseat animation whose progress matches a
* swipe progress.
*
* @param duration a placeholder duration to be used to ensure all full-length
- * sub-animations are properly coordinated. This duration should
- * not actually
+ * sub-animations are properly coordinated. This duration should not actually
* be used since this animation tracks a swipe progress.
*/
protected AnimatorPlaybackController createLauncherStartFromSuwAnim(int duration) {
@@ -1524,41 +2102,29 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
duration);
View allAppsButton = mControllers.taskbarViewController.getAllAppsButtonView();
- if (allAppsButton != null && !FeatureFlags.ENABLE_ALL_APPS_BUTTON_IN_HOTSEAT.get()) {
+ if (!FeatureFlags.enableAllAppsButtonInHotseat()) {
ValueAnimator alphaOverride = ValueAnimator.ofFloat(0, 1);
alphaOverride.setDuration(duration);
alphaOverride.addUpdateListener(a -> {
// Override the alpha updates in the icon alignment animation.
allAppsButton.setAlpha(0);
});
+ alphaOverride.addListener(AnimatorListeners.forSuccessCallback(
+ () -> allAppsButton.setAlpha(1f)));
fullAnimation.play(alphaOverride);
}
return AnimatorPlaybackController.wrap(fullAnimation, duration);
}
- /**
- * Called when we determine the touchable region.
- *
- * @param exclude {@code true} then the magnification region computation will
- * omit the window.
- */
- public void excludeFromMagnificationRegion(boolean exclude) {
- if (mIsExcludeFromMagnificationRegion == exclude) {
- return;
- }
-
- mIsExcludeFromMagnificationRegion = exclude;
- if (exclude) {
- mWindowLayoutParams.privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
- } else {
- mWindowLayoutParams.privateFlags &= ~WindowManager.LayoutParams.PRIVATE_FLAG_EXCLUDE_FROM_SCREEN_MAGNIFICATION;
- }
- notifyUpdateLayoutParams();
- }
-
void notifyUpdateLayoutParams() {
if (mDragLayer.isAttachedToWindow()) {
+ // Copy the current windowLayoutParams to mLastUpdatedLayoutParams and compare the diff.
+ // If there is no change, we will skip the call to updateViewLayout.
+ int changes = mLastUpdatedLayoutParams.copyFrom(mWindowLayoutParams);
+ if (changes == 0) {
+ return;
+ }
if (enableTaskbarNoRecreate()) {
mWindowManager.updateViewLayout(mDragLayer.getRootView(), mWindowLayoutParams);
} else {
@@ -1580,10 +2146,22 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
return mControllers.taskbarStashController.isInApp();
}
+ public boolean isInOverview() {
+ return mControllers.taskbarStashController.isInOverview();
+ }
+
public boolean isInStashedLauncherState() {
return mControllers.taskbarStashController.isInStashedLauncherState();
}
+ public TaskbarFeatureEvaluator getTaskbarFeatureEvaluator() {
+ return mTaskbarFeatureEvaluator;
+ }
+
+ public TaskbarSpecsEvaluator getTaskbarSpecsEvaluator() {
+ return mTaskbarSpecsEvaluator;
+ }
+
protected void dumpLogs(String prefix, PrintWriter pw) {
pw.println(prefix + "TaskbarActivityContext:");
@@ -1595,8 +2173,6 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
"%s\tmIsUserSetupComplete=%b", prefix, mIsUserSetupComplete));
pw.println(String.format(
"%s\tmWindowLayoutParams.height=%dpx", prefix, mWindowLayoutParams.height));
- pw.println(String.format(
- "%s\tmBindInProgress=%b", prefix, mBindingItems));
mControllers.dumpLogs(prefix + "\t", pw);
mDeviceProfile.dump(this, prefix, pw);
}
@@ -1621,11 +2197,12 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mControllers.keyboardQuickSwitchController.closeQuickSwitchView(false);
}
- boolean canToggleHomeAllApps() {
- return mControllers.uiController.canToggleHomeAllApps();
+ boolean isIconAlignedWithHotseat() {
+ return mControllers.uiController.isIconAlignedWithHotseat();
}
- @VisibleForTesting
+ // TODO(b/395061396): Remove `otherwise` when overview in widow is enabled.
+ @VisibleForTesting(otherwise = PACKAGE_PRIVATE)
public TaskbarControllers getControllers() {
return mControllers;
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
index b9136e9f0f..03eef098dc 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarAutohideSuspendController.java
@@ -49,6 +49,12 @@ public class TaskbarAutohideSuspendController implements
public static final int FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR = 1 << 5;
// User has hovered the taskbar.
public static final int FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS = 1 << 6;
+ // User has multi instance window open.
+ public static final int FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN = 1 << 7;
+ // User has taskbar overflow open.
+ public static final int FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW = 1 << 8;
+ // Growth Framework nudge overlay is open above the Taskbar.
+ public static final int FLAG_AUTOHIDE_SUSPEND_GROWTH_NUDGE_OPEN = 1 << 9;
@IntDef(flag = true, value = {
FLAG_AUTOHIDE_SUSPEND_FULLSCREEN,
@@ -58,6 +64,9 @@ public class TaskbarAutohideSuspendController implements
FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER,
FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS,
+ FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
+ FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW,
+ FLAG_AUTOHIDE_SUSPEND_GROWTH_NUDGE_OPEN,
})
@Retention(RetentionPolicy.SOURCE)
public @interface AutohideSuspendFlag {
@@ -138,6 +147,12 @@ public class TaskbarAutohideSuspendController implements
"FLAG_AUTOHIDE_SUSPEND_IN_LAUNCHER");
appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR,
"FLAG_AUTOHIDE_SUSPEND_TRANSIENT_TASKBAR");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN,
+ "FLAG_AUTOHIDE_SUSPEND_MULTI_INSTANCE_MENU_OPEN");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW,
+ "FLAG_AUTOHIDE_SUSPEND_TASKBAR_OVERFLOW");
+ appendFlag(str, flags, FLAG_AUTOHIDE_SUSPEND_GROWTH_NUDGE_OPEN,
+ "FLAG_AUTOHIDE_SUSPEND_GROWTH_NUDGE_OPEN");
return str.toString();
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
index 2737cbd467..bd33177bfa 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarBackgroundRenderer.kt
@@ -23,6 +23,7 @@ import android.graphics.Paint
import android.graphics.Path
import android.graphics.RectF
import com.android.app.animation.Interpolators
+import com.android.launcher3.Flags
import com.android.launcher3.R
import com.android.launcher3.Utilities
import com.android.launcher3.Utilities.mapRange
@@ -30,7 +31,7 @@ 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
+import com.android.launcher3.taskbar.Utilities.getShapedTaskbarRadius
import kotlin.math.min
/** Helps draw the taskbar background, made up of a rectangle plus two inverted rounded corners. */
@@ -39,24 +40,27 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
private val isInSetup: Boolean = !context.isUserSetupComplete
private val maxTransientTaskbarHeight =
- context.transientTaskbarDeviceProfile.taskbarHeight.toFloat()
+ context.transientTaskbarDeviceProfile.taskbarProfile.height.toFloat()
private val maxPersistentTaskbarHeight =
- context.persistentTaskbarDeviceProfile.taskbarHeight.toFloat()
+ context.persistentTaskbarDeviceProfile.taskbarProfile.height.toFloat()
var backgroundProgress =
- if (DisplayController.isTransientTaskbar(context)) {
+ if (context.isTransientTaskbar) {
PINNING_TRANSIENT
} else {
PINNING_PERSISTENT
}
var isAnimatingPinning = false
+ var isAnimatingPersistentTaskbar = false
+ var isAnimatingTransientTaskbar = false
val paint = Paint()
private val strokePaint = Paint()
val lastDrawnTransientRect = RectF()
- var backgroundHeight = context.deviceProfile.taskbarHeight.toFloat()
+ var backgroundHeight = context.deviceProfile.taskbarProfile.height.toFloat()
var translationYForSwipe = 0f
var translationYForStash = 0f
+ var translationXForBubbleBar = 0f
private val transientBackgroundBounds = context.transientTaskbarBounds
@@ -66,8 +70,8 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
private var keyShadowDistance = 0f
private var bottomMargin = 0
- private val fullCornerRadius = context.cornerRadius.toFloat()
- private var cornerRadius = fullCornerRadius
+ private val fullCornerRadius: Float
+ private var cornerRadius = 0f
private var widthInsetPercentage = 0f
private val square = Path()
private val circle = Path()
@@ -97,13 +101,17 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
shadowAlpha = LIGHT_THEME_SHADOW_ALPHA
}
- setCornerRoundness(DEFAULT_ROUNDNESS)
+ fullCornerRadius = context.cornerRadius.toFloat()
+ cornerRadius = fullCornerRadius
+ if (!context.isInDesktopMode()) {
+ setCornerRoundness(MAX_ROUNDNESS)
+ }
}
fun updateStashedHandleWidth(context: TaskbarActivityContext, res: Resources) {
stashedHandleWidth =
res.getDimensionPixelSize(
- if (context.isPhoneMode || context.isTinyTaskbar) {
+ if (context.isPhoneMode || context.isTinyTaskbar || context.isBubbleBarOnPhone) {
R.dimen.taskbar_stashed_small_screen
} else {
R.dimen.taskbar_stashed_handle_width
@@ -117,7 +125,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
* @param cornerRoundness 0 has no round corner, 1 has complete round corner.
*/
fun setCornerRoundness(cornerRoundness: Float) {
- if (DisplayController.isTransientTaskbar(context) && !transientBackgroundBounds.isEmpty) {
+ if (context.isTransientTaskbar && !transientBackgroundBounds.isEmpty) {
return
}
@@ -139,7 +147,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
/** Draws the background with the given paint and height, on the provided canvas. */
fun draw(canvas: Canvas) {
if (isInSetup) return
- val isTransientTaskbar = backgroundProgress == 0f
+ val isTransientTaskbar = context.isTransientTaskbar
canvas.save()
if (!isTransientTaskbar || transientBackgroundBounds.isEmpty || isAnimatingPinning) {
drawPersistentBackground(canvas)
@@ -153,7 +161,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
}
private fun drawPersistentBackground(canvas: Canvas) {
- if (isAnimatingPinning) {
+ if (isAnimatingPinning || isAnimatingPersistentTaskbar) {
val persistentTaskbarHeight = maxPersistentTaskbarHeight * backgroundProgress
canvas.translate(0f, canvas.height - persistentTaskbarHeight)
// Draw the background behind taskbar content.
@@ -176,19 +184,20 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
private fun drawTransientBackground(canvas: Canvas) {
val res = context.resources
val transientTaskbarHeight = maxTransientTaskbarHeight * (1f - backgroundProgress)
+ val isAnimating = isAnimatingPinning || isAnimatingTransientTaskbar
val heightProgressWhileAnimating =
- if (isAnimatingPinning) transientTaskbarHeight else backgroundHeight
+ if (isAnimating) transientTaskbarHeight else backgroundHeight
var progress = heightProgressWhileAnimating / maxTransientTaskbarHeight
progress = Math.round(progress * 100f) / 100f
- if (isAnimatingPinning) {
+ if (isAnimating) {
var scale = transientTaskbarHeight / maxTransientTaskbarHeight
scale = Math.round(scale * 100f) / 100f
bottomMargin =
mapRange(
scale,
0f,
- res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat()
+ res.getDimensionPixelSize(R.dimen.transient_taskbar_bottom_margin).toFloat(),
)
.toInt()
shadowBlur =
@@ -215,7 +224,12 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
val newWidth = mapRange(progress, backgroundWidthWhileAnimating, fullWidth.toFloat())
val halfWidthDelta = (fullWidth - newWidth) / 2f
- val radius = newBackgroundHeight / 2f
+ val radius =
+ if (Flags.enableLauncherIconShapes()) {
+ getShapedTaskbarRadius(context)
+ } else {
+ newBackgroundHeight / 2f
+ }
val bottomMarginProgress = bottomMargin * ((1f - progress) / 2f)
// Aligns the bottom with the bottom of the stashed handle.
@@ -227,7 +241,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
-mapRange(
1f - progress,
0f,
- if (isAnimatingPinning) 0f else stashedHandleHeight / 2f
+ if (isAnimatingPinning) 0f else stashedHandleHeight / 2f,
)
// Draw shadow.
@@ -237,15 +251,15 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
shadowBlur,
0f,
keyShadowDistance,
- setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha))
+ setColorAlphaBound(Color.BLACK, Math.round(newShadowAlpha)),
)
strokePaint.alpha = (paint.alpha * strokeAlpha) / 255
-
+ val currentTranslationX = translationXForBubbleBar * progress
lastDrawnTransientRect.set(
- transientBackgroundBounds.left + halfWidthDelta,
+ transientBackgroundBounds.left + halfWidthDelta + currentTranslationX,
bottom - newBackgroundHeight,
- transientBackgroundBounds.right - halfWidthDelta,
- bottom
+ transientBackgroundBounds.right - halfWidthDelta + currentTranslationX,
+ bottom,
)
val horizontalInset = fullWidth * widthInsetPercentage
lastDrawnTransientRect.inset(horizontalInset, 0f)
@@ -263,7 +277,7 @@ class TaskbarBackgroundRenderer(private val context: TaskbarActivityContext) {
}
companion object {
- const val DEFAULT_ROUNDNESS = 1f
+ const val MAX_ROUNDNESS = 1f
private const val DARK_THEME_STROKE_ALPHA = 51
private const val LIGHT_THEME_STROKE_ALPHA = 41
private const val DARK_THEME_SHADOW_ALPHA = 51f
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
index 58c5e835c9..f24bd28330 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarControllers.java
@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
+import android.animation.AnimatorSet;
import android.content.pm.ActivityInfo.Config;
import androidx.annotation.NonNull;
@@ -24,8 +25,10 @@ import androidx.annotation.VisibleForTesting;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.allapps.TaskbarAllAppsController;
import com.android.launcher3.taskbar.bubbles.BubbleControllers;
+import com.android.launcher3.taskbar.growth.NudgeController;
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;
@@ -64,6 +67,9 @@ public class TaskbarControllers {
public final KeyboardQuickSwitchController keyboardQuickSwitchController;
public final TaskbarPinningController taskbarPinningController;
public final Optional bubbleControllers;
+ public final TaskbarDesktopModeController taskbarDesktopModeController;
+ public final NudgeController nudgeController;
+ public final NudgeViewController nudgeViewController;
@Nullable private LoggableTaskbarController[] mControllersToLog = null;
@Nullable private BackgroundRendererController[] mBackgroundRendererControllers = null;
@@ -111,7 +117,10 @@ public class TaskbarControllers {
TaskbarEduTooltipController taskbarEduTooltipController,
KeyboardQuickSwitchController keyboardQuickSwitchController,
TaskbarPinningController taskbarPinningController,
- Optional bubbleControllers) {
+ Optional bubbleControllers,
+ TaskbarDesktopModeController taskbarDesktopModeController,
+ NudgeController nudgeController,
+ NudgeViewController nudgeViewController) {
this.taskbarActivityContext = taskbarActivityContext;
this.taskbarDragController = taskbarDragController;
this.navButtonController = navButtonController;
@@ -138,6 +147,9 @@ public class TaskbarControllers {
this.keyboardQuickSwitchController = keyboardQuickSwitchController;
this.taskbarPinningController = taskbarPinningController;
this.bubbleControllers = bubbleControllers;
+ this.taskbarDesktopModeController = taskbarDesktopModeController;
+ this.nudgeController = nudgeController;
+ this.nudgeViewController = nudgeViewController;
}
/**
@@ -145,15 +157,15 @@ public class TaskbarControllers {
* TaskbarControllers instance, but should be careful to only access things that were created
* in constructors for now, as some controllers may still be waiting for init().
*/
- public void init(@NonNull TaskbarSharedState sharedState) {
+ public void init(@NonNull TaskbarSharedState sharedState, AnimatorSet startAnimation) {
mAreAllControllersInitialized = false;
mSharedState = sharedState;
taskbarDragController.init(this);
navbarButtonsViewController.init(this);
rotationButtonController.init();
- taskbarDragLayerController.init(this);
- taskbarViewController.init(this);
+ taskbarDragLayerController.init(this, startAnimation);
+ taskbarViewController.init(this, startAnimation);
taskbarScrimViewController.init(this);
taskbarUnfoldAnimationController.init(this);
taskbarKeyguardController.init(navbarButtonsViewController);
@@ -165,14 +177,17 @@ public class TaskbarControllers {
taskbarOverlayController.init(this);
taskbarAllAppsController.init(this, sharedState.allAppsVisible);
navButtonController.init(this);
+ bubbleControllers.ifPresentOrElse(controllers -> controllers.init(sharedState, this),
+ sharedState::clearBubbleData);
taskbarInsetsController.init(this);
voiceInteractionWindowController.init(this);
- taskbarRecentAppsController.init(this);
+ taskbarRecentAppsController.init(this, sharedState.recentTasksBeforeTaskbarRecreate);
taskbarTranslationController.init(this);
taskbarEduTooltipController.init(this);
keyboardQuickSwitchController.init(this);
taskbarPinningController.init(this, mSharedState);
- bubbleControllers.ifPresent(controllers -> controllers.init(this));
+ taskbarDesktopModeController.init(this, mSharedState);
+ nudgeController.init(this);
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -183,13 +198,29 @@ public class TaskbarControllers {
voiceInteractionWindowController, taskbarRecentAppsController,
taskbarTranslationController, taskbarEduTooltipController,
keyboardQuickSwitchController, taskbarPinningController,
+ nudgeController
};
mBackgroundRendererControllers = new BackgroundRendererController[] {
taskbarDragLayerController, taskbarScrimViewController,
voiceInteractionWindowController
};
- mCornerRoundness.updateValue(TaskbarBackgroundRenderer.DEFAULT_ROUNDNESS);
+ // TODO(b/401061748): get primary status from
+ // TaskbarDesktopModeController/DesktopVisibilityController.
+ if (taskbarDesktopModeController.isInDesktopModeAndNotInOverview(
+ taskbarActivityContext.getDisplayId())
+ || !taskbarActivityContext.isPrimaryDisplay()) {
+ mCornerRoundness.value = taskbarDesktopModeController.getTaskbarCornerRoundness(
+ mSharedState.showCornerRadiusInDesktopMode);
+ } else {
+ mCornerRoundness.value = TaskbarBackgroundRenderer.MAX_ROUNDNESS;
+ }
+ updateCornerRoundness();
+ onPostInit();
+ }
+
+ @VisibleForTesting
+ public void onPostInit() {
mAreAllControllersInitialized = true;
for (Runnable postInitCallback : mPostInitCallbacks) {
postInitCallback.run();
@@ -205,9 +236,20 @@ public class TaskbarControllers {
uiController = newUiController;
uiController.init(this);
uiController.updateStateForSysuiFlags(mSharedState.sysuiStateFlags);
-
+ // if bubble controllers are present configure the UI controller
+ bubbleControllers.ifPresentOrElse(bubbleControllers -> {
+ BubbleBarLocation location =
+ bubbleControllers.bubbleBarViewController.getBubbleBarLocation();
+ boolean hiddenForBubbles =
+ bubbleControllers.bubbleBarViewController.isHiddenForNoBubbles();
+ if (!hiddenForBubbles) {
+ uiController.adjustHotseatForBubbleBar(/* isBubbleBarVisible= */ true);
+ }
+ uiController.onBubbleBarLocationUpdated(location);
+ }, () -> uiController.onBubbleBarLocationUpdated(null));
// Notify that the ui controller has changed
navbarButtonsViewController.onUiControllerChanged();
+ taskbarViewController.onUiControllerChanged();
}
@Nullable
@@ -227,8 +269,8 @@ public class TaskbarControllers {
*/
public void onDestroy() {
mAreAllControllersInitialized = false;
- mSharedState = null;
+ taskbarDragController.onDestroy();
navbarButtonsViewController.onDestroy();
uiController.onDestroy();
rotationButtonController.onDestroy();
@@ -236,6 +278,7 @@ public class TaskbarControllers {
taskbarUnfoldAnimationController.onDestroy();
taskbarViewController.onDestroy();
stashedHandleViewController.onDestroy();
+ nudgeViewController.onDestroy();
taskbarAutohideSuspendController.onDestroy();
taskbarPopupController.onDestroy();
taskbarForceVisibleImmersiveController.onDestroy();
@@ -248,9 +291,10 @@ public class TaskbarControllers {
keyboardQuickSwitchController.onDestroy();
taskbarStashController.onDestroy();
bubbleControllers.ifPresent(controllers -> controllers.onDestroy());
-
+ taskbarDesktopModeController.onDestroy();
mControllersToLog = null;
mBackgroundRendererControllers = null;
+ mSharedState = null;
}
/**
@@ -282,6 +326,11 @@ public class TaskbarControllers {
}
uiController.dumpLogs(prefix + "\t", pw);
rotationButtonController.dumpLogs(prefix + "\t", pw);
+ if (bubbleControllers.isPresent()) {
+ bubbleControllers.get().dump(pw);
+ } else {
+ pw.println(String.format("%s\t%s", prefix, "Bubble controllers are empty."));
+ }
}
/**
@@ -307,7 +356,7 @@ public class TaskbarControllers {
return taskbarActivityContext;
}
- protected interface LoggableTaskbarController {
+ public interface LoggableTaskbarController {
void dumpLogs(String prefix, PrintWriter pw);
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
index e96e67dfbc..ab502451ac 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDesktopModeController.kt
@@ -16,19 +16,21 @@
package com.android.launcher3.taskbar
-import android.content.Context
import com.android.launcher3.statehandlers.DesktopVisibilityController
import com.android.launcher3.statehandlers.DesktopVisibilityController.TaskbarDesktopModeListener
import com.android.launcher3.taskbar.TaskbarBackgroundRenderer.Companion.MAX_ROUNDNESS
/** Handles Taskbar in Desktop Windowing mode. */
class TaskbarDesktopModeController(
- private val context: Context,
+ private val taskbarActivityContext: TaskbarActivityContext,
private val desktopVisibilityController: DesktopVisibilityController,
) : TaskbarDesktopModeListener {
private lateinit var taskbarControllers: TaskbarControllers
private lateinit var taskbarSharedState: TaskbarSharedState
+ val isLauncherAnimationRunning: Boolean
+ get() = desktopVisibilityController.launcherAnimationRunning
+
fun init(controllers: TaskbarControllers, sharedState: TaskbarSharedState) {
taskbarControllers = controllers
taskbarSharedState = sharedState
@@ -48,10 +50,13 @@ class TaskbarDesktopModeController(
}
fun shouldShowDesktopTasksInTaskbar(): Boolean {
- val activityContext = taskbarControllers.taskbarActivityContext
- return isInDesktopMode(context.displayId) ||
- activityContext.showDesktopTaskbarForFreeformDisplay() ||
- (activityContext.showLockedTaskbarOnHome() &&
+ return shouldShowDesktopTasksInTaskbar(taskbarActivityContext.displayId)
+ }
+
+ fun shouldShowDesktopTasksInTaskbar(displayId: Int): Boolean {
+ return isInDesktopMode(displayId) ||
+ taskbarActivityContext.showDesktopTaskbarForFreeformDisplay() ||
+ (taskbarActivityContext.showLockedTaskbarOnHome() &&
taskbarControllers.taskbarStashController.isOnHome)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
index a635537907..3ae06abea4 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDividerPopupView.kt
@@ -29,23 +29,25 @@ import android.view.MotionEvent
import android.view.View
import android.widget.LinearLayout
import android.widget.Switch
+import androidx.core.content.res.ResourcesCompat
import androidx.core.view.postDelayed
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
+import com.android.launcher3.Flags
+import com.android.launcher3.LauncherPrefs
import com.android.launcher3.R
import com.android.launcher3.popup.ArrowPopup
import com.android.launcher3.popup.RoundedArrowDrawable
-import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
+import com.android.wm.shell.Flags.enableGsf
+import kotlin.math.max
+import kotlin.math.min
/** Popup view with arrow for taskbar pinning */
class TaskbarDividerPopupView
@JvmOverloads
-constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
-) : ArrowPopup(context, attrs, defStyleAttr) {
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+ ArrowPopup(context, attrs, defStyleAttr) {
companion object {
private const val TAG = "TaskbarDividerPopupView"
private const val DIVIDER_POPUP_CLOSING_DELAY = 333L
@@ -55,26 +57,38 @@ constructor(
fun createAndPopulate(
view: View,
taskbarActivityContext: TaskbarActivityContext,
+ horizontalPosition: Float,
): TaskbarDividerPopupView<*> {
val taskMenuViewWithArrow =
taskbarActivityContext.layoutInflater.inflate(
R.layout.taskbar_divider_popup_menu,
taskbarActivityContext.dragLayer,
- false
+ false,
) as TaskbarDividerPopupView<*>
- return taskMenuViewWithArrow.populateForView(view)
+ return taskMenuViewWithArrow.populateForView(view, horizontalPosition)
}
}
private lateinit var dividerView: View
+ private var horizontalPosition = 0.0f
+ private val taskbarActivityContext: TaskbarActivityContext =
+ ActivityContext.lookupContext(context)
private val popupCornerRadius = Themes.getDialogCornerRadius(context)
private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
private val arrowHeight = resources.getDimension(R.dimen.popup_arrow_height)
private val arrowPointRadius = resources.getDimension(R.dimen.popup_arrow_corner_radius)
+ private val minPaddingFromScreenEdge =
+ resources.getDimension(R.dimen.taskbar_pinning_popup_menu_min_padding_from_screen_edge)
+
+ private var alwaysShowTaskbarOn =
+ if (taskbarActivityContext.isTaskbarShowingDesktopTasks) {
+ LauncherPrefs.TASKBAR_PINNING_IN_DESKTOP_MODE.get(context)
+ } else {
+ !taskbarActivityContext.isTransientTaskbar
+ }
- private var alwaysShowTaskbarOn = !DisplayController.isTransientTaskbar(context)
private var didPreferenceChange = false
private var verticalOffsetForPopupView =
resources.getDimensionPixelSize(R.dimen.taskbar_pinning_popup_menu_vertical_margin)
@@ -103,13 +117,22 @@ constructor(
val alwaysShowTaskbarSwitch = requireViewById(R.id.taskbar_pinning_switch)
val taskbarVisibilityIcon = requireViewById(R.id.taskbar_pinning_visibility_icon)
+ if (enableGsf()) {
+ taskbarVisibilityIcon.background =
+ ResourcesCompat.getDrawable(
+ context.resources,
+ R.drawable.ic_visibility_filled,
+ context.theme,
+ )
+ }
+
alwaysShowTaskbarSwitch.isChecked = alwaysShowTaskbarOn
alwaysShowTaskbarSwitch.setOnTouchListener { view, event ->
(view.parent as View).onTouchEvent(event)
}
alwaysShowTaskbarSwitch.setOnClickListener { view -> (view.parent as View).performClick() }
- if (ActivityContext.lookupContext(context).isGestureNav) {
+ if (taskbarActivityContext.isGestureNav) {
taskbarSwitchOption.setOnClickListener {
alwaysShowTaskbarSwitch.isChecked = !alwaysShowTaskbarOn
onClickAlwaysShowTaskbarSwitchOption()
@@ -128,7 +151,36 @@ constructor(
/** Orient object as usual and then center object horizontally. */
override fun orientAboutObject() {
super.orientAboutObject()
- x = mTempRect.centerX() - measuredWidth / 2f
+ x =
+ if (Flags.showTaskbarPinningPopupFromAnywhere()) {
+ val xForCenterAlignment = horizontalPosition - measuredWidth / 2f
+ val maxX = popupContainer.getWidth() - measuredWidth - minPaddingFromScreenEdge
+ when {
+ // Left-aligned popup and its arrow pointing to the event position if there is
+ // not enough space to center it.
+ xForCenterAlignment < minPaddingFromScreenEdge ->
+ max(
+ minPaddingFromScreenEdge,
+ horizontalPosition - mArrowOffsetHorizontal - mArrowWidth / 2,
+ )
+
+ // Right-aligned popup and its arrow pointing to the event position if there
+ // is not enough space to center it.
+ xForCenterAlignment > maxX ->
+ min(
+ horizontalPosition - measuredWidth +
+ mArrowOffsetHorizontal +
+ mArrowWidth / 2,
+ popupContainer.getWidth() - measuredWidth - minPaddingFromScreenEdge,
+ )
+
+ // Default alignment where the popup and its arrow are centered relative to the
+ // event position.
+ else -> xForCenterAlignment
+ }
+ } else {
+ mTempRect.centerX() - measuredWidth / 2f
+ }
}
override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean {
@@ -142,8 +194,9 @@ constructor(
return false
}
- private fun populateForView(view: View): TaskbarDividerPopupView<*> {
+ private fun populateForView(view: View, horizontalPosition: Float): TaskbarDividerPopupView<*> {
dividerView = view
+ this@TaskbarDividerPopupView.horizontalPosition = horizontalPosition
tryUpdateBackground()
return this
}
@@ -169,12 +222,31 @@ constructor(
override fun addArrow() {
super.addArrow()
- // Change arrow location to the middle of popup.
- mArrow.x = (dividerView.x + dividerView.width / 2) - (mArrowWidth / 2)
+ if (Flags.showTaskbarPinningPopupFromAnywhere()) {
+ mArrow.x =
+ min(
+ max(
+ minPaddingFromScreenEdge + mArrowOffsetHorizontal,
+ horizontalPosition - mArrowWidth / 2,
+ ),
+ popupContainer.getWidth() -
+ minPaddingFromScreenEdge -
+ mArrowOffsetHorizontal -
+ mArrowWidth,
+ )
+ } else {
+ val location = IntArray(2)
+ popupContainer.getLocationInDragLayer(dividerView, location)
+ val dividerViewX = location[0].toFloat()
+ // Change arrow location to the middle of popup.
+ mArrow.x = (dividerViewX + dividerView.width / 2) - (mArrowWidth / 2)
+ }
}
override fun updateArrowColor() {
- if (!Gravity.isVertical(mGravity)) {
+ if (Flags.showTaskbarPinningPopupFromAnywhere()) {
+ super.updateArrowColor()
+ } else if (!Gravity.isVertical(mGravity)) {
mArrow.background =
RoundedArrowDrawable(
arrowWidth,
@@ -195,8 +267,8 @@ constructor(
}
override fun getExtraVerticalOffset(): Int {
- return (mActivityContext.deviceProfile.taskbarHeight -
- mActivityContext.deviceProfile.taskbarIconSize) / 2 + verticalOffsetForPopupView
+ return (mActivityContext.deviceProfile.taskbarProfile.height -
+ mActivityContext.deviceProfile.taskbarProfile.iconSize) / 2 + verticalOffsetForPopupView
}
override fun onCreateCloseAnimation(anim: AnimatorSet?) {
@@ -210,7 +282,7 @@ constructor(
/** Aligning the view pivot to center for animation. */
override fun setPivotForOpenCloseAnimation() {
- pivotX = measuredWidth / 2f
+ pivotX = mArrow.x + mArrowWidth / 2 - x
pivotY = measuredHeight.toFloat()
}
@@ -224,13 +296,13 @@ constructor(
ObjectAnimator.ofFloat(
this,
TRANSLATION_Y,
- *floatArrayOf(this.translationY, this.translationY + translateYValue)
+ *floatArrayOf(this.translationY, this.translationY + translateYValue),
)
val arrowTranslateY =
ObjectAnimator.ofFloat(
mArrow,
TRANSLATION_Y,
- *floatArrayOf(mArrow.translationY, mArrow.translationY + translateYValue)
+ *floatArrayOf(mArrow.translationY, mArrow.translationY + translateYValue),
)
val animatorSet = AnimatorSet()
animatorSet.playTogether(alpha, arrowAlpha, translateY, arrowTranslateY)
@@ -240,7 +312,7 @@ constructor(
private fun getAnimatorOfFloat(
view: View,
property: Property,
- vararg values: Float
+ vararg values: Float,
): Animator {
val animator: Animator = ObjectAnimator.ofFloat(view, property, *values)
animator.setDuration(DIVIDER_POPUP_CLOSING_ANIMATION_DURATION)
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
index 536daecdbf..eac264736e 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragController.java
@@ -18,7 +18,7 @@ package com.android.launcher3.taskbar;
import static com.android.app.animation.Interpolators.FAST_OUT_SLOW_IN;
import static com.android.launcher3.AbstractFloatingView.TYPE_TASKBAR_ALL_APPS;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS;
-import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_PREDICTION;
+import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_ALL_APPS_PREDICTION;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_DEEP_SHORTCUT;
import static com.android.launcher3.LauncherSettings.Favorites.ITEM_TYPE_SEARCH_ACTION;
import static com.android.launcher3.logger.LauncherAtom.ContainerInfo.ContainerCase.EXTENDED_CONTAINERS;
@@ -34,6 +34,7 @@ import android.content.ClipData;
import android.content.ClipDescription;
import android.content.Intent;
import android.content.pm.LauncherApps;
+import android.content.pm.ShortcutInfo;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
@@ -51,6 +52,7 @@ import android.view.ViewRootImpl;
import android.window.SurfaceSyncGroup;
import androidx.annotation.Nullable;
+import androidx.annotation.VisibleForTesting;
import com.android.app.animation.Interpolators;
import com.android.internal.logging.InstanceId;
@@ -66,6 +68,7 @@ import com.android.launcher3.dragndrop.DragDriver;
import com.android.launcher3.dragndrop.DragOptions;
import com.android.launcher3.dragndrop.DragView;
import com.android.launcher3.dragndrop.DraggableView;
+import com.android.launcher3.folder.Folder;
import com.android.launcher3.graphics.DragPreviewProvider;
import com.android.launcher3.logger.LauncherAtom.ContainerInfo;
import com.android.launcher3.logging.StatsLogManager;
@@ -74,18 +77,18 @@ import com.android.launcher3.model.data.WorkspaceItemInfo;
import com.android.launcher3.popup.PopupContainerWithArrow;
import com.android.launcher3.shortcuts.DeepShortcutView;
import com.android.launcher3.shortcuts.ShortcutDragPreviewProvider;
-import com.android.launcher3.statehandlers.DesktopVisibilityController;
+import com.android.launcher3.taskbar.bubbles.BubbleBarViewController;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.IntSet;
import com.android.launcher3.util.ItemInfoMatcher;
import com.android.launcher3.views.BubbleTextHolder;
-import com.android.quickstep.LauncherActivityInterface;
import com.android.quickstep.util.LogUtils;
import com.android.quickstep.util.MultiValueUpdateListener;
+import com.android.quickstep.util.SingleTask;
import com.android.systemui.shared.recents.model.Task;
-import com.android.wm.shell.draganddrop.DragAndDropConstants;
+import com.android.wm.shell.shared.bubbles.BubbleAnythingFlagHelper;
+import com.android.wm.shell.shared.draganddrop.DragAndDropConstants;
import java.io.PrintWriter;
import java.util.Arrays;
@@ -93,8 +96,7 @@ import java.util.Collections;
import java.util.function.Predicate;
/**
- * Handles long click on Taskbar items to start a system drag and drop
- * operation.
+ * Handles long click on Taskbar items to start a system drag and drop operation.
*/
public class TaskbarDragController extends DragController implements
TaskbarControllers.LoggableTaskbarController {
@@ -114,6 +116,7 @@ public class TaskbarDragController extends DragController im
private int mRegistrationY;
private boolean mIsSystemDragInProgress;
+ private boolean mIsDropHandledByDropTarget;
// Animation for the drag shadow back into position after an unsuccessful drag
private ValueAnimator mReturnAnimator;
@@ -128,6 +131,14 @@ public class TaskbarDragController extends DragController im
public void init(TaskbarControllers controllers) {
mControllers = controllers;
+ mControllers.runAfterInit(() -> mControllers.bubbleControllers.ifPresent(
+ c -> c.dragToBubbleController.addBubbleBarDropTargets(this)));
+ }
+
+ /** Called when the controller is destroyed. */
+ public void onDestroy() {
+ mControllers.bubbleControllers.ifPresent(
+ c -> c.dragToBubbleController.removeBubbleBarDropTargets(this));
}
public void setDisallowGlobalDrag(boolean disallowGlobalDrag) {
@@ -139,10 +150,8 @@ public class TaskbarDragController extends DragController im
}
/**
- * Attempts to start a system drag and drop operation for the given View, using
- * its tag to
+ * Attempts to start a system drag and drop operation for the given View, using its tag to
* generate the ClipDescription and Intent.
- *
* @return Whether {@link View#startDragAndDrop} started successfully.
*/
public boolean startDragOnLongClick(View view) {
@@ -184,7 +193,9 @@ public class TaskbarDragController extends DragController im
private DragView startInternalDrag(
BubbleTextView btv, @Nullable DragPreviewProvider dragPreviewProvider) {
- float iconScale = btv.getIcon().getAnimatedScale();
+ // TODO(b/344038728): null check is only necessary because Recents doesn't use
+ // FastBitmapDrawable
+ float iconScale = btv.getIcon() == null ? 1f : btv.getIcon().getAnimatedScale();
// Clear the pressed state if necessary
btv.clearFocus();
@@ -192,8 +203,7 @@ public class TaskbarDragController extends DragController im
btv.clearPressedBackground();
final DragPreviewProvider previewProvider = dragPreviewProvider == null
- ? new DragPreviewProvider(btv)
- : dragPreviewProvider;
+ ? new DragPreviewProvider(btv) : dragPreviewProvider;
final Drawable drawable = previewProvider.createDrawable();
final float scale = previewProvider.getScaleAndPosition(drawable, mTempXY);
int dragLayerX = mTempXY[0];
@@ -205,12 +215,13 @@ public class TaskbarDragController extends DragController im
DragOptions dragOptions = new DragOptions();
// First, see if view is a search result that needs custom pre-drag conditions.
- dragOptions.preDragCondition = mControllers.taskbarAllAppsController.createPreDragConditionForSearch(btv);
+ dragOptions.preDragCondition =
+ mControllers.taskbarAllAppsController.createPreDragConditionForSearch(btv);
if (dragOptions.preDragCondition == null) {
// See if view supports a popup container.
- PopupContainerWithArrow popupContainer = mControllers.taskbarPopupController
- .showForIcon(btv);
+ PopupContainerWithArrow popupContainer =
+ mControllers.taskbarPopupController.showForIcon(btv);
if (popupContainer != null) {
dragOptions.preDragCondition = popupContainer.createPreDragCondition(false);
}
@@ -250,9 +261,9 @@ public class TaskbarDragController extends DragController im
/* originalView = */ btv,
dragLayerX + dragOffset.x,
dragLayerY + dragOffset.y,
- (View target, DropTarget.DragObject d, boolean success) -> {
- } /* DragSource */,
- (ItemInfo) btv.getTag(),
+ (View target, DropTarget.DragObject d, boolean success) ->
+ mIsDropHandledByDropTarget = success /* DragSource */,
+ btv.getTag() instanceof ItemInfo itemInfo ? itemInfo : null,
dragRect,
scale * iconScale,
scale,
@@ -292,21 +303,23 @@ public class TaskbarDragController extends DragController im
initialDragViewScale,
dragViewScaleOnDrop,
scalePx);
- dragView.setItemInfo(dragInfo);
+ if (dragInfo != null) {
+ dragView.setItemInfo(dragInfo);
+ }
mDragObject.dragComplete = false;
mDragObject.xOffset = mMotionDown.x - (dragLayerX + dragRegionLeft);
mDragObject.yOffset = mMotionDown.y - (dragLayerY + dragRegionTop);
- mDragDriver = DragDriver.create(this, mOptions, /* secondaryEventConsumer = */ ev -> {
- });
+ mDragDriver = DragDriver.create(this, mOptions, /* secondaryEventConsumer = */ ev -> {});
if (!mOptions.isAccessibleDrag) {
mDragObject.stateAnnouncer = DragViewStateAnnouncer.createFor(dragView);
}
mDragObject.dragSource = source;
mDragObject.dragInfo = dragInfo;
- mDragObject.originalDragInfo = mDragObject.dragInfo.makeShallowCopy();
+ mDragObject.originalDragInfo =
+ mDragObject.dragInfo != null ? mDragObject.dragInfo.makeShallowCopy() : null;
if (mOptions.preDragCondition != null) {
dragView.setHasDragOffset(mOptions.preDragCondition.getDragOffset().x != 0
@@ -333,8 +346,7 @@ public class TaskbarDragController extends DragController im
/** Invoked when an animation running as part of pre-drag finishes. */
public void onPreDragAnimationEnd() {
- // Drag might be cancelled during the DragView animation, so check mIsPreDrag
- // again.
+ // Drag might be cancelled during the DragView animation, so check mIsPreDrag again.
if (mIsInPreDrag) {
callOnDragStart();
}
@@ -344,12 +356,10 @@ public class TaskbarDragController extends DragController im
protected void callOnDragStart() {
super.callOnDragStart();
// TODO(297921594) clean it up when taskbar to desktop drag is implemented.
- DesktopVisibilityController desktopController = LauncherActivityInterface.INSTANCE
- .getDesktopVisibilityController();
-
// Pre-drag has ended, start the global system drag.
- if (mDisallowGlobalDrag || (desktopController != null
- && desktopController.areDesktopTasksVisible())) {
+ if (mDisallowGlobalDrag
+ || mControllers.taskbarDesktopModeController
+ .isInDesktopModeAndNotInOverview(mActivity.getDisplayId())) {
AbstractFloatingView.closeAllOpenViewsExcept(mActivity, TYPE_TASKBAR_ALL_APPS);
return;
}
@@ -420,9 +430,12 @@ public class TaskbarDragController extends DragController im
item.user));
intent.putExtra(Intent.EXTRA_PACKAGE_NAME, item.getIntent().getPackage());
intent.putExtra(Intent.EXTRA_SHORTCUT_ID, deepShortcutId);
+ ShortcutInfo shortcutInfo = ((WorkspaceItemInfo) item).getDeepShortcutInfo();
+ if (BubbleAnythingFlagHelper.enableCreateAnyBubble() && shortcutInfo != null) {
+ intent.putExtra(DragAndDropConstants.EXTRA_SHORTCUT_INFO, shortcutInfo);
+ }
} else if (item.itemType == ITEM_TYPE_SEARCH_ACTION) {
- // TODO(b/289261756): Buggy behavior when split opposite to an existing search
- // pane.
+ // TODO(b/289261756): Buggy behavior when split opposite to an existing search pane.
intent.putExtra(
ClipDescription.EXTRA_PENDING_INTENT,
PendingIntent.getActivityAsUser(
@@ -438,8 +451,8 @@ public class TaskbarDragController extends DragController im
null, item.user));
}
intent.putExtra(Intent.EXTRA_USER, item.user);
- } else if (tag instanceof Task) {
- Task task = (Task) tag;
+ } else if (tag instanceof SingleTask singleTask) {
+ Task task = singleTask.getTask();
clipDescription = new ClipDescription(task.titleDescription,
new String[] {
ClipDescription.MIMETYPE_APPLICATION_TASK
@@ -450,14 +463,14 @@ public class TaskbarDragController extends DragController im
}
if (clipDescription != null && intent != null) {
- Pair instanceIds = LogUtils
- .getShellShareableInstanceId();
+ Pair instanceIds =
+ LogUtils.getShellShareableInstanceId();
// Need to share the same InstanceId between launcher3 and WM Shell (internal).
InstanceId internalInstanceId = instanceIds.first;
com.android.launcher3.logging.InstanceId launcherInstanceId = instanceIds.second;
intent.putExtra(ClipDescription.EXTRA_LOGGING_INSTANCE_ID, internalInstanceId);
- if (DisplayController.isTransientTaskbar(mActivity)) {
+ if (mActivity.isTransientTaskbar()) {
// Tell WM Shell to ignore drag events in the provided transient taskbar region.
TaskbarDragLayer dragLayer = mControllers.taskbarActivityContext.getDragLayer();
int[] locationOnScreen = dragLayer.getLocationOnScreen();
@@ -497,6 +510,8 @@ public class TaskbarDragController extends DragController im
} else {
// This will take care of calling maybeOnDragEnd() after the animation
animateGlobalDragViewToOriginalPosition(btv, dragEvent);
+ //TODO(b/399678274): hide drop target in shell
+ notifyBubbleBarItemDragCanceled();
}
mActivity.getDragLayer().setOnDragListener(null);
@@ -516,39 +531,61 @@ public class TaskbarDragController extends DragController im
return mIsSystemDragInProgress;
}
+ @VisibleForTesting
private void maybeOnDragEnd() {
if (!isDragging()) {
((BubbleTextView) mDragObject.originalView).setIconDisabled(false);
mControllers.taskbarAutohideSuspendController.updateFlag(
TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_DRAGGING, false);
mActivity.onDragEnd();
+ // If an item is dropped on the bubble bar, the bubble bar handles the drop,
+ // so it should not collapse along with the taskbar.
+ boolean droppedOnBubbleBar = notifyBubbleBarItemDropped();
if (mReturnAnimator == null) {
// Upon successful drag, immediately stash taskbar.
// Note, this must be done last to ensure no AutohideSuspendFlags are active, as
// that will prevent us from stashing until the timeout.
- mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(true);
-
+ mControllers.taskbarStashController.updateAndAnimateTransientTaskbar(
+ /* stash = */ true,
+ /* shouldBubblesFollow = */ !droppedOnBubbleBar
+ );
mActivity.getStatsLogManager().logger().withItemInfo(mDragObject.dragInfo)
.log(LAUNCHER_APP_LAUNCH_DRAGDROP);
}
}
}
+ /**
+ * Exits the Bubble Bar drop target mode if applicable.
+ *
+ * @return {@code true} if drop target mode was active.
+ */
+ private boolean notifyBubbleBarItemDropped() {
+ return mControllers.bubbleControllers.map(bc -> {
+ BubbleBarViewController bubbleBarViewController = bc.bubbleBarViewController;
+ boolean showingDropTarget = bubbleBarViewController.isShowingDropTarget();
+ if (showingDropTarget) {
+ bubbleBarViewController.onItemDragCompleted();
+ }
+ return showingDropTarget;
+ }).orElse(false);
+ }
+
+ private void notifyBubbleBarItemDragCanceled() {
+ mControllers.bubbleControllers.ifPresent(bc ->
+ bc.bubbleBarViewController.onItemDraggedOutsideBubbleBarDropZone());
+ }
+
@Override
protected void endDrag() {
- if (mDisallowGlobalDrag) {
- // We need to explicitly set deferDragViewCleanupPostAnimation to true here so
- // the
- // super call doesn't remove it from the drag layer before the animation
- // completes.
+ if (mDisallowGlobalDrag && !mIsDropHandledByDropTarget) {
+ // We need to explicitly set deferDragViewCleanupPostAnimation to true here so the
+ // super call doesn't remove it from the drag layer before the animation completes.
// This variable gets set in to false in super.dispatchDropComplete() because it
- // (rightfully so, perhaps) thinks this drag operation has failed, and does its
- // own
+ // (rightfully so, perhaps) thinks this drag operation has failed, and does its own
// internal cleanup.
- // Another way to approach this would be to make all of overview a drop target
- // and
- // accept the drop as successful and then run the setupReturnDragAnimator to
- // simulate
+ // Another way to approach this would be to make all of overview a drop target and
+ // accept the drop as successful and then run the setupReturnDragAnimator to simulate
// drop failure to the user
mDragObject.deferDragViewCleanupPostAnimation = true;
@@ -633,8 +670,7 @@ public class TaskbarDragController extends DragController im
syncGroup.add(viewRoot, null /* runnable */);
syncGroup.addTransaction(transaction);
syncGroup.markSyncReady();
- // Do this after maybeOnDragEnd(), because we use mReturnAnimator != null to
- // imply
+ // Do this after maybeOnDragEnd(), because we use mReturnAnimator != null to imply
// the drag was canceled rather than successful.
mReturnAnimator = null;
}
@@ -649,14 +685,13 @@ public class TaskbarDragController extends DragController im
if (tag instanceof ItemInfo) {
ItemInfo item = (ItemInfo) tag;
if (item.container == CONTAINER_ALL_APPS
- || item.container == CONTAINER_PREDICTION
+ || item.container == CONTAINER_ALL_APPS_PREDICTION
|| isInSearchResultContainer(item)) {
if (mDisallowGlobalDrag) {
// We're dragging in taskbarAllApps, we don't have folders or shortcuts
return iconView;
}
- // Since all apps closes when the drag starts, target the all apps button
- // instead.
+ // Since all apps closes when the drag starts, target the all apps button instead.
return taskbarViewController.getAllAppsButtonView();
} else if (item.container >= 0) {
// Since folders close when the drag starts, target the folder icon instead.
@@ -676,7 +711,8 @@ public class TaskbarDragController extends DragController im
private static boolean isInSearchResultContainer(ItemInfo item) {
ContainerInfo containerInfo = item.getContainerInfo();
return containerInfo.getContainerCase() == EXTENDED_CONTAINERS
- && containerInfo.getExtendedContainers().getContainerCase() == DEVICE_SEARCH_RESULT_CONTAINER;
+ && containerInfo.getExtendedContainers().getContainerCase()
+ == DEVICE_SEARCH_RESULT_CONTAINER;
}
private void setupReturnDragAnimator(float fromX, float fromY, View originalView,
@@ -705,7 +741,6 @@ public class TaskbarDragController extends DragController im
final FloatProp mDy = new FloatProp(fromY, toPosition[1], FAST_OUT_SLOW_IN);
final FloatProp mScale = new FloatProp(1f, toScale, FAST_OUT_SLOW_IN);
final FloatProp mAlpha = new FloatProp(1f, toAlpha, Interpolators.ACCELERATE_2);
-
@Override
public void onUpdate(float percent, boolean initOnly) {
animListener.updateDragShadow(mDx.value, mDy.value, mScale.value, mAlpha.value);
@@ -719,19 +754,15 @@ public class TaskbarDragController extends DragController im
@Override
protected float getX(MotionEvent ev) {
- // We will resize to fill the screen while dragging, so use screen coordinates.
- // This ensures
- // we start at the correct position even though touch down is on the smaller
- // DragLayer size.
+ // We will resize to fill the screen while dragging, so use screen coordinates. This ensures
+ // we start at the correct position even though touch down is on the smaller DragLayer size.
return ev.getRawX();
}
@Override
protected float getY(MotionEvent ev) {
- // We will resize to fill the screen while dragging, so use screen coordinates.
- // This ensures
- // we start at the correct position even though touch down is on the smaller
- // DragLayer size.
+ // We will resize to fill the screen while dragging, so use screen coordinates. This ensures
+ // we start at the correct position even though touch down is on the smaller DragLayer size.
return ev.getRawY();
}
@@ -751,8 +782,11 @@ public class TaskbarDragController extends DragController im
@Override
public void addDropTarget(DropTarget target) {
- // No-op as Taskbar currently doesn't support any drop targets internally.
- // Note: if we do add internal DropTargets, we'll still need to ignore Folder.
+ if (target instanceof Folder) {
+ // we need to ignore Folder.
+ return;
+ }
+ super.addDropTarget(target);
}
@Override
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
index 046bb54419..5fedee6a8d 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayer.java
@@ -18,7 +18,6 @@ package com.android.launcher3.taskbar;
import static android.view.KeyEvent.ACTION_UP;
import static android.view.KeyEvent.KEYCODE_BACK;
-import static com.android.launcher3.Flags.enableScalingRevealHomeAnimation;
import static com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION;
import android.content.Context;
@@ -43,7 +42,6 @@ import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.Utilities;
import com.android.launcher3.testing.TestLogging;
import com.android.launcher3.testing.shared.TestProtocol;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.views.BaseDragLayer;
@@ -102,20 +100,16 @@ public class TaskbarDragLayer extends BaseDragLayer {
public TaskbarDragLayer(@NonNull Context context, @Nullable AttributeSet attrs,
int defStyleAttr, int defStyleRes) {
super(context, attrs, 1 /* alphaChannelCount */);
- mBackgroundRenderer = new TaskbarBackgroundRenderer(mActivity);
+ mBackgroundRenderer = new TaskbarBackgroundRenderer(mContainer);
mTaskbarBackgroundAlpha = new MultiPropertyFactory<>(this, BG_ALPHA, INDEX_COUNT,
(a, b) -> a * b, 1f);
mTaskbarBackgroundAlpha.get(INDEX_ALL_OTHER_STATES).setValue(0);
- mTaskbarBackgroundAlpha.get(INDEX_STASH_ANIM).setValue(
- enableScalingRevealHomeAnimation() && DisplayController.isTransientTaskbar(context)
- ? 0
- : 1);
}
public void init(TaskbarDragLayerController.TaskbarDragLayerCallbacks callbacks) {
mControllerCallbacks = callbacks;
- mBackgroundRenderer.updateStashedHandleWidth(mActivity, getResources());
+ mBackgroundRenderer.updateStashedHandleWidth(mContainer, getResources());
recreateControllers();
}
@@ -133,6 +127,7 @@ public class TaskbarDragLayer extends BaseDragLayer {
@Override
public void recreateControllers() {
+ super.recreateControllers();
mControllers = mControllerCallbacks.getTouchControllers();
}
@@ -197,6 +192,7 @@ public class TaskbarDragLayer extends BaseDragLayer {
@Override
protected void dispatchDraw(Canvas canvas) {
+ if (mContainer.isDestroyed()) return;
float backgroundHeight = mControllerCallbacks.getTaskbarBackgroundHeight()
* (1f - mTaskbarBackgroundOffset);
mBackgroundRenderer.setBackgroundHeight(backgroundHeight);
@@ -265,6 +261,11 @@ public class TaskbarDragLayer extends BaseDragLayer {
invalidate();
}
+ protected void setBackgroundTranslationXForBubbleBar(float translationX) {
+ mBackgroundRenderer.setTranslationXForBubbleBar(translationX);
+ invalidate();
+ }
+
/** Returns the bounds in DragLayer coordinates of where the transient background was drawn. */
protected RectF getLastDrawnTransientRect() {
return mBackgroundRenderer.getLastDrawnTransientRect();
@@ -273,6 +274,7 @@ public class TaskbarDragLayer extends BaseDragLayer {
@Override
public boolean dispatchTouchEvent(MotionEvent ev) {
TestLogging.recordMotionEvent(TestProtocol.SEQUENCE_MAIN, "Touch event", ev);
+ mControllerCallbacks.onDispatchTouchEvent(ev);
return super.dispatchTouchEvent(ev);
}
@@ -280,7 +282,7 @@ public class TaskbarDragLayer extends BaseDragLayer {
@Override
public boolean dispatchKeyEvent(KeyEvent event) {
if (event.getAction() == ACTION_UP && event.getKeyCode() == KEYCODE_BACK) {
- AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mActivity);
+ AbstractFloatingView topView = AbstractFloatingView.getTopOpenView(mContainer);
if (topView != null && topView.canHandleBack()) {
topView.onBackInvoked();
// Handled by the floating view.
@@ -290,6 +292,21 @@ public class TaskbarDragLayer extends BaseDragLayer {
return super.dispatchKeyEvent(event);
}
+ /**
+ * Sets animation boolean when only animating persistent taskbar.
+ */
+ public void setIsAnimatingPersistentTaskbarBackground(boolean animatingPersistentTaskbarBg) {
+ mBackgroundRenderer.setAnimatingPersistentTaskbar(animatingPersistentTaskbarBg);
+ }
+
+ /**
+ * Sets animation boolean when only animating transient taskbar.
+ */
+ public void setIsAnimatingTransientTaskbarBackground(boolean animatingTransientTaskbarBg) {
+ mBackgroundRenderer.setAnimatingTransientTaskbar(animatingTransientTaskbarBg);
+ }
+
+
/**
* Sets the width percentage to inset the transient taskbar's background from the left and from
* the right.
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
index ff890fb18e..8bd685b3d6 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarDragLayerController.java
@@ -15,21 +15,25 @@
*/
package com.android.launcher3.taskbar;
+import static com.android.app.animation.Interpolators.EMPHASIZED;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
+import android.animation.AnimatorSet;
+import android.animation.ObjectAnimator;
import android.content.res.Resources;
import android.graphics.Canvas;
import android.graphics.Point;
import android.graphics.Rect;
import android.os.SystemProperties;
+import android.view.MotionEvent;
import android.view.ViewTreeObserver;
import com.android.launcher3.DeviceProfile;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
+import com.android.launcher3.anim.AnimatorListeners;
import com.android.launcher3.util.DimensionUtils;
-import com.android.launcher3.util.DisplayController;
import com.android.launcher3.util.MultiPropertyFactory.MultiProperty;
import com.android.launcher3.util.TouchController;
@@ -57,6 +61,8 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
private final AnimatedFloat mImeBgTaskbar = new AnimatedFloat(this::updateBackgroundAlpha);
private final AnimatedFloat mAssistantBgTaskbar = new AnimatedFloat(
this::updateBackgroundAlpha);
+ private final AnimatedFloat mBgTaskbarRecreate = new AnimatedFloat(
+ this::updateBackgroundAlpha);
// Used to hide our background color when someone else (e.g. ScrimView) is handling it.
private final AnimatedFloat mBgOverride = new AnimatedFloat(this::updateBackgroundAlpha);
@@ -87,7 +93,10 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
mFolderMargin = resources.getDimensionPixelSize(R.dimen.taskbar_folder_margin);
}
- public void init(TaskbarControllers controllers) {
+ /**
+ * Init of taskbar drag layer controller
+ */
+ public void init(TaskbarControllers controllers, AnimatorSet startAnimation) {
mControllers = controllers;
mTaskbarStashViaTouchController = new TaskbarStashViaTouchController(mControllers);
mTaskbarDragLayer.init(new TaskbarDragLayerCallbacks());
@@ -95,15 +104,43 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
mOnBackgroundNavButtonColorIntensity = mControllers.navbarButtonsViewController
.getOnTaskbarBackgroundNavButtonColorOverride();
- mTaskbarBackgroundProgress.updateValue(DisplayController.isTransientTaskbar(mActivity)
- ? PINNING_TRANSIENT
- : PINNING_PERSISTENT);
+
+ if (startAnimation != null) {
+ // set taskbar background render animation boolean
+ if (mActivity.isTransientTaskbar()) {
+ mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(true);
+ } else {
+ mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(true);
+ }
+
+ float desiredValue = mActivity.isTransientTaskbar()
+ ? PINNING_TRANSIENT
+ : PINNING_PERSISTENT;
+
+ float nonDesiredvalue =
+ !mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT;
+
+ ObjectAnimator objectAnimator = mTaskbarBackgroundProgress.animateToValue(
+ nonDesiredvalue, desiredValue);
+ objectAnimator.setInterpolator(EMPHASIZED);
+ startAnimation.play(objectAnimator);
+ startAnimation.addListener(AnimatorListeners.forEndCallback(()-> {
+ // reset taskbar background render animation boolean
+ mTaskbarDragLayer.setIsAnimatingPersistentTaskbarBackground(false);
+ mTaskbarDragLayer.setIsAnimatingTransientTaskbarBackground(false);
+ }));
+
+ } else {
+ mTaskbarBackgroundProgress.updateValue(
+ mActivity.isTransientTaskbar() ? PINNING_TRANSIENT : PINNING_PERSISTENT);
+ }
mBgTaskbar.value = 1;
mKeyguardBgTaskbar.value = 1;
mNotificationShadeBgTaskbar.value = 1;
mImeBgTaskbar.value = 1;
mAssistantBgTaskbar.value = 1;
+ mBgTaskbarRecreate.value = 1;
mBgOverride.value = 1;
updateBackgroundAlpha();
@@ -111,6 +148,13 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
updateTaskbarAlpha();
}
+ /**
+ * Called when destroying Taskbar with animation.
+ */
+ public void onDestroyAnimation(AnimatorSet animatorSet) {
+ animatorSet.play(mBgTaskbarRecreate.animateToValue(0f));
+ }
+
public void onDestroy() {
mTaskbarDragLayer.onDestroy();
}
@@ -119,9 +163,14 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
* @return Bounds (in TaskbarDragLayer coordinates) where an opened Folder can display.
*/
public Rect getFolderBoundingBox() {
- Rect boundingBox = new Rect(0, 0, mTaskbarDragLayer.getWidth(),
- mTaskbarDragLayer.getHeight() - mActivity.getDeviceProfile().taskbarHeight
- - mActivity.getDeviceProfile().taskbarBottomMargin);
+ Rect boundingBox = new Rect(
+ 0,
+ 0,
+ mTaskbarDragLayer.getWidth(),
+ mTaskbarDragLayer.getHeight()
+ - mActivity.getDeviceProfile().getTaskbarProfile().getHeight()
+ - mActivity.getDeviceProfile().getTaskbarProfile().getBottomMargin()
+ );
boundingBox.inset(mFolderMargin, mFolderMargin);
return boundingBox;
}
@@ -171,10 +220,14 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
}
private void updateBackgroundAlpha() {
+ if (!mActivity.drawsTaskbarBackground() || mActivity.isDestroyed()) {
+ return;
+ }
+
final float bgNavbar = mBgNavbar.value;
final float bgTaskbar = mBgTaskbar.value * mKeyguardBgTaskbar.value
* mNotificationShadeBgTaskbar.value * mImeBgTaskbar.value
- * mAssistantBgTaskbar.value;
+ * mAssistantBgTaskbar.value * mBgTaskbarRecreate.value;
mLastSetBackgroundAlpha = mBgOverride.value * Math.max(bgNavbar, bgTaskbar);
mBackgroundRendererAlpha.setValue(mLastSetBackgroundAlpha);
@@ -192,6 +245,13 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
mTaskbarDragLayer.setBackgroundTranslationYForSwipe(transY);
}
+ /**
+ * Sets the translation of the background for the bubble bar.
+ */
+ public void setTranslationXForBubbleBar(float transX) {
+ mTaskbarDragLayer.setBackgroundTranslationXForBubbleBar(transX);
+ }
+
/**
* Sets the translation of the background during the spring on stash animation.
*/
@@ -254,6 +314,7 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
pw.println(prefix + "\t\tmNotificationShadeBgTaskbar=" + mNotificationShadeBgTaskbar.value);
pw.println(prefix + "\t\tmImeBgTaskbar=" + mImeBgTaskbar.value);
pw.println(prefix + "\t\tmAssistantBgTaskbar=" + mAssistantBgTaskbar.value);
+ pw.println(prefix + "\t\tmBgTaskbarRecreate=" + mBgTaskbarRecreate.value);
}
/**
@@ -291,12 +352,12 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
if (mActivity.isPhoneMode()) {
Resources resources = mActivity.getResources();
Point taskbarDimensions = DimensionUtils.getTaskbarPhoneDimensions(deviceProfile,
- resources, true /* isPhoneMode */);
+ resources, true /* isPhoneMode */, mActivity.isGestureNav());
return taskbarDimensions.y == -1 ?
deviceProfile.getDisplayInfo().currentSize.y :
taskbarDimensions.y;
} else {
- return deviceProfile.taskbarHeight;
+ return deviceProfile.getTaskbarProfile().getHeight();
}
}
@@ -321,5 +382,15 @@ public class TaskbarDragLayerController implements TaskbarControllers.LoggableTa
}
mControllers.taskbarInsetsController.drawDebugTouchableRegionBounds(canvas);
}
+
+ /** Handles any touch event before it is dispatched to the rest of TaskbarDragLayer. */
+ public void onDispatchTouchEvent(MotionEvent ev) {
+ if (mActivity.isThreeButtonNav() && ev.getAction() == MotionEvent.ACTION_OUTSIDE
+ && mControllers.uiController.isAnimatingToHotseat()) {
+ // When touching during animation to home, jump to the end so Hotseat can handle
+ // the touch. (Gesture Navigation handles this in AbsSwipeUpHandler.)
+ mControllers.uiController.endAnimationToHotseat();
+ }
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
index 5adb25821d..eb2d1d98d1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltip.kt
@@ -29,7 +29,6 @@ import android.view.ViewGroup.LayoutParams.MATCH_PARENT
import android.view.animation.Interpolator
import android.window.OnBackInvokedDispatcher
import androidx.core.view.updateLayoutParams
-import app.lawnchair.theme.color.tokens.ColorTokens
import com.android.app.animation.Interpolators.EMPHASIZED_ACCELERATE
import com.android.app.animation.Interpolators.EMPHASIZED_DECELERATE
import com.android.app.animation.Interpolators.STANDARD
@@ -40,22 +39,20 @@ import com.android.launcher3.popup.RoundedArrowDrawable
import com.android.launcher3.util.Themes
import com.android.launcher3.views.ActivityContext
+import app.lawnchair.theme.color.tokens.ColorTokens
+
private const val ENTER_DURATION_MS = 300L
private const val EXIT_DURATION_MS = 150L
/** Floating tooltip for Taskbar education. */
class TaskbarEduTooltip
@JvmOverloads
-constructor(
- context: Context,
- attrs: AttributeSet? = null,
- defStyleAttr: Int = 0,
-) : AbstractFloatingView(context, attrs, defStyleAttr) {
+constructor(context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0) :
+ AbstractFloatingView(context, attrs, defStyleAttr) {
private val activityContext: ActivityContext = ActivityContext.lookupContext(context)
- private val backgroundColor =
- ColorTokens.SurfaceBrightColor.resolveColor(getContext())
+ private val backgroundColor = ColorTokens.SurfaceBrightColor.resolveColor(getContext())
private val tooltipCornerRadius = Themes.getDialogCornerRadius(context)
private val arrowWidth = resources.getDimension(R.dimen.popup_arrow_width)
@@ -90,8 +87,8 @@ constructor(
// constraint to reduce the number of lines of text and hopefully free up some height.
activityContext.dragLayer.measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED)
if (
- measuredHeight + activityContext.deviceProfile.taskbarHeight >=
- activityContext.deviceProfile.availableHeightPx
+ measuredHeight + activityContext.deviceProfile.taskbarProfile.height >=
+ activityContext.deviceProfile.deviceProperties.availableHeightPx
) {
updateLayoutParams { width = MATCH_PARENT }
}
@@ -102,8 +99,8 @@ constructor(
override fun onFinishInflate() {
super.onFinishInflate()
- content = requireViewById(R.id.content)
- arrow = requireViewById(R.id.arrow)
+ content = requireViewById(R.id.content)
+ arrow = requireViewById(R.id.arrow)
arrow.background =
RoundedArrowDrawable(
arrowWidth,
@@ -151,6 +148,7 @@ constructor(
override fun onAttachedToWindow() {
super.onAttachedToWindow()
+ // Lawnchair-TODO-Merge: This was disabled but enabled in 16r2, this function likely disable the gesture system during edu
// findOnBackInvokedDispatcher()
// ?.registerOnBackInvokedCallback(OnBackInvokedDispatcher.PRIORITY_DEFAULT, this)
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
index d57c4838d7..9a120f5611 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarEduTooltipController.kt
@@ -33,22 +33,26 @@ import android.view.accessibility.AccessibilityNodeInfo
import android.widget.TextView
import androidx.annotation.IntDef
import androidx.annotation.LayoutRes
+import androidx.annotation.VisibleForTesting
import androidx.core.text.HtmlCompat
import androidx.core.view.updateLayoutParams
import com.airbnb.lottie.LottieAnimationView
import com.android.launcher3.LauncherPrefs
import com.android.launcher3.R
+import com.android.launcher3.RemoveAnimationSettingsTracker
import com.android.launcher3.Utilities
import com.android.launcher3.config.FeatureFlags.enableTaskbarPinning
import com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_EDU_OPEN
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
-import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_EDU_TOOLTIP_STEP
import com.android.launcher3.util.OnboardingPrefs.TASKBAR_SEARCH_EDU_SEEN
import com.android.launcher3.util.ResourceBasedOverride
import com.android.launcher3.views.ActivityContext
import com.android.launcher3.views.BaseDragLayer
+import com.android.quickstep.util.ContextualSearchInvoker
import com.android.quickstep.util.LottieAnimationColorUtils
+import com.android.wm.shell.shared.TypefaceUtils
+import com.android.wm.shell.shared.TypefaceUtils.FontFamily
import java.io.PrintWriter
/** First EDU step for swiping up to show transient Taskbar. */
@@ -79,7 +83,11 @@ open class TaskbarEduTooltipController(context: Context) :
ResourceBasedOverride, LoggableTaskbarController {
protected val activityContext: TaskbarActivityContext = ActivityContext.lookupContext(context)
- open val shouldShowSearchEdu = false
+ open val shouldShowSearchEdu: Boolean
+ get() =
+ ContextualSearchInvoker(activityContext)
+ .runContextualSearchInvocationChecksAndLogFailures()
+
private val isTooltipEnabled: Boolean
get() {
return !Utilities.isRunningInTestHarness() &&
@@ -87,7 +95,7 @@ open class TaskbarEduTooltipController(context: Context) :
!activityContext.isTinyTaskbar
}
- private val isOpen: Boolean
+ val isTooltipOpen: Boolean
get() = tooltip?.isOpen ?: false
val isBeforeTooltipFeaturesStep: Boolean
@@ -96,7 +104,8 @@ open class TaskbarEduTooltipController(context: Context) :
private lateinit var controllers: TaskbarControllers
// Keep track of whether the user has seen the Search Edu
- private var userHasSeenSearchEdu: Boolean
+ @VisibleForTesting
+ var userHasSeenSearchEdu: Boolean
get() {
return TASKBAR_SEARCH_EDU_SEEN.get(activityContext)
}
@@ -121,11 +130,31 @@ open class TaskbarEduTooltipController(context: Context) :
activityContext.dragLayer.post { maybeShowSearchEdu() }
}
+ /**
+ * Turns off auto play of lottie animations if user has opted to remove animation else attaches
+ * click listener to allow user to play or pause animations.
+ */
+ fun handleEduAnimations(animationViews: List) {
+ for (animationView in animationViews) {
+ if (
+ RemoveAnimationSettingsTracker.INSTANCE.get(animationView.context)
+ .isRemoveAnimationEnabled()
+ ) {
+ animationView.pauseAnimation()
+ } else {
+ animationView.setOnClickListener {
+ if (animationView.isAnimating) animationView.pauseAnimation()
+ else animationView.playAnimation()
+ }
+ }
+ }
+ }
+
/** Shows swipe EDU tooltip if it is the current [tooltipStep]. */
fun maybeShowSwipeEdu() {
if (
!isTooltipEnabled ||
- !DisplayController.isTransientTaskbar(activityContext) ||
+ !activityContext.isTransientTaskbar ||
tooltipStep > TOOLTIP_STEP_SWIPE
) {
return
@@ -134,7 +163,15 @@ open class TaskbarEduTooltipController(context: Context) :
tooltipStep = TOOLTIP_STEP_FEATURES
inflateTooltip(R.layout.taskbar_edu_swipe)
tooltip?.run {
- requireViewById(R.id.swipe_animation).supportLightTheme()
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.taskbar_edu_title),
+ FontFamily.GSF_HEADLINE_SMALL_EMPHASIZED,
+ )
+ val swipeAnimation = requireViewById(R.id.swipe_animation)
+ swipeAnimation.contentDescription =
+ context.getString(R.string.taskbar_edu_swipe_animation_description)
+ swipeAnimation.supportLightTheme()
+ handleEduAnimations(listOf(swipeAnimation))
show()
}
}
@@ -157,13 +194,20 @@ open class TaskbarEduTooltipController(context: Context) :
tooltip?.run {
allowTouchDismissal = false
val splitscreenAnim = requireViewById(R.id.splitscreen_animation)
+ splitscreenAnim.contentDescription =
+ context.getString(R.string.taskbar_edu_split_screen_animation_description)
val suggestionsAnim = requireViewById(R.id.suggestions_animation)
+ suggestionsAnim.contentDescription =
+ context.getString(R.string.taskbar_edu_suggested_app_animation_description)
val pinningAnim = requireViewById(R.id.pinning_animation)
+ pinningAnim.contentDescription =
+ context.getString(R.string.taskbar_edu_pinning_animation_description)
val pinningEdu = requireViewById(R.id.pinning_edu)
splitscreenAnim.supportLightTheme()
suggestionsAnim.supportLightTheme()
pinningAnim.supportLightTheme()
- if (DisplayController.isTransientTaskbar(activityContext)) {
+ handleEduAnimations(listOf(splitscreenAnim, suggestionsAnim, pinningAnim))
+ if (activityContext.isTransientTaskbar) {
splitscreenAnim.setAnimation(R.raw.taskbar_edu_splitscreen_transient)
suggestionsAnim.setAnimation(R.raw.taskbar_edu_suggestions_transient)
pinningEdu.visibility = if (enableTaskbarPinning()) VISIBLE else GONE
@@ -173,10 +217,27 @@ open class TaskbarEduTooltipController(context: Context) :
pinningEdu.visibility = GONE
}
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.taskbar_edu_title),
+ FontFamily.GSF_HEADLINE_SMALL_EMPHASIZED,
+ )
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.splitscreen_text),
+ FontFamily.GSF_BODY_MEDIUM,
+ )
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.suggestions_text),
+ FontFamily.GSF_BODY_MEDIUM,
+ )
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.pinning_text),
+ FontFamily.GSF_BODY_MEDIUM,
+ )
+
// Set up layout parameters.
content.updateLayoutParams { width = MATCH_PARENT }
updateLayoutParams {
- if (DisplayController.isTransientTaskbar(activityContext)) {
+ if (activityContext.isTransientTaskbar) {
width =
resources.getDimensionPixelSize(
if (enableTaskbarPinning())
@@ -184,7 +245,7 @@ open class TaskbarEduTooltipController(context: Context) :
else R.dimen.taskbar_edu_features_tooltip_width_with_two_features
)
- bottomMargin += activityContext.deviceProfile.taskbarHeight
+ bottomMargin += activityContext.deviceProfile.taskbarProfile.height
} else {
width =
resources.getDimensionPixelSize(
@@ -209,7 +270,7 @@ open class TaskbarEduTooltipController(context: Context) :
// for the original 2 edu steps) as a proxy to needing to show the separate pinning edu
if (
!enableTaskbarPinning() ||
- !DisplayController.isTransientTaskbar(activityContext) ||
+ !activityContext.isTransientTaskbar ||
!isTooltipEnabled ||
tooltipStep > TOOLTIP_STEP_PINNING ||
tooltipStep < TOOLTIP_STEP_FEATURES
@@ -221,12 +282,24 @@ open class TaskbarEduTooltipController(context: Context) :
tooltip?.run {
allowTouchDismissal = true
- requireViewById(R.id.standalone_pinning_animation)
- .supportLightTheme()
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.taskbar_edu_title),
+ FontFamily.GSF_HEADLINE_SMALL_EMPHASIZED,
+ )
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.pinning_text),
+ FontFamily.GSF_BODY_MEDIUM,
+ )
+ val pinningAnim =
+ requireViewById(R.id.standalone_pinning_animation)
+ pinningAnim.contentDescription =
+ context.getString(R.string.taskbar_edu_pinning_animation_description)
+ pinningAnim.supportLightTheme()
+ handleEduAnimations(listOf(pinningAnim))
updateLayoutParams {
- if (DisplayController.isTransientTaskbar(activityContext)) {
- bottomMargin += activityContext.deviceProfile.taskbarHeight
+ if (activityContext.isTransientTaskbar) {
+ bottomMargin += activityContext.deviceProfile.taskbarProfile.height
}
// Unlike other tooltips, we want to align with taskbar divider rather than center.
gravity = Gravity.BOTTOM
@@ -255,10 +328,11 @@ open class TaskbarEduTooltipController(context: Context) :
fun maybeShowSearchEdu() {
if (
!enableTaskbarPinning() ||
- !DisplayController.isPinnedTaskbar(activityContext) ||
+ !activityContext.isPinnedTaskbar ||
!isTooltipEnabled ||
!shouldShowSearchEdu ||
- userHasSeenSearchEdu
+ userHasSeenSearchEdu ||
+ !controllers.taskbarStashController.isTaskbarVisibleAndNotStashing
) {
return
}
@@ -266,12 +340,23 @@ open class TaskbarEduTooltipController(context: Context) :
inflateTooltip(R.layout.taskbar_edu_search)
tooltip?.run {
allowTouchDismissal = true
- requireViewById(R.id.search_edu_animation).supportLightTheme()
+ val searchEdu = requireViewById(R.id.search_edu_animation)
+ searchEdu.contentDescription =
+ context.getString(R.string.taskbar_edu_suggested_search_animation_description)
+ searchEdu.supportLightTheme()
+ handleEduAnimations(listOf(searchEdu))
val eduSubtitle: TextView = requireViewById(R.id.search_edu_text)
+
+ TypefaceUtils.setTypeface(
+ requireViewById(R.id.taskbar_edu_title),
+ FontFamily.GSF_HEADLINE_SMALL_EMPHASIZED,
+ )
+ TypefaceUtils.setTypeface(eduSubtitle, FontFamily.GSF_BODY_SMALL)
+
showDisclosureText(eduSubtitle)
updateLayoutParams {
- if (DisplayController.isTransientTaskbar(activityContext)) {
- bottomMargin += activityContext.deviceProfile.taskbarHeight
+ if (activityContext.isTransientTaskbar) {
+ bottomMargin += activityContext.deviceProfile.taskbarProfile.height
}
// Unlike other tooltips, we want to align with the all apps button rather than
// center.
@@ -349,19 +434,19 @@ open class TaskbarEduTooltipController(context: Context) :
overlayContext.layoutInflater.inflate(
R.layout.taskbar_edu_tooltip,
overlayContext.dragLayer,
- false
+ false,
) as TaskbarEduTooltip
controllers.taskbarAutohideSuspendController.updateFlag(
FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
- true
+ true,
)
tooltip.onCloseCallback = {
this.tooltip = null
controllers.taskbarAutohideSuspendController.updateFlag(
FLAG_AUTOHIDE_SUSPEND_EDU_OPEN,
- false
+ false,
)
controllers.taskbarStashController.updateAndAnimateTransientTaskbar(true)
}
@@ -376,7 +461,7 @@ open class TaskbarEduTooltipController(context: Context) :
override fun performAccessibilityAction(
host: View,
action: Int,
- args: Bundle?
+ args: Bundle?,
): Boolean {
if (action == R.id.close) {
hide()
@@ -394,13 +479,13 @@ open class TaskbarEduTooltipController(context: Context) :
override fun onInitializeAccessibilityNodeInfo(
host: View,
- info: AccessibilityNodeInfo
+ info: AccessibilityNodeInfo,
) {
super.onInitializeAccessibilityNodeInfo(host, info)
info.addAction(
AccessibilityNodeInfo.AccessibilityAction(
R.id.close,
- host.context?.getText(R.string.taskbar_edu_close)
+ host.context?.getText(R.string.taskbar_edu_close),
)
)
}
@@ -409,7 +494,7 @@ open class TaskbarEduTooltipController(context: Context) :
override fun dumpLogs(prefix: String?, pw: PrintWriter?) {
pw?.println(prefix + "TaskbarEduTooltipController:")
pw?.println("$prefix\tisTooltipEnabled=$isTooltipEnabled")
- pw?.println("$prefix\tisOpen=$isOpen")
+ pw?.println("$prefix\tisOpen=$isTooltipOpen")
pw?.println("$prefix\ttooltipStep=$tooltipStep")
}
@@ -419,7 +504,7 @@ open class TaskbarEduTooltipController(context: Context) :
return ResourceBasedOverride.Overrides.getObject(
TaskbarEduTooltipController::class.java,
context,
- R.string.taskbar_edu_tooltip_controller_class
+ R.string.taskbar_edu_tooltip_controller_class,
)
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
index 6ac862e9e0..b7f55756c1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarForceVisibleImmersiveController.java
@@ -85,6 +85,9 @@ public class TaskbarForceVisibleImmersiveController implements TouchController {
/** Update values tracked via sysui flags. */
public void updateSysuiFlags(@SystemUiStateFlags long sysuiFlags) {
+ if (mContext.isPhoneMode()) {
+ return;
+ }
mIsImmersiveMode = (sysuiFlags & SYSUI_STATE_ALLOW_GESTURE_IGNORING_BAR_VISIBILITY) == 0;
if (mContext.isNavBarForceVisible()) {
if (mIsImmersiveMode) {
@@ -105,8 +108,10 @@ public class TaskbarForceVisibleImmersiveController implements TouchController {
/** Clean up animations. */
public void onDestroy() {
startIconUndimming();
- mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(null);
- mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(null);
+ if (mControllers != null) {
+ mControllers.navbarButtonsViewController.setHomeButtonAccessibilityDelegate(null);
+ mControllers.navbarButtonsViewController.setBackButtonAccessibilityDelegate(null);
+ }
}
private void startIconUndimming() {
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
index 044319796e..42ad5b2aa1 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarHoverToolTipController.java
@@ -18,29 +18,24 @@ package com.android.launcher3.taskbar;
import static android.view.MotionEvent.ACTION_HOVER_ENTER;
import static android.view.MotionEvent.ACTION_HOVER_EXIT;
import static android.view.View.ALPHA;
-import static android.view.View.SCALE_Y;
-import static android.view.accessibility.AccessibilityManager.FLAG_CONTENT_TEXT;
-import static com.android.app.animation.Interpolators.LINEAR;
-import static com.android.launcher3.AbstractFloatingView.TYPE_ALL_EXCEPT_ON_BOARD_POPUP;
+import static com.android.launcher3.AbstractFloatingView.TYPE_ACTION_POPUP;
+import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER;
import static com.android.launcher3.taskbar.TaskbarAutohideSuspendController.FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS;
-import static com.android.launcher3.views.ArrowTipView.TEXT_ALPHA;
import android.animation.AnimatorSet;
import android.animation.ObjectAnimator;
import android.graphics.Rect;
-import android.os.Handler;
-import android.os.Looper;
+import android.text.TextUtils;
import android.view.ContextThemeWrapper;
import android.view.MotionEvent;
import android.view.View;
-import com.android.app.animation.Interpolators;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BubbleTextView;
import com.android.launcher3.R;
import com.android.launcher3.Utilities;
-import com.android.launcher3.compat.AccessibilityManagerCompat;
+import com.android.launcher3.apppairs.AppPairIcon;
import com.android.launcher3.folder.FolderIcon;
import com.android.launcher3.views.ArrowTipView;
@@ -48,19 +43,15 @@ import com.android.launcher3.views.ArrowTipView;
* Controls showing a tooltip in the taskbar above each icon when it is hovered.
*/
public class TaskbarHoverToolTipController implements View.OnHoverListener {
-
- private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 250;
- private static final int HOVER_TOOL_TIP_EXIT_DURATION = 150;
-
- private final Handler mHoverToolTipHandler = new Handler(Looper.getMainLooper());
- private final Runnable mRevealHoverToolTipRunnable = this::revealHoverToolTip;
- private final Runnable mHideHoverToolTipRunnable = this::hideHoverToolTip;
+ // Short duration to reveal tooltip, as it is positioned in the x/y via a post() call in
+ // parallel with the open animation. An instant animation could show in the wrong location.
+ private static final int HOVER_TOOL_TIP_REVEAL_DURATION = 15;
private final TaskbarActivityContext mActivity;
private final TaskbarView mTaskbarView;
private final View mHoverView;
private final ArrowTipView mHoverToolTipView;
- private final String mToolTipText;
+ private final int mYOffset;
public TaskbarHoverToolTipController(TaskbarActivityContext activity, TaskbarView taskbarView,
View hoverView) {
@@ -68,15 +59,6 @@ public class TaskbarHoverToolTipController implements View.OnHoverListener {
mTaskbarView = taskbarView;
mHoverView = hoverView;
- if (mHoverView instanceof BubbleTextView) {
- mToolTipText = ((BubbleTextView) mHoverView).getText().toString();
- } else if (mHoverView instanceof FolderIcon
- && ((FolderIcon) mHoverView).mInfo.title != null) {
- mToolTipText = ((FolderIcon) mHoverView).mInfo.title.toString();
- } else {
- mToolTipText = null;
- }
-
ContextThemeWrapper arrowContextWrapper = new ContextThemeWrapper(mActivity,
R.style.ArrowTipTaskbarStyle);
mHoverToolTipView = new ArrowTipView(arrowContextWrapper, /* isPointingUp = */ false,
@@ -87,90 +69,75 @@ public class TaskbarHoverToolTipController implements View.OnHoverListener {
R.dimen.taskbar_tooltip_horizontal_padding);
mHoverToolTipView.findViewById(R.id.text).setPadding(horizontalPadding, verticalPadding,
horizontalPadding, verticalPadding);
-
- AnimatorSet hoverCloseAnimator = new AnimatorSet();
- ObjectAnimator textCloseAnimator = ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0);
- textCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0, 0.33f));
- ObjectAnimator alphaCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0);
- alphaCloseAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.33f, 0.66f));
- ObjectAnimator scaleCloseAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0);
- scaleCloseAnimator.setInterpolator(Interpolators.STANDARD);
- hoverCloseAnimator.playTogether(
- textCloseAnimator,
- alphaCloseAnimator,
- scaleCloseAnimator);
- hoverCloseAnimator.setStartDelay(0);
- hoverCloseAnimator.setDuration(HOVER_TOOL_TIP_EXIT_DURATION);
- mHoverToolTipView.setCustomCloseAnimation(hoverCloseAnimator);
+ mHoverToolTipView.setAlpha(0);
+ mYOffset = arrowContextWrapper.getResources().getDimensionPixelSize(
+ R.dimen.taskbar_tooltip_y_offset);
AnimatorSet hoverOpenAnimator = new AnimatorSet();
- ObjectAnimator textOpenAnimator =
- ObjectAnimator.ofInt(mHoverToolTipView, TEXT_ALPHA, 0, 255);
- textOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0.15f, 0.75f));
- ObjectAnimator scaleOpenAnimator =
- ObjectAnimator.ofFloat(mHoverToolTipView, SCALE_Y, 0f, 1f);
- scaleOpenAnimator.setInterpolator(Interpolators.EMPHASIZED);
ObjectAnimator alphaOpenAnimator = ObjectAnimator.ofFloat(mHoverToolTipView, ALPHA, 0f, 1f);
- alphaOpenAnimator.setInterpolator(Interpolators.clampToProgress(LINEAR, 0f, 0.33f));
- hoverOpenAnimator.playTogether(
- scaleOpenAnimator,
- textOpenAnimator,
- alphaOpenAnimator);
+ hoverOpenAnimator.play(alphaOpenAnimator);
hoverOpenAnimator.setDuration(HOVER_TOOL_TIP_REVEAL_DURATION);
mHoverToolTipView.setCustomOpenAnimation(hoverOpenAnimator);
mHoverToolTipView.addOnLayoutChangeListener(
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
mHoverToolTipView.setPivotY(bottom);
- mHoverToolTipView.setY(mTaskbarView.getTop() - (bottom - top));
+ mHoverToolTipView.setY(mTaskbarView.getTop() - mYOffset - (bottom - top));
});
}
@Override
public boolean onHover(View v, MotionEvent event) {
- boolean isAnyOtherFloatingViewOpen =
- AbstractFloatingView.hasOpenView(mActivity, TYPE_ALL_EXCEPT_ON_BOARD_POPUP);
- if (isAnyOtherFloatingViewOpen) {
- mHoverToolTipHandler.removeCallbacksAndMessages(null);
- }
// If hover leaves a taskbar icon animate the tooltip closed.
if (event.getAction() == ACTION_HOVER_EXIT) {
- startHideHoverToolTip();
+ mHoverToolTipView.close(/* animate= */ false);
mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, false);
- return true;
- } else if (!isAnyOtherFloatingViewOpen && event.getAction() == ACTION_HOVER_ENTER) {
- // If hovering above a taskbar icon starts, animate the tooltip open. Do not
- // reveal if any floating views such as folders or edu pop-ups are open.
- startRevealHoverToolTip();
+ } else if (event.getAction() == ACTION_HOVER_ENTER) {
+ maybeRevealHoverToolTip();
mActivity.setAutohideSuspendFlag(FLAG_AUTOHIDE_SUSPEND_HOVERING_ICONS, true);
- return true;
}
return false;
}
- private void startRevealHoverToolTip() {
- mHoverToolTipHandler.post(mRevealHoverToolTipRunnable);
- }
+ private void maybeRevealHoverToolTip() {
+ if (mHoverView == null) {
+ return;
+ }
- private void revealHoverToolTip() {
- if (mHoverView == null || mToolTipText == null) {
+ final String toolTipText = getToolTipText();
+ if (TextUtils.isEmpty(toolTipText)) {
+ return;
+ }
+
+ // Do not show tooltip if taskbar icons are transitioning to hotseat.
+ if (mActivity.isIconAlignedWithHotseat()) {
return;
}
if (mHoverView instanceof FolderIcon && !((FolderIcon) mHoverView).getIconVisible()) {
return;
}
+ // Do not reveal if floating views such as folders or app pop-ups are open,
+ // as these views will overlap and not look great.
+ if (AbstractFloatingView.hasOpenView(mActivity, TYPE_FOLDER | TYPE_ACTION_POPUP)) {
+ return;
+ }
+
Rect iconViewBounds = Utilities.getViewBounds(mHoverView);
- mHoverToolTipView.showAtLocation(mToolTipText, iconViewBounds.centerX(),
- mTaskbarView.getTop(), /* shouldAutoClose= */ false);
+ mHoverToolTipView.showAtLocation(toolTipText, iconViewBounds.centerX(),
+ mTaskbarView.getTop() - mYOffset, /* shouldAutoClose= */ false);
}
- private void startHideHoverToolTip() {
- int accessibilityHideTimeout = AccessibilityManagerCompat.getRecommendedTimeoutMillis(
- mActivity, /* originalTimeout= */ 0, FLAG_CONTENT_TEXT);
- mHoverToolTipHandler.postDelayed(mHideHoverToolTipRunnable, accessibilityHideTimeout);
- }
-
- private void hideHoverToolTip() {
- mHoverToolTipView.close(/* animate = */ true);
+ private String getToolTipText() {
+ if (mHoverView instanceof BubbleTextView btv) {
+ return btv.getText().toString();
+ } else if (mHoverView instanceof FolderIcon icon && icon.mInfo.title != null) {
+ return icon.mInfo.title.toString();
+ } else if (mHoverView instanceof AppPairIcon icon) {
+ return icon.getTitleTextView().getText().toString();
+ } else if (mHoverView instanceof TaskbarOverflowView icon) {
+ return icon.getTextForTooltipPopup();
+ } else {
+ return null;
+ }
}
}
diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
index 01eeb082d5..c07ae1d5b3 100644
--- a/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
+++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarInsetsController.kt
@@ -21,7 +21,6 @@ import android.graphics.Insets
import android.graphics.Paint
import android.graphics.Rect
import android.graphics.Region
-import android.inputmethodservice.InputMethodService.ENABLE_HIDE_IME_CAPTION_BAR
import android.os.Binder
import android.os.IBinder
import android.view.DisplayInfo
@@ -33,8 +32,10 @@ import android.view.InsetsSource.FLAG_INSETS_ROUNDED_CORNER
import android.view.InsetsSource.FLAG_SUPPRESS_SCRIM
import android.view.Surface
import android.view.ViewTreeObserver
+import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_CONTENT
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_FRAME
import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION
+import android.view.ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_VISIBLE
import android.view.WindowInsets
import android.view.WindowInsets.Type.mandatorySystemGestures
import android.view.WindowInsets.Type.navigationBars
@@ -43,7 +44,9 @@ import android.view.WindowInsets.Type.tappableElement
import android.view.WindowManager
import android.view.WindowManager.LayoutParams.TYPE_INPUT_METHOD
import android.view.WindowManager.LayoutParams.TYPE_VOICE_INTERACTION
+import androidx.annotation.VisibleForTesting
import androidx.core.graphics.toRegion
+
import com.android.internal.policy.GestureNavigationSettingsObserver
import com.android.launcher3.DeviceProfile
import com.android.launcher3.R
@@ -51,12 +54,18 @@ import com.android.launcher3.anim.AlphaUpdateListener
import com.android.launcher3.config.FeatureFlags.ENABLE_TASKBAR_NAVBAR_UNIFICATION
import com.android.launcher3.config.FeatureFlags.enableTaskbarNoRecreate
import com.android.launcher3.taskbar.TaskbarControllers.LoggableTaskbarController
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.DEFAULT_TOUCH_REGION
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.DRAG_LAYER_INVISIBLE
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.FULLSCREEN_TASKBAR_WINDOW
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.ICONS_INVISIBLE
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.PHONE_MODE
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.SYSTEM_DRAG_IN_PROGRESS
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.TRANSIENT_IN_OVERVIEW
+import com.android.launcher3.taskbar.TaskbarInsetsController.DebugTouchableRegion.Companion.UI_CONTROLLER_UNTOUCHABLE
import com.android.launcher3.testing.shared.ResourceUtils
-import com.android.launcher3.util.DisplayController
import com.android.launcher3.util.Executors
import java.io.PrintWriter
import kotlin.jvm.optionals.getOrNull
-import kotlin.math.max
/** Handles the insets that Taskbar provides to underlying apps and the IME. */
class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTaskbarController {
@@ -64,7 +73,11 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
companion object {
private const val INDEX_LEFT = 0
private const val INDEX_RIGHT = 1
- const val FLAG_INSETS_ROUNDED_CORNER = 1 shl 1
+ private const val TAG = "TaskbarInsetsController"
+
+ private fun Region.addBoundsToRegion(bounds: Rect?) {
+ bounds?.let { op(it, Region.Op.UNION) }
+ }
}
/** The bottom insets taskbar provides to the IME when IME is visible. */
@@ -80,9 +93,9 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
context.mainThreadHandler,
Executors.UI_HELPER_EXECUTOR.handler,
context,
- this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged
+ this::onTaskbarOrBubblebarWindowHeightOrInsetsChanged,
)
- private val debugTouchableRegion = DebugTouchableRegion()
+ @VisibleForTesting val debugTouchableRegion = DebugTouchableRegion()
// Initialized in init.
private lateinit var controllers: TaskbarControllers
@@ -94,11 +107,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
onTaskbarOrBubblebarWindowHeightOrInsetsChanged()
context.addOnDeviceProfileChangeListener(deviceProfileChangeListener)
- try {
- gestureNavSettingsObserver.registerForCallingUser()
- } catch (t: Throwable) {
- // Ignore
- }
+ gestureNavSettingsObserver.registerForCallingUser()
}
fun onDestroy() {
@@ -107,90 +116,81 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
}
fun onTaskbarOrBubblebarWindowHeightOrInsetsChanged() {
- val tappableHeight = controllers.taskbarStashController.tappableHeightToReportToApps
- // We only report tappableElement height for unstashed, persistent taskbar,
- // which is also when we draw the rounded corners above taskbar.
- val insetsRoundedCornerFlag =
- if (tappableHeight > 0) {
- FLAG_INSETS_ROUNDED_CORNER
- } else {
- 0
+ val taskbarStashController = controllers.taskbarStashController
+ val tappableHeight = taskbarStashController.tappableHeightToReportToApps
+ // We only report tappableElement height for unstashed, persistent taskbar,
+ // which is also when we draw the rounded corners above taskbar on tablets.
+ val insetsRoundedCornerFlag =
+ if (tappableHeight > 0 && context.drawsTaskbarBackground()) {
+ FLAG_INSETS_ROUNDED_CORNER
+ } else {
+ 0
+ }
+
+ windowLayoutParams.providedInsets =
+ if (enableTaskbarNoRecreate() && controllers.sharedState != null) {
+ getProvidedInsets(
+ controllers.sharedState!!.insetsFrameProviders,
+ insetsRoundedCornerFlag,
+ )
+ } else {
+ getProvidedInsets(insetsRoundedCornerFlag)
+ }
+
+ if (windowLayoutParams.paramsForRotation != null) {
+ for (layoutParams in windowLayoutParams.paramsForRotation) {
+ layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
+ }
}
- windowLayoutParams.providedInsets =
- if (enableTaskbarNoRecreate() && controllers.sharedState != null) {
- getProvidedInsets(
- controllers.sharedState!!.insetsFrameProviders,
- insetsRoundedCornerFlag
- )
- } else {
- getProvidedInsets(insetsRoundedCornerFlag)
+ val bubbleControllers = controllers.bubbleControllers.getOrNull()
+ val taskbarTouchableHeight = taskbarStashController.touchableHeight
+ val bubblesTouchableHeight =
+ bubbleControllers?.bubbleStashController?.getTouchableHeight() ?: 0
+ // reset touch bounds
+ defaultTouchableRegion.setEmpty()
+ if (bubbleControllers != null) {
+ val bubbleBarViewController = bubbleControllers.bubbleBarViewController
+ val isBubbleBarVisible =
+ bubbleControllers.bubbleStashController.isBubbleBarVisible()
+ val isAnimatingNewBubble = bubbleBarViewController.isAnimatingNewBubble
+ // if bubble bar is visible or animating new bubble, add bar bounds to the touch
+ // region
+ if (isBubbleBarVisible || isAnimatingNewBubble) {
+ defaultTouchableRegion.addBoundsToRegion(
+ bubbleBarViewController.bubbleBarBounds
+ )
+ defaultTouchableRegion.addBoundsToRegion(bubbleBarViewController.flyoutBounds)
+ }
+ }
+ if (
+ taskbarStashController.isInApp ||
+ controllers.uiController.isInOverviewUi ||
+ context.showLockedTaskbarOnHome()
+ ) {
+ // only add the taskbar touch region if not on home
+ val bottom = windowLayoutParams.height
+ val top = bottom - taskbarTouchableHeight
+ val right = context.deviceProfile.deviceProperties.widthPx
+ defaultTouchableRegion.addBoundsToRegion(Rect(/* left= */ 0, top, right, bottom))
}
- if (windowLayoutParams.paramsForRotation != null) {
- for (layoutParams in windowLayoutParams.paramsForRotation) {
- layoutParams.providedInsets = getProvidedInsets(insetsRoundedCornerFlag)
+ // Pre-calculate insets for different providers across different rotations for this
+ // gravity
+ for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
+ // Add insets for navbar rotated params
+ val layoutParams = windowLayoutParams.paramsForRotation[rotation]
+ for (provider in layoutParams.providedInsets) {
+ setProviderInsets(provider, layoutParams.gravity, rotation)
+ }
}
+ // Also set the parent providers (i.e. not in paramsForRotation).
+ for (provider in windowLayoutParams.providedInsets) {
+ setProviderInsets(provider, windowLayoutParams.gravity, context.display.rotation)
+ }
+ context.notifyUpdateLayoutParams()
}
- val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
- val bubblesTouchableHeight =
- if (controllers.bubbleControllers.isPresent) {
- controllers.bubbleControllers.get().bubbleStashController.touchableHeight
- } else {
- 0
- }
- val touchableHeight = max(taskbarTouchableHeight, bubblesTouchableHeight)
-
- if (
- controllers.bubbleControllers.isPresent &&
- controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome
- ) {
- val iconBounds =
- controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
- defaultTouchableRegion.set(
- iconBounds.left,
- iconBounds.top,
- iconBounds.right,
- iconBounds.bottom
- )
- } else {
- defaultTouchableRegion.set(
- 0,
- windowLayoutParams.height - touchableHeight,
- context.deviceProfile.widthPx,
- windowLayoutParams.height
- )
-
- // if there's an animating bubble add it to the touch region so that it's clickable
- val isAnimatingNewBubble =
- controllers.bubbleControllers
- .getOrNull()
- ?.bubbleBarViewController
- ?.isAnimatingNewBubble
- ?: false
- if (isAnimatingNewBubble) {
- val iconBounds =
- controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
- defaultTouchableRegion.op(iconBounds, Region.Op.UNION)
- }
- }
-
- // Pre-calculate insets for different providers across different rotations for this gravity
- for (rotation in Surface.ROTATION_0..Surface.ROTATION_270) {
- // Add insets for navbar rotated params
- val layoutParams = windowLayoutParams.paramsForRotation[rotation]
- for (provider in layoutParams.providedInsets) {
- setProviderInsets(provider, layoutParams.gravity, rotation)
- }
- }
- // Also set the parent providers (i.e. not in paramsForRotation).
- for (provider in windowLayoutParams.providedInsets) {
- setProviderInsets(provider, windowLayoutParams.gravity, context.display.rotation)
- }
- context.notifyUpdateLayoutParams()
- }
-
/**
* This is for when ENABLE_TASKBAR_NO_RECREATION is enabled. We generate one instance of
* providedInsets and use it across the entire lifecycle of TaskbarManager. The only thing we
@@ -198,7 +198,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
*/
private fun getProvidedInsets(
providedInsets: Array,
- insetsRoundedCornerFlag: Int
+ insetsRoundedCornerFlag: Int,
): Array