summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/java/android/service/dreams/DreamOverlayService.java9
-rw-r--r--core/java/android/service/dreams/DreamService.java34
-rw-r--r--core/java/android/service/dreams/IDreamOverlay.aidl8
-rw-r--r--packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java83
-rw-r--r--packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java127
5 files changed, 178 insertions, 83 deletions
diff --git a/core/java/android/service/dreams/DreamOverlayService.java b/core/java/android/service/dreams/DreamOverlayService.java
index 432444211bce..aa45c20a8e13 100644
--- a/core/java/android/service/dreams/DreamOverlayService.java
+++ b/core/java/android/service/dreams/DreamOverlayService.java
@@ -42,8 +42,11 @@ public abstract class DreamOverlayService extends Service {
private IDreamOverlay mDreamOverlay = new IDreamOverlay.Stub() {
@Override
public void startDream(WindowManager.LayoutParams layoutParams,
- IDreamOverlayCallback callback) {
+ IDreamOverlayCallback callback, String dreamComponent,
+ boolean shouldShowComplications) {
mDreamOverlayCallback = callback;
+ mDreamComponent = ComponentName.unflattenFromString(dreamComponent);
+ mShowComplications = shouldShowComplications;
onStartDream(layoutParams);
}
};
@@ -56,10 +59,6 @@ public abstract class DreamOverlayService extends Service {
@Nullable
@Override
public final IBinder onBind(@NonNull Intent intent) {
- mShowComplications = intent.getBooleanExtra(DreamService.EXTRA_SHOW_COMPLICATIONS,
- DreamService.DEFAULT_SHOW_COMPLICATIONS);
- mDreamComponent = intent.getParcelableExtra(DreamService.EXTRA_DREAM_COMPONENT,
- ComponentName.class);
return mDreamOverlay.asBinder();
}
diff --git a/core/java/android/service/dreams/DreamService.java b/core/java/android/service/dreams/DreamService.java
index 3b7698e3954b..3c1fef02f9ba 100644
--- a/core/java/android/service/dreams/DreamService.java
+++ b/core/java/android/service/dreams/DreamService.java
@@ -214,19 +214,6 @@ public class DreamService extends Service implements Window.Callback {
private static final String DREAM_META_DATA_ROOT_TAG = "dream";
/**
- * Extra containing a boolean for whether to show complications on the overlay.
- * @hide
- */
- public static final String EXTRA_SHOW_COMPLICATIONS =
- "android.service.dreams.SHOW_COMPLICATIONS";
-
- /**
- * Extra containing the component name for the active dream.
- * @hide
- */
- public static final String EXTRA_DREAM_COMPONENT = "android.service.dreams.DREAM_COMPONENT";
-
- /**
* The default value for whether to show complications on the overlay.
*
* @hide
@@ -252,6 +239,9 @@ public class DreamService extends Service implements Window.Callback {
private boolean mDebug = false;
+ private ComponentName mDreamComponent;
+ private boolean mShouldShowComplications;
+
private DreamServiceWrapper mDreamServiceWrapper;
private Runnable mDispatchAfterOnAttachedToWindow;
@@ -947,6 +937,11 @@ public class DreamService extends Service implements Window.Callback {
@Override
public void onCreate() {
if (mDebug) Slog.v(mTag, "onCreate()");
+
+ mDreamComponent = new ComponentName(this, getClass());
+ mShouldShowComplications = fetchShouldShowComplications(this /*context*/,
+ fetchServiceInfo(this /*context*/, mDreamComponent));
+
super.onCreate();
}
@@ -994,14 +989,7 @@ public class DreamService extends Service implements Window.Callback {
// Connect to the overlay service if present.
if (!mWindowless && overlayComponent != null) {
final Resources resources = getResources();
- final ComponentName dreamService = new ComponentName(this, getClass());
-
- final ServiceInfo serviceInfo = fetchServiceInfo(this, dreamService);
- final Intent overlayIntent = new Intent()
- .setComponent(overlayComponent)
- .putExtra(EXTRA_SHOW_COMPLICATIONS,
- fetchShouldShowComplications(this, serviceInfo))
- .putExtra(EXTRA_DREAM_COMPONENT, dreamService);
+ final Intent overlayIntent = new Intent().setComponent(overlayComponent);
mOverlayConnection = new OverlayConnection(
/* context= */ this,
@@ -1364,7 +1352,9 @@ public class DreamService extends Service implements Window.Callback {
// parameters once the window has been attached.
mDreamStartOverlayConsumer = overlay -> {
try {
- overlay.startDream(mWindow.getAttributes(), mOverlayCallback);
+ overlay.startDream(mWindow.getAttributes(), mOverlayCallback,
+ mDreamComponent.flattenToString(),
+ mShouldShowComplications);
} catch (RemoteException e) {
Log.e(mTag, "could not send window attributes:" + e);
}
diff --git a/core/java/android/service/dreams/IDreamOverlay.aidl b/core/java/android/service/dreams/IDreamOverlay.aidl
index 2b6633d93dc5..05ebbfe98c9f 100644
--- a/core/java/android/service/dreams/IDreamOverlay.aidl
+++ b/core/java/android/service/dreams/IDreamOverlay.aidl
@@ -31,7 +31,11 @@ interface IDreamOverlay {
* @param params The {@link LayoutParams} for the associated DreamWindow, including the window
token of the Dream Activity.
* @param callback The {@link IDreamOverlayCallback} for requesting actions such as exiting the
- * dream.
+ * dream.
+ * @param dreamComponent The component name of the dream service requesting overlay.
+ * @param shouldShowComplications Whether the dream overlay should show complications, e.g. clock
+ * and weather.
*/
- void startDream(in LayoutParams params, in IDreamOverlayCallback callback);
+ void startDream(in LayoutParams params, in IDreamOverlayCallback callback,
+ in String dreamComponent, in boolean shouldShowComplications);
}
diff --git a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
index 696fc7254308..d1b73685a3f3 100644
--- a/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
+++ b/packages/SystemUI/src/com/android/systemui/dreams/DreamOverlayService.java
@@ -64,29 +64,26 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private final Executor mExecutor;
// A controller for the dream overlay container view (which contains both the status bar and the
// content area).
- private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
+ private DreamOverlayContainerViewController mDreamOverlayContainerViewController;
private final KeyguardUpdateMonitor mKeyguardUpdateMonitor;
@Nullable
private final ComponentName mLowLightDreamComponent;
private final UiEventLogger mUiEventLogger;
+ private final WindowManager mWindowManager;
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
+ // True if a dream has bound to the service and dream overlay service has started.
+ private boolean mStarted = false;
+
// True if the service has been destroyed.
- private boolean mDestroyed;
+ private boolean mDestroyed = false;
- private final Complication.Host mHost = new Complication.Host() {
- @Override
- public void requestExitDream() {
- mExecutor.execute(DreamOverlayService.this::requestExit);
- }
- };
+ private final DreamOverlayComponent mDreamOverlayComponent;
private final LifecycleRegistry mLifecycleRegistry;
- private ViewModelStore mViewModelStore = new ViewModelStore();
-
private DreamOverlayTouchMonitor mDreamOverlayTouchMonitor;
private final KeyguardUpdateMonitorCallback mKeyguardCallback =
@@ -103,7 +100,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
}
};
- private DreamOverlayStateController mStateController;
+ private final DreamOverlayStateController mStateController;
@VisibleForTesting
public enum DreamOverlayEvent implements UiEventLogger.UiEventEnum {
@@ -128,6 +125,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
public DreamOverlayService(
Context context,
@Main Executor executor,
+ WindowManager windowManager,
DreamOverlayComponent.Factory dreamOverlayComponentFactory,
DreamOverlayStateController stateController,
KeyguardUpdateMonitor keyguardUpdateMonitor,
@@ -136,19 +134,19 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
ComponentName lowLightDreamComponent) {
mContext = context;
mExecutor = executor;
+ mWindowManager = windowManager;
mKeyguardUpdateMonitor = keyguardUpdateMonitor;
mLowLightDreamComponent = lowLightDreamComponent;
mKeyguardUpdateMonitor.registerCallback(mKeyguardCallback);
mStateController = stateController;
mUiEventLogger = uiEventLogger;
- final DreamOverlayComponent component =
- dreamOverlayComponentFactory.create(mViewModelStore, mHost);
- mDreamOverlayContainerViewController = component.getDreamOverlayContainerViewController();
+ final ViewModelStore viewModelStore = new ViewModelStore();
+ final Complication.Host host =
+ () -> mExecutor.execute(DreamOverlayService.this::requestExit);
+ mDreamOverlayComponent = dreamOverlayComponentFactory.create(viewModelStore, host);
+ mLifecycleRegistry = mDreamOverlayComponent.getLifecycleRegistry();
setCurrentState(Lifecycle.State.CREATED);
- mLifecycleRegistry = component.getLifecycleRegistry();
- mDreamOverlayTouchMonitor = component.getDreamOverlayTouchMonitor();
- mDreamOverlayTouchMonitor.init();
}
private void setCurrentState(Lifecycle.State state) {
@@ -159,34 +157,48 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
public void onDestroy() {
mKeyguardUpdateMonitor.removeCallback(mKeyguardCallback);
setCurrentState(Lifecycle.State.DESTROYED);
- final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- if (mWindow != null) {
- windowManager.removeView(mWindow.getDecorView());
- }
- mStateController.setOverlayActive(false);
- mStateController.setLowLightActive(false);
+
+ resetCurrentDreamOverlay();
+
mDestroyed = true;
super.onDestroy();
}
@Override
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
- mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
setCurrentState(Lifecycle.State.STARTED);
- final ComponentName dreamComponent = getDreamComponent();
- mStateController.setLowLightActive(
- dreamComponent != null && dreamComponent.equals(mLowLightDreamComponent));
+
mExecutor.execute(() -> {
+ mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
+
if (mDestroyed) {
// The task could still be executed after the service has been destroyed. Bail if
// that is the case.
return;
}
+
+ if (mStarted) {
+ // Reset the current dream overlay before starting a new one. This can happen
+ // when two dreams overlap (briefly, for a smoother dream transition) and both
+ // dreams are bound to the dream overlay service.
+ resetCurrentDreamOverlay();
+ }
+
+ mDreamOverlayContainerViewController =
+ mDreamOverlayComponent.getDreamOverlayContainerViewController();
+ mDreamOverlayTouchMonitor = mDreamOverlayComponent.getDreamOverlayTouchMonitor();
+ mDreamOverlayTouchMonitor.init();
+
mStateController.setShouldShowComplications(shouldShowComplications());
addOverlayWindowLocked(layoutParams);
setCurrentState(Lifecycle.State.RESUMED);
mStateController.setOverlayActive(true);
+ final ComponentName dreamComponent = getDreamComponent();
+ mStateController.setLowLightActive(
+ dreamComponent != null && dreamComponent.equals(mLowLightDreamComponent));
mUiEventLogger.log(DreamOverlayEvent.DREAM_OVERLAY_COMPLETE_START);
+
+ mStarted = true;
});
}
@@ -222,8 +234,7 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
removeContainerViewFromParent();
mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());
- final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
- windowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
+ mWindowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
}
private void removeContainerViewFromParent() {
@@ -238,4 +249,18 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
Log.w(TAG, "Removing dream overlay container view parent!");
parentView.removeView(containerView);
}
+
+ private void resetCurrentDreamOverlay() {
+ if (mStarted && mWindow != null) {
+ mWindowManager.removeView(mWindow.getDecorView());
+ }
+
+ mStateController.setOverlayActive(false);
+ mStateController.setLowLightActive(false);
+
+ mDreamOverlayContainerViewController = null;
+ mDreamOverlayTouchMonitor = 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 eec33ca2ff78..f370be190761 100644
--- a/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
+++ b/packages/SystemUI/tests/src/com/android/systemui/dreams/DreamOverlayServiceTest.java
@@ -19,6 +19,7 @@ package com.android.systemui.dreams;
import static com.google.common.truth.Truth.assertThat;
import static org.mockito.ArgumentMatchers.any;
+import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -27,10 +28,10 @@ import android.content.ComponentName;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
-import android.service.dreams.DreamService;
import android.service.dreams.IDreamOverlay;
import android.service.dreams.IDreamOverlayCallback;
import android.testing.AndroidTestingRunner;
+import android.view.View;
import android.view.ViewGroup;
import android.view.WindowManager;
import android.view.WindowManagerImpl;
@@ -53,6 +54,8 @@ import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.junit.runner.RunWith;
+import org.mockito.ArgumentCaptor;
+import org.mockito.Captor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@@ -61,6 +64,7 @@ import org.mockito.MockitoAnnotations;
public class DreamOverlayServiceTest extends SysuiTestCase {
private static final ComponentName LOW_LIGHT_COMPONENT = new ComponentName("package",
"lowlight");
+ private static final String DREAM_COMPONENT = "package/dream";
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@@ -108,12 +112,14 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
@Mock
UiEventLogger mUiEventLogger;
+ @Captor
+ ArgumentCaptor<View> mViewCaptor;
+
DreamOverlayService mService;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
- mContext.addMockSystemService(WindowManager.class, mWindowManager);
when(mDreamOverlayComponent.getDreamOverlayContainerViewController())
.thenReturn(mDreamOverlayContainerViewController);
@@ -129,7 +135,7 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
when(mDreamOverlayContainerViewController.getContainerView())
.thenReturn(mDreamOverlayContainerView);
- mService = new DreamOverlayService(mContext, mMainExecutor,
+ mService = new DreamOverlayService(mContext, mMainExecutor, mWindowManager,
mDreamOverlayComponentFactory,
mStateController,
mKeyguardUpdateMonitor,
@@ -143,7 +149,8 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ false /*shouldShowComplication*/);
mMainExecutor.runAllReady();
verify(mUiEventLogger).log(DreamOverlayService.DreamOverlayEvent.DREAM_OVERLAY_ENTER_START);
@@ -157,7 +164,8 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ false /*shouldShowComplication*/);
mMainExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
@@ -169,7 +177,8 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ false /*shouldShowComplication*/);
mMainExecutor.runAllReady();
verify(mDreamOverlayContainerViewController).init();
@@ -186,49 +195,76 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ false /*shouldShowComplication*/);
mMainExecutor.runAllReady();
verify(mDreamOverlayContainerViewParent).removeView(mDreamOverlayContainerView);
}
@Test
- public void testShouldShowComplicationsFalseByDefault() {
- mService.onBind(new Intent());
+ public void testShouldShowComplicationsSetByStartDream() throws RemoteException {
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
- assertThat(mService.shouldShowComplications()).isFalse();
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ true /*shouldShowComplication*/);
+
+ assertThat(mService.shouldShowComplications()).isTrue();
}
@Test
- public void testShouldShowComplicationsSetByIntentExtra() {
- final Intent intent = new Intent();
- intent.putExtra(DreamService.EXTRA_SHOW_COMPLICATIONS, true);
- mService.onBind(intent);
+ public void testLowLightSetByStartDream() throws RemoteException {
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
- assertThat(mService.shouldShowComplications()).isTrue();
+ // Inform the overlay service of dream starting.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback,
+ LOW_LIGHT_COMPONENT.flattenToString(), false /*shouldShowComplication*/);
+ mMainExecutor.runAllReady();
+
+ assertThat(mService.getDreamComponent()).isEqualTo(LOW_LIGHT_COMPONENT);
+ verify(mStateController).setLowLightActive(true);
}
@Test
- public void testLowLightSetByIntentExtra() throws RemoteException {
- final Intent intent = new Intent();
- intent.putExtra(DreamService.EXTRA_DREAM_COMPONENT, LOW_LIGHT_COMPONENT);
-
- final IBinder proxy = mService.onBind(intent);
+ public void testDestroy() throws RemoteException {
+ final IBinder proxy = mService.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
- assertThat(mService.getDreamComponent()).isEqualTo(LOW_LIGHT_COMPONENT);
// Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ overlay.startDream(mWindowParams, mDreamOverlayCallback,
+ LOW_LIGHT_COMPONENT.flattenToString(), false /*shouldShowComplication*/);
mMainExecutor.runAllReady();
- verify(mStateController).setLowLightActive(true);
+ // Verify view added.
+ verify(mWindowManager).addView(mViewCaptor.capture(), any());
+
+ // Service destroyed.
+ mService.onDestroy();
+ mMainExecutor.runAllReady();
+
+ // Verify view removed.
+ verify(mWindowManager).removeView(mViewCaptor.getValue());
+
+ // Verify state correctly set.
+ verify(mKeyguardUpdateMonitor).removeCallback(any());
+ verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED);
+ verify(mStateController).setOverlayActive(false);
+ verify(mStateController).setLowLightActive(false);
}
@Test
- public void testDestroy() {
+ public void testDoNotRemoveViewOnDestroyIfOverlayNotStarted() {
+ // Service destroyed without ever starting dream.
mService.onDestroy();
mMainExecutor.runAllReady();
+ // Verify no view is removed.
+ verify(mWindowManager, never()).removeView(any());
+
+ // Verify state still correctly set.
verify(mKeyguardUpdateMonitor).removeCallback(any());
verify(mLifecycleRegistry).setCurrentState(Lifecycle.State.DESTROYED);
verify(mStateController).setOverlayActive(false);
@@ -245,7 +281,8 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
- overlay.startDream(mWindowParams, mDreamOverlayCallback);
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ false /*shouldShowComplication*/);
// Destroy the service.
mService.onDestroy();
@@ -255,4 +292,44 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
verify(mWindowManager, never()).addView(any(), any());
}
+
+ @Test
+ public void testResetCurrentOverlayWhenConnectedToNewDream() throws RemoteException {
+ final IBinder proxy = mService.onBind(new Intent());
+ final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
+
+ // Inform the overlay service of dream starting. Do not show dream complications.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ false /*shouldShowComplication*/);
+ mMainExecutor.runAllReady();
+
+ // Verify that a new window is added.
+ verify(mWindowManager).addView(mViewCaptor.capture(), any());
+ final View windowDecorView = mViewCaptor.getValue();
+
+ // Assert that the overlay is not showing complications.
+ assertThat(mService.shouldShowComplications()).isFalse();
+
+ clearInvocations(mDreamOverlayComponent);
+ clearInvocations(mWindowManager);
+
+ // New dream starting with dream complications showing. Note that when a new dream is
+ // binding to the dream overlay service, it receives the same instance of IBinder as the
+ // first one.
+ overlay.startDream(mWindowParams, mDreamOverlayCallback, DREAM_COMPONENT,
+ true /*shouldShowComplication*/);
+ mMainExecutor.runAllReady();
+
+ // Assert that the overlay is showing complications.
+ assertThat(mService.shouldShowComplications()).isTrue();
+
+ // Verify that the old overlay window has been removed, and a new one created.
+ verify(mWindowManager).removeView(windowDecorView);
+ verify(mWindowManager).addView(any(), any());
+
+ // Verify that new instances of overlay container view controller and overlay touch monitor
+ // are created.
+ verify(mDreamOverlayComponent).getDreamOverlayContainerViewController();
+ verify(mDreamOverlayComponent).getDreamOverlayTouchMonitor();
+ }
}