Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 815722a7 authored by Liran Binyamin's avatar Liran Binyamin
Browse files

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
parent 4b3863df
Loading
Loading
Loading
Loading
+4 −3
Original line number Diff line number Diff line
@@ -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) {
+85 −35
Original line number Diff line number Diff line
@@ -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() {
        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 {
+16 −0
Original line number Diff line number Diff line
@@ -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.
     */
+22 −20
Original line number Diff line number Diff line
@@ -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() {
@@ -178,7 +181,6 @@ public interface Bubbles {
     * @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,
+0 −2
Original line number Diff line number Diff line
@@ -35,6 +35,4 @@ interface IBubbles {

    oneway void collapseBubbles() = 5;

    oneway void onTaskbarStateChanged(in int newState) = 6;

}
 No newline at end of file
Loading