diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java index 3eb9fa2eef6b2..698681029595d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/BubbleController.java @@ -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 { 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 configuration, used to detect changes in + * {@link #onConfigurationChanged(Configuration)} + */ + private final Configuration mLastConfiguration = new Configuration(); - /** 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 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) { - if (mBubblePositioner != null) { - mBubblePositioner.update(); - } - if (mStackView != null && newConfig != null) { - if (newConfig.densityDpi != mDensityDpi - || !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().getColor(R.color.important_conversation), - mContext.getResources().getDimensionPixelSize( - com.android.internal.R.dimen.importance_ring_stroke_width)); - mStackView.onDisplaySizeChanged(); + 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 (newConfig.fontScale != mFontScale) { - mFontScale = newConfig.fontScale; - mStackView.updateFontScale(); + if (mBubblePositioner != null) { + mBubblePositioner.update(); } - if (newConfig.getLayoutDirection() != mLayoutDirection) { - mLayoutDirection = newConfig.getLayoutDirection(); - mStackView.onLayoutDirectionChanged(mLayoutDirection); + 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)) { + 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().getColor(R.color.important_conversation), + mContext.getResources().getDimensionPixelSize( + com.android.internal.R.dimen.importance_ring_stroke_width)); + mStackView.onDisplaySizeChanged(); + } + if (fontScaleChanged) { + mStackView.updateFontScale(); + } + 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) {