Fix dragging down the notification shade in dreams.

Also includes a small refactor of the dream overlay service code.

Test: atest DreamOverlayContainerViewControllerTest DreamOverlayServiceTest
Bug: 207681309

Change-Id: Ib7aadccfdc140d54407ef78850cbff2aee0cb187
This commit is contained in:
Will
2021-12-16 18:01:55 -08:00
parent 14dca2041f
commit 9710d3a2bb
8 changed files with 356 additions and 173 deletions

View File

@@ -32,8 +32,8 @@
android:id="@+id/dream_overlay_status_bar"
android:layout_width="match_parent"
android:layout_height="@dimen/dream_overlay_status_bar_height"
android:layout_marginEnd="@dimen/dream_overlay_status_bar_margin"
android:layout_marginStart="@dimen/dream_overlay_status_bar_margin"
android:paddingEnd="@dimen/dream_overlay_status_bar_margin"
android:paddingStart="@dimen/dream_overlay_status_bar_margin"
app:layout_constraintTop_toTopOf="parent">
<androidx.constraintlayout.widget.ConstraintLayout

View File

@@ -1309,4 +1309,7 @@
<dimen name="dream_overlay_status_bar_height">80dp</dimen>
<dimen name="dream_overlay_status_bar_margin">40dp</dimen>
<dimen name="dream_overlay_status_icon_margin">8dp</dimen>
<!-- Height of the area at the top of the dream overlay to allow dragging down the notifications
shade. -->
<dimen name="dream_overlay_notifications_drag_area_height">100dp</dimen>
</resources>

View File

@@ -0,0 +1,126 @@
/*
* Copyright (C) 2021 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.systemui.dreams;
import android.graphics.Rect;
import android.graphics.Region;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import androidx.constraintlayout.widget.ConstraintLayout;
import com.android.internal.annotations.VisibleForTesting;
import com.android.systemui.R;
import com.android.systemui.dreams.dagger.DreamOverlayComponent;
import com.android.systemui.dreams.dagger.DreamOverlayModule;
import com.android.systemui.util.ViewController;
import javax.inject.Inject;
import javax.inject.Named;
/**
* View controller for {@link DreamOverlayContainerView}.
*/
@DreamOverlayComponent.DreamOverlayScope
public class DreamOverlayContainerViewController extends ViewController<DreamOverlayContainerView> {
// The height of the area at the top of the dream overlay to allow dragging down the
// notifications shade.
private final int mDreamOverlayNotificationsDragAreaHeight;
private final DreamOverlayStatusBarViewController mStatusBarViewController;
// The dream overlay's content view, which is located below the status bar (in z-order) and is
// the space into which widgets are placed.
private final ViewGroup mDreamOverlayContentView;
// A hook into the internal inset calculation where we declare the overlays as the only
// touchable regions.
private final ViewTreeObserver.OnComputeInternalInsetsListener
mOnComputeInternalInsetsListener =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
inoutInfo.setTouchableInsets(
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
final Region region = new Region();
final Rect rect = new Rect();
final int childCount = mDreamOverlayContentView.getChildCount();
for (int i = 0; i < childCount; i++) {
View child = mDreamOverlayContentView.getChildAt(i);
if (child.getGlobalVisibleRect(rect)) {
region.op(rect, Region.Op.UNION);
}
}
// Add the notifications drag area to the tap region (otherwise the
// notifications shade can't be dragged down).
if (mDreamOverlayContentView.getGlobalVisibleRect(rect)) {
rect.bottom = rect.top + mDreamOverlayNotificationsDragAreaHeight;
region.op(rect, Region.Op.UNION);
}
inoutInfo.touchableRegion.set(region);
}
};
@Inject
public DreamOverlayContainerViewController(
DreamOverlayContainerView containerView,
@Named(DreamOverlayModule.DREAM_OVERLAY_CONTENT_VIEW) ViewGroup contentView,
DreamOverlayStatusBarViewController statusBarViewController) {
super(containerView);
mDreamOverlayContentView = contentView;
mStatusBarViewController = statusBarViewController;
mDreamOverlayNotificationsDragAreaHeight =
mView.getResources().getDimensionPixelSize(
R.dimen.dream_overlay_notifications_drag_area_height);
}
@Override
protected void onInit() {
mStatusBarViewController.init();
}
@Override
protected void onViewAttached() {
mView.getViewTreeObserver()
.addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
@Override
protected void onViewDetached() {
mView.getViewTreeObserver()
.removeOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
void addOverlay(View overlayView, ConstraintLayout.LayoutParams layoutParams) {
mDreamOverlayContentView.addView(overlayView, layoutParams);
}
View getContainerView() {
return mView;
}
void removeAllOverlays() {
mDreamOverlayContentView.removeAllViews();
}
@VisibleForTesting
int getDreamOverlayNotificationsDragAreaHeight() {
return mDreamOverlayNotificationsDragAreaHeight;
}
}

View File

@@ -17,13 +17,8 @@
package com.android.systemui.dreams;
import android.content.Context;
import android.graphics.Rect;
import android.graphics.Region;
import android.graphics.drawable.ColorDrawable;
import android.util.Log;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.view.Window;
import android.view.WindowInsets;
import android.view.WindowManager;
@@ -54,12 +49,12 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
private final Executor mExecutor;
// The state controller informs the service of updates to the complications present.
private final DreamOverlayStateController mStateController;
// The component used to resolve dream overlay dependencies.
private final DreamOverlayComponent mDreamOverlayComponent;
// A controller for the dream overlay container view (which contains both the status bar and the
// content area).
private final DreamOverlayContainerViewController mDreamOverlayContainerViewController;
// The dream overlay's content view, which is located below the status bar (in z-order) and is
// the space into which widgets are placed.
private ViewGroup mDreamOverlayContentView;
// A reference to the {@link Window} used to hold the dream overlay.
private Window mWindow;
private final DreamOverlayStateController.Callback mOverlayStateCallback =
new DreamOverlayStateController.Callback() {
@@ -69,47 +64,6 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
}
};
// The service listens to view changes in order to declare that input occurring in areas outside
// the overlay should be passed through to the dream underneath.
private final View.OnAttachStateChangeListener mRootViewAttachListener =
new View.OnAttachStateChangeListener() {
@Override
public void onViewAttachedToWindow(View v) {
v.getViewTreeObserver()
.addOnComputeInternalInsetsListener(mOnComputeInternalInsetsListener);
}
@Override
public void onViewDetachedFromWindow(View v) {
v.getViewTreeObserver()
.removeOnComputeInternalInsetsListener(
mOnComputeInternalInsetsListener);
}
};
// A hook into the internal inset calculation where we declare the complications as the only
// touchable regions.
private final ViewTreeObserver.OnComputeInternalInsetsListener
mOnComputeInternalInsetsListener =
new ViewTreeObserver.OnComputeInternalInsetsListener() {
@Override
public void onComputeInternalInsets(ViewTreeObserver.InternalInsetsInfo inoutInfo) {
if (mDreamOverlayContentView != null) {
inoutInfo.setTouchableInsets(
ViewTreeObserver.InternalInsetsInfo.TOUCHABLE_INSETS_REGION);
final Region region = new Region();
for (int i = 0; i < mDreamOverlayContentView.getChildCount(); i++) {
View child = mDreamOverlayContentView.getChildAt(i);
final Rect rect = new Rect();
child.getGlobalVisibleRect(rect);
region.op(rect, Region.Op.UNION);
}
inoutInfo.touchableRegion.set(region);
}
}
};
@Inject
public DreamOverlayService(
Context context,
@@ -119,23 +73,29 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
mContext = context;
mExecutor = executor;
mStateController = overlayStateController;
mDreamOverlayComponent = dreamOverlayComponentFactory.create();
mDreamOverlayContainerViewController =
dreamOverlayComponentFactory.create().getDreamOverlayContainerViewController();
mStateController.addCallback(mOverlayStateCallback);
}
@Override
public void onDestroy() {
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
windowManager.removeView(mWindow.getDecorView());
mStateController.removeCallback(mOverlayStateCallback);
super.onDestroy();
}
@Override
public void onStartDream(@NonNull WindowManager.LayoutParams layoutParams) {
mExecutor.execute(() -> addOverlayWindowLocked(layoutParams));
}
private void reloadComplicationsLocked() {
if (mDreamOverlayContentView == null) {
return;
}
mDreamOverlayContentView.removeAllViews();
for (ComplicationProvider complicationProvider : mStateController.getComplications()) {
addComplication(complicationProvider);
mDreamOverlayContainerViewController.removeAllOverlays();
for (ComplicationProvider overlayProvider : mStateController.getComplications()) {
addComplication(overlayProvider);
}
}
@@ -147,32 +107,28 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
* into the dream window.
*/
private void addOverlayWindowLocked(WindowManager.LayoutParams layoutParams) {
final PhoneWindow window = new PhoneWindow(mContext);
window.setAttributes(layoutParams);
window.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
mWindow = new PhoneWindow(mContext);
mWindow.setAttributes(layoutParams);
mWindow.setWindowManager(null, layoutParams.token, "DreamOverlay", true);
window.setBackgroundDrawable(new ColorDrawable(0));
mWindow.setBackgroundDrawable(new ColorDrawable(0));
window.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
window.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
window.requestFeature(Window.FEATURE_NO_TITLE);
mWindow.clearFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS);
mWindow.addFlags(WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE);
mWindow.requestFeature(Window.FEATURE_NO_TITLE);
// Hide all insets when the dream is showing
window.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
window.setDecorFitsSystemWindows(false);
mWindow.getDecorView().getWindowInsetsController().hide(WindowInsets.Type.systemBars());
mWindow.setDecorFitsSystemWindows(false);
if (DEBUG) {
Log.d(TAG, "adding overlay window to dream");
}
window.setContentView(mDreamOverlayComponent.getDreamOverlayContainerView());
mDreamOverlayContentView = mDreamOverlayComponent.getDreamOverlayContentView();
mDreamOverlayContentView.addOnAttachStateChangeListener(mRootViewAttachListener);
mDreamOverlayComponent.getDreamOverlayStatusBarViewController().init();
mDreamOverlayContainerViewController.init();
mWindow.setContentView(mDreamOverlayContainerViewController.getContainerView());
final WindowManager windowManager = mContext.getSystemService(WindowManager.class);
windowManager.addView(window.getDecorView(), window.getAttributes());
windowManager.addView(mWindow.getDecorView(), mWindow.getAttributes());
mExecutor.execute(this::reloadComplicationsLocked);
}
@@ -181,25 +137,12 @@ public class DreamOverlayService extends android.service.dreams.DreamOverlayServ
provider.onCreateComplication(mContext,
(view, layoutParams) -> {
// Always move UI related work to the main thread.
mExecutor.execute(() -> {
if (mDreamOverlayContentView == null) {
return;
}
mDreamOverlayContentView.addView(view, layoutParams);
});
mExecutor.execute(() -> mDreamOverlayContainerViewController
.addOverlay(view, layoutParams));
},
() -> {
// The Callback is set on the main thread.
mExecutor.execute(() -> {
requestExit();
});
mExecutor.execute(this::requestExit);
});
}
@Override
public void onDestroy() {
mStateController.removeCallback(mOverlayStateCallback);
super.onDestroy();
}
}

View File

@@ -18,10 +18,7 @@ package com.android.systemui.dreams.dagger;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import android.view.ViewGroup;
import com.android.systemui.dreams.DreamOverlayContainerView;
import com.android.systemui.dreams.DreamOverlayStatusBarViewController;
import com.android.systemui.dreams.DreamOverlayContainerViewController;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
@@ -48,15 +45,7 @@ public interface DreamOverlayComponent {
@Scope
@interface DreamOverlayScope {}
/** Builds a {@link DreamOverlayContainerView} */
/** Builds a {@link DreamOverlayContainerViewController}. */
@DreamOverlayScope
DreamOverlayContainerView getDreamOverlayContainerView();
/** Builds a content view for dream overlays */
@DreamOverlayScope
ViewGroup getDreamOverlayContentView();
/** Builds a {@link DreamOverlayStatusBarViewController}. */
@DreamOverlayScope
DreamOverlayStatusBarViewController getDreamOverlayStatusBarViewController();
DreamOverlayContainerViewController getDreamOverlayContainerViewController();
}

View File

@@ -44,6 +44,7 @@ public abstract class DreamOverlayModule {
private static final String DREAM_OVERLAY_BATTERY_VIEW = "dream_overlay_battery_view";
public static final String DREAM_OVERLAY_BATTERY_CONTROLLER =
"dream_overlay_battery_controller";
public static final String DREAM_OVERLAY_CONTENT_VIEW = "dream_overlay_content_view";
/** */
@Provides
@@ -58,6 +59,7 @@ public abstract class DreamOverlayModule {
/** */
@Provides
@DreamOverlayComponent.DreamOverlayScope
@Named(DREAM_OVERLAY_CONTENT_VIEW)
public static ViewGroup providesDreamOverlayContentView(DreamOverlayContainerView view) {
return Preconditions.checkNotNull(view.findViewById(R.id.dream_overlay_content),
"R.id.dream_overlay_content must not be null");

View File

@@ -0,0 +1,132 @@
/*
* Copyright (C) 2021 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.systemui.dreams;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import android.content.res.Resources;
import android.testing.AndroidTestingRunner;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.test.filters.SmallTest;
import com.android.systemui.R;
import com.android.systemui.SysuiTestCase;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.ArgumentCaptor;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayContainerViewControllerTest extends SysuiTestCase {
private static final int DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT = 100;
@Mock
Resources mResources;
@Mock
ViewTreeObserver mViewTreeObserver;
@Mock
DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
@Mock
DreamOverlayContainerView mDreamOverlayContainerView;
@Mock
ViewGroup mDreamOverlayContentView;
DreamOverlayContainerViewController mController;
@Before
public void setup() {
MockitoAnnotations.initMocks(this);
when(mResources.getDimensionPixelSize(
R.dimen.dream_overlay_notifications_drag_area_height)).thenReturn(
DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
when(mDreamOverlayContainerView.getResources()).thenReturn(mResources);
when(mDreamOverlayContainerView.getViewTreeObserver()).thenReturn(mViewTreeObserver);
mController = new DreamOverlayContainerViewController(
mDreamOverlayContainerView, mDreamOverlayContentView,
mDreamOverlayStatusBarViewController);
}
@Test
public void testDreamOverlayStatusBarViewControllerInitialized() {
mController.init();
verify(mDreamOverlayStatusBarViewController).init();
}
@Test
public void testSetsDreamOverlayNotificationsDragAreaHeight() {
assertEquals(
mController.getDreamOverlayNotificationsDragAreaHeight(),
DREAM_OVERLAY_NOTIFICATIONS_DRAG_AREA_HEIGHT);
}
@Test
public void testAddOverlayAddsOverlayToContentView() {
View overlay = new View(getContext());
ConstraintLayout.LayoutParams layoutParams = new ConstraintLayout.LayoutParams(100, 100);
mController.addOverlay(overlay, layoutParams);
verify(mDreamOverlayContentView).addView(overlay, layoutParams);
}
@Test
public void testRemoveAllOverlaysRemovesOverlaysFromContentView() {
mController.removeAllOverlays();
verify(mDreamOverlayContentView).removeAllViews();
}
@Test
public void testOnViewAttachedRegistersComputeInsetsListener() {
mController.onViewAttached();
verify(mViewTreeObserver).addOnComputeInternalInsetsListener(any());
}
@Test
public void testOnViewDetachedUnregistersComputeInsetsListener() {
mController.onViewDetached();
verify(mViewTreeObserver).removeOnComputeInternalInsetsListener(any());
}
@Test
public void testComputeInsetsListenerReturnsRegion() {
final ArgumentCaptor<ViewTreeObserver.OnComputeInternalInsetsListener>
computeInsetsListenerCapture =
ArgumentCaptor.forClass(ViewTreeObserver.OnComputeInternalInsetsListener.class);
mController.onViewAttached();
verify(mViewTreeObserver).addOnComputeInternalInsetsListener(
computeInsetsListenerCapture.capture());
final ViewTreeObserver.InternalInsetsInfo info = new ViewTreeObserver.InternalInsetsInfo();
computeInsetsListenerCapture.getValue().onComputeInternalInsets(info);
assertNotNull(info.touchableRegion);
}
}

View File

@@ -17,7 +17,6 @@
package com.android.systemui.dreams;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.clearInvocations;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@@ -55,8 +54,8 @@ import java.util.Arrays;
@SmallTest
@RunWith(AndroidTestingRunner.class)
public class DreamOverlayServiceTest extends SysuiTestCase {
private FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
private final FakeSystemClock mFakeSystemClock = new FakeSystemClock();
private final FakeExecutor mMainExecutor = new FakeExecutor(mFakeSystemClock);
@Rule
public final LeakCheckedTest.SysuiLeakCheck mLeakCheck = new LeakCheckedTest.SysuiLeakCheck();
@@ -80,51 +79,55 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
DreamOverlayStateController mDreamOverlayStateController;
@Mock
DreamOverlayComponent.Factory mDreamOverlayStatusBarViewComponentFactory;
DreamOverlayComponent.Factory mDreamOverlayComponentFactory;
@Mock
DreamOverlayComponent mDreamOverlayComponent;
@Mock
DreamOverlayStatusBarViewController mDreamOverlayStatusBarViewController;
@Mock
DreamOverlayContainerView mDreamOverlayContainerView;
@Mock
ViewGroup mDreamOverlayContentView;
DreamOverlayContainerViewController mDreamOverlayContainerViewController;
DreamOverlayService mService;
@Before
public void setup() {
public void setup() throws Exception {
MockitoAnnotations.initMocks(this);
mContext.addMockSystemService(WindowManager.class, mWindowManager);
when(mDreamOverlayComponent.getDreamOverlayContentView())
.thenReturn(mDreamOverlayContentView);
when(mDreamOverlayComponent.getDreamOverlayContainerView())
.thenReturn(mDreamOverlayContainerView);
when(mDreamOverlayComponent.getDreamOverlayStatusBarViewController())
.thenReturn(mDreamOverlayStatusBarViewController);
when(mDreamOverlayStatusBarViewComponentFactory.create())
when(mDreamOverlayComponent.getDreamOverlayContainerViewController())
.thenReturn(mDreamOverlayContainerViewController);
when(mDreamOverlayComponentFactory.create())
.thenReturn(mDreamOverlayComponent);
when(mDreamOverlayContainerViewController.getContainerView())
.thenReturn(mDreamOverlayContainerView);
}
@Test
public void testInteraction() throws Exception {
final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
final IBinder proxy = service.onBind(new Intent());
mService = new DreamOverlayService(mContext, mMainExecutor,
mDreamOverlayStateController, mDreamOverlayComponentFactory);
final IBinder proxy = mService.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
clearInvocations(mWindowManager);
// Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback);
mMainExecutor.runAllReady();
verify(mWindowManager).addView(any(), any());
}
@Test
public void testOverlayContainerViewAddedToWindow() {
verify(mWindowManager).addView(any(), any());
}
@Test
public void testDreamOverlayContainerViewControllerInitialized() {
verify(mDreamOverlayContainerViewController).init();
}
@Test
public void testAddingOverlayToDream() throws Exception {
// Add overlay.
service.addComplication(mProvider);
mService.addComplication(mProvider);
mMainExecutor.runAllReady();
final ArgumentCaptor<ComplicationHost.CreationCallback> creationCallbackCapture =
@@ -139,9 +142,26 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
// Inform service of overlay view creation.
final View view = new View(mContext);
creationCallbackCapture.getValue().onCreated(view, new ConstraintLayout.LayoutParams(
final ConstraintLayout.LayoutParams lp = new ConstraintLayout.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT
));
);
creationCallbackCapture.getValue().onCreated(view, lp);
mMainExecutor.runAllReady();
// Verify that DreamOverlayContainerViewController is asked to add an overlay for the view.
verify(mDreamOverlayContainerViewController).addOverlay(view, lp);
}
@Test
public void testDreamOverlayExit() throws Exception {
// Add overlay.
mService.addComplication(mProvider);
mMainExecutor.runAllReady();
// Capture interaction callback from overlay creation.
final ArgumentCaptor<ComplicationHost.InteractionCallback> interactionCallbackCapture =
ArgumentCaptor.forClass(ComplicationHost.InteractionCallback.class);
verify(mProvider).onCreateComplication(any(), any(), interactionCallbackCapture.capture());
// Ask service to exit.
interactionCallbackCapture.getValue().onExit();
@@ -152,17 +172,7 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
}
@Test
public void testListening() throws Exception {
final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
final IBinder proxy = service.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback);
mMainExecutor.runAllReady();
public void testListenerRegisteredWithDreamOverlayStateController() {
// Verify overlay service registered as listener with DreamOverlayStateController
// and inform callback of addition.
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
@@ -178,33 +188,11 @@ public class DreamOverlayServiceTest extends SysuiTestCase {
}
@Test
public void testDreamOverlayStatusBarViewControllerInitialized() throws Exception {
final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
final IBinder proxy = service.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback);
mMainExecutor.runAllReady();
verify(mDreamOverlayStatusBarViewController).init();
}
@Test
public void testRootViewAttachListenerIsAddedToDreamOverlayContentView() throws Exception {
final DreamOverlayService service = new DreamOverlayService(mContext, mMainExecutor,
mDreamOverlayStateController, mDreamOverlayStatusBarViewComponentFactory);
final IBinder proxy = service.onBind(new Intent());
final IDreamOverlay overlay = IDreamOverlay.Stub.asInterface(proxy);
// Inform the overlay service of dream starting.
overlay.startDream(mWindowParams, mDreamOverlayCallback);
mMainExecutor.runAllReady();
verify(mDreamOverlayContentView).addOnAttachStateChangeListener(
any(View.OnAttachStateChangeListener.class));
public void testOnDestroyRemovesOverlayStateCallback() {
final ArgumentCaptor<DreamOverlayStateController.Callback> callbackCapture =
ArgumentCaptor.forClass(DreamOverlayStateController.Callback.class);
verify(mDreamOverlayStateController).addCallback(callbackCapture.capture());
mService.onDestroy();
verify(mDreamOverlayStateController).removeCallback(callbackCapture.getValue());
}
}