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
This commit is contained in:
@@ -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();
|
||||
|
||||
@@ -50,6 +50,11 @@ public abstract class DreamOverlayService extends Service {
|
||||
onStartDream(layoutParams);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void endDream() {
|
||||
onEndDream();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void wakeUp() {
|
||||
onWakeUp(() -> {
|
||||
@@ -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() {
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@@ -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();
|
||||
}
|
||||
|
||||
@@ -164,6 +164,13 @@ public class ObservableServiceConnection<T> implements ServiceConnection {
|
||||
mFlags = flags;
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes code on the executor specified at construction.
|
||||
*/
|
||||
public void execute(Runnable runnable) {
|
||||
mExecutor.execute(runnable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Initiate binding to the service.
|
||||
*
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -233,6 +233,32 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
|
||||
verify(mStateController).setLowLightActive(true);
|
||||
}
|
||||
|
||||
@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());
|
||||
|
||||
Reference in New Issue
Block a user