e07699ae6a
Flag: com.android.wm.shell.enable_bubble_bar
Test: manual - check that optional overflow flag is off and get
bubbles in bubble bar, overflow should be present
Bug: 358304168
Change-Id: I1eb709003d4dcdde7ae465b837a2c68d40b1a828
1160 lines
45 KiB
Java
1160 lines
45 KiB
Java
/*
|
|
* 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 android.view.View.INVISIBLE;
|
|
import static android.view.View.VISIBLE;
|
|
|
|
import static com.android.launcher3.Utilities.mapRange;
|
|
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_PERSISTENT;
|
|
import static com.android.launcher3.taskbar.TaskbarPinningController.PINNING_TRANSIENT;
|
|
|
|
import android.animation.Animator;
|
|
import android.animation.AnimatorSet;
|
|
import android.content.res.Resources;
|
|
import android.graphics.Point;
|
|
import android.graphics.PointF;
|
|
import android.graphics.Rect;
|
|
import android.util.DisplayMetrics;
|
|
import android.util.Log;
|
|
import android.util.TypedValue;
|
|
import android.view.MotionEvent;
|
|
import android.view.View;
|
|
import android.widget.FrameLayout;
|
|
|
|
import androidx.annotation.NonNull;
|
|
import androidx.annotation.Nullable;
|
|
|
|
import com.android.app.animation.Interpolators;
|
|
import com.android.launcher3.DeviceProfile;
|
|
import com.android.launcher3.R;
|
|
import com.android.launcher3.anim.AnimatedFloat;
|
|
import com.android.launcher3.anim.RoundedRectRevealOutlineProvider;
|
|
import com.android.launcher3.taskbar.TaskbarActivityContext;
|
|
import com.android.launcher3.taskbar.TaskbarControllers;
|
|
import com.android.launcher3.taskbar.TaskbarInsetsController;
|
|
import com.android.launcher3.taskbar.TaskbarSharedState;
|
|
import com.android.launcher3.taskbar.TaskbarStashController;
|
|
import com.android.launcher3.taskbar.bubbles.animation.BubbleBarViewAnimator;
|
|
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutController;
|
|
import com.android.launcher3.taskbar.bubbles.flyout.BubbleBarFlyoutPositioner;
|
|
import com.android.launcher3.taskbar.bubbles.flyout.FlyoutCallbacks;
|
|
import com.android.launcher3.taskbar.bubbles.stashing.BubbleStashController;
|
|
import com.android.launcher3.util.DisplayController;
|
|
import com.android.launcher3.util.MultiPropertyFactory;
|
|
import com.android.launcher3.util.MultiValueAlpha;
|
|
import com.android.quickstep.SystemUiProxy;
|
|
import com.android.wm.shell.Flags;
|
|
import com.android.wm.shell.shared.bubbles.BubbleBarLocation;
|
|
|
|
import java.io.PrintWriter;
|
|
import java.util.List;
|
|
import java.util.Objects;
|
|
import java.util.function.Consumer;
|
|
|
|
/**
|
|
* Controller for {@link BubbleBarView}. Manages the visibility of the bubble bar as well as
|
|
* responding to changes in bubble state provided by BubbleBarController.
|
|
*/
|
|
public class BubbleBarViewController {
|
|
|
|
private static final String TAG = "BubbleBarViewController";
|
|
private static final float APP_ICON_SMALL_DP = 44f;
|
|
private static final float APP_ICON_MEDIUM_DP = 48f;
|
|
private static final float APP_ICON_LARGE_DP = 52f;
|
|
/** The dot size is defined as a percentage of the icon size. */
|
|
private static final float DOT_TO_BUBBLE_SIZE_RATIO = 0.228f;
|
|
public static final int TASKBAR_FADE_IN_DURATION_MS = 150;
|
|
public static final int TASKBAR_FADE_IN_DELAY_MS = 50;
|
|
public static final int TASKBAR_FADE_OUT_DURATION_MS = 100;
|
|
private final SystemUiProxy mSystemUiProxy;
|
|
private final TaskbarActivityContext mActivity;
|
|
private final BubbleBarView mBarView;
|
|
private int mIconSize;
|
|
private int mBubbleBarPadding;
|
|
|
|
// Initialized in init.
|
|
private BubbleStashController mBubbleStashController;
|
|
private BubbleBarController mBubbleBarController;
|
|
private BubbleDragController mBubbleDragController;
|
|
private TaskbarStashController mTaskbarStashController;
|
|
private TaskbarInsetsController mTaskbarInsetsController;
|
|
private TaskbarViewPropertiesProvider mTaskbarViewPropertiesProvider;
|
|
private View.OnClickListener mBubbleClickListener;
|
|
private View.OnClickListener mBubbleBarClickListener;
|
|
private BubbleView.Controller mBubbleViewController;
|
|
private BubbleBarOverflow mOverflowBubble;
|
|
|
|
// These are exposed to {@link BubbleStashController} to animate for stashing/un-stashing
|
|
private final MultiValueAlpha mBubbleBarAlpha;
|
|
private final AnimatedFloat mBubbleBarBubbleAlpha = new AnimatedFloat(this::updateBubbleAlpha);
|
|
private final AnimatedFloat mBubbleBarBackgroundAlpha = new AnimatedFloat(
|
|
this::updateBackgroundAlpha);
|
|
private final AnimatedFloat mBubbleBarScaleX = new AnimatedFloat(this::updateScaleX);
|
|
private final AnimatedFloat mBubbleBarScaleY = new AnimatedFloat(this::updateScaleY);
|
|
private final AnimatedFloat mBubbleBarBackgroundScaleX = new AnimatedFloat(
|
|
this::updateBackgroundScaleX);
|
|
private final AnimatedFloat mBubbleBarBackgroundScaleY = new AnimatedFloat(
|
|
this::updateBackgroundScaleY);
|
|
private final AnimatedFloat mBubbleBarTranslationY = new AnimatedFloat(
|
|
this::updateTranslationY);
|
|
private final AnimatedFloat mBubbleOffsetY = new AnimatedFloat(
|
|
this::updateBubbleOffsetY);
|
|
private final AnimatedFloat mBubbleBarPinning = new AnimatedFloat(pinningProgress -> {
|
|
updateTranslationY();
|
|
setBubbleBarScaleAndPadding(pinningProgress);
|
|
});
|
|
|
|
// Modified when swipe up is happening on the bubble bar or task bar.
|
|
private float mBubbleBarSwipeUpTranslationY;
|
|
// Modified when bubble bar is springing back into the stash handle.
|
|
private float mBubbleBarStashTranslationY;
|
|
|
|
// Whether the bar is hidden for a sysui state.
|
|
private boolean mHiddenForSysui;
|
|
// Whether the bar is hidden because there are no bubbles.
|
|
private boolean mHiddenForNoBubbles = true;
|
|
// Whether the bar is hidden when stashed
|
|
private boolean mHiddenForStashed;
|
|
private boolean mShouldShowEducation;
|
|
|
|
public boolean mOverflowAdded;
|
|
|
|
private BubbleBarViewAnimator mBubbleBarViewAnimator;
|
|
private final FrameLayout mBubbleBarContainer;
|
|
private BubbleBarFlyoutController mBubbleBarFlyoutController;
|
|
private TaskbarSharedState mTaskbarSharedState;
|
|
private final TimeSource mTimeSource = System::currentTimeMillis;
|
|
private final int mTaskbarTranslationDelta;
|
|
|
|
@Nullable
|
|
private BubbleBarBoundsChangeListener mBoundsChangeListener;
|
|
|
|
public BubbleBarViewController(TaskbarActivityContext activity, BubbleBarView barView,
|
|
FrameLayout bubbleBarContainer) {
|
|
mActivity = activity;
|
|
mBarView = barView;
|
|
mBubbleBarContainer = bubbleBarContainer;
|
|
mSystemUiProxy = SystemUiProxy.INSTANCE.get(mActivity);
|
|
mBubbleBarAlpha = new MultiValueAlpha(mBarView, 1 /* num alpha channels */);
|
|
mIconSize = activity.getResources().getDimensionPixelSize(
|
|
R.dimen.bubblebar_icon_size);
|
|
mTaskbarTranslationDelta = getBubbleBarTranslationDeltaForTaskbar(activity);
|
|
}
|
|
|
|
/** Initializes controller. */
|
|
public void init(TaskbarControllers controllers, BubbleControllers bubbleControllers,
|
|
TaskbarViewPropertiesProvider taskbarViewPropertiesProvider) {
|
|
mTaskbarSharedState = controllers.getSharedState();
|
|
mBubbleStashController = bubbleControllers.bubbleStashController;
|
|
mBubbleBarController = bubbleControllers.bubbleBarController;
|
|
mBubbleDragController = bubbleControllers.bubbleDragController;
|
|
mTaskbarStashController = controllers.taskbarStashController;
|
|
mTaskbarInsetsController = controllers.taskbarInsetsController;
|
|
mBubbleBarFlyoutController = new BubbleBarFlyoutController(
|
|
mBubbleBarContainer, createFlyoutPositioner(), createFlyoutCallbacks());
|
|
mBubbleBarViewAnimator = new BubbleBarViewAnimator(
|
|
mBarView, mBubbleStashController, mBubbleBarFlyoutController,
|
|
mBubbleBarController::showExpandedView);
|
|
mTaskbarViewPropertiesProvider = taskbarViewPropertiesProvider;
|
|
onBubbleBarConfigurationChanged(/* animate= */ false);
|
|
mActivity.addOnDeviceProfileChangeListener(
|
|
dp -> onBubbleBarConfigurationChanged(/* animate= */ true));
|
|
mBubbleBarScaleY.updateValue(1f);
|
|
mBubbleClickListener = v -> onBubbleClicked((BubbleView) v);
|
|
mBubbleBarClickListener = v -> expandBubbleBar();
|
|
mBubbleDragController.setupBubbleBarView(mBarView);
|
|
mOverflowBubble = bubbleControllers.bubbleCreator.createOverflow(mBarView);
|
|
if (!Flags.enableOptionalBubbleOverflow()) {
|
|
showOverflow(true);
|
|
}
|
|
mBarView.setOnClickListener(mBubbleBarClickListener);
|
|
mBarView.addOnLayoutChangeListener(
|
|
(v, left, top, right, bottom, oldLeft, oldTop, oldRight, oldBottom) -> {
|
|
mTaskbarInsetsController.onTaskbarOrBubblebarWindowHeightOrInsetsChanged();
|
|
if (mBoundsChangeListener != null) {
|
|
mBoundsChangeListener.onBoundsChanged();
|
|
}
|
|
});
|
|
float pinningValue = DisplayController.isTransientTaskbar(mActivity)
|
|
? PINNING_TRANSIENT
|
|
: PINNING_PERSISTENT;
|
|
mBubbleBarPinning.updateValue(pinningValue);
|
|
mBarView.setController(new BubbleBarView.Controller() {
|
|
@Override
|
|
public float getBubbleBarTranslationY() {
|
|
return mBubbleStashController.getBubbleBarTranslationY();
|
|
}
|
|
|
|
@Override
|
|
public void onBubbleBarTouched() {
|
|
if (isAnimatingNewBubble()) {
|
|
interruptAnimationForTouch();
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public void expandBubbleBar() {
|
|
BubbleBarViewController.this.expandBubbleBar();
|
|
}
|
|
|
|
@Override
|
|
public void dismissBubbleBar() {
|
|
onDismissAllBubbles();
|
|
}
|
|
|
|
@Override
|
|
public void updateBubbleBarLocation(BubbleBarLocation location) {
|
|
mBubbleBarController.updateBubbleBarLocation(location);
|
|
}
|
|
});
|
|
|
|
mBubbleViewController = new BubbleView.Controller() {
|
|
@Override
|
|
public BubbleBarLocation getBubbleBarLocation() {
|
|
return BubbleBarViewController.this.getBubbleBarLocation();
|
|
}
|
|
|
|
@Override
|
|
public void dismiss(BubbleView bubble) {
|
|
if (bubble.getBubble() != null) {
|
|
notifySysUiBubbleDismissed(bubble.getBubble());
|
|
}
|
|
onBubbleDismissed(bubble);
|
|
}
|
|
|
|
@Override
|
|
public void collapse() {
|
|
collapseBubbleBar();
|
|
}
|
|
|
|
@Override
|
|
public void updateBubbleBarLocation(BubbleBarLocation location) {
|
|
mBubbleBarController.updateBubbleBarLocation(location);
|
|
}
|
|
};
|
|
}
|
|
|
|
/** Returns animated float property responsible for pinning transition animation. */
|
|
public AnimatedFloat getBubbleBarPinning() {
|
|
return mBubbleBarPinning;
|
|
}
|
|
|
|
private BubbleBarFlyoutPositioner createFlyoutPositioner() {
|
|
return new BubbleBarFlyoutPositioner() {
|
|
|
|
@Override
|
|
public boolean isOnLeft() {
|
|
return mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl());
|
|
}
|
|
|
|
@Override
|
|
public float getTargetTy() {
|
|
return mBarView.getTranslationY() - mBarView.getHeight();
|
|
}
|
|
|
|
@Override
|
|
@NonNull
|
|
public PointF getDistanceToCollapsedPosition() {
|
|
// the flyout animates from the selected bubble dot. calculate the distance it needs
|
|
// to translate itself to its starting position.
|
|
PointF distanceToDotCenter = mBarView.getSelectedBubbleDotDistanceFromTopLeft();
|
|
|
|
// if we're gravitating left, return the distance between the top left corner of the
|
|
// bubble bar and the bottom left corner of the dot.
|
|
// if we're gravitating right, return the distance between the top right corner of
|
|
// the bubble bar and the bottom right corner of the dot.
|
|
float distanceX = isOnLeft()
|
|
? distanceToDotCenter.x - getCollapsedSize() / 2
|
|
: mBarView.getWidth() - distanceToDotCenter.x - getCollapsedSize() / 2;
|
|
float distanceY = distanceToDotCenter.y + getCollapsedSize() / 2;
|
|
return new PointF(distanceX, distanceY);
|
|
}
|
|
|
|
@Override
|
|
public float getCollapsedSize() {
|
|
return mIconSize * DOT_TO_BUBBLE_SIZE_RATIO;
|
|
}
|
|
|
|
@Override
|
|
public int getCollapsedColor() {
|
|
return mBarView.getSelectedBubbleDotColor();
|
|
}
|
|
|
|
@Override
|
|
public float getCollapsedElevation() {
|
|
return mBarView.getBubbleElevation();
|
|
}
|
|
|
|
@Override
|
|
public float getDistanceToRevealTriangle() {
|
|
return getDistanceToCollapsedPosition().y - mBarView.getPointerSize();
|
|
}
|
|
};
|
|
}
|
|
|
|
private FlyoutCallbacks createFlyoutCallbacks() {
|
|
return new FlyoutCallbacks() {
|
|
@Override
|
|
public void extendTopBoundary(int space) {
|
|
int defaultSize = mActivity.getDefaultTaskbarWindowSize();
|
|
mActivity.setTaskbarWindowSize(defaultSize + space);
|
|
}
|
|
|
|
@Override
|
|
public void resetTopBoundary() {
|
|
mActivity.setTaskbarWindowSize(mActivity.getDefaultTaskbarWindowSize());
|
|
}
|
|
|
|
@Override
|
|
public void flyoutClicked() {
|
|
interruptAnimationForTouch();
|
|
expandBubbleBar();
|
|
}
|
|
};
|
|
}
|
|
|
|
private void onBubbleClicked(BubbleView bubbleView) {
|
|
bubbleView.markSeen();
|
|
BubbleBarItem bubble = bubbleView.getBubble();
|
|
if (bubble == null) {
|
|
Log.e(TAG, "bubble click listener, bubble was null");
|
|
}
|
|
|
|
final String currentlySelected = mBubbleBarController.getSelectedBubbleKey();
|
|
if (mBarView.isExpanded() && Objects.equals(bubble.getKey(), currentlySelected)) {
|
|
// Tapping the currently selected bubble while expanded collapses the view.
|
|
collapseBubbleBar();
|
|
} else {
|
|
mBubbleBarController.showAndSelectBubble(bubble);
|
|
}
|
|
}
|
|
|
|
/** Interrupts the running animation for a touch event on the bubble bar or flyout. */
|
|
private void interruptAnimationForTouch() {
|
|
mBubbleBarViewAnimator.interruptForTouch();
|
|
mBubbleStashController.onNewBubbleAnimationInterrupted(false, mBarView.getTranslationY());
|
|
}
|
|
|
|
private void expandBubbleBar() {
|
|
if (mShouldShowEducation) {
|
|
mShouldShowEducation = false;
|
|
// Get the bubble bar bounds on screen
|
|
Rect bounds = new Rect();
|
|
mBarView.getBoundsOnScreen(bounds);
|
|
// Calculate user education reference position in Screen coordinates
|
|
Point position = new Point(bounds.centerX(), bounds.top);
|
|
// Show user education relative to the reference point
|
|
mSystemUiProxy.showUserEducation(position);
|
|
} else {
|
|
// ensure that the bubble bar has the correct translation. we may have just interrupted
|
|
// the animation by touching the bubble bar.
|
|
mBubbleBarTranslationY.animateToValue(mBubbleStashController.getBubbleBarTranslationY())
|
|
.start();
|
|
setExpanded(true);
|
|
}
|
|
}
|
|
|
|
private void collapseBubbleBar() {
|
|
setExpanded(false);
|
|
mBubbleStashController.stashBubbleBar();
|
|
}
|
|
|
|
/** Notifies that the stash state is changing. */
|
|
public void onStashStateChanging() {
|
|
if (isAnimatingNewBubble()) {
|
|
mBubbleBarViewAnimator.onStashStateChangingWhileAnimating();
|
|
}
|
|
}
|
|
|
|
//
|
|
// The below animators are exposed to BubbleStashController so it can manage the stashing
|
|
// animation.
|
|
//
|
|
|
|
public MultiPropertyFactory<View> getBubbleBarAlpha() {
|
|
return mBubbleBarAlpha;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarBubbleAlpha() {
|
|
return mBubbleBarBubbleAlpha;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarBackgroundAlpha() {
|
|
return mBubbleBarBackgroundAlpha;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarScaleX() {
|
|
return mBubbleBarScaleX;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarScaleY() {
|
|
return mBubbleBarScaleY;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarBackgroundScaleX() {
|
|
return mBubbleBarBackgroundScaleX;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarBackgroundScaleY() {
|
|
return mBubbleBarBackgroundScaleY;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleBarTranslationY() {
|
|
return mBubbleBarTranslationY;
|
|
}
|
|
|
|
public AnimatedFloat getBubbleOffsetY() {
|
|
return mBubbleOffsetY;
|
|
}
|
|
|
|
public float getBubbleBarCollapsedWidth() {
|
|
return mBarView.collapsedWidth();
|
|
}
|
|
|
|
public float getBubbleBarCollapsedHeight() {
|
|
return mBarView.getBubbleBarCollapsedHeight();
|
|
}
|
|
|
|
/**
|
|
* @see BubbleBarView#getRelativePivotX()
|
|
*/
|
|
public float getBubbleBarRelativePivotX() {
|
|
return mBarView.getRelativePivotX();
|
|
}
|
|
|
|
/**
|
|
* @see BubbleBarView#getRelativePivotY()
|
|
*/
|
|
public float getBubbleBarRelativePivotY() {
|
|
return mBarView.getRelativePivotY();
|
|
}
|
|
|
|
/**
|
|
* @see BubbleBarView#setRelativePivot(float, float)
|
|
*/
|
|
public void setBubbleBarRelativePivot(float x, float y) {
|
|
mBarView.setRelativePivot(x, y);
|
|
}
|
|
|
|
/**
|
|
* Whether the bubble bar is visible or not.
|
|
*/
|
|
public boolean isBubbleBarVisible() {
|
|
return mBarView.getVisibility() == VISIBLE;
|
|
}
|
|
|
|
/** Whether the bubble bar has bubbles. */
|
|
public boolean hasBubbles() {
|
|
return mBubbleBarController.getSelectedBubbleKey() != null;
|
|
}
|
|
|
|
/**
|
|
* @return current {@link BubbleBarLocation}
|
|
*/
|
|
public BubbleBarLocation getBubbleBarLocation() {
|
|
return mBarView.getBubbleBarLocation();
|
|
}
|
|
|
|
/**
|
|
* @return {@code true} if bubble bar is on the left edge of the screen, {@code false} if on
|
|
* the right
|
|
*/
|
|
public boolean isBubbleBarOnLeft() {
|
|
return mBarView.getBubbleBarLocation().isOnLeft(mBarView.isLayoutRtl());
|
|
}
|
|
|
|
/**
|
|
* Update bar {@link BubbleBarLocation}
|
|
*/
|
|
public void setBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
|
|
mBarView.setBubbleBarLocation(bubbleBarLocation);
|
|
}
|
|
|
|
/**
|
|
* Animate bubble bar to the given location. The location change is transient. It does not
|
|
* update the state of the bubble bar.
|
|
* To update bubble bar pinned location, use {@link #setBubbleBarLocation(BubbleBarLocation)}.
|
|
*/
|
|
public void animateBubbleBarLocation(BubbleBarLocation bubbleBarLocation) {
|
|
mBarView.animateToBubbleBarLocation(bubbleBarLocation);
|
|
}
|
|
|
|
/**
|
|
* The bounds of the bubble bar.
|
|
*/
|
|
public Rect getBubbleBarBounds() {
|
|
return mBarView.getBubbleBarBounds();
|
|
}
|
|
|
|
/** Returns the bounds of the flyout view if it exists, or {@code null} otherwise. */
|
|
@Nullable
|
|
public Rect getFlyoutBounds() {
|
|
return mBubbleBarFlyoutController.getFlyoutBounds();
|
|
}
|
|
|
|
/** Checks that bubble bar is visible and that the motion event is within bounds. */
|
|
public boolean isEventOverBubbleBar(MotionEvent event) {
|
|
if (!isBubbleBarVisible()) return false;
|
|
final Rect bounds = getBubbleBarBounds();
|
|
final int bubbleBarTopOnScreen = mBarView.getRestingTopPositionOnScreen();
|
|
final float x = event.getX();
|
|
return event.getRawY() >= bubbleBarTopOnScreen && x >= bounds.left && x <= bounds.right;
|
|
}
|
|
|
|
/** Whether a new bubble is animating. */
|
|
public boolean isAnimatingNewBubble() {
|
|
return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.isAnimating();
|
|
}
|
|
|
|
public boolean isNewBubbleAnimationRunningOrPending() {
|
|
return mBubbleBarViewAnimator != null && mBubbleBarViewAnimator.hasAnimation();
|
|
}
|
|
|
|
/** The horizontal margin of the bubble bar from the edge of the screen. */
|
|
public int getHorizontalMargin() {
|
|
return mBarView.getHorizontalMargin();
|
|
}
|
|
|
|
/**
|
|
* When the bubble bar is not stashed, it can be collapsed (the icons are in a stack) or
|
|
* expanded (the icons are in a row). This indicates whether the bubble bar is expanded.
|
|
*/
|
|
public boolean isExpanded() {
|
|
return mBarView.isExpanded();
|
|
}
|
|
|
|
/**
|
|
* Whether the motion event is within the bounds of the bubble bar.
|
|
*/
|
|
public boolean isEventOverAnyItem(MotionEvent ev) {
|
|
return mBarView.isEventOverAnyItem(ev);
|
|
}
|
|
|
|
//
|
|
// Visibility of the bubble bar
|
|
//
|
|
|
|
/**
|
|
* Returns whether the bubble bar is hidden because there are no bubbles.
|
|
*/
|
|
public boolean isHiddenForNoBubbles() {
|
|
return mHiddenForNoBubbles;
|
|
}
|
|
|
|
/**
|
|
* Sets whether the bubble bar should be hidden because there are no bubbles.
|
|
*/
|
|
public void setHiddenForBubbles(boolean hidden) {
|
|
if (mHiddenForNoBubbles != hidden) {
|
|
mHiddenForNoBubbles = hidden;
|
|
updateVisibilityForStateChange();
|
|
if (hidden) {
|
|
mBarView.setAlpha(0);
|
|
mBarView.setExpanded(false);
|
|
adjustTaskbarAndHotseatToBubbleBarState(/* isBubbleBarExpanded = */ false);
|
|
}
|
|
mActivity.bubbleBarVisibilityChanged(!hidden);
|
|
}
|
|
}
|
|
|
|
/** Sets a callback that updates the selected bubble after the bubble bar collapses. */
|
|
public void setUpdateSelectedBubbleAfterCollapse(
|
|
Consumer<String> updateSelectedBubbleAfterCollapse) {
|
|
mBarView.setUpdateSelectedBubbleAfterCollapse(updateSelectedBubbleAfterCollapse);
|
|
}
|
|
|
|
/** Returns whether the bubble bar should be hidden because of the current sysui state. */
|
|
boolean isHiddenForSysui() {
|
|
return mHiddenForSysui;
|
|
}
|
|
|
|
/**
|
|
* Sets whether the bubble bar should be hidden due to SysUI state (e.g. on lockscreen).
|
|
*/
|
|
public void setHiddenForSysui(boolean hidden) {
|
|
if (mHiddenForSysui != hidden) {
|
|
mHiddenForSysui = hidden;
|
|
updateVisibilityForStateChange();
|
|
}
|
|
}
|
|
|
|
/** Sets whether the bubble bar should be hidden due to stashed state */
|
|
public void setHiddenForStashed(boolean hidden) {
|
|
if (mHiddenForStashed != hidden) {
|
|
mHiddenForStashed = hidden;
|
|
updateVisibilityForStateChange();
|
|
}
|
|
}
|
|
|
|
// TODO: (b/273592694) animate it
|
|
private void updateVisibilityForStateChange() {
|
|
if (!mHiddenForSysui && !mHiddenForNoBubbles && !mHiddenForStashed) {
|
|
mBarView.setVisibility(VISIBLE);
|
|
} else {
|
|
mBarView.setVisibility(INVISIBLE);
|
|
}
|
|
}
|
|
|
|
//
|
|
// Modifying view related properties.
|
|
//
|
|
|
|
/** Notifies controller of configuration change, so bubble bar can be adjusted */
|
|
public void onBubbleBarConfigurationChanged(boolean animate) {
|
|
int newIconSize;
|
|
int newPadding;
|
|
Resources res = mActivity.getResources();
|
|
if (mBubbleStashController.isBubblesShowingOnHome()
|
|
|| mBubbleStashController.isTransientTaskBar()) {
|
|
newIconSize = getBubbleBarIconSizeFromDeviceProfile(res);
|
|
newPadding = getBubbleBarPaddingFromDeviceProfile(res);
|
|
} else {
|
|
// the bubble bar is shown inside the persistent task bar, use preset sizes
|
|
newIconSize = res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_persistent_taskbar);
|
|
newPadding = res.getDimensionPixelSize(
|
|
R.dimen.bubblebar_icon_spacing_persistent_taskbar);
|
|
}
|
|
updateBubbleBarIconSizeAndPadding(newIconSize, newPadding, animate);
|
|
}
|
|
|
|
private int getBubbleBarIconSizeFromDeviceProfile(Resources res) {
|
|
return getBubbleBarIconSizeFromDeviceProfile(res, mActivity.getDeviceProfile());
|
|
}
|
|
|
|
private int getBubbleBarIconSizeFromDeviceProfile(Resources res, DeviceProfile deviceProfile) {
|
|
DisplayMetrics dm = res.getDisplayMetrics();
|
|
float smallIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
|
APP_ICON_SMALL_DP, dm);
|
|
float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
|
APP_ICON_MEDIUM_DP, dm);
|
|
float smallMediumThreshold = (smallIconSize + mediumIconSize) / 2f;
|
|
int taskbarIconSize = deviceProfile.taskbarIconSize;
|
|
return taskbarIconSize <= smallMediumThreshold
|
|
? res.getDimensionPixelSize(R.dimen.bubblebar_icon_size_small) :
|
|
res.getDimensionPixelSize(R.dimen.bubblebar_icon_size);
|
|
|
|
}
|
|
|
|
private int getBubbleBarPaddingFromDeviceProfile(Resources res) {
|
|
return getBubbleBarPaddingFromDeviceProfile(res, mActivity.getDeviceProfile());
|
|
}
|
|
|
|
private int getBubbleBarPaddingFromDeviceProfile(Resources res, DeviceProfile deviceProfile) {
|
|
DisplayMetrics dm = res.getDisplayMetrics();
|
|
float mediumIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
|
APP_ICON_MEDIUM_DP, dm);
|
|
float largeIconSize = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_DIP,
|
|
APP_ICON_LARGE_DP, dm);
|
|
float mediumLargeThreshold = (mediumIconSize + largeIconSize) / 2f;
|
|
return deviceProfile.taskbarIconSize >= mediumLargeThreshold
|
|
? res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_large) :
|
|
res.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing);
|
|
}
|
|
|
|
private void updateBubbleBarIconSizeAndPadding(int iconSize, int padding, boolean animate) {
|
|
if (mIconSize == iconSize && mBubbleBarPadding == padding) return;
|
|
mIconSize = iconSize;
|
|
mBubbleBarPadding = padding;
|
|
if (animate) {
|
|
mBarView.animateBubbleBarIconSize(iconSize, padding);
|
|
} else {
|
|
mBarView.setIconSizeAndPadding(iconSize, padding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets the translation of the bubble bar during the swipe up gesture.
|
|
*/
|
|
public void setTranslationYForSwipe(float transY) {
|
|
mBubbleBarSwipeUpTranslationY = transY;
|
|
updateTranslationY();
|
|
}
|
|
|
|
/**
|
|
* Sets the translation of the bubble bar during the stash animation.
|
|
*/
|
|
public void setTranslationYForStash(float transY) {
|
|
mBubbleBarStashTranslationY = transY;
|
|
updateTranslationY();
|
|
}
|
|
|
|
private void updateTranslationY() {
|
|
mBarView.setTranslationY(mBubbleBarTranslationY.value + mBubbleBarSwipeUpTranslationY
|
|
+ mBubbleBarStashTranslationY + getBubbleBarTranslationYForTaskbarPinning());
|
|
}
|
|
|
|
/** Computes translation y for taskbar pinning. */
|
|
private float getBubbleBarTranslationYForTaskbarPinning() {
|
|
if (mTaskbarSharedState == null) return 0f;
|
|
float pinningProgress = mBubbleBarPinning.value;
|
|
if (mTaskbarSharedState.startTaskbarVariantIsTransient) {
|
|
return mapRange(pinningProgress, /* min = */ 0f, mTaskbarTranslationDelta);
|
|
} else {
|
|
return mapRange(pinningProgress, -mTaskbarTranslationDelta, /* max = */ 0f);
|
|
}
|
|
}
|
|
|
|
private void setBubbleBarScaleAndPadding(float pinningProgress) {
|
|
Resources res = mActivity.getResources();
|
|
// determine icon scale for pinning
|
|
int persistentIconSize = res.getDimensionPixelSize(
|
|
R.dimen.bubblebar_icon_size_persistent_taskbar);
|
|
int transientIconSize = getBubbleBarIconSizeFromDeviceProfile(res,
|
|
mActivity.getTransientTaskbarDeviceProfile());
|
|
float pinningIconSize = mapRange(pinningProgress, transientIconSize, persistentIconSize);
|
|
|
|
// determine bubble bar padding for pinning
|
|
int persistentPadding = res.getDimensionPixelSize(
|
|
R.dimen.bubblebar_icon_spacing_persistent_taskbar);
|
|
int transientPadding = getBubbleBarPaddingFromDeviceProfile(res,
|
|
mActivity.getTransientTaskbarDeviceProfile());
|
|
float pinningPadding = mapRange(pinningProgress, transientPadding, persistentPadding);
|
|
mBarView.setIconSizeAndPaddingForPinning(pinningIconSize, pinningPadding);
|
|
}
|
|
|
|
/**
|
|
* Calculates the vertical difference in the bubble bar positions for pinned and transient
|
|
* taskbar modes.
|
|
*/
|
|
private int getBubbleBarTranslationDeltaForTaskbar(TaskbarActivityContext activity) {
|
|
Resources res = activity.getResources();
|
|
int persistentBubbleSize = res
|
|
.getDimensionPixelSize(R.dimen.bubblebar_icon_size_persistent_taskbar);
|
|
int persistentSpacingSize = res
|
|
.getDimensionPixelSize(R.dimen.bubblebar_icon_spacing_persistent_taskbar);
|
|
int persistentBubbleBarSize = persistentBubbleSize + persistentSpacingSize * 2;
|
|
int persistentTaskbarHeight = activity.getPersistentTaskbarDeviceProfile().taskbarHeight;
|
|
int persistentBubbleBarY = (persistentTaskbarHeight - persistentBubbleBarSize) / 2;
|
|
int transientBubbleBarY = activity.getTransientTaskbarDeviceProfile().taskbarBottomMargin;
|
|
return transientBubbleBarY - persistentBubbleBarY;
|
|
}
|
|
|
|
private void updateScaleX(float scale) {
|
|
mBarView.setScaleX(scale);
|
|
}
|
|
|
|
private void updateScaleY(float scale) {
|
|
mBarView.setScaleY(scale);
|
|
}
|
|
|
|
private void updateBackgroundScaleX(float scale) {
|
|
mBarView.setBackgroundScaleX(scale);
|
|
}
|
|
|
|
private void updateBackgroundScaleY(float scale) {
|
|
mBarView.setBackgroundScaleY(scale);
|
|
}
|
|
|
|
private void updateBubbleAlpha(float alpha) {
|
|
mBarView.setBubbleAlpha(alpha);
|
|
}
|
|
|
|
private void updateBubbleOffsetY(float transY) {
|
|
mBarView.setBubbleOffsetY(transY);
|
|
}
|
|
|
|
private void updateBackgroundAlpha(float alpha) {
|
|
mBarView.setBackgroundAlpha(alpha);
|
|
}
|
|
|
|
//
|
|
// Manipulating the specific bubble views in the bar
|
|
//
|
|
|
|
/**
|
|
* Removes the provided bubble from the bubble bar.
|
|
*/
|
|
public void removeBubble(BubbleBarBubble b) {
|
|
if (b != null) {
|
|
mBarView.removeBubble(b.getView());
|
|
b.getView().setController(null);
|
|
} else {
|
|
Log.w(TAG, "removeBubble, bubble was null!");
|
|
}
|
|
}
|
|
|
|
/** Adds a new bubble and removes an old bubble at the same time. */
|
|
public void addBubbleAndRemoveBubble(BubbleBarBubble addedBubble,
|
|
BubbleBarBubble removedBubble, boolean isExpanding, boolean suppressAnimation,
|
|
boolean addOverflowToo) {
|
|
mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), removedBubble.getView(),
|
|
addOverflowToo ? () -> showOverflow(true) : null);
|
|
addedBubble.getView().setOnClickListener(mBubbleClickListener);
|
|
addedBubble.getView().setController(mBubbleViewController);
|
|
removedBubble.getView().setController(null);
|
|
mBubbleDragController.setupBubbleView(addedBubble.getView());
|
|
if (!suppressAnimation) {
|
|
animateBubbleNotification(addedBubble, isExpanding, /* isUpdate= */ false);
|
|
}
|
|
}
|
|
|
|
/** Whether the overflow view is added to the bubble bar. */
|
|
public boolean isOverflowAdded() {
|
|
return mOverflowAdded;
|
|
}
|
|
|
|
/** Shows or hides the overflow view. */
|
|
public void showOverflow(boolean showOverflow) {
|
|
if (mOverflowAdded == showOverflow) return;
|
|
mOverflowAdded = showOverflow;
|
|
if (mOverflowAdded) {
|
|
mBarView.addBubble(mOverflowBubble.getView());
|
|
mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
|
|
mOverflowBubble.getView().setController(mBubbleViewController);
|
|
} else {
|
|
mBarView.removeBubble(mOverflowBubble.getView());
|
|
mOverflowBubble.getView().setOnClickListener(null);
|
|
mOverflowBubble.getView().setController(null);
|
|
}
|
|
}
|
|
|
|
/** Adds the overflow view to the bubble bar while animating a view away. */
|
|
public void addOverflowAndRemoveBubble(BubbleBarBubble removedBubble) {
|
|
if (mOverflowAdded) return;
|
|
mOverflowAdded = true;
|
|
mBarView.addBubbleAndRemoveBubble(mOverflowBubble.getView(), removedBubble.getView(),
|
|
null /* onEndRunnable */);
|
|
mOverflowBubble.getView().setOnClickListener(mBubbleClickListener);
|
|
mOverflowBubble.getView().setController(mBubbleViewController);
|
|
removedBubble.getView().setController(null);
|
|
}
|
|
|
|
/** Removes the overflow view to the bubble bar while animating a view in. */
|
|
public void removeOverflowAndAddBubble(BubbleBarBubble addedBubble) {
|
|
if (!mOverflowAdded) return;
|
|
mOverflowAdded = false;
|
|
mBarView.addBubbleAndRemoveBubble(addedBubble.getView(), mOverflowBubble.getView(),
|
|
null /* onEndRunnable */);
|
|
addedBubble.getView().setOnClickListener(mBubbleClickListener);
|
|
addedBubble.getView().setController(mBubbleViewController);
|
|
mOverflowBubble.getView().setController(null);
|
|
}
|
|
|
|
/**
|
|
* Adds the provided bubble to the bubble bar.
|
|
*/
|
|
public void addBubble(BubbleBarItem b, boolean isExpanding, boolean suppressAnimation) {
|
|
if (b != null) {
|
|
mBarView.addBubble(b.getView());
|
|
b.getView().setOnClickListener(mBubbleClickListener);
|
|
mBubbleDragController.setupBubbleView(b.getView());
|
|
b.getView().setController(mBubbleViewController);
|
|
|
|
if (suppressAnimation || !(b instanceof BubbleBarBubble bubble)) {
|
|
// 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()
|
|
&& mBubbleStashController.isTransientTaskBar()
|
|
&& mTaskbarStashController.isStashed()) {
|
|
mBubbleStashController.stashBubbleBarImmediate();
|
|
} else {
|
|
mBubbleStashController.showBubbleBarImmediate();
|
|
}
|
|
return;
|
|
}
|
|
animateBubbleNotification(bubble, isExpanding, /* isUpdate= */ false);
|
|
} else {
|
|
Log.w(TAG, "addBubble, bubble was null!");
|
|
}
|
|
}
|
|
|
|
/** Animates the bubble bar to notify the user about a bubble change. */
|
|
public void animateBubbleNotification(BubbleBarBubble bubble, boolean isExpanding,
|
|
boolean isUpdate) {
|
|
// if we're expanded, don't animate the bubble bar. just show the notification dot.
|
|
if (isExpanded()) {
|
|
bubble.getView().updateDotVisibility(/* animate= */ true);
|
|
return;
|
|
}
|
|
boolean isInApp = mTaskbarStashController.isInApp();
|
|
// if this is the first bubble, animate to the initial state.
|
|
if (mBarView.getBubbleChildCount() == 1 && !isUpdate) {
|
|
mBubbleBarViewAnimator.animateToInitialState(bubble, isInApp, isExpanding);
|
|
return;
|
|
}
|
|
boolean persistentTaskbarOrOnHome = mBubbleStashController.isBubblesShowingOnHome()
|
|
|| !mBubbleStashController.isTransientTaskBar();
|
|
if (persistentTaskbarOrOnHome) {
|
|
mBubbleBarViewAnimator.animateBubbleBarForCollapsed(bubble, isExpanding);
|
|
return;
|
|
}
|
|
|
|
if (isInApp && mBubbleStashController.getHasHandleView()) {
|
|
mBubbleBarViewAnimator.animateBubbleInForStashed(bubble, isExpanding);
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Reorders the bubbles based on the provided list.
|
|
*/
|
|
public void reorderBubbles(List<BubbleBarBubble> newOrder) {
|
|
List<BubbleView> viewList = newOrder.stream().filter(Objects::nonNull)
|
|
.map(BubbleBarBubble::getView).toList();
|
|
mBarView.reorder(viewList);
|
|
}
|
|
|
|
/**
|
|
* Updates the selected bubble.
|
|
*/
|
|
public void updateSelectedBubble(BubbleBarItem newlySelected) {
|
|
mBarView.setSelectedBubble(newlySelected.getView());
|
|
}
|
|
|
|
/**
|
|
* Sets whether the bubble bar should be expanded (not unstashed, but have the contents
|
|
* within it expanded). This method notifies SystemUI that the bubble bar is expanded and
|
|
* showing a selected bubble. This method should ONLY be called from UI events originating
|
|
* from Launcher.
|
|
*/
|
|
public void setExpanded(boolean isExpanded) {
|
|
if (isExpanded != mBarView.isExpanded()) {
|
|
mBarView.setExpanded(isExpanded);
|
|
adjustTaskbarAndHotseatToBubbleBarState(isExpanded);
|
|
if (!isExpanded) {
|
|
mSystemUiProxy.collapseBubbles();
|
|
} else {
|
|
mBubbleBarController.showSelectedBubble();
|
|
mTaskbarStashController.updateAndAnimateTransientTaskbar(true /* stash */,
|
|
false /* shouldBubblesFollow */);
|
|
}
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Hides the persistent taskbar if it is going to intersect with the expanded bubble bar if in
|
|
* app or overview.
|
|
*/
|
|
private void adjustTaskbarAndHotseatToBubbleBarState(boolean isBubbleBarExpanded) {
|
|
if (!mBubbleStashController.isBubblesShowingOnHome()
|
|
&& !mBubbleStashController.isTransientTaskBar()) {
|
|
boolean hideTaskbar = isBubbleBarExpanded && isIntersectingTaskbar();
|
|
Animator taskbarAlphaAnimator = mTaskbarViewPropertiesProvider.getIconsAlpha()
|
|
.animateToValue(hideTaskbar ? 0 : 1);
|
|
taskbarAlphaAnimator.setDuration(hideTaskbar
|
|
? TASKBAR_FADE_OUT_DURATION_MS : TASKBAR_FADE_IN_DURATION_MS);
|
|
if (!hideTaskbar) {
|
|
taskbarAlphaAnimator.setStartDelay(TASKBAR_FADE_IN_DELAY_MS);
|
|
}
|
|
taskbarAlphaAnimator.setInterpolator(Interpolators.LINEAR);
|
|
taskbarAlphaAnimator.start();
|
|
}
|
|
}
|
|
|
|
/** Return {@code true} if expanded bubble bar would intersect the taskbar. */
|
|
public boolean isIntersectingTaskbar() {
|
|
if (mBarView.isExpanding() || mBarView.isExpanded()) {
|
|
Rect taskbarViewBounds = mTaskbarViewPropertiesProvider.getTaskbarViewBounds();
|
|
return mBarView.getBubbleBarExpandedBounds().intersect(taskbarViewBounds);
|
|
} else {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Sets whether the bubble bar should be expanded. This method is used in response to UI events
|
|
* from SystemUI.
|
|
*/
|
|
public void setExpandedFromSysui(boolean isExpanded) {
|
|
if (isNewBubbleAnimationRunningOrPending() && isExpanded) {
|
|
mBubbleBarViewAnimator.expandedWhileAnimating();
|
|
return;
|
|
}
|
|
if (!isExpanded) {
|
|
mBubbleStashController.stashBubbleBar();
|
|
} else {
|
|
mBubbleStashController.showBubbleBar(true /* expand the bubbles */);
|
|
}
|
|
}
|
|
|
|
/** Marks as should show education and shows the bubble bar in a collapsed state */
|
|
public void prepareToShowEducation() {
|
|
mShouldShowEducation = true;
|
|
mBubbleStashController.showBubbleBar(false /* expand the bubbles */);
|
|
}
|
|
|
|
/**
|
|
* 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) {
|
|
if (bubbleView.getBubble() == null) return;
|
|
|
|
mSystemUiProxy.startBubbleDrag(bubbleView.getBubble().getKey());
|
|
mBarView.setDraggedBubble(bubbleView);
|
|
}
|
|
|
|
/**
|
|
* Notifies SystemUI to expand the selected bubble when the bubble is released.
|
|
*/
|
|
public void onBubbleDragRelease(BubbleBarLocation location) {
|
|
mSystemUiProxy.stopBubbleDrag(location, mBarView.getRestingTopPositionOnScreen());
|
|
}
|
|
|
|
/** Handle given bubble being dismissed */
|
|
public void onBubbleDismissed(BubbleView bubble) {
|
|
mBubbleBarController.onBubbleDismissed(bubble);
|
|
mBarView.removeBubble(bubble);
|
|
}
|
|
|
|
/**
|
|
* Notifies {@link BubbleBarView} that drag and all animations are finished.
|
|
*/
|
|
public void onBubbleDragEnd() {
|
|
mBarView.setDraggedBubble(null);
|
|
}
|
|
|
|
/** Notifies that dragging the bubble bar ended. */
|
|
public void onBubbleBarDragEnd() {
|
|
// we may have changed the bubble bar translation Y value from the value it had at the
|
|
// beginning of the drag, so update the translation Y animator state
|
|
mBubbleBarTranslationY.updateValue(mBarView.getTranslationY());
|
|
}
|
|
|
|
/**
|
|
* Get translation for bubble bar when drag is released.
|
|
*
|
|
* @see BubbleBarView#getBubbleBarDragReleaseTranslation(PointF, BubbleBarLocation)
|
|
*/
|
|
public PointF getBubbleBarDragReleaseTranslation(PointF initialTranslation,
|
|
BubbleBarLocation location) {
|
|
return mBarView.getBubbleBarDragReleaseTranslation(initialTranslation, location);
|
|
}
|
|
|
|
/**
|
|
* Get translation for bubble view when drag is released.
|
|
*
|
|
* @see BubbleBarView#getDraggedBubbleReleaseTranslation(PointF, BubbleBarLocation)
|
|
*/
|
|
public PointF getDraggedBubbleReleaseTranslation(PointF initialTranslation,
|
|
BubbleBarLocation location) {
|
|
if (location == mBarView.getBubbleBarLocation()) {
|
|
return initialTranslation;
|
|
}
|
|
return mBarView.getDraggedBubbleReleaseTranslation(initialTranslation, location);
|
|
}
|
|
|
|
/**
|
|
* Notify SystemUI that the given bubble has been dismissed.
|
|
*/
|
|
public void notifySysUiBubbleDismissed(@NonNull BubbleBarItem bubble) {
|
|
mSystemUiProxy.dragBubbleToDismiss(bubble.getKey(), mTimeSource.currentTimeMillis());
|
|
}
|
|
|
|
/**
|
|
* Called when bubble stack was dismissed
|
|
*/
|
|
public void onDismissAllBubbles() {
|
|
mSystemUiProxy.removeAllBubbles();
|
|
}
|
|
|
|
/**
|
|
* Set listener to be notified when bubble bar bounds have changed
|
|
*/
|
|
public void setBoundsChangeListener(@Nullable BubbleBarBoundsChangeListener listener) {
|
|
mBoundsChangeListener = listener;
|
|
}
|
|
|
|
/** Called when the controller is destroyed. */
|
|
public void onDestroy() {
|
|
adjustTaskbarAndHotseatToBubbleBarState(/*isBubbleBarExpanded = */false);
|
|
}
|
|
|
|
/**
|
|
* Create an animator for showing or hiding bubbles when stashed state changes
|
|
*
|
|
* @param isStashed {@code true} when bubble bar should be stashed to the handle
|
|
*/
|
|
public Animator createRevealAnimatorForStashChange(boolean isStashed) {
|
|
Rect stashedHandleBounds = new Rect();
|
|
mBubbleStashController.getHandleBounds(stashedHandleBounds);
|
|
int childCount = mBarView.getChildCount();
|
|
float newChildWidth = (float) stashedHandleBounds.width() / childCount;
|
|
AnimatorSet animatorSet = new AnimatorSet();
|
|
for (int i = 0; i < childCount; i++) {
|
|
BubbleView child = (BubbleView) mBarView.getChildAt(i);
|
|
animatorSet.play(
|
|
createRevealAnimForBubble(child, isStashed, stashedHandleBounds,
|
|
newChildWidth));
|
|
}
|
|
return animatorSet;
|
|
}
|
|
|
|
private Animator createRevealAnimForBubble(BubbleView bubbleView, boolean isStashed,
|
|
Rect stashedHandleBounds, float newWidth) {
|
|
Rect viewBounds = new Rect(0, 0, bubbleView.getWidth(), bubbleView.getHeight());
|
|
|
|
int viewCenterY = viewBounds.centerY();
|
|
int halfHandleHeight = stashedHandleBounds.height() / 2;
|
|
int widthDelta = Math.max(0, (int) (viewBounds.width() - newWidth) / 2);
|
|
|
|
Rect stashedViewBounds = new Rect(
|
|
viewBounds.left + widthDelta,
|
|
viewCenterY - halfHandleHeight,
|
|
viewBounds.right - widthDelta,
|
|
viewCenterY + halfHandleHeight
|
|
);
|
|
|
|
float viewRadius = 0f; // Use 0 to not clip the new message dot or the app icon
|
|
float stashedRadius = stashedViewBounds.height() / 2f;
|
|
|
|
return new RoundedRectRevealOutlineProvider(viewRadius, stashedRadius, viewBounds,
|
|
stashedViewBounds).createRevealAnimator(bubbleView, !isStashed, 0);
|
|
}
|
|
|
|
/**
|
|
* Listener to receive updates about bubble bar bounds changing
|
|
*/
|
|
public interface BubbleBarBoundsChangeListener {
|
|
/** Called when bounds have changed */
|
|
void onBoundsChanged();
|
|
}
|
|
|
|
/** Interface for getting the current timestamp. */
|
|
interface TimeSource {
|
|
long currentTimeMillis();
|
|
}
|
|
|
|
/** Dumps the state of BubbleBarViewController. */
|
|
public void dump(PrintWriter pw) {
|
|
pw.println("Bubble bar view controller state:");
|
|
pw.println(" mHiddenForSysui: " + mHiddenForSysui);
|
|
pw.println(" mHiddenForNoBubbles: " + mHiddenForNoBubbles);
|
|
pw.println(" mShouldShowEducation: " + mShouldShowEducation);
|
|
pw.println(" mBubbleBarTranslationY.value: " + mBubbleBarTranslationY.value);
|
|
pw.println(" mBubbleBarSwipeUpTranslationY: " + mBubbleBarSwipeUpTranslationY);
|
|
pw.println(" mOverflowAdded: " + mOverflowAdded);
|
|
if (mBarView != null) {
|
|
mBarView.dump(pw);
|
|
} else {
|
|
pw.println(" Bubble bar view is null!");
|
|
}
|
|
}
|
|
|
|
/** Interface for BubbleBarViewController to get the taskbar view properties. */
|
|
public interface TaskbarViewPropertiesProvider {
|
|
|
|
/** Returns the bounds of the taskbar. */
|
|
Rect getTaskbarViewBounds();
|
|
|
|
/** Returns taskbar icons alpha */
|
|
MultiPropertyFactory<View>.MultiProperty getIconsAlpha();
|
|
}
|
|
}
|