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

Commit 2c33f8d9 authored by Mady Mellor's avatar Mady Mellor Committed by Automerger Merge Worker
Browse files

Merge "Use ComponentCallbacks instead of ConfigurationChangeListener" into...

Merge "Use ComponentCallbacks instead of ConfigurationChangeListener" into udc-dev am: 3af5b545 am: f9bd1dd9

Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/23186046



Change-Id: I7eeea7a498e618b9f94c17aa9a3f64fd904de75c
Signed-off-by: default avatarAutomerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com>
parents d8a1acb4 f9bd1dd9
Loading
Loading
Loading
Loading
+80 −48
Original line number Diff line number Diff line
@@ -17,12 +17,18 @@
package com.android.wm.shell.bubbles;

import static android.app.ActivityTaskManager.INVALID_TASK_ID;
import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS;
import static android.content.pm.ActivityInfo.CONFIG_DENSITY;
import static android.content.pm.ActivityInfo.CONFIG_FONT_SCALE;
import static android.content.pm.ActivityInfo.CONFIG_LAYOUT_DIRECTION;
import static android.content.pm.ActivityInfo.CONFIG_UI_MODE;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_DELETED;
import static android.service.notification.NotificationListenerService.NOTIFICATION_CHANNEL_OR_GROUP_UPDATED;
import static android.service.notification.NotificationListenerService.REASON_CANCEL;
import static android.view.View.INVISIBLE;
import static android.view.View.VISIBLE;
import static android.view.WindowManager.LayoutParams.LAYOUT_IN_DISPLAY_CUTOUT_MODE_ALWAYS;
import static android.view.WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY;

import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_CONTROLLER;
import static com.android.wm.shell.bubbles.BubbleDebugConfig.DEBUG_BUBBLE_GESTURE;
@@ -47,6 +53,7 @@ import android.app.Notification;
import android.app.NotificationChannel;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ComponentCallbacks2;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
@@ -74,7 +81,6 @@ import android.util.Pair;
import android.util.SparseArray;
import android.view.IWindowManager;
import android.view.SurfaceControl;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewRootImpl;
import android.view.WindowInsets;
@@ -102,6 +108,7 @@ import com.android.wm.shell.common.SingleInstanceRemoteListener;
import com.android.wm.shell.common.SyncTransactionQueue;
import com.android.wm.shell.common.TaskStackListenerCallback;
import com.android.wm.shell.common.TaskStackListenerImpl;
import com.android.wm.shell.common.annotations.ExternalMainThread;
import com.android.wm.shell.common.annotations.ShellBackgroundThread;
import com.android.wm.shell.common.annotations.ShellMainThread;
import com.android.wm.shell.common.bubbles.BubbleBarUpdate;
@@ -109,7 +116,6 @@ import com.android.wm.shell.draganddrop.DragAndDropController;
import com.android.wm.shell.onehanded.OneHandedController;
import com.android.wm.shell.onehanded.OneHandedTransitionCallback;
import com.android.wm.shell.pip.PinnedStackListenerForwarder;
import com.android.wm.shell.sysui.ConfigurationChangeListener;
import com.android.wm.shell.sysui.ShellCommandHandler;
import com.android.wm.shell.sysui.ShellController;
import com.android.wm.shell.sysui.ShellInit;
@@ -135,7 +141,7 @@ import java.util.function.IntConsumer;
 *
 * The controller manages addition, removal, and visible state of bubbles on screen.
 */
public class BubbleController implements ConfigurationChangeListener,
public class BubbleController implements ComponentCallbacks2,
        RemoteCallable<BubbleController> {

    private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES;
@@ -153,7 +159,6 @@ public class BubbleController implements ConfigurationChangeListener,
    private static final boolean BUBBLE_BAR_ENABLED =
            SystemProperties.getBoolean("persist.wm.debug.bubble_bar", false);


    /**
     * Common interface to send updates to bubble views.
     */
@@ -237,17 +242,17 @@ public class BubbleController implements ConfigurationChangeListener,
    /** Whether or not the BubbleStackView has been added to the WindowManager. */
    private boolean mAddedToWindowManager = false;

    /** Saved screen density, used to detect display size changes in {@link #onConfigChanged}. */
    private int mDensityDpi = Configuration.DENSITY_DPI_UNDEFINED;

    /** Saved screen bounds, used to detect screen size changes in {@link #onConfigChanged}. **/
    private Rect mScreenBounds = new Rect();

    /** Saved font scale, used to detect font size changes in {@link #onConfigChanged}. */
    private float mFontScale = 0;
    /**
     * Saved configuration, used to detect changes in
     * {@link #onConfigurationChanged(Configuration)}
     */
    private final Configuration mLastConfiguration = new Configuration();

    /** Saved direction, used to detect layout direction changes @link #onConfigChanged}. */
    private int mLayoutDirection = View.LAYOUT_DIRECTION_UNDEFINED;
    /**
     * Saved screen bounds, used to detect screen size changes in
     * {@link #onConfigurationChanged(Configuration)}.
     */
    private final Rect mScreenBounds = new Rect();

    /** Saved insets, used to detect WindowInset changes. */
    private WindowInsets mWindowInsets;
@@ -293,7 +298,8 @@ public class BubbleController implements ConfigurationChangeListener,
            TaskViewTransitions taskViewTransitions,
            SyncTransactionQueue syncQueue,
            IWindowManager wmService) {
        mContext = context;
        mContext = context.createWindowContext(TYPE_APPLICATION_OVERLAY, null);
        mLastConfiguration.setTo(mContext.getResources().getConfiguration());
        mShellCommandHandler = shellCommandHandler;
        mShellController = shellController;
        mLauncherApps = launcherApps;
@@ -317,11 +323,11 @@ public class BubbleController implements ConfigurationChangeListener,
        mBubblePositioner = positioner;
        mBubbleData = data;
        mSavedUserBubbleData = new SparseArray<>();
        mBubbleIconFactory = new BubbleIconFactory(context,
                context.getResources().getDimensionPixelSize(R.dimen.bubble_size),
                context.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
                context.getResources().getColor(R.color.important_conversation),
                context.getResources().getDimensionPixelSize(
        mBubbleIconFactory = new BubbleIconFactory(mContext,
                mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
                mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
                mContext.getResources().getColor(R.color.important_conversation),
                mContext.getResources().getDimensionPixelSize(
                        com.android.internal.R.dimen.importance_ring_stroke_width));
        mDisplayController = displayController;
        mTaskViewTransitions = taskViewTransitions;
@@ -482,7 +488,6 @@ public class BubbleController implements ConfigurationChangeListener,
        }
        mCurrentProfiles = userProfiles;

        mShellController.addConfigurationChangeListener(this);
        mShellController.addExternalInterface(KEY_EXTRA_SHELL_BUBBLES,
                this::createExternalInterface, this);
        mShellCommandHandler.addDumpCallback(this::dump, this);
@@ -774,6 +779,7 @@ public class BubbleController implements ConfigurationChangeListener,
        try {
            mAddedToWindowManager = true;
            registerBroadcastReceiver();
            mContext.registerComponentCallbacks(this);
            mBubbleData.getOverflow().initialize(this);
            // (TODO: b/273314541) some duplication in the inset listener
            if (isShowingAsBubbleBar()) {
@@ -831,6 +837,7 @@ public class BubbleController implements ConfigurationChangeListener,
        // Put on background for this binder call, was causing jank
        mBackgroundExecutor.execute(() -> {
            try {
                mContext.unregisterComponentCallbacks(this);
                mContext.unregisterReceiver(mBroadcastReceiver);
            } catch (IllegalArgumentException e) {
                // Not sure if this happens in production, but was happening in tests
@@ -930,8 +937,7 @@ public class BubbleController implements ConfigurationChangeListener,
        mSavedUserBubbleData.remove(userId);
    }

    @Override
    public void onThemeChanged() {
    private void onThemeChanged() {
        if (mStackView != null) {
            mStackView.onThemeChanged();
        }
@@ -963,34 +969,60 @@ public class BubbleController implements ConfigurationChangeListener,
        }
    }

    // Note: Component callbacks are always called on the main thread of the process
    @ExternalMainThread
    @Override
    public void onConfigurationChanged(Configuration newConfig) {
        mMainExecutor.execute(() -> {
            final int diff = newConfig.diff(mLastConfiguration);
            final boolean themeChanged = (diff & CONFIG_ASSETS_PATHS) != 0
                    || (diff & CONFIG_UI_MODE) != 0;
            if (themeChanged) {
                onThemeChanged();
            }
            if (mBubblePositioner != null) {
                mBubblePositioner.update();
            }
        if (mStackView != null && newConfig != null) {
            if (newConfig.densityDpi != mDensityDpi
            if (mStackView != null) {
                final boolean densityChanged = (diff & CONFIG_DENSITY) != 0;
                final boolean fontScaleChanged = (diff & CONFIG_FONT_SCALE) != 0;
                final boolean layoutDirectionChanged = (diff & CONFIG_LAYOUT_DIRECTION) != 0;
                if (densityChanged
                        || !newConfig.windowConfiguration.getBounds().equals(mScreenBounds)) {
                mDensityDpi = newConfig.densityDpi;
                    mScreenBounds.set(newConfig.windowConfiguration.getBounds());
                    mBubbleData.onMaxBubblesChanged();
                    mBubbleIconFactory = new BubbleIconFactory(mContext,
                            mContext.getResources().getDimensionPixelSize(R.dimen.bubble_size),
                        mContext.getResources().getDimensionPixelSize(R.dimen.bubble_badge_size),
                            mContext.getResources().getDimensionPixelSize(
                                    R.dimen.bubble_badge_size),
                            mContext.getResources().getColor(R.color.important_conversation),
                            mContext.getResources().getDimensionPixelSize(
                                    com.android.internal.R.dimen.importance_ring_stroke_width));
                    mStackView.onDisplaySizeChanged();
                }
            if (newConfig.fontScale != mFontScale) {
                mFontScale = newConfig.fontScale;
                if (fontScaleChanged) {
                    mStackView.updateFontScale();
                }
            if (newConfig.getLayoutDirection() != mLayoutDirection) {
                mLayoutDirection = newConfig.getLayoutDirection();
                mStackView.onLayoutDirectionChanged(mLayoutDirection);
                if (layoutDirectionChanged) {
                    mStackView.onLayoutDirectionChanged(newConfig.getLayoutDirection());
                }
            }
            mLastConfiguration.setTo(newConfig);
        });
    }

    // Note: Component callbacks are always called on the main thread of the process
    @ExternalMainThread
    @Override
    public void onTrimMemory(int level) {
        // Do nothing
    }

    // Note: Component callbacks are always called on the main thread of the process
    @ExternalMainThread
    @Override
    public void onLowMemory() {
        // Do nothing
    }

    private void onNotificationPanelExpandedChanged(boolean expanded) {
+44 −21
Original line number Diff line number Diff line
@@ -300,6 +300,10 @@ public class BubblesTest extends SysuiTestCase {

    private UserHandle mUser0;

    // The window context being used by the controller, use this to verify
    // any actions on the context.
    private Context mBubbleControllerContext;

    @Before
    public void setUp() throws Exception {
        MockitoAnnotations.initMocks(this);
@@ -436,6 +440,8 @@ public class BubblesTest extends SysuiTestCase {
        // Get a reference to KeyguardStateController.Callback
        verify(mKeyguardStateController, atLeastOnce())
                .addCallback(mKeyguardStateControllerCallbackCaptor.capture());

        mBubbleControllerContext = mBubbleController.getContext();
    }

    @After
@@ -467,11 +473,6 @@ public class BubblesTest extends SysuiTestCase {
        verify(mShellInit, times(1)).addInitCallback(any(), any());
    }

    @Test
    public void instantiateController_registerConfigChangeListener() {
        verify(mShellController, times(1)).addConfigurationChangeListener(any());
    }

    @Test
    public void testAddBubble() {
        mBubbleController.updateBubble(mBubbleEntry);
@@ -1385,13 +1386,28 @@ public class BubblesTest extends SysuiTestCase {
        assertStackCollapsed();
    }

    @Test
    public void testRegisterUnregisterComponentCallbacks() {
        spyOn(mBubbleControllerContext);
        mBubbleController.updateBubble(mBubbleEntry);
        verify(mBubbleControllerContext).registerComponentCallbacks(eq(mBubbleController));

        mBubbleData.dismissBubbleWithKey(mBubbleEntry.getKey(), REASON_APP_CANCEL);
        // TODO: not certain why this isn't called normally when tests are run, perhaps because
        // it's after an animation in BSV. This calls BubbleController#removeFromWindowManagerMaybe
        mBubbleController.onAllBubblesAnimatedOut();

        verify(mBubbleControllerContext).unregisterComponentCallbacks(eq(mBubbleController));
    }

    @Test
    public void testRegisterUnregisterBroadcastListener() {
        spyOn(mContext);
        spyOn(mBubbleControllerContext);
        mBubbleController.updateBubble(mBubbleEntry);
        verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(), eq(Context.RECEIVER_EXPORTED));
        verify(mBubbleControllerContext).registerReceiver(
                mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(),
                eq(Context.RECEIVER_EXPORTED));
        assertThat(mFilterArgumentCaptor.getValue()
                .hasAction(Intent.ACTION_CLOSE_SYSTEM_DIALOGS)).isTrue();
        assertThat(mFilterArgumentCaptor.getValue()
@@ -1402,47 +1418,54 @@ public class BubblesTest extends SysuiTestCase {
        // it's after an animation in BSV. This calls BubbleController#removeFromWindowManagerMaybe
        mBubbleController.onAllBubblesAnimatedOut();

        verify(mContext).unregisterReceiver(eq(mBroadcastReceiverArgumentCaptor.getValue()));
        verify(mBubbleControllerContext).unregisterReceiver(
                eq(mBroadcastReceiverArgumentCaptor.getValue()));
    }

    @Test
    public void testBroadcastReceiverCloseDialogs_notGestureNav() {
        spyOn(mContext);
        spyOn(mBubbleControllerContext);
        mBubbleController.updateBubble(mBubbleEntry);
        mBubbleData.setExpanded(true);
        verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(), eq(Context.RECEIVER_EXPORTED));
        verify(mBubbleControllerContext).registerReceiver(
                mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(),
                eq(Context.RECEIVER_EXPORTED));
        Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mBubbleControllerContext, i);

        assertStackExpanded();
    }

    @Test
    public void testBroadcastReceiverCloseDialogs_reasonGestureNav() {
        spyOn(mContext);
        spyOn(mBubbleControllerContext);
        mBubbleController.updateBubble(mBubbleEntry);
        mBubbleData.setExpanded(true);

        verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(), eq(Context.RECEIVER_EXPORTED));
        verify(mBubbleControllerContext).registerReceiver(
                mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(),
                eq(Context.RECEIVER_EXPORTED));
        Intent i = new Intent(Intent.ACTION_CLOSE_SYSTEM_DIALOGS);
        i.putExtra("reason", "gestureNav");
        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mBubbleControllerContext, i);
        assertStackCollapsed();
    }

    @Test
    public void testBroadcastReceiver_screenOff() {
        spyOn(mContext);
        spyOn(mBubbleControllerContext);
        mBubbleController.updateBubble(mBubbleEntry);
        mBubbleData.setExpanded(true);

        verify(mContext).registerReceiver(mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(), eq(Context.RECEIVER_EXPORTED));
        verify(mBubbleControllerContext).registerReceiver(
                mBroadcastReceiverArgumentCaptor.capture(),
                mFilterArgumentCaptor.capture(),
                eq(Context.RECEIVER_EXPORTED));

        Intent i = new Intent(Intent.ACTION_SCREEN_OFF);
        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mContext, i);
        mBroadcastReceiverArgumentCaptor.getValue().onReceive(mBubbleControllerContext, i);
        assertStackCollapsed();
    }

+5 −0
Original line number Diff line number Diff line
@@ -19,6 +19,7 @@ import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.hardware.display.DisplayManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.UserHandle;
import android.testing.LeakCheck;
@@ -62,6 +63,10 @@ public class SysuiTestableContext extends TestableContext {
        return (SysuiTestableContext) createDisplayContext(display);
    }

    public SysuiTestableContext createWindowContext(int type, Bundle bundle) {
        return new SysuiTestableContext(getBaseContext().createWindowContext(type, bundle));
    }

    public void cleanUpReceivers(String testName) {
        Set<BroadcastReceiver> copy;
        synchronized (mRegisteredReceivers) {