Support switching navigation modes.
Switching navigation modes in Settings updates how bubbles are displayed. Existing bubbles are re-added to the appropriate view. Bug: 269670598 Test: In Settings go to Display and Navigation mode and switch between Gesture and 3-button modes after creating bubbles. Change-Id: I7562040ce907907325a00bac041b2eb3923d4848
This commit is contained in:
@@ -422,6 +422,7 @@ public class Bubble implements BubbleViewProvider {
|
||||
}
|
||||
if (mBubbleBarExpandedView != null) {
|
||||
mBubbleBarExpandedView.cleanUpExpandedState();
|
||||
mBubbleBarExpandedView = null;
|
||||
}
|
||||
if (mIntent != null) {
|
||||
mIntent.unregisterCancelListener(mIntentCancelListener);
|
||||
@@ -549,10 +550,10 @@ public class Bubble implements BubbleViewProvider {
|
||||
/**
|
||||
* Set visibility of bubble in the expanded state.
|
||||
*
|
||||
* @param visibility {@code true} if the expanded bubble should be visible on the screen.
|
||||
*
|
||||
* Note that this contents visibility doesn't affect visibility at {@link android.view.View},
|
||||
* <p>Note that this contents visibility doesn't affect visibility at {@link android.view.View},
|
||||
* and setting {@code false} actually means rendering the expanded view in transparent.
|
||||
*
|
||||
* @param visibility {@code true} if the expanded bubble should be visible on the screen.
|
||||
*/
|
||||
@Override
|
||||
public void setTaskViewVisibility(boolean visibility) {
|
||||
|
||||
@@ -64,7 +64,6 @@ import android.os.Bundle;
|
||||
import android.os.Handler;
|
||||
import android.os.RemoteException;
|
||||
import android.os.ServiceManager;
|
||||
import android.os.SystemProperties;
|
||||
import android.os.UserHandle;
|
||||
import android.os.UserManager;
|
||||
import android.service.notification.NotificationListenerService;
|
||||
@@ -92,6 +91,7 @@ import com.android.wm.shell.R;
|
||||
import com.android.wm.shell.ShellTaskOrganizer;
|
||||
import com.android.wm.shell.WindowManagerShellWrapper;
|
||||
import com.android.wm.shell.bubbles.bar.BubbleBarLayerView;
|
||||
import com.android.wm.shell.bubbles.properties.BubbleProperties;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.ExternalInterfaceBinder;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
@@ -143,16 +143,6 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
private static final String SYSTEM_DIALOG_REASON_KEY = "reason";
|
||||
private static final String SYSTEM_DIALOG_REASON_GESTURE_NAV = "gestureNav";
|
||||
|
||||
// TODO(b/256873975) Should use proper flag when available to shell/launcher
|
||||
/**
|
||||
* Whether bubbles are showing in the bubble bar from launcher. This is only available
|
||||
* on large screens and {@link BubbleController#isShowingAsBubbleBar()} should be used
|
||||
* to check all conditions that indicate if the bubble bar is in use.
|
||||
*/
|
||||
private static final boolean BUBBLE_BAR_ENABLED =
|
||||
SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);
|
||||
|
||||
|
||||
/**
|
||||
* Common interface to send updates to bubble views.
|
||||
*/
|
||||
@@ -195,6 +185,7 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
private final ShellController mShellController;
|
||||
private final ShellCommandHandler mShellCommandHandler;
|
||||
private final IWindowManager mWmService;
|
||||
private final BubbleProperties mBubbleProperties;
|
||||
|
||||
// Used to post to main UI thread
|
||||
private final ShellExecutor mMainExecutor;
|
||||
@@ -291,7 +282,8 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
@ShellBackgroundThread ShellExecutor bgExecutor,
|
||||
TaskViewTransitions taskViewTransitions,
|
||||
SyncTransactionQueue syncQueue,
|
||||
IWindowManager wmService) {
|
||||
IWindowManager wmService,
|
||||
BubbleProperties bubbleProperties) {
|
||||
mContext = context;
|
||||
mShellCommandHandler = shellCommandHandler;
|
||||
mShellController = shellController;
|
||||
@@ -328,6 +320,7 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
mDragAndDropController = dragAndDropController;
|
||||
mSyncQueue = syncQueue;
|
||||
mWmService = wmService;
|
||||
mBubbleProperties = bubbleProperties;
|
||||
shellInit.addInitCallback(this::onInit, this);
|
||||
}
|
||||
|
||||
@@ -518,11 +511,14 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
/**
|
||||
* Sets a listener to be notified of bubble updates. This is used by launcher so that
|
||||
* it may render bubbles in itself. Only one listener is supported.
|
||||
*
|
||||
* <p>If bubble bar is supported, bubble views will be updated to switch to bar mode.
|
||||
*/
|
||||
public void registerBubbleStateListener(Bubbles.BubbleStateListener listener) {
|
||||
if (isShowingAsBubbleBar()) {
|
||||
// Only set the listener if bubble bar is showing.
|
||||
if (canShowAsBubbleBar() && listener != null) {
|
||||
// Only set the listener if we can show the bubble bar.
|
||||
mBubbleStateListener = listener;
|
||||
setUpBubbleViewsForMode();
|
||||
sendInitialListenerUpdate();
|
||||
} else {
|
||||
mBubbleStateListener = null;
|
||||
@@ -531,9 +527,15 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
|
||||
/**
|
||||
* Unregisters the {@link Bubbles.BubbleStateListener}.
|
||||
*
|
||||
* <p>If there's an existing listener, then we're switching back to stack mode and bubble views
|
||||
* will be updated accordingly.
|
||||
*/
|
||||
public void unregisterBubbleStateListener() {
|
||||
mBubbleStateListener = null;
|
||||
if (mBubbleStateListener != null) {
|
||||
mBubbleStateListener = null;
|
||||
setUpBubbleViewsForMode();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -645,8 +647,12 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
|
||||
/** Whether bubbles are showing in the bubble bar. */
|
||||
public boolean isShowingAsBubbleBar() {
|
||||
// TODO(b/269670598): should also check that we're in gesture nav
|
||||
return BUBBLE_BAR_ENABLED && mBubblePositioner.isLargeScreen();
|
||||
return canShowAsBubbleBar() && mBubbleStateListener != null;
|
||||
}
|
||||
|
||||
/** Whether the current configuration supports showing as bubble bar. */
|
||||
private boolean canShowAsBubbleBar() {
|
||||
return mBubbleProperties.isBubbleBarEnabled() && mBubblePositioner.isLargeScreen();
|
||||
}
|
||||
|
||||
/** Whether this userId belongs to the current user. */
|
||||
@@ -779,7 +785,7 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
if (isShowingAsBubbleBar()) {
|
||||
mWindowManager.addView(mLayerView, mWmLayoutParams);
|
||||
mLayerView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
|
||||
if (!windowInsets.equals(mWindowInsets)) {
|
||||
if (!windowInsets.equals(mWindowInsets) && mLayerView != null) {
|
||||
mWindowInsets = windowInsets;
|
||||
mBubblePositioner.update();
|
||||
mLayerView.onDisplaySizeChanged();
|
||||
@@ -789,7 +795,7 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
} else {
|
||||
mWindowManager.addView(mStackView, mWmLayoutParams);
|
||||
mStackView.setOnApplyWindowInsetsListener((view, windowInsets) -> {
|
||||
if (!windowInsets.equals(mWindowInsets)) {
|
||||
if (!windowInsets.equals(mWindowInsets) && mStackView != null) {
|
||||
mWindowInsets = windowInsets;
|
||||
mBubblePositioner.update();
|
||||
mStackView.onDisplaySizeChanged();
|
||||
@@ -1066,9 +1072,11 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
* Expands and selects the provided bubble as long as it already exists in the stack or the
|
||||
* overflow.
|
||||
*
|
||||
* This is used by external callers (launcher).
|
||||
* <p>This is used by external callers (launcher).
|
||||
*/
|
||||
public void expandStackAndSelectBubbleFromLauncher(String key) {
|
||||
@VisibleForTesting
|
||||
public void expandStackAndSelectBubbleFromLauncher(String key, boolean onLauncherHome) {
|
||||
mBubblePositioner.setShowingInBubbleBar(onLauncherHome);
|
||||
Bubble b = mBubbleData.getAnyBubbleWithkey(key);
|
||||
if (b == null) {
|
||||
return;
|
||||
@@ -1286,6 +1294,50 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
});
|
||||
}
|
||||
|
||||
void setUpBubbleViewsForMode() {
|
||||
mBubbleViewCallback = isShowingAsBubbleBar()
|
||||
? mBubbleBarViewCallback
|
||||
: mBubbleStackViewCallback;
|
||||
|
||||
// reset the overflow so that it can be re-added later if needed.
|
||||
if (mStackView != null) {
|
||||
mStackView.resetOverflowView();
|
||||
mStackView.removeAllViews();
|
||||
}
|
||||
// cleanup existing bubble views so they can be recreated later if needed.
|
||||
mBubbleData.getBubbles().forEach(Bubble::cleanupViews);
|
||||
|
||||
// remove the current bubble container from window manager, null it out, and create a new
|
||||
// container based on the current mode.
|
||||
removeFromWindowManagerMaybe();
|
||||
mLayerView = null;
|
||||
mStackView = null;
|
||||
ensureBubbleViewsAndWindowCreated();
|
||||
|
||||
// inflate bubble views
|
||||
BubbleViewInfoTask.Callback callback = null;
|
||||
if (!isShowingAsBubbleBar()) {
|
||||
callback = b -> {
|
||||
if (mStackView != null) {
|
||||
mStackView.addBubble(b);
|
||||
mStackView.setSelectedBubble(b);
|
||||
} else {
|
||||
Log.w(TAG, "Tried to add a bubble to the stack but the stack is null");
|
||||
}
|
||||
};
|
||||
}
|
||||
for (int i = mBubbleData.getBubbles().size() - 1; i >= 0; i--) {
|
||||
Bubble bubble = mBubbleData.getBubbles().get(i);
|
||||
bubble.inflate(callback,
|
||||
mContext,
|
||||
this,
|
||||
mStackView,
|
||||
mLayerView,
|
||||
mBubbleIconFactory,
|
||||
false /* skipInflation */);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a bubble associated with the provided notification entry.
|
||||
*
|
||||
@@ -1746,7 +1798,7 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
// Update the cached state for queries from SysUI
|
||||
mImpl.mCachedState.update(update);
|
||||
|
||||
if (isShowingAsBubbleBar() && mBubbleStateListener != null) {
|
||||
if (isShowingAsBubbleBar()) {
|
||||
BubbleBarUpdate bubbleBarUpdate = update.toBubbleBarUpdate();
|
||||
// Some updates aren't relevant to the bubble bar so check first.
|
||||
if (bubbleBarUpdate.anythingChanged()) {
|
||||
@@ -1868,10 +1920,17 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public BubbleStackView getStackView() {
|
||||
return mStackView;
|
||||
}
|
||||
|
||||
@VisibleForTesting
|
||||
@Nullable
|
||||
public BubbleBarLayerView getLayerView() {
|
||||
return mLayerView;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if notification panel is in an expanded state.
|
||||
* Makes a call to System UI process and delivers the result via {@code callback} on the
|
||||
@@ -2010,22 +2069,18 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
|
||||
@Override
|
||||
public void registerBubbleListener(IBubblesListener listener) {
|
||||
mMainExecutor.execute(() -> {
|
||||
mListener.register(listener);
|
||||
});
|
||||
mMainExecutor.execute(() -> mListener.register(listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterBubbleListener(IBubblesListener listener) {
|
||||
mMainExecutor.execute(() -> mListener.unregister());
|
||||
mMainExecutor.execute(mListener::unregister);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void showBubble(String key, boolean onLauncherHome) {
|
||||
mMainExecutor.execute(() -> {
|
||||
mBubblePositioner.setShowingInBubbleBar(onLauncherHome);
|
||||
mController.expandStackAndSelectBubbleFromLauncher(key);
|
||||
});
|
||||
mMainExecutor.execute(
|
||||
() -> mController.expandStackAndSelectBubbleFromLauncher(key, onLauncherHome));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -2037,11 +2092,6 @@ public class BubbleController implements ConfigurationChangeListener,
|
||||
public void collapseBubbles() {
|
||||
mMainExecutor.execute(() -> mController.collapseStack());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onTaskbarStateChanged(int newState) {
|
||||
// TODO (b/269670598)
|
||||
}
|
||||
}
|
||||
|
||||
private class BubblesImpl implements Bubbles {
|
||||
|
||||
@@ -309,6 +309,7 @@ public class BubbleStackView extends FrameLayout
|
||||
|
||||
String bubblesOnScreen = BubbleDebugConfig.formatBubblesString(
|
||||
getBubblesOnScreen(), getExpandedBubble());
|
||||
pw.print(" stack visibility : "); pw.println(getVisibility());
|
||||
pw.print(" bubbles on screen: "); pw.println(bubblesOnScreen);
|
||||
pw.print(" gestureInProgress: "); pw.println(mIsGestureInProgress);
|
||||
pw.print(" showingDismiss: "); pw.println(mDismissView.isShowing());
|
||||
@@ -970,6 +971,8 @@ public class BubbleStackView extends FrameLayout
|
||||
mBubbleContainer.bringToFront();
|
||||
|
||||
mBubbleOverflow = mBubbleData.getOverflow();
|
||||
|
||||
resetOverflowView();
|
||||
mBubbleContainer.addView(mBubbleOverflow.getIconView(),
|
||||
mBubbleContainer.getChildCount() /* index */,
|
||||
new FrameLayout.LayoutParams(mPositioner.getBubbleSize(),
|
||||
@@ -3413,6 +3416,19 @@ public class BubbleStackView extends FrameLayout
|
||||
mDismissView.setPadding(/* left = */ 0, /* top = */ 0, /* right = */ 0, offset);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes the overflow view from the stack. This allows for re-adding it later to a new stack.
|
||||
*/
|
||||
void resetOverflowView() {
|
||||
BadgedImageView overflowIcon = mBubbleOverflow.getIconView();
|
||||
if (overflowIcon != null) {
|
||||
PhysicsAnimationLayout parent = (PhysicsAnimationLayout) overflowIcon.getParent();
|
||||
if (parent != null) {
|
||||
parent.removeViewNoAnimation(overflowIcon);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Holds some commonly queried information about the stack.
|
||||
*/
|
||||
|
||||
@@ -60,9 +60,11 @@ public interface Bubbles {
|
||||
DISMISS_NOTIF_CANCEL, DISMISS_ACCESSIBILITY_ACTION, DISMISS_NO_LONGER_BUBBLE,
|
||||
DISMISS_USER_CHANGED, DISMISS_GROUP_CANCELLED, DISMISS_INVALID_INTENT,
|
||||
DISMISS_OVERFLOW_MAX_REACHED, DISMISS_SHORTCUT_REMOVED, DISMISS_PACKAGE_REMOVED,
|
||||
DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED})
|
||||
DISMISS_NO_BUBBLE_UP, DISMISS_RELOAD_FROM_DISK, DISMISS_USER_REMOVED,
|
||||
DISMISS_SWITCH_TO_STACK})
|
||||
@Target({FIELD, LOCAL_VARIABLE, PARAMETER})
|
||||
@interface DismissReason {}
|
||||
@interface DismissReason {
|
||||
}
|
||||
|
||||
int DISMISS_USER_GESTURE = 1;
|
||||
int DISMISS_AGED = 2;
|
||||
@@ -80,6 +82,7 @@ public interface Bubbles {
|
||||
int DISMISS_NO_BUBBLE_UP = 14;
|
||||
int DISMISS_RELOAD_FROM_DISK = 15;
|
||||
int DISMISS_USER_REMOVED = 16;
|
||||
int DISMISS_SWITCH_TO_STACK = 17;
|
||||
|
||||
/** Returns a binder that can be passed to an external process to manipulate Bubbles. */
|
||||
default IBubbles createExternalInterface() {
|
||||
@@ -120,8 +123,8 @@ public interface Bubbles {
|
||||
|
||||
/**
|
||||
* This method has different behavior depending on:
|
||||
* - if an app bubble exists
|
||||
* - if an app bubble is expanded
|
||||
* - if an app bubble exists
|
||||
* - if an app bubble is expanded
|
||||
*
|
||||
* If no app bubble exists, this will add and expand a bubble with the provided intent. The
|
||||
* intent must be explicit (i.e. include a package name or fully qualified component class name)
|
||||
@@ -135,13 +138,13 @@ public interface Bubbles {
|
||||
* the bubble or bubble stack.
|
||||
*
|
||||
* Some notes:
|
||||
* - Only one app bubble is supported at a time, regardless of users. Multi-users support is
|
||||
* tracked in b/273533235.
|
||||
* - Calling this method with a different intent than the existing app bubble will do nothing
|
||||
* - Only one app bubble is supported at a time, regardless of users. Multi-users support is
|
||||
* tracked in b/273533235.
|
||||
* - Calling this method with a different intent than the existing app bubble will do nothing
|
||||
*
|
||||
* @param intent the intent to display in the bubble expanded view.
|
||||
* @param user the {@link UserHandle} of the user to start this activity for.
|
||||
* @param icon the {@link Icon} to use for the bubble view.
|
||||
* @param user the {@link UserHandle} of the user to start this activity for.
|
||||
* @param icon the {@link Icon} to use for the bubble view.
|
||||
*/
|
||||
void showOrHideAppBubble(Intent intent, UserHandle user, @Nullable Icon icon);
|
||||
|
||||
@@ -172,13 +175,12 @@ public interface Bubbles {
|
||||
* {@link Bubble#setSuppressNotification}. For the case of suppressed summaries, we also add
|
||||
* {@link BubbleData#addSummaryToSuppress}.
|
||||
*
|
||||
* @param entry the notification of the BubbleEntry should be removed.
|
||||
* @param children the list of child notification of the BubbleEntry from 1st param entry,
|
||||
* this will be null if entry does have no children.
|
||||
* @param entry the notification of the BubbleEntry should be removed.
|
||||
* @param children the list of child notification of the BubbleEntry from 1st param entry,
|
||||
* this will be null if entry does have no children.
|
||||
* @param removeCallback the remove callback for SystemUI side to remove notification, the int
|
||||
* number should be list position of children list and use -1 for
|
||||
* removing the parent notification.
|
||||
*
|
||||
* @return true if we want to intercept the dismissal of the entry, else false.
|
||||
*/
|
||||
boolean handleDismissalInterception(BubbleEntry entry, @Nullable List<BubbleEntry> children,
|
||||
@@ -200,9 +202,9 @@ public interface Bubbles {
|
||||
/**
|
||||
* Called when new notification entry updated.
|
||||
*
|
||||
* @param entry the {@link BubbleEntry} by the notification.
|
||||
* @param entry the {@link BubbleEntry} by the notification.
|
||||
* @param shouldBubbleUp {@code true} if this notification should bubble up.
|
||||
* @param fromSystem {@code true} if this update is from NotificationManagerService.
|
||||
* @param fromSystem {@code true} if this update is from NotificationManagerService.
|
||||
*/
|
||||
void onEntryUpdated(BubbleEntry entry, boolean shouldBubbleUp, boolean fromSystem);
|
||||
|
||||
@@ -218,7 +220,7 @@ public interface Bubbles {
|
||||
* filtering and sorting. This is used to dismiss or create bubbles based on changes in
|
||||
* permissions on the notification channel or the global setting.
|
||||
*
|
||||
* @param rankingMap the updated ranking map from NotificationListenerService
|
||||
* @param rankingMap the updated ranking map from NotificationListenerService
|
||||
* @param entryDataByKey a map of ranking key to bubble entry and whether the entry should
|
||||
* bubble up
|
||||
*/
|
||||
@@ -230,9 +232,9 @@ public interface Bubbles {
|
||||
* Called when a notification channel is modified, in response to
|
||||
* {@link NotificationListenerService#onNotificationChannelModified}.
|
||||
*
|
||||
* @param pkg the package the notification channel belongs to.
|
||||
* @param user the user the notification channel belongs to.
|
||||
* @param channel the channel being modified.
|
||||
* @param pkg the package the notification channel belongs to.
|
||||
* @param user the user the notification channel belongs to.
|
||||
* @param channel the channel being modified.
|
||||
* @param modificationType the type of modification that occurred to the channel.
|
||||
*/
|
||||
void onNotificationChannelModified(
|
||||
@@ -300,7 +302,7 @@ public interface Bubbles {
|
||||
* Called when the expansion state of the bubble stack changes.
|
||||
*
|
||||
* @param isExpanding whether it's expanding or collapsing
|
||||
* @param key the notification key associated with bubble being expanded
|
||||
* @param key the notification key associated with bubble being expanded
|
||||
*/
|
||||
void onBubbleExpandChanged(boolean isExpanding, String key);
|
||||
}
|
||||
|
||||
@@ -35,6 +35,4 @@ interface IBubbles {
|
||||
|
||||
oneway void collapseBubbles() = 5;
|
||||
|
||||
oneway void onTaskbarStateChanged(in int newState) = 6;
|
||||
|
||||
}
|
||||
@@ -327,6 +327,12 @@ public class PhysicsAnimationLayout extends FrameLayout {
|
||||
addViewInternal(child, index, params, false /* isReorder */);
|
||||
}
|
||||
|
||||
/** Removes the child view immediately. */
|
||||
public void removeViewNoAnimation(View view) {
|
||||
super.removeView(view);
|
||||
view.setTag(R.id.physics_animator_tag, null);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeView(View view) {
|
||||
if (mController != null) {
|
||||
|
||||
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.wm.shell.bubbles.properties
|
||||
|
||||
/**
|
||||
* An interface for exposing bubble properties via flags which can be controlled easily in tests.
|
||||
*/
|
||||
interface BubbleProperties {
|
||||
/**
|
||||
* Whether bubble bar is enabled.
|
||||
*
|
||||
* When this is `true`, depending on additional factors, such as screen size and taskbar state,
|
||||
* bubbles will be displayed in the bubble bar instead of floating.
|
||||
*
|
||||
* When this is `false`, bubbles will be floating.
|
||||
*/
|
||||
val isBubbleBarEnabled: Boolean
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
/*
|
||||
* 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.wm.shell.bubbles.properties
|
||||
|
||||
import android.os.SystemProperties
|
||||
|
||||
/** Provides bubble properties in production. */
|
||||
object ProdBubbleProperties : BubbleProperties {
|
||||
|
||||
// TODO(b/256873975) Should use proper flag when available to shell/launcher
|
||||
override val isBubbleBarEnabled =
|
||||
SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false)
|
||||
}
|
||||
@@ -36,6 +36,7 @@ import com.android.wm.shell.bubbles.BubbleData;
|
||||
import com.android.wm.shell.bubbles.BubbleDataRepository;
|
||||
import com.android.wm.shell.bubbles.BubbleLogger;
|
||||
import com.android.wm.shell.bubbles.BubblePositioner;
|
||||
import com.android.wm.shell.bubbles.properties.ProdBubbleProperties;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.DisplayImeController;
|
||||
import com.android.wm.shell.common.DisplayInsetsController;
|
||||
@@ -187,7 +188,7 @@ public abstract class WMShellModule {
|
||||
statusBarService, windowManager, windowManagerShellWrapper, userManager,
|
||||
launcherApps, logger, taskStackListener, organizer, positioner, displayController,
|
||||
oneHandedOptional, dragAndDropController, mainExecutor, mainHandler, bgExecutor,
|
||||
taskViewTransitions, syncQueue, wmService);
|
||||
taskViewTransitions, syncQueue, wmService, ProdBubbleProperties.INSTANCE);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -219,12 +220,12 @@ public abstract class WMShellModule {
|
||||
desktopTasksController);
|
||||
}
|
||||
return new CaptionWindowDecorViewModel(
|
||||
context,
|
||||
mainHandler,
|
||||
mainChoreographer,
|
||||
taskOrganizer,
|
||||
displayController,
|
||||
syncQueue);
|
||||
context,
|
||||
mainHandler,
|
||||
mainChoreographer,
|
||||
taskOrganizer,
|
||||
displayController,
|
||||
syncQueue);
|
||||
}
|
||||
|
||||
//
|
||||
@@ -584,13 +585,13 @@ public abstract class WMShellModule {
|
||||
animators.add(fullscreenAnimator);
|
||||
|
||||
return new UnfoldAnimationController(
|
||||
shellInit,
|
||||
transactionPool,
|
||||
progressProvider.get(),
|
||||
animators,
|
||||
unfoldTransitionHandler,
|
||||
mainExecutor
|
||||
);
|
||||
shellInit,
|
||||
transactionPool,
|
||||
progressProvider.get(),
|
||||
animators,
|
||||
unfoldTransitionHandler,
|
||||
mainExecutor
|
||||
);
|
||||
}
|
||||
|
||||
@Provides
|
||||
|
||||
@@ -137,11 +137,13 @@ import com.android.wm.shell.bubbles.BubbleStackView;
|
||||
import com.android.wm.shell.bubbles.BubbleViewInfoTask;
|
||||
import com.android.wm.shell.bubbles.Bubbles;
|
||||
import com.android.wm.shell.bubbles.StackEducationViewKt;
|
||||
import com.android.wm.shell.bubbles.properties.BubbleProperties;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
import com.android.wm.shell.common.SyncTransactionQueue;
|
||||
import com.android.wm.shell.common.TaskStackListenerImpl;
|
||||
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
|
||||
import com.android.wm.shell.draganddrop.DragAndDropController;
|
||||
import com.android.wm.shell.onehanded.OneHandedController;
|
||||
import com.android.wm.shell.sysui.ShellCommandHandler;
|
||||
@@ -299,6 +301,8 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
private UserHandle mUser0;
|
||||
|
||||
private FakeBubbleProperties mBubbleProperties;
|
||||
|
||||
@Before
|
||||
public void setUp() throws Exception {
|
||||
MockitoAnnotations.initMocks(this);
|
||||
@@ -360,6 +364,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mock(UserTracker.class)
|
||||
);
|
||||
when(mShellTaskOrganizer.getExecutor()).thenReturn(syncExecutor);
|
||||
mBubbleProperties = new FakeBubbleProperties();
|
||||
mBubbleController = new TestableBubbleController(
|
||||
mContext,
|
||||
mShellInit,
|
||||
@@ -384,7 +389,8 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mock(Handler.class),
|
||||
mTaskViewTransitions,
|
||||
mock(SyncTransactionQueue.class),
|
||||
mock(IWindowManager.class));
|
||||
mock(IWindowManager.class),
|
||||
mBubbleProperties);
|
||||
mBubbleController.setExpandListener(mBubbleExpandListener);
|
||||
spyOn(mBubbleController);
|
||||
|
||||
@@ -475,7 +481,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
public void testAddBubble() {
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -483,7 +489,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -498,7 +504,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
verify(mNotifCallback, times(2)).invalidateNotifications(anyString());
|
||||
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -561,7 +567,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow.getKey()));
|
||||
assertNull(mBubbleData.getBubbleInStackWithKey(mRow2.getKey()));
|
||||
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -580,7 +586,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Make sure the notif is suppressed
|
||||
assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
|
||||
@@ -589,7 +595,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleController.collapseStack();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertStackCollapsed();
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -611,7 +617,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertStackExpanded();
|
||||
verify(mBubbleExpandListener, atLeastOnce()).onBubbleExpandChanged(
|
||||
true, mRow2.getKey());
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Last added is the one that is expanded
|
||||
assertEquals(mRow2.getKey(), mBubbleData.getSelectedBubble().getKey());
|
||||
@@ -636,7 +642,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
// Collapse
|
||||
mBubbleController.collapseStack();
|
||||
assertStackCollapsed();
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -656,7 +662,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
|
||||
@@ -681,7 +687,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Notif is suppressed after expansion
|
||||
assertBubbleNotificationSuppressedFromShade(mBubbleEntry);
|
||||
@@ -710,7 +716,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
assertStackExpanded();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow2.getKey());
|
||||
@@ -741,7 +747,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
// We should be collapsed
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -754,7 +760,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
assertStackExpanded();
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true, mRow.getKey());
|
||||
|
||||
@@ -769,7 +775,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
// We should be collapsed
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(false, mRow.getKey());
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
|
||||
@@ -787,7 +793,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
verify(mBubbleExpandListener, never()).onBubbleExpandChanged(false /* expanded */,
|
||||
mRow.getKey());
|
||||
assertStackCollapsed();
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -803,7 +809,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
verify(mBubbleExpandListener).onBubbleExpandChanged(true /* expanded */,
|
||||
mRow.getKey());
|
||||
assertStackExpanded();
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -820,7 +826,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -842,7 +848,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
// Dot + flyout is hidden because notif is suppressed
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showDot());
|
||||
assertFalse(mBubbleData.getBubbleInStackWithKey(mRow.getKey()).showFlyout());
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1247,11 +1253,11 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Show the menu
|
||||
stackView.showManageMenu(true);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
|
||||
assertTrue(stackView.isManageMenuSettingsVisible());
|
||||
assertTrue(stackView.isManageMenuDontBubbleVisible());
|
||||
}
|
||||
@@ -1265,11 +1271,11 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Show the menu
|
||||
stackView.showManageMenu(true);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
|
||||
assertFalse(stackView.isManageMenuSettingsVisible());
|
||||
assertFalse(stackView.isManageMenuDontBubbleVisible());
|
||||
}
|
||||
@@ -1283,15 +1289,15 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Show the menu
|
||||
stackView.showManageMenu(true);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
|
||||
|
||||
// Hide the menu
|
||||
stackView.showManageMenu(false);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1303,16 +1309,16 @@ public class BubblesTest extends SysuiTestCase {
|
||||
BubbleStackView stackView = mBubbleController.getStackView();
|
||||
mBubbleData.setExpanded(true);
|
||||
assertStackExpanded();
|
||||
assertSysuiStates(true /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
|
||||
// Show the menu
|
||||
stackView.showManageMenu(true);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* mangeMenuExpanded */);
|
||||
assertSysuiStates(true /* stackExpanded */, true /* manageMenuExpanded */);
|
||||
|
||||
// Collapse the stack
|
||||
mBubbleData.setExpanded(false);
|
||||
|
||||
assertSysuiStates(false /* stackExpanded */, false /* mangeMenuExpanded */);
|
||||
assertSysuiStates(false /* stackExpanded */, false /* manageMenuExpanded */);
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -1574,7 +1580,7 @@ public class BubblesTest extends SysuiTestCase {
|
||||
|
||||
NotificationListenerService.RankingMap rankingMap =
|
||||
mock(NotificationListenerService.RankingMap.class);
|
||||
when(rankingMap.getOrderedKeys()).thenReturn(new String[] { mBubbleEntry.getKey() });
|
||||
when(rankingMap.getOrderedKeys()).thenReturn(new String[]{mBubbleEntry.getKey()});
|
||||
mBubbleController.onRankingUpdated(rankingMap, entryDataByKey);
|
||||
|
||||
// Should no longer be in the stack
|
||||
@@ -1882,7 +1888,108 @@ public class BubblesTest extends SysuiTestCase {
|
||||
);
|
||||
}
|
||||
|
||||
/** Creates a bubble using the userId and package. */
|
||||
@Test
|
||||
public void registerBubbleBarListener_barDisabled_largeScreen_shouldBeIgnored() {
|
||||
mBubbleProperties.mIsBubbleBarEnabled = false;
|
||||
mPositioner.setIsLargeScreen(true);
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
assertStackMode();
|
||||
|
||||
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
|
||||
mBubbleController.registerBubbleStateListener(bubbleStateListener);
|
||||
|
||||
assertStackMode();
|
||||
|
||||
assertThat(mBubbleController.getStackView().getBubbleCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerBubbleBarListener_barEnabled_smallScreen_shouldBeIgnored() {
|
||||
mBubbleProperties.mIsBubbleBarEnabled = true;
|
||||
mPositioner.setIsLargeScreen(false);
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
assertStackMode();
|
||||
|
||||
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
|
||||
mBubbleController.registerBubbleStateListener(bubbleStateListener);
|
||||
|
||||
assertStackMode();
|
||||
|
||||
assertThat(mBubbleController.getStackView().getBubbleCount()).isEqualTo(1);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void registerBubbleBarListener_switchToBarAndBackToStack() {
|
||||
mBubbleProperties.mIsBubbleBarEnabled = true;
|
||||
mPositioner.setIsLargeScreen(true);
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
assertTrue(mBubbleController.hasBubbles());
|
||||
|
||||
assertStackMode();
|
||||
|
||||
assertThat(mBubbleData.getBubbles()).hasSize(1);
|
||||
assertBubbleIsInflatedForStack(mBubbleData.getBubbles().get(0));
|
||||
|
||||
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
|
||||
mBubbleController.registerBubbleStateListener(bubbleStateListener);
|
||||
|
||||
assertBarMode();
|
||||
|
||||
assertThat(mBubbleData.getBubbles()).hasSize(1);
|
||||
assertBubbleIsInflatedForBar(mBubbleData.getBubbles().get(0));
|
||||
|
||||
mBubbleController.unregisterBubbleStateListener();
|
||||
|
||||
assertStackMode();
|
||||
|
||||
assertThat(mBubbleData.getBubbles()).hasSize(1);
|
||||
assertBubbleIsInflatedForStack(mBubbleData.getBubbles().get(0));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void switchBetweenBarAndStack_noBubbles_shouldBeIgnored() {
|
||||
mBubbleProperties.mIsBubbleBarEnabled = false;
|
||||
mPositioner.setIsLargeScreen(true);
|
||||
assertFalse(mBubbleController.hasBubbles());
|
||||
|
||||
assertNoBubbleContainerViews();
|
||||
|
||||
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
|
||||
mBubbleController.registerBubbleStateListener(bubbleStateListener);
|
||||
|
||||
assertNoBubbleContainerViews();
|
||||
|
||||
mBubbleController.unregisterBubbleStateListener();
|
||||
|
||||
assertNoBubbleContainerViews();
|
||||
}
|
||||
|
||||
@Test
|
||||
public void bubbleBarBubbleExpandedAndCollapsed() {
|
||||
mBubbleProperties.mIsBubbleBarEnabled = true;
|
||||
mPositioner.setIsLargeScreen(true);
|
||||
mEntryListener.onEntryAdded(mRow);
|
||||
mBubbleController.updateBubble(mBubbleEntry);
|
||||
|
||||
FakeBubbleStateListener bubbleStateListener = new FakeBubbleStateListener();
|
||||
mBubbleController.registerBubbleStateListener(bubbleStateListener);
|
||||
mBubbleController.expandStackAndSelectBubbleFromLauncher(mBubbleEntry.getKey(), true);
|
||||
|
||||
assertThat(mBubbleController.getLayerView().isExpanded()).isTrue();
|
||||
|
||||
mBubbleController.collapseStack();
|
||||
|
||||
assertThat(mBubbleController.getLayerView().isExpanded()).isFalse();
|
||||
}
|
||||
|
||||
/** Creates a bubble using the userId and package. */
|
||||
private Bubble createBubble(int userId, String pkg) {
|
||||
final UserHandle userHandle = new UserHandle(userId);
|
||||
NotificationEntry workEntry = new NotificationEntryBuilder()
|
||||
@@ -1998,6 +2105,38 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertFalse(mBubbleController.getImplCachedState().isStackExpanded());
|
||||
}
|
||||
|
||||
/** Asserts that both the bubble stack and bar views don't exist. */
|
||||
private void assertNoBubbleContainerViews() {
|
||||
assertThat(mBubbleController.getStackView()).isNull();
|
||||
assertThat(mBubbleController.getLayerView()).isNull();
|
||||
}
|
||||
|
||||
/** Asserts that the stack is created and the bar is null. */
|
||||
private void assertStackMode() {
|
||||
assertThat(mBubbleController.getStackView()).isNotNull();
|
||||
assertThat(mBubbleController.getLayerView()).isNull();
|
||||
}
|
||||
|
||||
/** Asserts that the given bubble has the stack expanded view inflated. */
|
||||
private void assertBubbleIsInflatedForStack(Bubble b) {
|
||||
assertThat(b.getIconView()).isNotNull();
|
||||
assertThat(b.getExpandedView()).isNotNull();
|
||||
assertThat(b.getBubbleBarExpandedView()).isNull();
|
||||
}
|
||||
|
||||
/** Asserts that the bar is created and the stack is null. */
|
||||
private void assertBarMode() {
|
||||
assertThat(mBubbleController.getStackView()).isNull();
|
||||
assertThat(mBubbleController.getLayerView()).isNotNull();
|
||||
}
|
||||
|
||||
/** Asserts that the given bubble has the bar expanded view inflated. */
|
||||
private void assertBubbleIsInflatedForBar(Bubble b) {
|
||||
assertThat(b.getIconView()).isNull();
|
||||
assertThat(b.getExpandedView()).isNull();
|
||||
assertThat(b.getBubbleBarExpandedView()).isNotNull();
|
||||
}
|
||||
|
||||
/**
|
||||
* Asserts that a bubble notification is suppressed from the shade and also validates the cached
|
||||
* state is updated.
|
||||
@@ -2027,4 +2166,19 @@ public class BubblesTest extends SysuiTestCase {
|
||||
assertThat(mSysUiStateBubblesExpanded).isEqualTo(stackExpanded);
|
||||
assertThat(mSysUiStateBubblesManageMenuExpanded).isEqualTo(manageMenuExpanded);
|
||||
}
|
||||
|
||||
private static class FakeBubbleStateListener implements Bubbles.BubbleStateListener {
|
||||
@Override
|
||||
public void onBubbleStateChange(BubbleBarUpdate update) {
|
||||
}
|
||||
}
|
||||
|
||||
private static class FakeBubbleProperties implements BubbleProperties {
|
||||
boolean mIsBubbleBarEnabled = false;
|
||||
|
||||
@Override
|
||||
public boolean isBubbleBarEnabled() {
|
||||
return mIsBubbleBarEnabled;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -31,6 +31,7 @@ import com.android.wm.shell.bubbles.BubbleData;
|
||||
import com.android.wm.shell.bubbles.BubbleDataRepository;
|
||||
import com.android.wm.shell.bubbles.BubbleLogger;
|
||||
import com.android.wm.shell.bubbles.BubblePositioner;
|
||||
import com.android.wm.shell.bubbles.properties.BubbleProperties;
|
||||
import com.android.wm.shell.common.DisplayController;
|
||||
import com.android.wm.shell.common.FloatingContentCoordinator;
|
||||
import com.android.wm.shell.common.ShellExecutor;
|
||||
@@ -74,13 +75,14 @@ public class TestableBubbleController extends BubbleController {
|
||||
Handler shellMainHandler,
|
||||
TaskViewTransitions taskViewTransitions,
|
||||
SyncTransactionQueue syncQueue,
|
||||
IWindowManager wmService) {
|
||||
IWindowManager wmService,
|
||||
BubbleProperties bubbleProperties) {
|
||||
super(context, shellInit, shellCommandHandler, shellController, data, Runnable::run,
|
||||
floatingContentCoordinator, dataRepository, statusBarService, windowManager,
|
||||
windowManagerShellWrapper, userManager, launcherApps, bubbleLogger,
|
||||
taskStackListener, shellTaskOrganizer, positioner, displayController,
|
||||
oneHandedOptional, dragAndDropController, shellMainExecutor, shellMainHandler,
|
||||
new SyncExecutor(), taskViewTransitions, syncQueue, wmService);
|
||||
new SyncExecutor(), taskViewTransitions, syncQueue, wmService, bubbleProperties);
|
||||
setInflateSynchronously(true);
|
||||
onInit();
|
||||
}
|
||||
|
||||
@@ -27,6 +27,7 @@ import com.android.wm.shell.bubbles.BubblePositioner;
|
||||
|
||||
public class TestableBubblePositioner extends BubblePositioner {
|
||||
private int mMaxBubbles;
|
||||
private boolean mIsLargeScreen = false;
|
||||
|
||||
public TestableBubblePositioner(Context context,
|
||||
WindowManager windowManager) {
|
||||
@@ -46,4 +47,13 @@ public class TestableBubblePositioner extends BubblePositioner {
|
||||
public int getMaxBubbles() {
|
||||
return mMaxBubbles;
|
||||
}
|
||||
|
||||
public void setIsLargeScreen(boolean isLargeScreen) {
|
||||
mIsLargeScreen = isLargeScreen;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isLargeScreen() {
|
||||
return mIsLargeScreen;
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user