Merge "Integrated new BubbleStashControllers into the existing code." into main

This commit is contained in:
Mykola Podolian
2024-07-31 16:43:17 +00:00
committed by Android (Google) Code Review
20 changed files with 169 additions and 549 deletions
@@ -111,8 +111,12 @@ import com.android.launcher3.taskbar.bubbles.BubbleControllers;
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.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.navbutton.NearestTouchFrame;
@@ -150,6 +154,7 @@ 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.Flags;
import java.io.PrintWriter;
import java.util.Collections;
@@ -250,15 +255,18 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
mWindowManager = c.getSystemService(WindowManager.class);
// Inflate views.
int taskbarLayout = DisplayController.isTransientTaskbar(this) && !isPhoneMode()
? R.layout.transient_taskbar
: R.layout.taskbar;
final boolean isTransientTaskbar = DisplayController.isTransientTaskbar(this)
&& !isPhoneMode();
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);
BubbleBarView bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
BubbleBarView bubbleBarView = null;
if (isTransientTaskbar || Flags.enableBubbleBarInPersistentTaskBar()) {
bubbleBarView = mDragLayer.findViewById(R.id.taskbar_bubbles);
}
StashedHandleView bubbleHandleView = mDragLayer.findViewById(R.id.stashed_bubble_handle);
mAccessibilityDelegate = new TaskbarShortcutMenuAccessibilityDelegate(this);
@@ -267,11 +275,21 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
Optional<BubbleControllers> bubbleControllersOptional = Optional.empty();
BubbleBarController.onTaskbarRecreated();
if (BubbleBarController.isBubbleBarEnabled() && bubbleBarView != null) {
Optional<BubbleStashedHandleViewController> bubbleHandleController = Optional.empty();
if (isTransientTaskbar) {
bubbleHandleController = Optional.of(
new BubbleStashedHandleViewController(this, bubbleHandleView));
}
TaskbarHotseatDimensionsProvider dimensionsProvider =
new DeviceProfileDimensionsProviderAdapter(this);
BubbleStashController bubbleStashController = isTransientTaskbar
? new TransientBubbleStashController(dimensionsProvider, getResources())
: new PersistentBubbleStashController(dimensionsProvider);
bubbleControllersOptional = Optional.of(new BubbleControllers(
new BubbleBarController(this, bubbleBarView),
new BubbleBarViewController(this, bubbleBarView),
new BubbleStashController(this),
new BubbleStashedHandleViewController(this, bubbleHandleView),
bubbleStashController,
bubbleHandleController,
new BubbleDragController(this),
new BubbleDismissController(this, mDragLayer),
new BubbleBarPinController(this, mDragLayer,
@@ -925,8 +943,9 @@ 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()));
});
}
@@ -964,6 +983,7 @@ public class TaskbarActivityContext extends BaseTaskbarContext {
public void onTransitionModeUpdated(int barMode, boolean checkBarModes) {
mControllers.navbarButtonsViewController.onTransitionModeUpdated(barMode, checkBarModes);
}
public void onNavButtonsDarkIntensityChanged(float darkIntensity) {
mControllers.navbarButtonsViewController.getTaskbarNavButtonDarkIntensity()
.updateValue(darkIntensity);
@@ -165,6 +165,7 @@ public class TaskbarControllers {
taskbarOverlayController.init(this);
taskbarAllAppsController.init(this, sharedState.allAppsVisible);
navButtonController.init(this);
bubbleControllers.ifPresent(controllers -> controllers.init(this));
taskbarInsetsController.init(this);
voiceInteractionWindowController.init(this);
taskbarRecentAppsController.init(this);
@@ -172,7 +173,6 @@ public class TaskbarControllers {
taskbarEduTooltipController.init(this);
keyboardQuickSwitchController.init(this);
taskbarPinningController.init(this, mSharedState);
bubbleControllers.ifPresent(controllers -> controllers.init(this));
mControllersToLog = new LoggableTaskbarController[] {
taskbarDragController, navButtonController, navbarButtonsViewController,
@@ -131,7 +131,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
val taskbarTouchableHeight = controllers.taskbarStashController.touchableHeight
val bubblesTouchableHeight =
if (controllers.bubbleControllers.isPresent) {
controllers.bubbleControllers.get().bubbleStashController.touchableHeight
controllers.bubbleControllers.get().bubbleStashController.getTouchableHeight()
} else {
0
}
@@ -139,7 +139,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
if (
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleStashController.isBubblesShowingOnHome
controllers.bubbleControllers.get().bubbleStashController.isBubbleBarVisible()
) {
val iconBounds =
controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
@@ -162,8 +162,7 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
controllers.bubbleControllers
.getOrNull()
?.bubbleBarViewController
?.isAnimatingNewBubble
?: false
?.isAnimatingNewBubble ?: false
if (isAnimatingNewBubble) {
val iconBounds =
controllers.bubbleControllers.get().bubbleBarViewController.bubbleBarBounds
@@ -358,13 +357,6 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
*/
fun updateInsetsTouchability(insetsInfo: ViewTreeObserver.InternalInsetsInfo) {
insetsInfo.touchableRegion.setEmpty()
// Always have nav buttons be touchable
controllers.navbarButtonsViewController.addVisibleButtonsRegion(
context.dragLayer,
insetsInfo.touchableRegion
)
debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
val bubbleBarVisible =
controllers.bubbleControllers.isPresent &&
controllers.bubbleControllers.get().bubbleBarViewController.isBubbleBarVisible()
@@ -443,6 +435,12 @@ class TaskbarInsetsController(val context: TaskbarActivityContext) : LoggableTas
debugTouchableRegion.lastSetTouchableReason =
"Icons are not visible, but other components such as 3 buttons might be"
}
// Always have nav buttons be touchable
controllers.navbarButtonsViewController.addVisibleButtonsRegion(
context.dragLayer,
insetsInfo.touchableRegion
)
debugTouchableRegion.lastSetTouchableBounds.set(insetsInfo.touchableRegion.bounds)
context.excludeFromMagnificationRegion(insetsIsTouchableRegion)
}
@@ -95,7 +95,8 @@ public class TaskbarTranslationController implements TaskbarControllers.Loggable
mControllers.taskbarDragLayerController.setTranslationYForSwipe(transY);
mControllers.bubbleControllers.ifPresent(controllers -> {
controllers.bubbleBarViewController.setTranslationYForSwipe(transY);
controllers.bubbleStashedHandleViewController.setTranslationYForSwipe(transY);
controllers.bubbleStashedHandleViewController.ifPresent(
controller -> controller.setTranslationYForSwipe(transY));
});
}
@@ -174,11 +174,11 @@ public class TaskbarUIController {
|| mControllers.navbarButtonsViewController.isEventOverAnyItem(ev);
}
/** Checks if the given {@link MotionEvent} is over the bubble bar stash handle. */
public boolean isEventOverBubbleBarStashHandle(MotionEvent ev) {
/** Checks if the given {@link MotionEvent} is over the bubble bar views. */
public boolean isEventOverBubbleBarViews(MotionEvent ev) {
return mControllers.bubbleControllers.map(
bubbleControllers ->
bubbleControllers.bubbleStashController.isEventOverStashHandle(ev))
bubbleControllers.bubbleStashController.isEventOverBubbleBarViews(ev))
.orElse(false);
}
@@ -63,6 +63,7 @@ import com.android.launcher3.R;
import com.android.launcher3.icons.BitmapInfo;
import com.android.launcher3.icons.BubbleIconFactory;
import com.android.launcher3.shortcuts.ShortcutRequest;
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.Executors.SimpleThreadFactory;
import com.android.quickstep.SystemUiProxy;
import com.android.systemui.shared.system.QuickStepContract.SystemUiStateFlags;
@@ -76,6 +77,7 @@ import com.android.wm.shell.common.bubbles.RemovedBubble;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.concurrent.Executor;
import java.util.concurrent.Executors;
@@ -144,7 +146,7 @@ public class BubbleBarController extends IBubblesListener.Stub {
private ImeVisibilityChecker mImeVisibilityChecker;
private BubbleBarViewController mBubbleBarViewController;
private BubbleStashController mBubbleStashController;
private BubbleStashedHandleViewController mBubbleStashedHandleViewController;
private Optional<BubbleStashedHandleViewController> mBubbleStashedHandleViewController;
private BubblePinController mBubblePinController;
// Cache last sent top coordinate to avoid sending duplicate updates to shell
@@ -221,8 +223,9 @@ public class BubbleBarController extends IBubblesListener.Stub {
bubbleControllers.runAfterInit(() -> {
mBubbleBarViewController.setHiddenForBubbles(
!sBubbleBarEnabled || mBubbles.isEmpty());
mBubbleStashedHandleViewController.setHiddenForBubbles(
!sBubbleBarEnabled || mBubbles.isEmpty());
mBubbleStashedHandleViewController.ifPresent(
controller -> controller.setHiddenForBubbles(
!sBubbleBarEnabled || mBubbles.isEmpty()));
mBubbleBarViewController.setUpdateSelectedBubbleAfterCollapse(
key -> setSelectedBubbleInternal(mBubbles.get(key)));
mBubbleBarViewController.setBoundsChangeListener(this::onBubbleBarBoundsChanged);
@@ -258,10 +261,11 @@ public class BubbleBarController extends IBubblesListener.Stub {
mBubbleBarViewController.setHiddenForSysui(hideBubbleBar);
boolean hideHandleView = (flags & MASK_HIDE_HANDLE_VIEW) != 0;
mBubbleStashedHandleViewController.setHiddenForSysui(hideHandleView);
mBubbleStashedHandleViewController.ifPresent(
controller -> controller.setHiddenForSysui(hideHandleView));
boolean sysuiLocked = (flags & MASK_SYSUI_LOCKED) != 0;
mBubbleStashController.onSysuiLockedStateChange(sysuiLocked);
mBubbleStashController.setSysuiLocked(sysuiLocked);
}
//
@@ -387,7 +391,8 @@ public class BubbleBarController extends IBubblesListener.Stub {
// Adds and removals have happened, update visibility before any other visual changes.
mBubbleBarViewController.setHiddenForBubbles(mBubbles.isEmpty());
mBubbleStashedHandleViewController.setHiddenForBubbles(mBubbles.isEmpty());
mBubbleStashedHandleViewController.ifPresent(
controller -> controller.setHiddenForBubbles(mBubbles.isEmpty()));
if (mBubbles.isEmpty()) {
// all bubbles were removed. clear the selected bubble
@@ -27,6 +27,7 @@ import android.view.View
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.common.bubbles.BaseBubblePinController
import com.android.wm.shell.common.bubbles.BubbleBarLocation
@@ -39,6 +39,7 @@ import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarInsetsController;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator;
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
import com.android.quickstep.SystemUiProxy;
@@ -92,7 +93,7 @@ public class BubbleBarViewController {
private BubbleBarViewAnimator mBubbleBarViewAnimator;
private TimeSource mTimeSource = System::currentTimeMillis;
private final TimeSource mTimeSource = System::currentTimeMillis;
@Nullable
private BubbleBarBoundsChangeListener mBoundsChangeListener;
@@ -386,7 +387,8 @@ public class BubbleBarViewController {
int newIconSize;
int newPadding;
Resources res = mActivity.getResources();
if (mBubbleStashController.isBubblesShowingOnHome()) {
if (mBubbleStashController.isBubblesShowingOnHome()
|| mBubbleStashController.isTransientTaskBar()) {
newIconSize = getBubbleBarIconSizeFromDeviceProfile(res);
newPadding = getBubbleBarPaddingFromDeviceProfile(res);
} else {
@@ -507,7 +509,8 @@ public class BubbleBarViewController {
// the bubble bar and handle are initialized as part of the first bubble animation.
// if the animation is suppressed, immediately stash or show the bubble bar to
// ensure they've been initialized.
if (mTaskbarStashController.isInApp()) {
if (mTaskbarStashController.isInApp()
&& mBubbleStashController.isTransientTaskBar()) {
mBubbleStashController.stashBubbleBarImmediate();
} else {
mBubbleStashController.showBubbleBarImmediate();
@@ -530,14 +533,15 @@ public class BubbleBarViewController {
mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
return;
}
if (mBubbleStashController.isBubblesShowingOnHome() && !isExpanding && !isExpanded()) {
boolean persistentTaskbarOrOnHome = mBubbleStashController.isBubblesShowingOnHome()
|| !mBubbleStashController.isTransientTaskBar();
if (persistentTaskbarOrOnHome && !isExpanding && !isExpanded()) {
mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble);
return;
}
// only animate the new bubble if we're in an app and not auto expanding
if (isInApp && !isExpanding && !isExpanded()) {
// only animate the new bubble if we're in an app, have handle view and not auto expanding
if (isInApp && !isExpanding && mBubbleStashController.getHasHandleView() && !isExpanded()) {
mBubbleBarViewAnimator.animateBubbleInForStashed(bubble);
}
}
@@ -598,6 +602,7 @@ public class BubbleBarViewController {
/**
* Updates the dragged bubble view in the bubble bar view, and notifies SystemUI
* that a bubble is being dragged to dismiss.
*
* @param bubbleView dragged bubble view
*/
public void onBubbleDragStart(@NonNull BubbleView bubbleView) {
@@ -16,19 +16,19 @@
package com.android.launcher3.taskbar.bubbles;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.RunnableList;
import java.io.PrintWriter;
import java.util.Optional;
/**
* Hosts various bubble controllers to facilitate passing between one another.
*/
/** Hosts various bubble controllers to facilitate passing between one another. */
public class BubbleControllers {
public final BubbleBarController bubbleBarController;
public final BubbleBarViewController bubbleBarViewController;
public final BubbleStashController bubbleStashController;
public final BubbleStashedHandleViewController bubbleStashedHandleViewController;
public final Optional<BubbleStashedHandleViewController> bubbleStashedHandleViewController;
public final BubbleDragController bubbleDragController;
public final BubbleDismissController bubbleDismissController;
public final BubbleBarPinController bubbleBarPinController;
@@ -45,7 +45,7 @@ public class BubbleControllers {
BubbleBarController bubbleBarController,
BubbleBarViewController bubbleBarViewController,
BubbleStashController bubbleStashController,
BubbleStashedHandleViewController bubbleStashedHandleViewController,
Optional<BubbleStashedHandleViewController> bubbleStashedHandleViewController,
BubbleDragController bubbleDragController,
BubbleDismissController bubbleDismissController,
BubbleBarPinController bubbleBarPinController,
@@ -68,9 +68,15 @@ public class BubbleControllers {
public void init(TaskbarControllers taskbarControllers) {
bubbleBarController.init(this,
taskbarControllers.navbarButtonsViewController::isImeVisible);
bubbleBarViewController.init(taskbarControllers, this);
bubbleStashedHandleViewController.init(taskbarControllers, this);
bubbleStashController.init(taskbarControllers, this);
bubbleStashedHandleViewController.ifPresent(
controller -> controller.init(/* bubbleControllers = */ this));
bubbleStashController.init(
taskbarControllers.taskbarInsetsController,
bubbleBarViewController,
bubbleStashedHandleViewController.orElse(null),
taskbarControllers::runAfterInit
);
bubbleBarViewController.init(taskbarControllers, /* bubbleControllers = */ this);
bubbleDragController.init(/* bubbleControllers = */ this);
bubbleDismissController.init(/* bubbleControllers = */ this);
bubbleBarPinController.init(this);
@@ -93,7 +99,7 @@ public class BubbleControllers {
* Cleans up all controllers.
*/
public void onDestroy() {
bubbleStashedHandleViewController.onDestroy();
bubbleStashedHandleViewController.ifPresent(BubbleStashedHandleViewController::onDestroy);
bubbleBarController.onDestroy();
}
@@ -27,6 +27,7 @@ import android.view.View
import android.widget.FrameLayout
import androidx.core.view.updateLayoutParams
import com.android.launcher3.R
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.common.bubbles.BaseBubblePinController
import com.android.wm.shell.common.bubbles.BubbleBarLocation
@@ -1,470 +0,0 @@
/*
* Copyright (C) 2023 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.taskbar.bubbles;
import static java.lang.Math.abs;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.annotation.Nullable;
import android.view.InsetsController;
import android.view.MotionEvent;
import android.view.View;
import com.android.launcher3.R;
import com.android.launcher3.anim.AnimatedFloat;
import com.android.launcher3.taskbar.StashedHandleViewController;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.TaskbarInsetsController;
import com.android.launcher3.taskbar.TaskbarStashController;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.wm.shell.common.bubbles.BubbleBarLocation;
import com.android.wm.shell.shared.animation.PhysicsAnimator;
import java.io.PrintWriter;
/**
* Coordinates between controllers such as BubbleBarView and BubbleHandleViewController to
* create a cohesive animation between stashed/unstashed states.
*/
public class BubbleStashController {
private static final String TAG = "BubbleStashController";
/**
* How long to stash/unstash.
*/
public static final long BAR_STASH_DURATION = InsetsController.ANIMATION_DURATION_RESIZE;
/**
* The scale bubble bar animates to when being stashed.
*/
private static final float STASHED_BAR_SCALE = 0.5f;
protected final TaskbarActivityContext mActivity;
// Initialized in init.
private TaskbarControllers mControllers;
private TaskbarInsetsController mTaskbarInsetsController;
private BubbleBarViewController mBarViewController;
private BubbleStashedHandleViewController mHandleViewController;
private TaskbarStashController mTaskbarStashController;
private MultiPropertyFactory.MultiProperty mIconAlphaForStash;
private AnimatedFloat mIconScaleForStash;
private AnimatedFloat mIconTranslationYForStash;
private MultiPropertyFactory.MultiProperty mBubbleStashedHandleAlpha;
private boolean mRequestedStashState;
private boolean mRequestedExpandedState;
private boolean mIsStashed;
private int mStashedHeight;
private int mUnstashedHeight;
private boolean mBubblesShowingOnHome;
private boolean mBubblesShowingOnOverview;
private boolean mIsSysuiLocked;
private final float mHandleCenterFromScreenBottom;
@Nullable
private AnimatorSet mAnimator;
public BubbleStashController(TaskbarActivityContext activity) {
mActivity = activity;
// the handle is centered within the stashed taskbar area
mHandleCenterFromScreenBottom =
mActivity.getResources().getDimensionPixelSize(R.dimen.bubblebar_stashed_size) / 2f;
}
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
mControllers = controllers;
mTaskbarInsetsController = controllers.taskbarInsetsController;
mBarViewController = bubbleControllers.bubbleBarViewController;
mHandleViewController = bubbleControllers.bubbleStashedHandleViewController;
mTaskbarStashController = controllers.taskbarStashController;
mIconAlphaForStash = mBarViewController.getBubbleBarAlpha().get(0);
mIconScaleForStash = mBarViewController.getBubbleBarScale();
mIconTranslationYForStash = mBarViewController.getBubbleBarTranslationY();
mBubbleStashedHandleAlpha = mHandleViewController.getStashedHandleAlpha().get(
StashedHandleViewController.ALPHA_INDEX_STASHED);
mStashedHeight = mHandleViewController.getStashedHeight();
mUnstashedHeight = mHandleViewController.getUnstashedHeight();
}
/**
* Returns the touchable height of the bubble bar based on it's stashed state.
*/
public int getTouchableHeight() {
return mIsStashed ? mStashedHeight : mUnstashedHeight;
}
/**
* Returns whether the bubble bar is currently stashed.
*/
public boolean isStashed() {
return mIsStashed;
}
/**
* Animates the handle (or bubble bar depending on state) to be visible after the device is
* unlocked.
*
* <p>Normally either the bubble bar or the handle is visible,
* and {@link #showBubbleBar(boolean)} and {@link #stashBubbleBar()} are used to transition
* between these two states. But the transition from the state where both the bar and handle
* are invisible is slightly different.
*/
private void animateAfterUnlock() {
AnimatorSet animatorSet = new AnimatorSet();
if (mBubblesShowingOnHome || mBubblesShowingOnOverview) {
mIsStashed = false;
animatorSet.playTogether(mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(getBubbleBarTranslationY()),
mIconAlphaForStash.animateToValue(1));
} else {
mIsStashed = true;
animatorSet.playTogether(mBubbleStashedHandleAlpha.animateToValue(1));
}
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
onIsStashedChanged();
}
});
animatorSet.setDuration(BAR_STASH_DURATION).start();
}
/**
* Called when launcher enters or exits the home page. Bubbles are unstashed on home.
*/
public void setBubblesShowingOnHome(boolean onHome) {
if (mBubblesShowingOnHome != onHome) {
mBubblesShowingOnHome = onHome;
if (!mBarViewController.hasBubbles()) {
// if there are no bubbles, there's nothing to show, so just return.
return;
}
if (mBubblesShowingOnHome) {
showBubbleBar(/* expanded= */ false);
// When transitioning from app to home the stash animator may already have been
// created, so we need to animate the bubble bar here to align with hotseat.
if (!mIsStashed) {
mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForHotseat())
.start();
}
// If the bubble bar is already unstashed, the taskbar touchable region won't be
// updated correctly, so force an update here.
mControllers.runAfterInit(() ->
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged());
} else if (!mBarViewController.isExpanded()) {
stashBubbleBar();
}
}
}
/** Whether bubbles are showing on the launcher home page. */
public boolean isBubblesShowingOnHome() {
boolean hasBubbles = mBarViewController != null && mBarViewController.hasBubbles();
return mBubblesShowingOnHome && hasBubbles;
}
// TODO: when tapping on an app in overview, this is a bit delayed compared to taskbar stashing
/** Called when launcher enters or exits overview. Bubbles are unstashed on overview. */
public void setBubblesShowingOnOverview(boolean onOverview) {
if (mBubblesShowingOnOverview != onOverview) {
mBubblesShowingOnOverview = onOverview;
if (!mBubblesShowingOnOverview && !mBarViewController.isExpanded()) {
stashBubbleBar();
} else {
// When transitioning to overview the stash animator may already have been
// created, so we need to animate the bubble bar here to align with taskbar.
mIconTranslationYForStash.animateToValue(getBubbleBarTranslationYForTaskbar())
.start();
}
}
}
/** Whether bubbles are showing on Overview. */
public boolean isBubblesShowingOnOverview() {
return mBubblesShowingOnOverview;
}
/** Called when sysui locked state changes, when locked, bubble bar is stashed. */
public void onSysuiLockedStateChange(boolean isSysuiLocked) {
if (isSysuiLocked != mIsSysuiLocked) {
mIsSysuiLocked = isSysuiLocked;
if (!mIsSysuiLocked && mBarViewController.hasBubbles()) {
animateAfterUnlock();
}
}
}
/**
* Stashes the bubble bar if allowed based on other state (e.g. on home and overview the
* bar does not stash).
*/
public void stashBubbleBar() {
mRequestedStashState = true;
mRequestedExpandedState = false;
updateStashedAndExpandedState();
}
/**
* Shows the bubble bar, and expands bubbles depending on {@param expandBubbles}.
*/
public void showBubbleBar(boolean expandBubbles) {
mRequestedStashState = false;
mRequestedExpandedState = expandBubbles;
updateStashedAndExpandedState();
}
private void updateStashedAndExpandedState() {
if (mBarViewController.isHiddenForNoBubbles()) {
// If there are no bubbles the bar and handle are invisible, nothing to do here.
return;
}
boolean isStashed = mRequestedStashState
&& !mBubblesShowingOnHome
&& !mBubblesShowingOnOverview;
if (mIsStashed != isStashed) {
// notify the view controller that the stash state is about to change so that it can
// cancel an ongoing animation if there is one.
// note that this has to be called before updating mIsStashed with the new value,
// otherwise interrupting an ongoing animation may update it again with the wrong state
mBarViewController.onStashStateChanging();
mIsStashed = isStashed;
if (mAnimator != null) {
mAnimator.cancel();
}
mAnimator = createStashAnimator(mIsStashed, BAR_STASH_DURATION);
mAnimator.start();
onIsStashedChanged();
}
if (mBarViewController.isExpanded() != mRequestedExpandedState) {
mBarViewController.setExpanded(mRequestedExpandedState);
}
}
/**
* Create a stash animation.
*
* @param isStashed whether it's a stash animation or an unstash animation
* @param duration duration of the animation
* @return the animation
*/
private AnimatorSet createStashAnimator(boolean isStashed, long duration) {
AnimatorSet animatorSet = new AnimatorSet();
AnimatorSet fullLengthAnimatorSet = new AnimatorSet();
// Not exactly half and may overlap. See [first|second]HalfDurationScale below.
AnimatorSet firstHalfAnimatorSet = new AnimatorSet();
AnimatorSet secondHalfAnimatorSet = new AnimatorSet();
final float firstHalfDurationScale;
final float secondHalfDurationScale;
if (isStashed) {
firstHalfDurationScale = 0.75f;
secondHalfDurationScale = 0.5f;
fullLengthAnimatorSet.play(
mIconTranslationYForStash.animateToValue(getStashTranslation()));
firstHalfAnimatorSet.playTogether(
mIconAlphaForStash.animateToValue(0),
mIconScaleForStash.animateToValue(STASHED_BAR_SCALE));
secondHalfAnimatorSet.playTogether(
mBubbleStashedHandleAlpha.animateToValue(1));
} else {
firstHalfDurationScale = 0.5f;
secondHalfDurationScale = 0.75f;
final float translationY = getBubbleBarTranslationY();
fullLengthAnimatorSet.playTogether(
mIconScaleForStash.animateToValue(1),
mIconTranslationYForStash.animateToValue(translationY));
firstHalfAnimatorSet.playTogether(
mBubbleStashedHandleAlpha.animateToValue(0)
);
secondHalfAnimatorSet.playTogether(
mIconAlphaForStash.animateToValue(1)
);
}
fullLengthAnimatorSet.play(mHandleViewController.createRevealAnimToIsStashed(isStashed));
fullLengthAnimatorSet.setDuration(duration);
firstHalfAnimatorSet.setDuration((long) (duration * firstHalfDurationScale));
secondHalfAnimatorSet.setDuration((long) (duration * secondHalfDurationScale));
secondHalfAnimatorSet.setStartDelay((long) (duration * (1 - secondHalfDurationScale)));
animatorSet.playTogether(fullLengthAnimatorSet, firstHalfAnimatorSet,
secondHalfAnimatorSet);
animatorSet.addListener(new AnimatorListenerAdapter() {
@Override
public void onAnimationEnd(Animator animation) {
mAnimator = null;
mControllers.runAfterInit(() -> {
if (isStashed) {
mBarViewController.setExpanded(false);
}
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
});
}
});
return animatorSet;
}
private float getStashTranslation() {
return (mUnstashedHeight - mStashedHeight) / 2f;
}
private void onIsStashedChanged() {
mControllers.runAfterInit(() -> {
mHandleViewController.onIsStashedChanged();
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
});
}
public float getBubbleBarTranslationYForTaskbar() {
return -mActivity.getDeviceProfile().taskbarBottomMargin;
}
private float getBubbleBarTranslationYForHotseat() {
final float hotseatBottomSpace = mActivity.getDeviceProfile().hotseatBarBottomSpacePx;
final float hotseatCellHeight = mActivity.getDeviceProfile().hotseatCellHeightPx;
return -hotseatBottomSpace - hotseatCellHeight + mUnstashedHeight - abs(
hotseatCellHeight - mUnstashedHeight) / 2;
}
public float getBubbleBarTranslationY() {
// If we're on home, adjust the translation so the bubble bar aligns with hotseat.
// Otherwise we're either showing in an app or in overview. In either case adjust it so
// the bubble bar aligns with the taskbar.
return mBubblesShowingOnHome ? getBubbleBarTranslationYForHotseat()
: getBubbleBarTranslationYForTaskbar();
}
/**
* The difference on the Y axis between the center of the handle and the center of the bubble
* bar.
*/
public float getDiffBetweenHandleAndBarCenters() {
// the difference between the centers of the handle and the bubble bar is the difference
// between their distance from the bottom of the screen.
float barCenter = mBarViewController.getBubbleBarCollapsedHeight() / 2f;
return mHandleCenterFromScreenBottom - barCenter;
}
/** The distance the handle moves as part of the new bubble animation. */
public float getStashedHandleTranslationForNewBubbleAnimation() {
// the should move up to the top of the stashed taskbar area. it is centered within it so
// it should move the same distance as it is away from the bottom.
return -mHandleCenterFromScreenBottom;
}
/** Checks whether the motion event is over the stash handle. */
public boolean isEventOverStashHandle(MotionEvent ev) {
return mHandleViewController.isEventOverHandle(ev);
}
/** Set a bubble bar location */
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
mHandleViewController.setBubbleBarLocation(bubbleBarLocation);
}
/** Returns the [PhysicsAnimator] for the stashed handle view. */
public PhysicsAnimator<View> getStashedHandlePhysicsAnimator() {
return mHandleViewController.getPhysicsAnimator();
}
/** Notifies taskbar that it should update its touchable region. */
public void updateTaskbarTouchRegion() {
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
}
/** Shows the bubble bar immediately without animation. */
public void showBubbleBarImmediate() {
mHandleViewController.setTranslationYForSwipe(0);
mIconTranslationYForStash.updateValue(getBubbleBarTranslationY());
mIconAlphaForStash.setValue(1);
mIconScaleForStash.updateValue(1);
mIsStashed = false;
onIsStashedChanged();
}
/** Stashes the bubble bar immediately without animation. */
public void stashBubbleBarImmediate() {
mHandleViewController.setTranslationYForSwipe(0);
mBubbleStashedHandleAlpha.setValue(1);
mIconAlphaForStash.setValue(0);
mIconTranslationYForStash.updateValue(getStashTranslation());
mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
mIsStashed = true;
onIsStashedChanged();
}
/**
* Updates the values of the internal animators after the new bubble animation was interrupted
*
* @param isStashed whether the current state should be stashed
* @param bubbleBarTranslationY the current bubble bar translation. this is only used if the
* bubble bar is showing to ensure that the stash animator runs
* smoothly.
*/
public void onNewBubbleAnimationInterrupted(boolean isStashed, float bubbleBarTranslationY) {
if (isStashed) {
mBubbleStashedHandleAlpha.setValue(1);
mIconAlphaForStash.setValue(0);
mIconScaleForStash.updateValue(STASHED_BAR_SCALE);
mIconTranslationYForStash.updateValue(getStashTranslation());
} else {
mBubbleStashedHandleAlpha.setValue(0);
mHandleViewController.setTranslationYForSwipe(0);
mIconAlphaForStash.setValue(1);
mIconScaleForStash.updateValue(1);
mIconTranslationYForStash.updateValue(bubbleBarTranslationY);
}
mIsStashed = isStashed;
onIsStashedChanged();
}
/** Set the translation Y for the stashed handle. */
public void setHandleTranslationY(float ty) {
mHandleViewController.setTranslationYForSwipe(ty);
}
/** Dumps the state of BubbleStashController. */
public void dump(PrintWriter pw) {
pw.println("Bubble stash controller state:");
pw.println(" mIsStashed: " + mIsStashed);
pw.println(" mBubblesShowingOnOverview: " + mBubblesShowingOnOverview);
pw.println(" mBubblesShowingOnHome: " + mBubblesShowingOnHome);
pw.println(" mIsSysuiLocked: " + mIsSysuiLocked);
}
}
@@ -33,7 +33,7 @@ import com.android.launcher3.anim.RevealOutlineAnimation;
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
import com.android.launcher3.taskbar.StashedHandleView;
import com.android.launcher3.taskbar.TaskbarActivityContext;
import com.android.launcher3.taskbar.TaskbarControllers;
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
import com.android.launcher3.util.Executors;
import com.android.launcher3.util.MultiPropertyFactory;
import com.android.launcher3.util.MultiValueAlpha;
@@ -79,7 +79,8 @@ public class BubbleStashedHandleViewController {
mStashedHandleAlpha = new MultiValueAlpha(mStashedHandleView, 1);
}
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers) {
/** Initialize controller. */
public void init(BubbleControllers bubbleControllers) {
mBarViewController = bubbleControllers.bubbleBarViewController;
mBubbleStashController = bubbleControllers.bubbleStashController;
@@ -117,7 +118,7 @@ public class BubbleStashedHandleViewController {
public Rect getSampledRegion(View sampledView) {
return mStashedHandleView.getSampledRegion();
}
}, Executors.UI_HELPER_EXECUTOR);
}, Executors.MAIN_EXECUTOR, Executors.UI_HELPER_EXECUTOR);
mStashedHandleView.addOnLayoutChangeListener((view, i, i1, i2, i3, i4, i5, i6, i7) ->
updateBounds(mBarViewController.getBubbleBarLocation()));
@@ -26,8 +26,8 @@ import androidx.dynamicanimation.animation.SpringForce
import com.android.launcher3.R
import com.android.launcher3.taskbar.bubbles.BubbleBarBubble
import com.android.launcher3.taskbar.bubbles.BubbleBarView
import com.android.launcher3.taskbar.bubbles.BubbleStashController
import com.android.launcher3.taskbar.bubbles.BubbleView
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController
import com.android.wm.shell.shared.animation.PhysicsAnimator
/** Handles animations for bubble bar bubbles. */
@@ -138,19 +138,20 @@ constructor(
// handle. when the handle becomes invisible and we start animating in the bubble bar,
// the translation y is offset by this value to make the transition from the handle to the
// bar smooth.
val offset = bubbleStashController.diffBetweenHandleAndBarCenters
val stashedHandleTranslationY =
bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
val offset: Float = bubbleStashController.getDiffBetweenHandleAndBarCenters()
val stashedHandleTranslationY: Float =
bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
// this is the total distance that both the stashed handle and the bubble will be traveling
// at the end of the animation the bubble bar will be positioned in the same place when it
// shows while we're in an app.
val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
val animator = bubbleStashController.stashedHandlePhysicsAnimator
val animator = bubbleStashController.getStashedHandlePhysicsAnimator() ?: return@Runnable
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, totalTranslationY)
animator.addUpdateListener { handle, values ->
val ty = values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
val ty: Float =
values[DynamicAnimation.TRANSLATION_Y]?.value ?: return@addUpdateListener
when {
ty >= stashedHandleTranslationY -> {
// we're in the first leg of the animation. only animate the handle. the bubble
@@ -226,13 +227,13 @@ constructor(
*/
private fun buildBubbleBarToHandleAnimation() = Runnable {
if (animatingBubble == null) return@Runnable
val offset = bubbleStashController.diffBetweenHandleAndBarCenters
val offset = bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
val stashedHandleTranslationY =
bubbleStashController.stashedHandleTranslationForNewBubbleAnimation
bubbleStashController.getStashedHandleTranslationForNewBubbleAnimation()
// this is the total distance that both the stashed handle and the bar will be traveling
val totalTranslationY = bubbleStashController.bubbleBarTranslationYForTaskbar + offset
bubbleStashController.setHandleTranslationY(totalTranslationY)
val animator = bubbleStashController.stashedHandlePhysicsAnimator
val animator = bubbleStashController.getStashedHandlePhysicsAnimator() ?: return@Runnable
animator.setDefaultSpringConfig(springConfig)
animator.spring(DynamicAnimation.TRANSLATION_Y, 0f)
animator.addUpdateListener { handle, values ->
@@ -363,7 +364,7 @@ constructor(
/** Handles touching the animating bubble bar. */
fun onBubbleBarTouchedWhileAnimating() {
PhysicsAnimator.getInstance(bubbleBarView).cancelIfRunning()
bubbleStashController.stashedHandlePhysicsAnimator.cancelIfRunning()
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
bubbleBarView.onAnimatingBubbleCompleted()
@@ -376,7 +377,7 @@ constructor(
val hideAnimation = animatingBubble?.hideAnimation ?: return
scheduler.cancel(hideAnimation)
animatingBubble = null
bubbleStashController.stashedHandlePhysicsAnimator.cancel()
bubbleStashController.getStashedHandlePhysicsAnimator().cancelIfRunning()
bubbleBarView.onAnimatingBubbleCompleted()
bubbleBarView.relativePivotY = 1f
bubbleStashController.onNewBubbleAnimationInterrupted(
@@ -385,8 +386,8 @@ constructor(
)
}
private fun <T> PhysicsAnimator<T>.cancelIfRunning() {
if (isRunning()) cancel()
private fun <T> PhysicsAnimator<T>?.cancelIfRunning() {
if (this?.isRunning() == true) cancel()
}
private fun ObjectAnimator.withDuration(duration: Long): ObjectAnimator {
@@ -52,7 +52,7 @@ interface BubbleStashController {
/** Execute passed action only after controllers are initiated. */
interface ControllersAfterInitAction {
/** Execute action after controllers are initiated. */
fun runAfterInit(action: () -> Unit)
fun runAfterInit(action: Runnable)
}
/** Whether bubble bar is currently stashed */
@@ -0,0 +1,39 @@
/*
* Copyright (C) 2024 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.launcher3.taskbar.bubbles.stashing
import com.android.launcher3.DeviceProfile
import com.android.launcher3.taskbar.TaskbarActivityContext
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController.TaskbarHotseatDimensionsProvider
/**
* Implementation of the [TaskbarHotseatDimensionsProvider] that take sizes from the
* [DeviceProfile].
*/
class DeviceProfileDimensionsProviderAdapter(
private val taskbarActivityContext: TaskbarActivityContext
) : TaskbarHotseatDimensionsProvider {
override fun getTaskbarBottomSpace(): Int = deviceProfile().taskbarBottomMargin
override fun getTaskbarHeight(): Int = deviceProfile().taskbarHeight
override fun getHotseatBottomSpace(): Int = deviceProfile().hotseatBarBottomSpacePx
override fun getHotseatHeight(): Int = deviceProfile().hotseatCellHeightPx
private fun deviceProfile(): DeviceProfile = taskbarActivityContext.deviceProfile
}
@@ -31,7 +31,6 @@ import static com.android.quickstep.views.RecentsView.TASK_SECONDARY_TRANSLATION
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
import android.animation.AnimatorSet;
import android.graphics.Color;
import android.view.MotionEvent;
import androidx.annotation.Nullable;
@@ -133,7 +132,7 @@ public abstract class BaseActivityInterface<STATE_TYPE extends BaseState<STATE_T
public boolean deferStartingActivity(RecentsAnimationDeviceState deviceState, MotionEvent ev) {
TaskbarUIController controller = getTaskbarController();
boolean isEventOverBubbleBarStashHandle =
controller != null && controller.isEventOverBubbleBarStashHandle(ev);
controller != null && controller.isEventOverBubbleBarViews(ev);
return deviceState.isInDeferredGestureRegion(ev) || deviceState.isImeRenderingNavButtons()
|| isTrackpadMultiFingerSwipe(ev) || isEventOverBubbleBarStashHandle;
}
@@ -321,8 +321,9 @@ public class TaskbarUnstashInputConsumer extends DelegateInputConsumer {
if (controllers == null) {
return false;
}
if (controllers.bubbleStashController.isStashed()) {
return controllers.bubbleStashedHandleViewController.containsX((int) x);
if (controllers.bubbleStashController.isStashed()
&& controllers.bubbleStashedHandleViewController.isPresent()) {
return controllers.bubbleStashedHandleViewController.get().containsX((int) x);
} else {
Rect bubbleBarBounds = controllers.bubbleBarViewController.getBubbleBarBounds();
return x >= bubbleBarBounds.left && x <= bubbleBarBounds.right;