diff options
7 files changed, 109 insertions, 15 deletions
diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java index 34bf9e0dd98f..2e5448a9e8d5 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootDisplayAreaOrganizer.java @@ -18,6 +18,7 @@ package com.android.wm.shell; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_DESKTOP_MODE; +import android.annotation.SuppressLint; import android.app.WindowConfiguration; import android.util.SparseArray; import android.view.SurfaceControl; @@ -29,6 +30,7 @@ import android.window.WindowContainerTransaction; import androidx.annotation.NonNull; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; import java.util.List; @@ -44,9 +46,14 @@ public class RootDisplayAreaOrganizer extends DisplayAreaOrganizer { /** Display area leashes, which is mapped by display IDs. */ private final SparseArray<SurfaceControl> mLeashes = new SparseArray<>(); - public RootDisplayAreaOrganizer(Executor executor) { + public RootDisplayAreaOrganizer(@NonNull Executor executor, @NonNull ShellInit shellInit) { super(executor); - List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_ROOT); + shellInit.addInitCallback(this::onInit, this); + } + + @SuppressLint("MissingPermission") // Only called by SysUI. + private void onInit() { + final List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_ROOT); for (int i = infos.size() - 1; i >= 0; --i) { onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash()); } diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java index 38550b405c0e..ab61a48a715c 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/RootTaskDisplayAreaOrganizer.java @@ -18,6 +18,7 @@ package com.android.wm.shell; import static com.android.wm.shell.protolog.ShellProtoLogGroup.WM_SHELL_TASK_ORG; +import android.annotation.SuppressLint; import android.annotation.UiContext; import android.app.ResourcesManager; import android.content.Context; @@ -38,6 +39,7 @@ import androidx.annotation.NonNull; import androidx.annotation.Nullable; import com.android.internal.protolog.common.ProtoLog; +import com.android.wm.shell.sysui.ShellInit; import java.io.PrintWriter; import java.util.ArrayList; @@ -69,10 +71,17 @@ public class RootTaskDisplayAreaOrganizer extends DisplayAreaOrganizer { private final Context mContext; - public RootTaskDisplayAreaOrganizer(Executor executor, Context context) { + public RootTaskDisplayAreaOrganizer(@NonNull Executor executor, @NonNull Context context, + @NonNull ShellInit shellInit) { super(executor); mContext = context; - List<DisplayAreaAppearedInfo> infos = registerOrganizer(FEATURE_DEFAULT_TASK_CONTAINER); + shellInit.addInitCallback(this::onInit, this); + } + + @SuppressLint("MissingPermission") // Only called by SysUI. + private void onInit() { + final List<DisplayAreaAppearedInfo> infos = + registerOrganizer(FEATURE_DEFAULT_TASK_CONTAINER); for (int i = infos.size() - 1; i >= 0; --i) { onDisplayAreaAppeared(infos.get(i).getDisplayAreaInfo(), infos.get(i).getLeash()); } 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 e6d3abcc6e1d..c51af46accdb 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 @@ -110,13 +110,13 @@ import com.android.wm.shell.unfold.UnfoldAnimationController; import com.android.wm.shell.unfold.UnfoldTransitionHandler; import com.android.wm.shell.windowdecor.WindowDecorViewModel; -import java.util.Optional; - import dagger.BindsOptionalOf; import dagger.Lazy; import dagger.Module; import dagger.Provides; +import java.util.Optional; + /** * Provides basic dependencies from {@link com.android.wm.shell}, these dependencies are only * accessible from components within the WM subcomponent (can be explicitly exposed to the @@ -658,15 +658,15 @@ public abstract class WMShellBaseModule { @WMSingleton @Provides static RootTaskDisplayAreaOrganizer provideRootTaskDisplayAreaOrganizer( - @ShellMainThread ShellExecutor mainExecutor, Context context) { - return new RootTaskDisplayAreaOrganizer(mainExecutor, context); + @ShellMainThread ShellExecutor mainExecutor, Context context, ShellInit shellInit) { + return new RootTaskDisplayAreaOrganizer(mainExecutor, context, shellInit); } @WMSingleton @Provides static RootDisplayAreaOrganizer provideRootDisplayAreaOrganizer( - @ShellMainThread ShellExecutor mainExecutor) { - return new RootDisplayAreaOrganizer(mainExecutor); + @ShellMainThread ShellExecutor mainExecutor, ShellInit shellInit) { + return new RootDisplayAreaOrganizer(mainExecutor, shellInit); } @WMSingleton diff --git a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java index c74b3f30e52d..0d9a9e9f07ff 100644 --- a/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java +++ b/libs/WindowManager/Shell/src/com/android/wm/shell/transition/Transitions.java @@ -277,7 +277,7 @@ public class Transitions implements RemoteCallable<Transitions>, @NonNull ShellExecutor animExecutor) { this(context, shellInit, shellController, organizer, pool, displayController, mainExecutor, mainHandler, animExecutor, null, - new RootTaskDisplayAreaOrganizer(mainExecutor, context)); + new RootTaskDisplayAreaOrganizer(mainExecutor, context, shellInit)); } public Transitions(@NonNull Context context, diff --git a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java index d5986780d5d8..ded851c12690 100644 --- a/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java +++ b/libs/WindowManager/Shell/tests/unittest/src/com/android/wm/shell/transition/ShellTransitionTests.java @@ -50,6 +50,7 @@ import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.ArgumentMatchers.isA; import static org.mockito.ArgumentMatchers.isNull; import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.doAnswer; @@ -92,6 +93,7 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; import androidx.test.platform.app.InstrumentationRegistry; +import com.android.wm.shell.RootTaskDisplayAreaOrganizer; import com.android.wm.shell.ShellTestCase; import com.android.wm.shell.TestShellExecutor; import com.android.wm.shell.common.DisplayController; @@ -145,7 +147,9 @@ public class ShellTransitionTests extends ShellTestCase { final Transitions t = new Transitions(mContext, shellInit, mock(ShellController.class), mOrganizer, mTransactionPool, createTestDisplayController(), mMainExecutor, mMainHandler, mAnimExecutor); - verify(shellInit, times(1)).addInitCallback(any(), eq(t)); + // One from Transitions, one from RootTaskDisplayAreaOrganizer + verify(shellInit).addInitCallback(any(), eq(t)); + verify(shellInit).addInitCallback(any(), isA(RootTaskDisplayAreaOrganizer.class)); } @Test diff --git a/services/core/java/com/android/server/wm/DisplayArea.java b/services/core/java/com/android/server/wm/DisplayArea.java index f81e5d453434..df26b101a657 100644 --- a/services/core/java/com/android/server/wm/DisplayArea.java +++ b/services/core/java/com/android/server/wm/DisplayArea.java @@ -44,6 +44,7 @@ import android.util.proto.ProtoOutputStream; import android.window.DisplayAreaInfo; import android.window.IDisplayAreaOrganizer; +import com.android.internal.annotations.VisibleForTesting; import com.android.internal.protolog.common.ProtoLog; import com.android.server.policy.WindowManagerPolicy; @@ -79,6 +80,12 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { private final Configuration mTmpConfiguration = new Configuration(); /** + * Prevent duplicate calls to onDisplayAreaAppeared, or early call of onDisplayAreaInfoChanged. + */ + @VisibleForTesting + boolean mDisplayAreaAppearedSent; + + /** * Whether this {@link DisplayArea} should ignore fixed-orientation request. If {@code true}, it * can never specify orientation, but shows the fixed-orientation apps below it in the * letterbox; otherwise, it rotates based on the fixed-orientation request. @@ -582,18 +589,31 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { sendDisplayAreaVanished(lastOrganizer); if (!skipDisplayAreaAppeared) { sendDisplayAreaAppeared(); + } else if (organizer != null) { + // Set as sent since the DisplayAreaAppearedInfo will be sent back when registered. + mDisplayAreaAppearedSent = true; } } + @VisibleForTesting void sendDisplayAreaAppeared() { - if (mOrganizer == null) return; + if (mOrganizer == null || mDisplayAreaAppearedSent) return; mOrganizerController.onDisplayAreaAppeared(mOrganizer, this); + mDisplayAreaAppearedSent = true; + } + + @VisibleForTesting + void sendDisplayAreaInfoChanged() { + if (mOrganizer == null || !mDisplayAreaAppearedSent) return; + mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this); } + @VisibleForTesting void sendDisplayAreaVanished(IDisplayAreaOrganizer organizer) { - if (organizer == null) return; + if (organizer == null || !mDisplayAreaAppearedSent) return; migrateToNewSurfaceControl(getSyncTransaction()); mOrganizerController.onDisplayAreaVanished(organizer, this); + mDisplayAreaAppearedSent = false; } @Override @@ -603,7 +623,7 @@ public class DisplayArea<T extends WindowContainer> extends WindowContainer<T> { super.onConfigurationChanged(newParentConfig); if (mOrganizer != null && getConfiguration().diff(mTmpConfiguration) != 0) { - mOrganizerController.onDisplayAreaInfoChanged(mOrganizer, this); + sendDisplayAreaInfoChanged(); } } diff --git a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java index cd0389dce416..ba31944f412a 100644 --- a/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java +++ b/services/tests/wmtests/src/com/android/server/wm/DisplayAreaTest.java @@ -46,10 +46,13 @@ import static com.android.server.wm.testing.Assert.assertThrows; import static com.google.common.truth.Truth.assertThat; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertNull; +import static org.junit.Assert.assertTrue; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.argThat; import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.clearInvocations; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; @@ -583,6 +586,7 @@ public class DisplayAreaTest extends WindowTestsBase { final IDisplayAreaOrganizer mockDisplayAreaOrganizer = mock(IDisplayAreaOrganizer.class); doReturn(mock(IBinder.class)).when(mockDisplayAreaOrganizer).asBinder(); displayArea.mOrganizer = mockDisplayAreaOrganizer; + displayArea.mDisplayAreaAppearedSent = true; spyOn(mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController); mDisplayContent.addChild(displayArea, 0); @@ -687,6 +691,56 @@ public class DisplayAreaTest extends WindowTestsBase { assertEquals(parent.getChildAt(0), child); } + @Test + public void testSetOrganizer() { + final TaskDisplayArea displayArea = createTaskDisplayArea( + mDisplayContent, mWm, "NewArea", FEATURE_VENDOR_FIRST); + + assertNull(displayArea.mOrganizer); + assertFalse(displayArea.mDisplayAreaAppearedSent); + + final IDisplayAreaOrganizer organizer = mock(IDisplayAreaOrganizer.class); + final DisplayAreaOrganizerController controller = + mWm.mAtmService.mWindowOrganizerController.mDisplayAreaOrganizerController; + spyOn(controller); + doNothing().when(controller).onDisplayAreaVanished(any(), any()); + + displayArea.setOrganizer(organizer); + + assertEquals(organizer, displayArea.mOrganizer); + assertTrue(displayArea.mDisplayAreaAppearedSent); + verify(controller).onDisplayAreaAppeared(organizer, displayArea); + + // No duplicated appeared sent. + clearInvocations(controller); + displayArea.sendDisplayAreaAppeared(); + + verify(controller, never()).onDisplayAreaAppeared(any(), any()); + + // Sent info changed after appeared. + displayArea.sendDisplayAreaInfoChanged(); + + verify(controller).onDisplayAreaInfoChanged(organizer, displayArea); + + // Sent info vanished after appeared. + displayArea.setOrganizer(null); + + verify(controller).onDisplayAreaVanished(organizer, displayArea); + assertNull(displayArea.mOrganizer); + assertFalse(displayArea.mDisplayAreaAppearedSent); + + // No callback until appeared sent. + clearInvocations(controller); + + displayArea.sendDisplayAreaAppeared(); + displayArea.sendDisplayAreaInfoChanged(); + displayArea.sendDisplayAreaVanished(organizer); + + verify(controller, never()).onDisplayAreaAppeared(any(), any()); + verify(controller, never()).onDisplayAreaInfoChanged(any(), any()); + verify(controller, never()).onDisplayAreaVanished(any(), any()); + } + private static class TestDisplayArea<T extends WindowContainer> extends DisplayArea<T> { private TestDisplayArea(WindowManagerService wms, Rect bounds, String name) { super(wms, ANY, name); |