diff options
Diffstat (limited to 'libs')
25 files changed, 692 insertions, 185 deletions
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 62aa7fe28728..d7f1292cb717 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 @@ -101,6 +101,8 @@ 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.ShellController; import java.io.PrintWriter; import java.util.ArrayList; @@ -119,7 +121,7 @@ import java.util.function.IntConsumer; * * The controller manages addition, removal, and visible state of bubbles on screen. */ -public class BubbleController { +public class BubbleController implements ConfigurationChangeListener { private static final String TAG = TAG_WITH_CLASS_NAME ? "BubbleController" : TAG_BUBBLES; @@ -155,6 +157,7 @@ public class BubbleController { private final DisplayController mDisplayController; private final TaskViewTransitions mTaskViewTransitions; private final SyncTransactionQueue mSyncQueue; + private final ShellController mShellController; // Used to post to main UI thread private final ShellExecutor mMainExecutor; @@ -224,6 +227,7 @@ public class BubbleController { public BubbleController(Context context, + ShellController shellController, BubbleData data, @Nullable BubbleStackView.SurfaceSynchronizer synchronizer, FloatingContentCoordinator floatingContentCoordinator, @@ -246,6 +250,7 @@ public class BubbleController { TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { mContext = context; + mShellController = shellController; mLauncherApps = launcherApps; mBarService = statusBarService == null ? IStatusBarService.Stub.asInterface( @@ -414,6 +419,8 @@ public class BubbleController { // Clear out any persisted bubbles on disk that no longer have a valid user. List<UserInfo> users = mUserManager.getAliveUsers(); mDataRepository.sanitizeBubbles(users); + + mShellController.addConfigurationChangeListener(this); } @VisibleForTesting @@ -798,7 +805,8 @@ public class BubbleController { mSavedBubbleKeysPerUser.remove(userId); } - private void updateForThemeChanges() { + @Override + public void onThemeChanged() { if (mStackView != null) { mStackView.onThemeChanged(); } @@ -818,7 +826,8 @@ public class BubbleController { } } - private void onConfigChanged(Configuration newConfig) { + @Override + public void onConfigurationChanged(Configuration newConfig) { if (mBubblePositioner != null) { mBubblePositioner.update(); } @@ -1678,13 +1687,6 @@ public class BubbleController { } @Override - public void updateForThemeChanges() { - mMainExecutor.execute(() -> { - BubbleController.this.updateForThemeChanges(); - }); - } - - @Override public void expandStackAndSelectBubble(BubbleEntry entry) { mMainExecutor.execute(() -> { BubbleController.this.expandStackAndSelectBubble(entry); @@ -1823,13 +1825,6 @@ public class BubbleController { } @Override - public void onConfigChanged(Configuration newConfig) { - mMainExecutor.execute(() -> { - BubbleController.this.onConfigChanged(newConfig); - }); - } - - @Override public void onNotificationPanelExpandedChanged(boolean expanded) { mMainExecutor.execute( () -> BubbleController.this.onNotificationPanelExpandedChanged(expanded)); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java index 0072da19b9ef..f8ccf2364b4c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/bubbles/Bubbles.java @@ -107,9 +107,6 @@ public interface Bubbles { /** Tell the stack of bubbles to collapse. */ void collapseStack(); - /** Tell the controller need update its UI to fit theme. */ - void updateForThemeChanges(); - /** * Request the stack expand if needed, then select the specified Bubble as current. * If no bubble exists for this entry, one is created. @@ -255,13 +252,6 @@ public interface Bubbles { */ void onUserRemoved(int removedUserId); - /** - * Called when config changed. - * - * @param newConfig the new config. - */ - void onConfigChanged(Configuration newConfig); - /** Description of current bubble state. */ void dump(PrintWriter pw, String[] args); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java index 1ea5e21a2c1e..81904e291ad1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/TvPipModule.java @@ -48,6 +48,7 @@ import com.android.wm.shell.pip.tv.TvPipNotificationController; import com.android.wm.shell.pip.tv.TvPipTaskOrganizer; import com.android.wm.shell.pip.tv.TvPipTransition; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.transition.Transitions; import java.util.Optional; @@ -64,6 +65,7 @@ public abstract class TvPipModule { @Provides static Optional<Pip> providePip( Context context, + ShellController shellController, TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, @@ -81,6 +83,7 @@ public abstract class TvPipModule { return Optional.of( TvPipController.create( context, + shellController, tvPipBoundsState, tvPipBoundsAlgorithm, tvPipBoundsController, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java index 2ea111b113d8..511c46c23e5a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellBaseModule.java @@ -82,6 +82,8 @@ import com.android.wm.shell.startingsurface.StartingSurface; import com.android.wm.shell.startingsurface.StartingWindowController; import com.android.wm.shell.startingsurface.StartingWindowTypeAlgorithm; import com.android.wm.shell.startingsurface.phone.PhoneStartingWindowTypeAlgorithm; +import com.android.wm.shell.sysui.ShellController; +import com.android.wm.shell.sysui.ShellInterface; import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelper; import com.android.wm.shell.tasksurfacehelper.TaskSurfaceHelperController; import com.android.wm.shell.transition.ShellTransitions; @@ -159,10 +161,13 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static DragAndDropController provideDragAndDropController(Context context, - DisplayController displayController, UiEventLogger uiEventLogger, - IconProvider iconProvider, @ShellMainThread ShellExecutor mainExecutor) { - return new DragAndDropController(context, displayController, uiEventLogger, iconProvider, - mainExecutor); + ShellController shellController, + DisplayController displayController, + UiEventLogger uiEventLogger, + IconProvider iconProvider, + @ShellMainThread ShellExecutor mainExecutor) { + return new DragAndDropController(context, shellController, displayController, uiEventLogger, + iconProvider, mainExecutor); } @WMSingleton @@ -377,9 +382,11 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static Optional<HideDisplayCutoutController> provideHideDisplayCutoutController(Context context, - DisplayController displayController, @ShellMainThread ShellExecutor mainExecutor) { + ShellController shellController, DisplayController displayController, + @ShellMainThread ShellExecutor mainExecutor) { return Optional.ofNullable( - HideDisplayCutoutController.create(context, displayController, mainExecutor)); + HideDisplayCutoutController.create(context, shellController, displayController, + mainExecutor)); } // @@ -622,6 +629,22 @@ public abstract class WMShellBaseModule { } // + // SysUI -> Shell interface + // + + @WMSingleton + @Provides + static ShellInterface provideShellSysuiCallbacks(ShellController shellController) { + return shellController.asShell(); + } + + @WMSingleton + @Provides + static ShellController provideShellController(@ShellMainThread ShellExecutor mainExecutor) { + return new ShellController(mainExecutor); + } + + // // Misc // diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java index 189743728840..fb51473a4d98 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/dagger/WMShellModule.java @@ -71,6 +71,7 @@ import com.android.wm.shell.pip.phone.PipMotionHelper; import com.android.wm.shell.pip.phone.PipTouchHandler; import com.android.wm.shell.recents.RecentTasksController; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.transition.Transitions; import com.android.wm.shell.unfold.ShellUnfoldProgressProvider; import com.android.wm.shell.unfold.UnfoldAnimationController; @@ -134,6 +135,7 @@ public abstract class WMShellModule { @WMSingleton @Provides static BubbleController provideBubbleController(Context context, + ShellController shellController, BubbleData data, FloatingContentCoordinator floatingContentCoordinator, IStatusBarService statusBarService, @@ -153,7 +155,7 @@ public abstract class WMShellModule { @ShellBackgroundThread ShellExecutor bgExecutor, TaskViewTransitions taskViewTransitions, SyncTransactionQueue syncQueue) { - return new BubbleController(context, data, null /* synchronizer */, + return new BubbleController(context, shellController, data, null /* synchronizer */, floatingContentCoordinator, new BubbleDataRepository(context, launcherApps, mainExecutor), statusBarService, windowManager, windowManagerShellWrapper, userManager, @@ -205,12 +207,14 @@ public abstract class WMShellModule { @Provides @DynamicOverride static OneHandedController provideOneHandedController(Context context, + ShellController shellController, WindowManager windowManager, DisplayController displayController, DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, UiEventLogger uiEventLogger, InteractionJankMonitor jankMonitor, @ShellMainThread ShellExecutor mainExecutor, @ShellMainThread Handler mainHandler) { - return OneHandedController.create(context, windowManager, displayController, displayLayout, - taskStackListener, jankMonitor, uiEventLogger, mainExecutor, mainHandler); + return OneHandedController.create(context, shellController, windowManager, + displayController, displayLayout, taskStackListener, jankMonitor, uiEventLogger, + mainExecutor, mainHandler); } // @@ -242,7 +246,8 @@ public abstract class WMShellModule { @WMSingleton @Provides - static Optional<Pip> providePip(Context context, DisplayController displayController, + static Optional<Pip> providePip(Context context, + ShellController shellController, DisplayController displayController, PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm, PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, @@ -254,7 +259,7 @@ public abstract class WMShellModule { PipParamsChangedForwarder pipParamsChangedForwarder, Optional<OneHandedController> oneHandedController, @ShellMainThread ShellExecutor mainExecutor) { - return Optional.ofNullable(PipController.create(context, displayController, + return Optional.ofNullable(PipController.create(context, shellController, displayController, pipAppOpsListener, pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState, diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md index 68f970ff48df..0dd50b1bee68 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/docs/sysui.md @@ -52,4 +52,14 @@ For example, you might have: call, and the callback posts to the main SysUI thread Adding an interface to a Shell component may seem like a lot of boiler plate, but is currently -necessary to maintain proper threading and logic isolation.
\ No newline at end of file +necessary to maintain proper threading and logic isolation. + +## Configuration changes & other SysUI events + +Aside from direct calls into Shell controllers for exposed features, the Shell also receives +common event callbacks from SysUI via the `ShellController`. This includes things like: + +- Configuration changes +- TODO: Shell init +- TODO: Shell command +- TODO: Keyguard events
\ No newline at end of file diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java index edeff6e37182..03351871caad 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDrop.java @@ -16,8 +16,6 @@ package com.android.wm.shell.draganddrop; -import android.content.res.Configuration; - import com.android.wm.shell.common.annotations.ExternalThread; /** @@ -25,10 +23,4 @@ import com.android.wm.shell.common.annotations.ExternalThread; */ @ExternalThread public interface DragAndDrop { - - /** Called when the theme changes. */ - void onThemeChanged(); - - /** Called when the configuration changes. */ - void onConfigChanged(Configuration newConfig); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java index 95de2dc61a43..0d0961c41a87 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/draganddrop/DragAndDropController.java @@ -60,6 +60,8 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.protolog.ShellProtoLogGroup; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import java.util.ArrayList; import java.util.Optional; @@ -68,11 +70,12 @@ import java.util.Optional; * Handles the global drag and drop handling for the Shell. */ public class DragAndDropController implements DisplayController.OnDisplaysChangedListener, - View.OnDragListener { + View.OnDragListener, ConfigurationChangeListener { private static final String TAG = DragAndDropController.class.getSimpleName(); private final Context mContext; + private final ShellController mShellController; private final DisplayController mDisplayController; private final DragAndDropEventLogger mLogger; private final IconProvider mIconProvider; @@ -92,9 +95,14 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange void onDragStarted(); } - public DragAndDropController(Context context, DisplayController displayController, - UiEventLogger uiEventLogger, IconProvider iconProvider, ShellExecutor mainExecutor) { + public DragAndDropController(Context context, + ShellController shellController, + DisplayController displayController, + UiEventLogger uiEventLogger, + IconProvider iconProvider, + ShellExecutor mainExecutor) { mContext = context; + mShellController = shellController; mDisplayController = displayController; mLogger = new DragAndDropEventLogger(uiEventLogger); mIconProvider = iconProvider; @@ -109,6 +117,7 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange public void initialize(Optional<SplitScreenController> splitscreen) { mSplitScreen = splitscreen.orElse(null); mDisplayController.addDisplayWindowListener(this); + mShellController.addConfigurationChangeListener(this); } /** Adds a listener to be notified of drag and drop events. */ @@ -310,13 +319,15 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange return mimeTypes; } - private void onThemeChange() { + @Override + public void onThemeChanged() { for (int i = 0; i < mDisplayDropTargets.size(); i++) { mDisplayDropTargets.get(i).dragLayout.onThemeChange(); } } - private void onConfigChanged(Configuration newConfig) { + @Override + public void onConfigurationChanged(Configuration newConfig) { for (int i = 0; i < mDisplayDropTargets.size(); i++) { mDisplayDropTargets.get(i).dragLayout.onConfigChanged(newConfig); } @@ -344,19 +355,6 @@ public class DragAndDropController implements DisplayController.OnDisplaysChange } private class DragAndDropImpl implements DragAndDrop { - - @Override - public void onThemeChanged() { - mMainExecutor.execute(() -> { - DragAndDropController.this.onThemeChange(); - }); - } - - @Override - public void onConfigChanged(Configuration newConfig) { - mMainExecutor.execute(() -> { - DragAndDropController.this.onConfigChanged(newConfig); - }); - } + // TODO: To be removed } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java index 60123ab97fd7..dd1c8d6d49e1 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutout.java @@ -16,21 +16,11 @@ package com.android.wm.shell.hidedisplaycutout; -import android.content.res.Configuration; - -import androidx.annotation.NonNull; - import com.android.wm.shell.common.annotations.ExternalThread; -import java.io.PrintWriter; - /** * Interface to engage hide display cutout feature. */ @ExternalThread public interface HideDisplayCutout { - /** - * Notifies {@link Configuration} changed. - */ - void onConfigurationChanged(Configuration newConfig); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java index 23f76ca5f6ae..b091ab8c692c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutController.java @@ -19,7 +19,6 @@ package com.android.wm.shell.hidedisplaycutout; import android.content.Context; import android.content.res.Configuration; import android.os.SystemProperties; -import android.util.Slog; import androidx.annotation.NonNull; import androidx.annotation.Nullable; @@ -27,17 +26,19 @@ import androidx.annotation.VisibleForTesting; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import java.io.PrintWriter; -import java.util.concurrent.TimeUnit; /** * Manages the hide display cutout status. */ -public class HideDisplayCutoutController { +public class HideDisplayCutoutController implements ConfigurationChangeListener { private static final String TAG = "HideDisplayCutoutController"; private final Context mContext; + private final ShellController mShellController; private final HideDisplayCutoutOrganizer mOrganizer; private final ShellExecutor mMainExecutor; private final HideDisplayCutoutImpl mImpl = new HideDisplayCutoutImpl(); @@ -49,8 +50,9 @@ public class HideDisplayCutoutController { * supported. */ @Nullable - public static HideDisplayCutoutController create( - Context context, DisplayController displayController, ShellExecutor mainExecutor) { + public static HideDisplayCutoutController create(Context context, + ShellController shellController, DisplayController displayController, + ShellExecutor mainExecutor) { // The SystemProperty is set for devices that support this feature and is used to control // whether to create the HideDisplayCutout instance. // It's defined in the device.mk (e.g. device/google/crosshatch/device.mk). @@ -60,15 +62,17 @@ public class HideDisplayCutoutController { HideDisplayCutoutOrganizer organizer = new HideDisplayCutoutOrganizer(context, displayController, mainExecutor); - return new HideDisplayCutoutController(context, organizer, mainExecutor); + return new HideDisplayCutoutController(context, shellController, organizer, mainExecutor); } - HideDisplayCutoutController(Context context, HideDisplayCutoutOrganizer organizer, - ShellExecutor mainExecutor) { + HideDisplayCutoutController(Context context, ShellController shellController, + HideDisplayCutoutOrganizer organizer, ShellExecutor mainExecutor) { mContext = context; + mShellController = shellController; mOrganizer = organizer; mMainExecutor = mainExecutor; updateStatus(); + mShellController.addConfigurationChangeListener(this); } public HideDisplayCutout asHideDisplayCutout() { @@ -94,7 +98,8 @@ public class HideDisplayCutoutController { } } - private void onConfigurationChanged(Configuration newConfig) { + @Override + public void onConfigurationChanged(Configuration newConfig) { updateStatus(); } @@ -109,11 +114,6 @@ public class HideDisplayCutoutController { } private class HideDisplayCutoutImpl implements HideDisplayCutout { - @Override - public void onConfigurationChanged(Configuration newConfig) { - mMainExecutor.execute(() -> { - HideDisplayCutoutController.this.onConfigurationChanged(newConfig); - }); - } + // TODO: To be removed } } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java index b00182f36cc8..ee99f327f742 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHanded.java @@ -16,7 +16,6 @@ package com.android.wm.shell.onehanded; -import android.content.res.Configuration; import android.os.SystemProperties; import com.android.wm.shell.common.annotations.ExternalThread; @@ -83,11 +82,6 @@ public interface OneHanded { void registerTransitionCallback(OneHandedTransitionCallback callback); /** - * Receive onConfigurationChanged() events - */ - void onConfigChanged(Configuration newConfig); - - /** * Notifies when user switch complete */ void onUserSwitch(int userId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java index 3b9fcc78c932..ea2d50851dcc 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/onehanded/OneHandedController.java @@ -54,6 +54,8 @@ import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerCallback; import com.android.wm.shell.common.TaskStackListenerImpl; import com.android.wm.shell.common.annotations.ExternalThread; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import java.io.PrintWriter; @@ -61,7 +63,7 @@ import java.io.PrintWriter; * Manages and manipulates the one handed states, transitions, and gesture for phones. */ public class OneHandedController implements RemoteCallable<OneHandedController>, - DisplayChangeController.OnDisplayChangingListener { + DisplayChangeController.OnDisplayChangingListener, ConfigurationChangeListener { private static final String TAG = "OneHandedController"; private static final String ONE_HANDED_MODE_OFFSET_PERCENTAGE = @@ -81,6 +83,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, private Context mContext; + private final ShellController mShellController; private final AccessibilityManager mAccessibilityManager; private final DisplayController mDisplayController; private final OneHandedSettingsUtil mOneHandedSettingsUtil; @@ -188,8 +191,9 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, * Creates {@link OneHandedController}, returns {@code null} if the feature is not supported. */ public static OneHandedController create( - Context context, WindowManager windowManager, DisplayController displayController, - DisplayLayout displayLayout, TaskStackListenerImpl taskStackListener, + Context context, ShellController shellController, WindowManager windowManager, + DisplayController displayController, DisplayLayout displayLayout, + TaskStackListenerImpl taskStackListener, InteractionJankMonitor jankMonitor, UiEventLogger uiEventLogger, ShellExecutor mainExecutor, Handler mainHandler) { OneHandedSettingsUtil settingsUtil = new OneHandedSettingsUtil(); @@ -207,14 +211,15 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, context, displayLayout, settingsUtil, animationController, tutorialHandler, jankMonitor, mainExecutor); OneHandedUiEventLogger oneHandedUiEventsLogger = new OneHandedUiEventLogger(uiEventLogger); - return new OneHandedController(context, displayController, organizer, touchHandler, - tutorialHandler, settingsUtil, accessibilityUtil, timeoutHandler, oneHandedState, - oneHandedUiEventsLogger, taskStackListener, + return new OneHandedController(context, shellController, displayController, organizer, + touchHandler, tutorialHandler, settingsUtil, accessibilityUtil, timeoutHandler, + oneHandedState, oneHandedUiEventsLogger, taskStackListener, mainExecutor, mainHandler); } @VisibleForTesting OneHandedController(Context context, + ShellController shellController, DisplayController displayController, OneHandedDisplayAreaOrganizer displayAreaOrganizer, OneHandedTouchHandler touchHandler, @@ -228,6 +233,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, ShellExecutor mainExecutor, Handler mainHandler) { mContext = context; + mShellController = shellController; mOneHandedSettingsUtil = settingsUtil; mOneHandedAccessibilityUtil = oneHandedAccessibilityUtil; mDisplayAreaOrganizer = displayAreaOrganizer; @@ -272,6 +278,7 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, mAccessibilityStateChangeListener); mState.addSListeners(mTutorialHandler); + mShellController.addConfigurationChangeListener(this); } public OneHanded asOneHanded() { @@ -587,7 +594,8 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, mLockedDisabled = locked && !enabled; } - private void onConfigChanged(Configuration newConfig) { + @Override + public void onConfigurationChanged(Configuration newConfig) { if (mTutorialHandler == null) { return; } @@ -743,13 +751,6 @@ public class OneHandedController implements RemoteCallable<OneHandedController>, } @Override - public void onConfigChanged(Configuration newConfig) { - mMainExecutor.execute(() -> { - OneHandedController.this.onConfigChanged(newConfig); - }); - } - - @Override public void onUserSwitch(int userId) { mMainExecutor.execute(() -> { OneHandedController.this.onUserSwitch(userId); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java index bbc47e47afc5..2ac112977ece 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/Pip.java @@ -16,7 +16,6 @@ package com.android.wm.shell.pip; -import android.content.res.Configuration; import android.graphics.Rect; import com.android.wm.shell.common.annotations.ExternalThread; @@ -44,24 +43,6 @@ public interface Pip { } /** - * Called when configuration is changed. - */ - default void onConfigurationChanged(Configuration newConfig) { - } - - /** - * Called when display size or font size of settings changed - */ - default void onDensityOrFontScaleChanged() { - } - - /** - * Called when overlay package change invoked. - */ - default void onOverlayChanged() { - } - - /** * Called when SysUI state changed. * * @param isSysUiStateValid Is SysUI state valid or not. diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java index 3000998f210d..5ae460268635 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/phone/PipController.java @@ -87,6 +87,8 @@ import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.PipTransitionState; import com.android.wm.shell.pip.PipUtils; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import com.android.wm.shell.transition.Transitions; import java.io.PrintWriter; @@ -100,7 +102,7 @@ import java.util.function.Consumer; * Manages the picture-in-picture (PIP) UI and states for Phones. */ public class PipController implements PipTransitionController.PipTransitionCallback, - RemoteCallable<PipController> { + RemoteCallable<PipController>, ConfigurationChangeListener { private static final String TAG = "PipController"; private Context mContext; @@ -119,6 +121,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb private TaskStackListenerImpl mTaskStackListener; private PipParamsChangedForwarder mPipParamsChangedForwarder; private Optional<OneHandedController> mOneHandedController; + private final ShellController mShellController; protected final PipImpl mImpl; private final Rect mTmpInsetBounds = new Rect(); @@ -290,13 +293,20 @@ public class PipController implements PipTransitionController.PipTransitionCallb * Instantiates {@link PipController}, returns {@code null} if the feature not supported. */ @Nullable - public static Pip create(Context context, DisplayController displayController, - PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm, - PipKeepClearAlgorithm pipKeepClearAlgorithm, PipBoundsState pipBoundsState, - PipMotionHelper pipMotionHelper, PipMediaController pipMediaController, - PhonePipMenuController phonePipMenuController, PipTaskOrganizer pipTaskOrganizer, + public static Pip create(Context context, + ShellController shellController, + DisplayController displayController, + PipAppOpsListener pipAppOpsListener, + PipBoundsAlgorithm pipBoundsAlgorithm, + PipKeepClearAlgorithm pipKeepClearAlgorithm, + PipBoundsState pipBoundsState, + PipMotionHelper pipMotionHelper, + PipMediaController pipMediaController, + PhonePipMenuController phonePipMenuController, + PipTaskOrganizer pipTaskOrganizer, PipTransitionState pipTransitionState, - PipTouchHandler pipTouchHandler, PipTransitionController pipTransitionController, + PipTouchHandler pipTouchHandler, + PipTransitionController pipTransitionController, WindowManagerShellWrapper windowManagerShellWrapper, TaskStackListenerImpl taskStackListener, PipParamsChangedForwarder pipParamsChangedForwarder, @@ -308,9 +318,9 @@ public class PipController implements PipTransitionController.PipTransitionCallb return null; } - return new PipController(context, displayController, pipAppOpsListener, pipBoundsAlgorithm, - pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, pipMediaController, - phonePipMenuController, pipTaskOrganizer, pipTransitionState, + return new PipController(context, shellController, displayController, pipAppOpsListener, + pipBoundsAlgorithm, pipKeepClearAlgorithm, pipBoundsState, pipMotionHelper, + pipMediaController, phonePipMenuController, pipTaskOrganizer, pipTransitionState, pipTouchHandler, pipTransitionController, windowManagerShellWrapper, taskStackListener, pipParamsChangedForwarder, oneHandedController, mainExecutor) @@ -318,6 +328,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } protected PipController(Context context, + ShellController shellController, DisplayController displayController, PipAppOpsListener pipAppOpsListener, PipBoundsAlgorithm pipBoundsAlgorithm, @@ -343,6 +354,7 @@ public class PipController implements PipTransitionController.PipTransitionCallb } mContext = context; + mShellController = shellController; mImpl = new PipImpl(); mWindowManagerShellWrapper = windowManagerShellWrapper; mDisplayController = displayController; @@ -513,6 +525,8 @@ public class PipController implements PipTransitionController.PipTransitionCallb } }); }); + + mShellController.addConfigurationChangeListener(this); } @Override @@ -525,18 +539,21 @@ public class PipController implements PipTransitionController.PipTransitionCallb return mMainExecutor; } - private void onConfigurationChanged(Configuration newConfig) { + @Override + public void onConfigurationChanged(Configuration newConfig) { mPipBoundsAlgorithm.onConfigurationChanged(mContext); mTouchHandler.onConfigurationChanged(); mPipBoundsState.onConfigurationChanged(); } - private void onDensityOrFontScaleChanged() { + @Override + public void onDensityOrFontScaleChanged() { mPipTaskOrganizer.onDensityOrFontScaleChanged(mContext); onPipResourceDimensionsChanged(); } - private void onOverlayChanged() { + @Override + public void onThemeChanged() { mTouchHandler.onOverlayChanged(); onDisplayChanged(new DisplayLayout(mContext, mContext.getDisplay()), false /* saveRestoreSnapFraction */); @@ -923,27 +940,6 @@ public class PipController implements PipTransitionController.PipTransitionCallb } @Override - public void onConfigurationChanged(Configuration newConfig) { - mMainExecutor.execute(() -> { - PipController.this.onConfigurationChanged(newConfig); - }); - } - - @Override - public void onDensityOrFontScaleChanged() { - mMainExecutor.execute(() -> { - PipController.this.onDensityOrFontScaleChanged(); - }); - } - - @Override - public void onOverlayChanged() { - mMainExecutor.execute(() -> { - PipController.this.onOverlayChanged(); - }); - } - - @Override public void onSystemUiStateChanged(boolean isSysUiStateValid, int flag) { mMainExecutor.execute(() -> { PipController.this.onSystemUiStateChanged(isSysUiStateValid, flag); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java index fa48def9c7d7..a24d9618032d 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/pip/tv/TvPipController.java @@ -49,6 +49,8 @@ import com.android.wm.shell.pip.PipParamsChangedForwarder; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.protolog.ShellProtoLogGroup; +import com.android.wm.shell.sysui.ConfigurationChangeListener; +import com.android.wm.shell.sysui.ShellController; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -61,7 +63,8 @@ import java.util.Set; */ public class TvPipController implements PipTransitionController.PipTransitionCallback, TvPipBoundsController.PipBoundsListener, TvPipMenuController.Delegate, - TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener { + TvPipNotificationController.Delegate, DisplayController.OnDisplaysChangedListener, + ConfigurationChangeListener { private static final String TAG = "TvPipController"; static final boolean DEBUG = false; @@ -93,6 +96,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private final Context mContext; + private final ShellController mShellController; private final TvPipBoundsState mTvPipBoundsState; private final TvPipBoundsAlgorithm mTvPipBoundsAlgorithm; private final TvPipBoundsController mTvPipBoundsController; @@ -117,6 +121,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal public static Pip create( Context context, + ShellController shellController, TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, @@ -133,6 +138,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ShellExecutor mainExecutor) { return new TvPipController( context, + shellController, tvPipBoundsState, tvPipBoundsAlgorithm, tvPipBoundsController, @@ -151,6 +157,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private TvPipController( Context context, + ShellController shellController, TvPipBoundsState tvPipBoundsState, TvPipBoundsAlgorithm tvPipBoundsAlgorithm, TvPipBoundsController tvPipBoundsController, @@ -167,6 +174,7 @@ public class TvPipController implements PipTransitionController.PipTransitionCal ShellExecutor mainExecutor) { mContext = context; mMainExecutor = mainExecutor; + mShellController = shellController; mTvPipBoundsState = tvPipBoundsState; mTvPipBoundsState.setDisplayId(context.getDisplayId()); @@ -193,9 +201,12 @@ public class TvPipController implements PipTransitionController.PipTransitionCal registerTaskStackListenerCallback(taskStackListener); registerWmShellPinnedStackListener(wmShell); displayController.addDisplayWindowListener(this); + + mShellController.addConfigurationChangeListener(this); } - private void onConfigurationChanged(Configuration newConfig) { + @Override + public void onConfigurationChanged(Configuration newConfig) { if (DEBUG) { ProtoLog.d(ShellProtoLogGroup.WM_SHELL_PICTURE_IN_PICTURE, "%s: onConfigurationChanged(), state=%s", TAG, stateToName(mState)); @@ -669,13 +680,6 @@ public class TvPipController implements PipTransitionController.PipTransitionCal private class TvPipImpl implements Pip { @Override - public void onConfigurationChanged(Configuration newConfig) { - mMainExecutor.execute(() -> { - TvPipController.this.onConfigurationChanged(newConfig); - }); - } - - @Override public void registerSessionListenerForCurrentUser() { mMainExecutor.execute(() -> { TvPipController.this.registerSessionListenerForCurrentUser(); diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java index e31e0d674bec..b2961518b66a 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/protolog/ShellProtoLogGroup.java @@ -44,6 +44,8 @@ public enum ShellProtoLogGroup implements IProtoLogGroup { Consts.TAG_WM_SHELL), WM_SHELL_SPLIT_SCREEN(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, Consts.TAG_WM_SHELL), + WM_SHELL_SYSUI_EVENTS(Consts.ENABLE_DEBUG, Consts.ENABLE_LOG_TO_PROTO_DEBUG, false, + Consts.TAG_WM_SHELL), TEST_GROUP(true, true, false, "WindowManagerShellProtoLogTest"); private final boolean mEnabled; diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ConfigurationChangeListener.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ConfigurationChangeListener.java new file mode 100644 index 000000000000..2fca8f0ecc76 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ConfigurationChangeListener.java @@ -0,0 +1,51 @@ +/* + * Copyright (C) 2022 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.sysui; + +import android.content.res.Configuration; + +/** + * Callbacks for when the configuration changes. + */ +public interface ConfigurationChangeListener { + + /** + * Called when a configuration changes. This precedes all the following callbacks. + */ + default void onConfigurationChanged(Configuration newConfiguration) {} + + /** + * Convenience method to the above, called when the density or font scale changes. + */ + default void onDensityOrFontScaleChanged() {} + + /** + * Convenience method to the above, called when the smallest screen width changes. + */ + default void onSmallestScreenWidthChanged() {} + + /** + * Convenience method to the above, called when the system theme changes, including dark/light + * UI_MODE changes. + */ + default void onThemeChanged() {} + + /** + * Convenience method to the above, called when the local list or layout direction changes. + */ + default void onLocaleOrLayoutDirectionChanged() {} +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java new file mode 100644 index 000000000000..28a30f4905a5 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellController.java @@ -0,0 +1,140 @@ +/* + * Copyright (C) 2022 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.sysui; + +import static android.content.pm.ActivityInfo.CONFIG_ASSETS_PATHS; +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_LOCALE; +import static android.content.pm.ActivityInfo.CONFIG_SMALLEST_SCREEN_SIZE; +import static android.content.pm.ActivityInfo.CONFIG_UI_MODE; + +import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_SYSUI_EVENTS; + +import android.content.pm.ActivityInfo; +import android.content.res.Configuration; + +import androidx.annotation.NonNull; +import androidx.annotation.VisibleForTesting; + +import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.common.annotations.ExternalThread; + +import java.io.PrintWriter; +import java.util.concurrent.CopyOnWriteArrayList; + +/** + * Handles event callbacks from SysUI that can be used within the Shell. + */ +public class ShellController { + private static final String TAG = ShellController.class.getSimpleName(); + + private final ShellExecutor mMainExecutor; + private final ShellInterfaceImpl mImpl = new ShellInterfaceImpl(); + + private final CopyOnWriteArrayList<ConfigurationChangeListener> mListeners = + new CopyOnWriteArrayList<>(); + private Configuration mLastConfiguration; + + + public ShellController(ShellExecutor mainExecutor) { + mMainExecutor = mainExecutor; + } + + /** + * Returns the external interface to this controller. + */ + public ShellInterface asShell() { + return mImpl; + } + + /** + * Adds a new configuration listener. The configuration change callbacks are not made in any + * particular order. + */ + public void addConfigurationChangeListener(ConfigurationChangeListener listener) { + mListeners.remove(listener); + mListeners.add(listener); + } + + /** + * Removes an existing configuration listener. + */ + public void removeConfigurationChangeListener(ConfigurationChangeListener listener) { + mListeners.remove(listener); + } + + @VisibleForTesting + void onConfigurationChanged(Configuration newConfig) { + // The initial config is send on startup and doesn't trigger listener callbacks + if (mLastConfiguration == null) { + mLastConfiguration = new Configuration(newConfig); + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "Initial Configuration: %s", newConfig); + return; + } + + final int diff = newConfig.diff(mLastConfiguration); + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "New configuration change: %s", newConfig); + ProtoLog.v(WM_SHELL_SYSUI_EVENTS, "\tchanges=%s", + Configuration.configurationDiffToString(diff)); + final boolean densityFontScaleChanged = (diff & CONFIG_FONT_SCALE) != 0 + || (diff & ActivityInfo.CONFIG_DENSITY) != 0; + final boolean smallestScreenWidthChanged = (diff & CONFIG_SMALLEST_SCREEN_SIZE) != 0; + final boolean themeChanged = (diff & CONFIG_ASSETS_PATHS) != 0 + || (diff & CONFIG_UI_MODE) != 0; + final boolean localOrLayoutDirectionChanged = (diff & CONFIG_LOCALE) != 0 + || (diff & CONFIG_LAYOUT_DIRECTION) != 0; + + // Update the last configuration and call listeners + mLastConfiguration.updateFrom(newConfig); + for (ConfigurationChangeListener listener : mListeners) { + listener.onConfigurationChanged(newConfig); + if (densityFontScaleChanged) { + listener.onDensityOrFontScaleChanged(); + } + if (smallestScreenWidthChanged) { + listener.onSmallestScreenWidthChanged(); + } + if (themeChanged) { + listener.onThemeChanged(); + } + if (localOrLayoutDirectionChanged) { + listener.onLocaleOrLayoutDirectionChanged(); + } + } + } + + public void dump(@NonNull PrintWriter pw, String prefix) { + final String innerPrefix = prefix + " "; + pw.println(prefix + TAG); + pw.println(innerPrefix + "mListeners=" + mListeners.size()); + pw.println(innerPrefix + "mLastConfiguration=" + mLastConfiguration); + } + + /** + * The interface for calls from outside the Shell, within the host process. + */ + @ExternalThread + private class ShellInterfaceImpl implements ShellInterface { + @Override + public void onConfigurationChanged(Configuration newConfiguration) { + mMainExecutor.execute(() -> + ShellController.this.onConfigurationChanged(newConfiguration)); + } + } +} diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java new file mode 100644 index 000000000000..a2d072cd7d88 --- /dev/null +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/sysui/ShellInterface.java @@ -0,0 +1,33 @@ +/* + * Copyright (C) 2022 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.sysui; + +import android.content.res.Configuration; + +/** + * General interface for notifying the Shell of common SysUI events like configuration or keyguard + * changes. + * + * TODO: Move ShellInit and ShellCommandHandler into this interface + */ +public interface ShellInterface { + + /** + * Notifies the Shell that the configuration has changed. + */ + default void onConfigurationChanged(Configuration newConfiguration) {} +} diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java index 0b43163787f3..e209971998c8 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/draganddrop/DragAndDropControllerTest.java @@ -21,6 +21,7 @@ import static android.view.Display.DEFAULT_DISPLAY; import static android.view.DragEvent.ACTION_DRAG_STARTED; import static org.junit.Assert.assertFalse; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.doReturn; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; @@ -48,6 +49,7 @@ import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.splitscreen.SplitScreenController; +import com.android.wm.shell.sysui.ShellController; import org.junit.Before; import org.junit.Test; @@ -66,24 +68,34 @@ public class DragAndDropControllerTest extends ShellTestCase { @Mock private Context mContext; - + @Mock + private ShellController mShellController; @Mock private DisplayController mDisplayController; - @Mock private UiEventLogger mUiEventLogger; - @Mock private DragAndDropController.DragAndDropListener mDragAndDropListener; + @Mock + private IconProvider mIconProvider; + @Mock + private ShellExecutor mMainExecutor; + @Mock + private SplitScreenController mSplitScreenController; private DragAndDropController mController; @Before public void setUp() throws RemoteException { MockitoAnnotations.initMocks(this); - mController = new DragAndDropController(mContext, mDisplayController, mUiEventLogger, - mock(IconProvider.class), mock(ShellExecutor.class)); - mController.initialize(Optional.of(mock(SplitScreenController.class))); + mController = new DragAndDropController(mContext, mShellController, mDisplayController, + mUiEventLogger, mIconProvider, mMainExecutor); + mController.initialize(Optional.of(mSplitScreenController)); + } + + @Test + public void instantiateController_registerConfigChangeListener() { + verify(mShellController, times(1)).addConfigurationChangeListener(any()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java index 7ecd5020d56e..68e955e7cf7a 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/hidedisplaycutout/HideDisplayCutoutControllerTest.java @@ -16,7 +16,9 @@ package com.android.wm.shell.hidedisplaycutout; +import static org.mockito.ArgumentMatchers.any; import static org.mockito.Mockito.reset; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import android.testing.AndroidTestingRunner; @@ -28,6 +30,7 @@ import androidx.test.platform.app.InstrumentationRegistry; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.common.ShellExecutor; +import com.android.wm.shell.sysui.ShellController; import org.junit.Before; import org.junit.Test; @@ -42,17 +45,25 @@ public class HideDisplayCutoutControllerTest extends ShellTestCase { private TestableContext mContext = new TestableContext( InstrumentationRegistry.getInstrumentation().getTargetContext(), null); - private HideDisplayCutoutController mHideDisplayCutoutController; + @Mock + private ShellController mShellController; @Mock private HideDisplayCutoutOrganizer mMockDisplayAreaOrganizer; @Mock private ShellExecutor mMockMainExecutor; + private HideDisplayCutoutController mHideDisplayCutoutController; + @Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); mHideDisplayCutoutController = new HideDisplayCutoutController( - mContext, mMockDisplayAreaOrganizer, mMockMainExecutor); + mContext, mShellController, mMockDisplayAreaOrganizer, mMockMainExecutor); + } + + @Test + public void instantiateController_registerConfigChangeListener() { + verify(mShellController, times(1)).addConfigurationChangeListener(any()); } @Test diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java index 8a2bbd75db57..958969deb564 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedControllerTest.java @@ -30,6 +30,7 @@ import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.atLeastOnce; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -48,6 +49,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.sysui.ShellController; import org.junit.Before; import org.junit.Test; @@ -68,6 +70,8 @@ public class OneHandedControllerTest extends OneHandedTestCase { OneHandedState mSpiedTransitionState; @Mock + ShellController mMockShellController; + @Mock DisplayLayout mDisplayLayout; @Mock DisplayController mMockDisplayController; @@ -123,6 +127,7 @@ public class OneHandedControllerTest extends OneHandedTestCase { mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext); mSpiedOneHandedController = spy(new OneHandedController( mContext, + mMockShellController, mMockDisplayController, mMockDisplayAreaOrganizer, mMockTouchHandler, @@ -139,6 +144,11 @@ public class OneHandedControllerTest extends OneHandedTestCase { } @Test + public void testControllerRegistersConfigChangeListener() { + verify(mMockShellController, times(1)).addConfigurationChangeListener(any()); + } + + @Test public void testDefaultShouldNotInOneHanded() { // Assert default transition state is STATE_NONE assertThat(mSpiedTransitionState.getState()).isEqualTo(STATE_NONE); diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java index 7ee7536d454d..e6a8220e081b 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/onehanded/OneHandedStateTest.java @@ -31,7 +31,6 @@ import static org.mockito.Mockito.when; import android.graphics.Rect; import android.os.Handler; -import android.os.UserHandle; import android.testing.AndroidTestingRunner; import android.util.ArrayMap; import android.view.Display; @@ -42,6 +41,7 @@ import com.android.wm.shell.common.DisplayController; import com.android.wm.shell.common.DisplayLayout; import com.android.wm.shell.common.ShellExecutor; import com.android.wm.shell.common.TaskStackListenerImpl; +import com.android.wm.shell.sysui.ShellController; import org.junit.Before; import org.junit.Test; @@ -52,7 +52,6 @@ import org.mockito.MockitoAnnotations; @SmallTest @RunWith(AndroidTestingRunner.class) public class OneHandedStateTest extends OneHandedTestCase { - private int mCurrentUser = UserHandle.myUserId(); Display mDisplay; DisplayLayout mDisplayLayout; @@ -62,6 +61,8 @@ public class OneHandedStateTest extends OneHandedTestCase { OneHandedState mSpiedState; @Mock + ShellController mMockShellController; + @Mock DisplayController mMockDisplayController; @Mock OneHandedDisplayAreaOrganizer mMockDisplayAreaOrganizer; @@ -110,6 +111,7 @@ public class OneHandedStateTest extends OneHandedTestCase { mOneHandedAccessibilityUtil = new OneHandedAccessibilityUtil(mContext); mSpiedOneHandedController = spy(new OneHandedController( mContext, + mMockShellController, mMockDisplayController, mMockDisplayAreaOrganizer, mMockTouchHandler, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java index babc9707ef9c..827785bcc3e0 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/pip/phone/PipControllerTest.java @@ -24,6 +24,7 @@ import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.spy; +import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -54,6 +55,7 @@ import com.android.wm.shell.pip.PipSnapAlgorithm; import com.android.wm.shell.pip.PipTaskOrganizer; import com.android.wm.shell.pip.PipTransitionController; import com.android.wm.shell.pip.PipTransitionState; +import com.android.wm.shell.sysui.ShellController; import org.junit.Before; import org.junit.Test; @@ -73,6 +75,7 @@ import java.util.Set; public class PipControllerTest extends ShellTestCase { private PipController mPipController; + @Mock private ShellController mMockShellController; @Mock private DisplayController mMockDisplayController; @Mock private PhonePipMenuController mMockPhonePipMenuController; @Mock private PipAppOpsListener mMockPipAppOpsListener; @@ -102,7 +105,7 @@ public class PipControllerTest extends ShellTestCase { ((Runnable) invocation.getArgument(0)).run(); return null; }).when(mMockExecutor).execute(any()); - mPipController = new PipController(mContext, mMockDisplayController, + mPipController = new PipController(mContext, mMockShellController, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, @@ -115,6 +118,11 @@ public class PipControllerTest extends ShellTestCase { } @Test + public void instantiatePipController_registerConfigChangeListener() { + verify(mMockShellController, times(1)).addConfigurationChangeListener(any()); + } + + @Test public void instantiatePipController_registersPipTransitionCallback() { verify(mMockPipTransitionController).registerPipTransitionCallback(any()); } @@ -136,7 +144,7 @@ public class PipControllerTest extends ShellTestCase { when(mockPackageManager.hasSystemFeature(FEATURE_PICTURE_IN_PICTURE)).thenReturn(false); when(spyContext.getPackageManager()).thenReturn(mockPackageManager); - assertNull(PipController.create(spyContext, mMockDisplayController, + assertNull(PipController.create(spyContext, mMockShellController, mMockDisplayController, mMockPipAppOpsListener, mMockPipBoundsAlgorithm, mMockPipKeepClearAlgorithm, mMockPipBoundsState, mMockPipMotionHelper, mMockPipMediaController, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java new file mode 100644 index 000000000000..6cc3ae8001e4 --- /dev/null +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/sysui/ShellControllerTest.java @@ -0,0 +1,256 @@ +/* + * Copyright (C) 2022 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.sysui; + +import static org.junit.Assert.assertTrue; + +import android.content.res.Configuration; +import android.testing.AndroidTestingRunner; +import android.testing.TestableLooper; + +import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; + +import com.android.wm.shell.ShellTestCase; +import com.android.wm.shell.common.ShellExecutor; + +import org.junit.After; +import org.junit.Before; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.mockito.Mock; +import org.mockito.MockitoAnnotations; + +import java.util.Locale; + +@SmallTest +@RunWith(AndroidTestingRunner.class) +@TestableLooper.RunWithLooper(setAsMainLooper = true) +public class ShellControllerTest extends ShellTestCase { + + @Mock + private ShellExecutor mExecutor; + + private ShellController mController; + private TestConfigurationChangeListener mListener; + + @Before + public void setUp() { + MockitoAnnotations.initMocks(this); + mListener = new TestConfigurationChangeListener(); + mController = new ShellController(mExecutor); + mController.onConfigurationChanged(getConfigurationCopy()); + } + + @After + public void tearDown() { + // Do nothing + } + + @Test + public void testAddConfigurationChangeListener_ensureCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.densityDpi = 200; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + } + + @Test + public void testDoubleAddConfigurationChangeListener_ensureSingleCallback() { + mController.addConfigurationChangeListener(mListener); + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.densityDpi = 200; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + } + + @Test + public void testAddRemoveConfigurationChangeListener_ensureNoCallback() { + mController.addConfigurationChangeListener(mListener); + mController.removeConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.densityDpi = 200; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 0); + } + + @Test + public void testMultipleConfigurationChangeListeners() { + TestConfigurationChangeListener listener2 = new TestConfigurationChangeListener(); + mController.addConfigurationChangeListener(mListener); + mController.addConfigurationChangeListener(listener2); + + Configuration newConfig = getConfigurationCopy(); + newConfig.densityDpi = 200; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(listener2.configChanges == 1); + } + + @Test + public void testRemoveListenerDuringCallback() { + TestConfigurationChangeListener badListener = new TestConfigurationChangeListener() { + @Override + public void onConfigurationChanged(Configuration newConfiguration) { + mController.removeConfigurationChangeListener(this); + } + }; + mController.addConfigurationChangeListener(badListener); + mController.addConfigurationChangeListener(mListener); + + // Ensure we don't fail just because a listener was removed mid-callback + Configuration newConfig = getConfigurationCopy(); + newConfig.densityDpi = 200; + mController.onConfigurationChanged(newConfig); + } + + @Test + public void testDensityChangeCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.densityDpi = 200; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(mListener.densityChanges == 1); + assertTrue(mListener.smallestWidthChanges == 0); + assertTrue(mListener.themeChanges == 0); + assertTrue(mListener.localeChanges == 0); + } + + @Test + public void testFontScaleChangeCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.fontScale = 2; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(mListener.densityChanges == 1); + assertTrue(mListener.smallestWidthChanges == 0); + assertTrue(mListener.themeChanges == 0); + assertTrue(mListener.localeChanges == 0); + } + + @Test + public void testSmallestWidthChangeCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.smallestScreenWidthDp = 100; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(mListener.densityChanges == 0); + assertTrue(mListener.smallestWidthChanges == 1); + assertTrue(mListener.themeChanges == 0); + assertTrue(mListener.localeChanges == 0); + } + + @Test + public void testThemeChangeCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.assetsSeq++; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(mListener.densityChanges == 0); + assertTrue(mListener.smallestWidthChanges == 0); + assertTrue(mListener.themeChanges == 1); + assertTrue(mListener.localeChanges == 0); + } + + @Test + public void testNightModeChangeCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + newConfig.uiMode = Configuration.UI_MODE_NIGHT_YES; + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(mListener.densityChanges == 0); + assertTrue(mListener.smallestWidthChanges == 0); + assertTrue(mListener.themeChanges == 1); + assertTrue(mListener.localeChanges == 0); + } + + @Test + public void testLocaleChangeCallback() { + mController.addConfigurationChangeListener(mListener); + + Configuration newConfig = getConfigurationCopy(); + // Just change the locales to be different + if (newConfig.locale == Locale.CANADA) { + newConfig.locale = Locale.US; + } else { + newConfig.locale = Locale.CANADA; + } + mController.onConfigurationChanged(newConfig); + assertTrue(mListener.configChanges == 1); + assertTrue(mListener.densityChanges == 0); + assertTrue(mListener.smallestWidthChanges == 0); + assertTrue(mListener.themeChanges == 0); + assertTrue(mListener.localeChanges == 1); + } + + private Configuration getConfigurationCopy() { + final Configuration c = new Configuration(InstrumentationRegistry.getInstrumentation() + .getTargetContext().getResources().getConfiguration()); + // In tests this might be undefined so make sure it's valid + c.assetsSeq = 1; + return c; + } + + private class TestConfigurationChangeListener implements ConfigurationChangeListener { + // Counts of number of times each of the callbacks are called + public int configChanges; + public int densityChanges; + public int smallestWidthChanges; + public int themeChanges; + public int localeChanges; + + @Override + public void onConfigurationChanged(Configuration newConfiguration) { + configChanges++; + } + + @Override + public void onDensityOrFontScaleChanged() { + densityChanges++; + } + + @Override + public void onSmallestScreenWidthChanged() { + smallestWidthChanges++; + } + + @Override + public void onThemeChanged() { + themeChanges++; + } + + @Override + public void onLocaleOrLayoutDirectionChanged() { + localeChanges++; + } + } +} |