diff options
| author | 2023-01-06 00:53:28 +0000 | |
|---|---|---|
| committer | 2023-01-11 20:50:53 +0000 | |
| commit | 0aa0f4acb29b4b61d66aabc609d0be3ced06aeeb (patch) | |
| tree | acb20373c72a5daf41eed1ee73062a711368a302 | |
| parent | 16a8a796447566fc5fa3d2ee68f7ec809509398a (diff) | |
Remove Dream Overlay when Dream Window detaches.
This changelist removes the dream overlay window when the associated
dream window is removed. This follows closely to the attach behavior,
where the dream overlay window is added after the dream window is
attached. Previously, the dream overlay window was removed during
onDestroy. Deferring removal to this later point in the lifecycle
allows for the window to be incorrectly acted upon after the associated
dream is gone.
This changelist also implements a default implementation of
DreamOverlayService#onWakeUp which immediately runs the callback. It
also addresses an issue where service connection consumers were not
cleared in the overlay service connection.
Fixes: 261913526
Test: atest DreamOverlayServiceTest
Test: atest DreamOverlayTest
Change-Id: I4c80b585a484c20a8282fca75bd1908b494ce928
7 files changed, 82 insertions, 9 deletions
diff --git a/core/api/test-current.txt b/core/api/test-current.txt index 70a23cdf106b..1a9e75b31e62 100644 --- a/core/api/test-current.txt +++ b/core/api/test-current.txt @@ -2412,6 +2412,7 @@ package android.service.dreams { public abstract class DreamOverlayService extends android.app.Service { ctor public DreamOverlayService(); method @Nullable public final android.os.IBinder onBind(@NonNull android.content.Intent); + method public void onEndDream(); method public abstract void onStartDream(@NonNull android.view.WindowManager.LayoutParams); method public final void requestExit(); method public final boolean shouldShowComplications(); diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java index 6e8198ba0cd1..bf5b970311d0 100644 --- a/core/java/android/service/dreams/DreamOverlayService.java +++ b/core/java/android/service/dreams/DreamOverlayService.java @@ -51,6 +51,11 @@ public abstract class DreamOverlayService extends Service { } @Override + public void endDream() { + onEndDream(); + } + + @Override public void wakeUp() { onWakeUp(() -> { try { @@ -83,13 +88,22 @@ public abstract class DreamOverlayService extends Service { /** * This method is overridden by implementations to handle when the dream has been requested - * to wakeup. This allows any overlay animations to run. + * to wakeup. This allows any overlay animations to run. By default, the method will invoke + * the callback immediately. * * @param onCompleteCallback The callback to trigger to notify the dream service that the * overlay has completed waking up. * @hide */ public void onWakeUp(@NonNull Runnable onCompleteCallback) { + onCompleteCallback.run(); + } + + /** + * This method is overridden by implementations to handle when the dream has ended. There may + * be earlier signals leading up to this step, such as @{@link #onWakeUp(Runnable)}. + */ + public void onEndDream() { } /** diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java index 8b9852a8f1b7..d3788862b6c0 100644 --- a/core/java/android/service/dreams/DreamService.java +++ b/core/java/android/service/dreams/DreamService.java @@ -297,14 +297,20 @@ public class DreamService extends Service implements Window.Callback { } public void addConsumer(Consumer<IDreamOverlay> consumer) { - mConsumers.add(consumer); - if (mOverlay != null) { - consumer.accept(mOverlay); - } + execute(() -> { + mConsumers.add(consumer); + if (mOverlay != null) { + consumer.accept(mOverlay); + } + }); } public void removeConsumer(Consumer<IDreamOverlay> consumer) { - mConsumers.remove(consumer); + execute(() -> mConsumers.remove(consumer)); + } + + public void clearConsumers() { + execute(() -> mConsumers.clear()); } } @@ -1383,6 +1389,17 @@ public class DreamService extends Service implements Window.Callback { @Override public void onViewDetachedFromWindow(View v) { + if (mOverlayConnection != null) { + mOverlayConnection.addConsumer(overlay -> { + try { + overlay.endDream(); + } catch (RemoteException e) { + Log.e(mTag, "could not inform overlay of dream end:" + e); + } + }); + mOverlayConnection.clearConsumers(); + } + if (mActivity == null || !mActivity.isChangingConfigurations()) { // Only stop the dream if the view is not detached by relaunching // activity for configuration changes. It is important to also clear @@ -1391,9 +1408,6 @@ public class DreamService extends Service implements Window.Callback { mActivity = null; finish(); } - if (mOverlayConnection != null && mDreamStartOverlayConsumer != null) { - mOverlayConnection.removeConsumer(mDreamStartOverlayConsumer); - } } }); } diff --git a/core/java/android/service/dreams/IDreamOverlay.aidl b/core/java/android/service/dreams/IDreamOverlay.aidl index 7aeceb2ce538..0e4bd3bd547b 100644 --- a/core/java/android/service/dreams/IDreamOverlay.aidl +++ b/core/java/android/service/dreams/IDreamOverlay.aidl @@ -41,4 +41,7 @@ interface IDreamOverlay { /** Called when the dream is waking, to do any exit animations */ void wakeUp(); + + /** Called when the dream has ended. */ + void endDream(); } diff --git a/core/java/com/android/internal/util/ObservableServiceConnection.java b/core/java/com/android/internal/util/ObservableServiceConnection.java index 3165d293bd91..45256fd26cba 100644 --- a/core/java/com/android/internal/util/ObservableServiceConnection.java +++ b/core/java/com/android/internal/util/ObservableServiceConnection.java @@ -165,6 +165,13 @@ public class ObservableServiceConnection<T> implements ServiceConnection { } /** + * Executes code on the executor specified at construction. + */ + public void execute(Runnable runnable) { + mExecutor.execute(runnable); + } + + /** * Initiate binding to the service. * * @return {@code true} if initiating binding succeed, {@code false} if the binding failed or diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java index a9a9caed314b..dd01be0ef031 100644 --- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java +++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java @@ -208,6 +208,13 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ }); } + @Override + public void onEndDream() { + mExecutor.execute(() -> { + resetCurrentDreamOverlayLocked(); + }); + } + private Lifecycle.State getCurrentStateLocked() { return mLifecycleRegistry.getCurrentState(); } @@ -291,6 +298,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ mDreamOverlayContainerViewController = null; mDreamOverlayTouchMonitor = null; + mWindow = null; mStarted = false; } } diff --git a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java index 4568d1e9b3bd..3b8bb8089910 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java @@ -234,6 +234,32 @@ public class DreamOverlayServiceTest extends SysuiTestCase { } @Test + public void testOnEndDream() throws RemoteException { + final IBinder proxy = mService.onBind(new Intent()); + final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy); + + // Inform the overlay service of dream starting. + overlay.startDream(mWindowParams, mDreamOverlayCallback, + LOW_LIGHT_COMPONENT.flattenToString(), false /*shouldShowComplication*/); + mMainExecutor.runAllReady(); + + // Verify view added. + verify(mWindowManager).addView(mViewCaptor.capture(), any()); + + // Service destroyed. + mService.onEndDream(); + mMainExecutor.runAllReady(); + + // Verify view removed. + verify(mWindowManager).removeView(mViewCaptor.getValue()); + + // Verify state correctly set. + verify(mStateController).setOverlayActive(false); + verify(mStateController).setLowLightActive(false); + verify(mStateController).setEntryAnimationsFinished(false); + } + + @Test public void testDestroy() throws RemoteException { final IBinder proxy = mService.onBind(new Intent()); final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy); |