diff options
11 files changed, 637 insertions, 194 deletions
diff --git a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java index 9e194fb49d3a..288e5cf13c2e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/navigationbar/CarNavigationBarController.java @@ -73,7 +73,7 @@ public class CarNavigationBarController { } /** - * Hides all navigation bars. + * Hides all system bars. */ public void hideBars() { if (mTopView != null) { @@ -85,7 +85,7 @@ public class CarNavigationBarController { } /** - * Shows all navigation bars. + * Shows all system bars. */ public void showBars() { if (mTopView != null) { diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java index 20fcca0d0220..aeb1d39599db 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainer.java @@ -29,41 +29,40 @@ import android.widget.FrameLayout; import com.android.car.notification.R; import com.android.car.notification.headsup.CarHeadsUpNotificationContainer; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.window.OverlayViewGlobalStateController; import com.android.systemui.dagger.qualifiers.Main; import javax.inject.Inject; import javax.inject.Singleton; -import dagger.Lazy; - /** * A controller for SysUI's HUN display. */ @Singleton public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotificationContainer { private final CarDeviceProvisionedController mCarDeviceProvisionedController; - private final Lazy<NotificationPanelViewController> mNotificationPanelViewControllerLazy; + private final OverlayViewGlobalStateController mOverlayViewGlobalStateController; private final ViewGroup mWindow; private final FrameLayout mHeadsUpContentFrame; - private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen; - @Inject CarHeadsUpNotificationSystemContainer(Context context, @Main Resources resources, CarDeviceProvisionedController deviceProvisionedController, WindowManager windowManager, - Lazy<NotificationPanelViewController> notificationPanelViewControllerLazy) { + OverlayViewGlobalStateController overlayViewGlobalStateController) { mCarDeviceProvisionedController = deviceProvisionedController; - mNotificationPanelViewControllerLazy = notificationPanelViewControllerLazy; + mOverlayViewGlobalStateController = overlayViewGlobalStateController; boolean showOnBottom = resources.getBoolean(R.bool.config_showHeadsUpNotificationOnBottom); + // Use TYPE_STATUS_BAR_SUB_PANEL window type since we need to find a window that is above + // status bar but below navigation bar. WindowManager.LayoutParams lp = new WindowManager.LayoutParams( ViewGroup.LayoutParams.MATCH_PARENT, WindowManager.LayoutParams.WRAP_CONTENT, - WindowManager.LayoutParams.TYPE_KEYGUARD_DIALOG, + WindowManager.LayoutParams.TYPE_STATUS_BAR_SUB_PANEL, WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE | WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN, PixelFormat.TRANSLUCENT); @@ -78,15 +77,11 @@ public class CarHeadsUpNotificationSystemContainer implements CarHeadsUpNotifica windowManager.addView(mWindow, lp); mWindow.setVisibility(View.INVISIBLE); mHeadsUpContentFrame = mWindow.findViewById(R.id.headsup_content); - - mEnableHeadsUpNotificationWhenNotificationShadeOpen = resources.getBoolean( - R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen); } private void animateShow() { - if ((mEnableHeadsUpNotificationWhenNotificationShadeOpen - || !mNotificationPanelViewControllerLazy.get().isPanelExpanded()) - && mCarDeviceProvisionedController.isCurrentUserFullySetup()) { + if (mCarDeviceProvisionedController.isCurrentUserFullySetup() + && mOverlayViewGlobalStateController.shouldShowHUN()) { mWindow.setVisibility(View.VISIBLE); } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java index cb9539ad5b1d..1738091d14c9 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/notification/NotificationPanelViewController.java @@ -73,6 +73,7 @@ public class NotificationPanelViewController extends OverlayPanelViewController private final CarNotificationListener mCarNotificationListener; private final NotificationClickHandlerFactory mNotificationClickHandlerFactory; private final StatusBarStateController mStatusBarStateController; + private final boolean mEnableHeadsUpNotificationWhenNotificationShadeOpen; private float mInitialBackgroundAlpha; private float mBackgroundAlphaDiff; @@ -144,6 +145,10 @@ public class NotificationPanelViewController extends OverlayPanelViewController + " percentage"); } mBackgroundAlphaDiff = finalBackgroundAlpha - mInitialBackgroundAlpha; + + mEnableHeadsUpNotificationWhenNotificationShadeOpen = mResources.getBoolean( + com.android.car.notification.R.bool + .config_enableHeadsUpNotificationWhenNotificationShadeOpen); } @Override @@ -151,6 +156,16 @@ public class NotificationPanelViewController extends OverlayPanelViewController reinflate(); } + @Override + protected boolean shouldShowNavigationBar() { + return true; + } + + @Override + protected boolean shouldShowHUN() { + return mEnableHeadsUpNotificationWhenNotificationShadeOpen; + } + /** Reinflates the view. */ public void reinflate() { ViewGroup container = (ViewGroup) getLayout(); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java index 0fe985684543..45808a8a0b3e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayPanelViewController.java @@ -375,10 +375,10 @@ public abstract class OverlayPanelViewController extends OverlayViewController { } if (visible && !getOverlayViewGlobalStateController().isWindowVisible()) { - getOverlayViewGlobalStateController().setWindowVisible(true); + getOverlayViewGlobalStateController().showView(/* panelViewController= */ this); } if (!visible && getOverlayViewGlobalStateController().isWindowVisible()) { - getOverlayViewGlobalStateController().setWindowVisible(false); + getOverlayViewGlobalStateController().hideView(/* panelViewController= */ this); } getLayout().setVisibility(visible ? View.VISIBLE : View.INVISIBLE); getOverlayViewGlobalStateController().setWindowFocusable(visible); diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java index 87f20208476b..30e26578bd73 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java @@ -54,7 +54,6 @@ public class OverlayViewController { mOverlayViewGlobalStateController.hideView(/* viewController= */ this, this::hide); } - /** * Inflate layout owned by controller. */ @@ -72,7 +71,7 @@ public class OverlayViewController { } /** - * Returns [@code true} if layout owned by controller has been inflated. + * Returns {@code true} if layout owned by controller has been inflated. */ public final boolean isInflated() { return mLayout != null; @@ -125,4 +124,18 @@ public class OverlayViewController { protected final OverlayViewGlobalStateController getOverlayViewGlobalStateController() { return mOverlayViewGlobalStateController; } + + /** + * Returns {@code true} if heads up notifications should be displayed over this view. + */ + protected boolean shouldShowHUN() { + return true; + } + + /** + * Returns {@code true} if navigation bar should be displayed over this view. + */ + protected boolean shouldShowNavigationBar() { + return false; + } } diff --git a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java index 290505f5042a..70260b0d4cef 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java @@ -16,14 +16,17 @@ package com.android.systemui.car.window; +import android.annotation.Nullable; import android.util.Log; import androidx.annotation.VisibleForTesting; import com.android.systemui.car.navigationbar.CarNavigationBarController; -import java.util.HashSet; -import java.util.Set; +import java.util.HashMap; +import java.util.Map; +import java.util.SortedMap; +import java.util.TreeMap; import javax.inject.Inject; import javax.inject.Singleton; @@ -39,11 +42,17 @@ import javax.inject.Singleton; */ @Singleton public class OverlayViewGlobalStateController { + private static final boolean DEBUG = false; private static final String TAG = OverlayViewGlobalStateController.class.getSimpleName(); + private static final int UNKNOWN_Z_ORDER = -1; private final SystemUIOverlayWindowController mSystemUIOverlayWindowController; private final CarNavigationBarController mCarNavigationBarController; @VisibleForTesting - Set<String> mShownSet; + Map<OverlayViewController, Integer> mZOrderMap; + @VisibleForTesting + SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap; + @VisibleForTesting + OverlayViewController mHighestZOrder; @Inject public OverlayViewGlobalStateController( @@ -52,7 +61,8 @@ public class OverlayViewGlobalStateController { mSystemUIOverlayWindowController = systemUIOverlayWindowController; mSystemUIOverlayWindowController.attach(); mCarNavigationBarController = carNavigationBarController; - mShownSet = new HashSet<>(); + mZOrderMap = new HashMap<>(); + mZOrderVisibleSortedMap = new TreeMap<>(); } /** @@ -66,51 +76,127 @@ public class OverlayViewGlobalStateController { } /** - * Show content in Overlay Window. + * Show content in Overlay Window using {@link OverlayPanelViewController}. + * + * This calls {@link OverlayViewGlobalStateController#showView(OverlayViewController, Runnable)} + * where the runnable is nullified since the actual showing of the panel is handled by the + * controller itself. */ - public void showView(OverlayViewController viewController, Runnable show) { - if (mShownSet.isEmpty()) { - mCarNavigationBarController.hideBars(); + public void showView(OverlayPanelViewController panelViewController) { + showView(panelViewController, /* show= */ null); + } + + /** + * Show content in Overlay Window using {@link OverlayViewController}. + */ + public void showView(OverlayViewController viewController, @Nullable Runnable show) { + debugLog(); + if (mZOrderVisibleSortedMap.isEmpty()) { setWindowVisible(true); } + if (!(viewController instanceof OverlayPanelViewController)) { + inflateView(viewController); + } - inflateView(viewController); + if (show != null) { + show.run(); + } - show.run(); - mShownSet.add(viewController.getClass().getName()); + updateInternalsWhenShowingView(viewController); + refreshNavigationBarVisibility(); Log.d(TAG, "Content shown: " + viewController.getClass().getName()); + debugLog(); + } + + private void updateInternalsWhenShowingView(OverlayViewController viewController) { + int zOrder; + if (mZOrderMap.containsKey(viewController)) { + zOrder = mZOrderMap.get(viewController); + } else { + zOrder = mSystemUIOverlayWindowController.getBaseLayout().indexOfChild( + viewController.getLayout()); + mZOrderMap.put(viewController, zOrder); + } + + mZOrderVisibleSortedMap.put(zOrder, viewController); + + refreshHighestZOrderWhenShowingView(viewController); + } + + private void refreshHighestZOrderWhenShowingView(OverlayViewController viewController) { + if (mZOrderMap.getOrDefault(mHighestZOrder, UNKNOWN_Z_ORDER) < mZOrderMap.get( + viewController)) { + mHighestZOrder = viewController; + } + } + + /** + * Hide content in Overlay Window using {@link OverlayPanelViewController}. + * + * This calls {@link OverlayViewGlobalStateController#hideView(OverlayViewController, Runnable)} + * where the runnable is nullified since the actual hiding of the panel is handled by the + * controller itself. + */ + public void hideView(OverlayPanelViewController panelViewController) { + hideView(panelViewController, /* hide= */ null); } /** - * Hide content in Overlay Window. + * Hide content in Overlay Window using {@link OverlayViewController}. */ - public void hideView(OverlayViewController viewController, Runnable hide) { + public void hideView(OverlayViewController viewController, @Nullable Runnable hide) { + debugLog(); if (!viewController.isInflated()) { Log.d(TAG, "Content cannot be hidden since it isn't inflated: " + viewController.getClass().getName()); return; } - if (!mShownSet.contains(viewController.getClass().getName())) { - Log.d(TAG, "Content cannot be hidden since it isn't shown: " + if (!mZOrderMap.containsKey(viewController)) { + Log.d(TAG, "Content cannot be hidden since it has never been shown: " + + viewController.getClass().getName()); + return; + } + if (!mZOrderVisibleSortedMap.containsKey(mZOrderMap.get(viewController))) { + Log.d(TAG, "Content cannot be hidden since it isn't currently shown: " + viewController.getClass().getName()); return; } - hide.run(); - mShownSet.remove(viewController.getClass().getName()); + if (hide != null) { + hide.run(); + } - if (mShownSet.isEmpty()) { - mCarNavigationBarController.showBars(); + mZOrderVisibleSortedMap.remove(mZOrderMap.get(viewController)); + refreshHighestZOrderWhenHidingView(viewController); + refreshNavigationBarVisibility(); + + if (mZOrderVisibleSortedMap.isEmpty()) { setWindowVisible(false); } Log.d(TAG, "Content hidden: " + viewController.getClass().getName()); + debugLog(); + } + + private void refreshHighestZOrderWhenHidingView(OverlayViewController viewController) { + if (mZOrderVisibleSortedMap.isEmpty()) { + mHighestZOrder = null; + return; + } + if (!mHighestZOrder.equals(viewController)) { + return; + } + + mHighestZOrder = mZOrderVisibleSortedMap.get(mZOrderVisibleSortedMap.lastKey()); } - /** Sets the window visibility state. */ - public void setWindowVisible(boolean expanded) { - mSystemUIOverlayWindowController.setWindowVisible(expanded); + private void refreshNavigationBarVisibility() { + if (mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowNavigationBar()) { + mCarNavigationBarController.showBars(); + } else { + mCarNavigationBarController.hideBars(); + } } /** Returns {@code true} is the window is visible. */ @@ -118,13 +204,14 @@ public class OverlayViewGlobalStateController { return mSystemUIOverlayWindowController.isWindowVisible(); } - /** Sets the focusable flag of the sysui overlawy window. */ - public void setWindowFocusable(boolean focusable) { - mSystemUIOverlayWindowController.setWindowFocusable(focusable); + private void setWindowVisible(boolean visible) { + mSystemUIOverlayWindowController.setWindowVisible(visible); } - /** Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the - * sysui overlay window */ + /** + * Sets the {@link android.view.WindowManager.LayoutParams#FLAG_ALT_FOCUSABLE_IM} flag of the + * sysui overlay window. + */ public void setWindowNeedsInput(boolean needsInput) { mSystemUIOverlayWindowController.setWindowNeedsInput(needsInput); } @@ -134,10 +221,34 @@ public class OverlayViewGlobalStateController { return mSystemUIOverlayWindowController.isWindowFocusable(); } + /** Sets the focusable flag of the sysui overlawy window. */ + public void setWindowFocusable(boolean focusable) { + mSystemUIOverlayWindowController.setWindowFocusable(focusable); + } + /** Inflates the view controlled by the given view controller. */ public void inflateView(OverlayViewController viewController) { if (!viewController.isInflated()) { viewController.inflate(mSystemUIOverlayWindowController.getBaseLayout()); } } + + /** + * Return {@code true} if OverlayWindow is in a state where HUNs should be displayed above it. + */ + public boolean shouldShowHUN() { + return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN(); + } + + private void debugLog() { + if (!DEBUG) { + return; + } + + Log.d(TAG, "mHighestZOrder: " + mHighestZOrder); + Log.d(TAG, "mZOrderVisibleSortedMap.size(): " + mZOrderVisibleSortedMap.size()); + Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap); + Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size()); + Log.d(TAG, "mZOrderMap: " + mZOrderMap); + } } diff --git a/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml new file mode 100644 index 000000000000..03fe0e4fcf2e --- /dev/null +++ b/packages/CarSystemUI/tests/res/layout/overlay_view_global_state_controller_test.xml @@ -0,0 +1,43 @@ +<?xml version="1.0" encoding="utf-8"?> +<!-- + ~ Copyright (C) 2020 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. + --> + +<!-- Fullscreen views in sysui should be listed here in increasing Z order. --> +<FrameLayout + xmlns:android="http://schemas.android.com/apk/res/android" + android:background="@android:color/transparent" + android:layout_width="match_parent" + android:layout_height="match_parent"> + + <ViewStub android:id="@+id/overlay_view_controller_stub_1" + android:inflatedId="@+id/overlay_view_controller_1" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/overlay_view_controller_stub"/> + + <ViewStub android:id="@+id/overlay_view_controller_stub_2" + android:inflatedId="@+id/overlay_view_controller_2" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/overlay_view_controller_stub"/> + + <ViewStub android:id="@+id/overlay_view_controller_stub_3" + android:inflatedId="@+id/overlay_view_controller_3" + android:layout_width="match_parent" + android:layout_height="match_parent" + android:layout="@layout/overlay_view_controller_stub"/> + +</FrameLayout>
\ No newline at end of file diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java index a2192af14758..1b4621f1c279 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/keyguard/CarKeyguardViewControllerTest.java @@ -16,9 +16,10 @@ package com.android.systemui.car.keyguard; -import static com.google.common.truth.Truth.assertThat; - +import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyBoolean; +import static org.mockito.ArgumentMatchers.eq; +import static org.mockito.Mockito.inOrder; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.never; import static org.mockito.Mockito.verify; @@ -29,7 +30,6 @@ import android.os.Handler; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; import android.view.LayoutInflater; -import android.view.View; import android.view.ViewGroup; import com.android.internal.widget.LockPatternUtils; @@ -40,7 +40,6 @@ import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarServiceProvider; import com.android.systemui.car.navigationbar.CarNavigationBarController; import com.android.systemui.car.window.OverlayViewGlobalStateController; -import com.android.systemui.car.window.SystemUIOverlayWindowController; import com.android.systemui.keyguard.DismissCallbackRegistry; import com.android.systemui.plugins.FalsingManager; import com.android.systemui.statusbar.phone.BiometricUnlockController; @@ -51,6 +50,7 @@ import com.android.systemui.statusbar.policy.KeyguardStateController; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; +import org.mockito.InOrder; import org.mockito.Mock; import org.mockito.MockitoAnnotations; @@ -61,28 +61,20 @@ import dagger.Lazy; public class CarKeyguardViewControllerTest extends SysuiTestCase { private TestableCarKeyguardViewController mCarKeyguardViewController; - private OverlayViewGlobalStateController mOverlayViewGlobalStateController; - private ViewGroup mBaseLayout; @Mock + private OverlayViewGlobalStateController mOverlayViewGlobalStateController; + @Mock private KeyguardBouncer mBouncer; @Mock private CarNavigationBarController mCarNavigationBarController; @Mock - private SystemUIOverlayWindowController mSystemUIOverlayWindowController; - @Mock private CarKeyguardViewController.OnKeyguardCancelClickedListener mCancelClickedListener; @Before public void setUp() { MockitoAnnotations.initMocks(this); - mOverlayViewGlobalStateController = new OverlayViewGlobalStateController( - mCarNavigationBarController, mSystemUIOverlayWindowController); - mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate( - R.layout.sysui_overlay_window, /* root= */ null); - when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); - mCarKeyguardViewController = new TestableCarKeyguardViewController( mContext, Handler.getMain(), @@ -98,6 +90,8 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { mock(FalsingManager.class), () -> mock(KeyguardBypassController.class) ); + mCarKeyguardViewController.inflate((ViewGroup) LayoutInflater.from(mContext).inflate( + R.layout.sysui_overlay_window, /* root= */ null)); } @Test @@ -113,8 +107,7 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { when(mBouncer.isSecure()).thenReturn(true); mCarKeyguardViewController.show(/* options= */ null); - assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo( - View.VISIBLE); + verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController), any()); } @Test @@ -130,8 +123,17 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { when(mBouncer.isSecure()).thenReturn(false); mCarKeyguardViewController.show(/* options= */ null); - assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo( - View.GONE); + // Here we check for both showView and hideView since the current implementation of show + // with bouncer being not secure has the following method execution orders: + // 1) show -> start -> showView + // 2) show -> reset -> dismissAndCollapse -> hide -> stop -> hideView + // Hence, we want to make sure that showView is called before hideView and not in any + // other combination. + InOrder inOrder = inOrder(mOverlayViewGlobalStateController); + inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController), + any()); + inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController), + any()); } @Test @@ -156,8 +158,11 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { mCarKeyguardViewController.show(/* options= */ null); mCarKeyguardViewController.hide(/* startTime= */ 0, /* fadeoutDelay= */ 0); - assertThat(mBaseLayout.findViewById(R.id.keyguard_container).getVisibility()).isEqualTo( - View.GONE); + InOrder inOrder = inOrder(mOverlayViewGlobalStateController); + inOrder.verify(mOverlayViewGlobalStateController).showView(eq(mCarKeyguardViewController), + any()); + inOrder.verify(mOverlayViewGlobalStateController).hideView(eq(mCarKeyguardViewController), + any()); } @Test diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java index 6ac72a681bfe..ccaeb458fe54 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/notification/CarHeadsUpNotificationSystemContainerTest.java @@ -28,9 +28,9 @@ import android.view.WindowManager; import androidx.test.filters.SmallTest; -import com.android.systemui.R; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.CarDeviceProvisionedController; +import com.android.systemui.car.window.OverlayViewGlobalStateController; import org.junit.Before; import org.junit.Test; @@ -42,12 +42,11 @@ import org.mockito.MockitoAnnotations; @TestableLooper.RunWithLooper @SmallTest public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase { - private CarHeadsUpNotificationSystemContainer mDefaultController; - private CarHeadsUpNotificationSystemContainer mOverrideEnabledController; + private CarHeadsUpNotificationSystemContainer mCarHeadsUpNotificationSystemContainer; @Mock private CarDeviceProvisionedController mCarDeviceProvisionedController; @Mock - private NotificationPanelViewController mNotificationPanelViewController; + private OverlayViewGlobalStateController mOverlayViewGlobalStateController; @Mock private WindowManager mWindowManager; @@ -58,76 +57,63 @@ public class CarHeadsUpNotificationSystemContainerTest extends SysuiTestCase { @Before public void setUp() { - MockitoAnnotations.initMocks(this); + MockitoAnnotations.initMocks(/* testClass= */this); - when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(false); - when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(true); - when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(false); + when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(true); + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(true); TestableResources testableResources = mContext.getOrCreateTestableResources(); - testableResources.addOverride( - R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, false); - - mDefaultController = new CarHeadsUpNotificationSystemContainer(mContext, - testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager, - () -> mNotificationPanelViewController); - - testableResources.addOverride( - R.bool.config_enableHeadsUpNotificationWhenNotificationShadeOpen, true); - - mOverrideEnabledController = new CarHeadsUpNotificationSystemContainer(mContext, + mCarHeadsUpNotificationSystemContainer = new CarHeadsUpNotificationSystemContainer(mContext, testableResources.getResources(), mCarDeviceProvisionedController, mWindowManager, - () -> mNotificationPanelViewController); + mOverlayViewGlobalStateController); } @Test public void testDisplayNotification_firstNotification_isVisible() { - mDefaultController.displayNotification(mNotificationView); - assertThat(mDefaultController.isVisible()).isTrue(); + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue(); } @Test public void testRemoveNotification_lastNotification_isInvisible() { - mDefaultController.displayNotification(mNotificationView); - mDefaultController.removeNotification(mNotificationView); - assertThat(mDefaultController.isVisible()).isFalse(); + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse(); } @Test public void testRemoveNotification_nonLastNotification_isVisible() { - mDefaultController.displayNotification(mNotificationView); - mDefaultController.displayNotification(mNotificationView2); - mDefaultController.removeNotification(mNotificationView); - assertThat(mDefaultController.isVisible()).isTrue(); + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView2); + mCarHeadsUpNotificationSystemContainer.removeNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue(); } @Test - public void testDisplayNotification_userSetupInProgress_isInvisible() { - when(mCarDeviceProvisionedController.isCurrentUserSetupInProgress()).thenReturn(true); - mDefaultController.displayNotification(mNotificationView); - assertThat(mDefaultController.isVisible()).isFalse(); + public void testDisplayNotification_userFullySetupTrue_isInvisible() { + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue(); } @Test - public void testDisplayNotification_userSetupIncomplete_isInvisible() { - when(mCarDeviceProvisionedController.isCurrentUserSetup()).thenReturn(false); - mDefaultController.displayNotification(mNotificationView); - assertThat(mDefaultController.isVisible()).isFalse(); + public void testDisplayNotification_userFullySetupFalse_isInvisible() { + when(mCarDeviceProvisionedController.isCurrentUserFullySetup()).thenReturn(false); + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse(); } @Test - public void testDisplayNotification_notificationPanelExpanded_isInvisible() { - when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true); - mDefaultController.displayNotification(mNotificationView); - assertThat(mDefaultController.isVisible()).isFalse(); + public void testDisplayNotification_overlayWindowStateShouldShowHUNFalse_isInvisible() { + when(mOverlayViewGlobalStateController.shouldShowHUN()).thenReturn(false); + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isFalse(); } @Test - public void testDisplayNotification_notificationPanelExpandedEnabledHUNWhenOpen_isVisible() { - when(mNotificationPanelViewController.isPanelExpanded()).thenReturn(true); - mOverrideEnabledController.displayNotification(mNotificationView); - assertThat(mOverrideEnabledController.isVisible()).isTrue(); + public void testDisplayNotification_overlayWindowStateShouldShowHUNTrue_isVisible() { + mCarHeadsUpNotificationSystemContainer.displayNotification(mNotificationView); + assertThat(mCarHeadsUpNotificationSystemContainer.isVisible()).isTrue(); } } diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java index 8d705a8cca1f..45a05ac69bd7 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayPanelViewControllerTest.java @@ -339,7 +339,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(true); - verify(mOverlayViewGlobalStateController).setWindowVisible(true); + verify(mOverlayViewGlobalStateController).showView(mOverlayPanelViewController); } @Test @@ -349,7 +349,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(true); - verify(mOverlayViewGlobalStateController, never()).setWindowVisible(true); + verify(mOverlayViewGlobalStateController, never()).showView(mOverlayPanelViewController); } @Test @@ -377,7 +377,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(false); - verify(mOverlayViewGlobalStateController).setWindowVisible(false); + verify(mOverlayViewGlobalStateController).hideView(mOverlayPanelViewController); } @Test @@ -387,7 +387,7 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { mOverlayPanelViewController.setPanelVisible(false); - verify(mOverlayViewGlobalStateController, never()).setWindowVisible(false); + verify(mOverlayViewGlobalStateController, never()).hideView(mOverlayPanelViewController); } @Test @@ -428,10 +428,6 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { private static class TestOverlayPanelViewController extends OverlayPanelViewController { - private boolean mShouldAnimateCollapsePanel; - private boolean mShouldAnimateExpandPanel; - private boolean mShouldAllowClosingScroll; - boolean mOnAnimateCollapsePanelCalled; boolean mAnimateCollapsePanelCalled; boolean mOnAnimateExpandPanelCalled; @@ -440,6 +436,9 @@ public class OverlayPanelViewControllerTest extends SysuiTestCase { boolean mOnExpandAnimationEndCalled; boolean mOnOpenScrollStartEnd; List<Integer> mOnScrollHeights; + private boolean mShouldAnimateCollapsePanel; + private boolean mShouldAnimateExpandPanel; + private boolean mShouldAllowClosingScroll; TestOverlayPanelViewController( Context context, diff --git a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java index 25dd4f502fb7..9e6e616e3ccf 100644 --- a/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java +++ b/packages/CarSystemUI/tests/src/com/android/systemui/car/window/OverlayViewGlobalStateControllerTest.java @@ -24,25 +24,33 @@ import static org.mockito.Mockito.when; import android.testing.AndroidTestingRunner; import android.testing.TestableLooper; +import android.view.LayoutInflater; +import android.view.View; import android.view.ViewGroup; -import android.widget.FrameLayout; +import android.view.ViewStub; import androidx.test.filters.SmallTest; import com.android.systemui.SysuiTestCase; import com.android.systemui.car.navigationbar.CarNavigationBarController; +import com.android.systemui.tests.R; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.Mock; +import org.mockito.Mockito; import org.mockito.MockitoAnnotations; +import java.util.Arrays; + @RunWith(AndroidTestingRunner.class) @TestableLooper.RunWithLooper @SmallTest public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { - private static final String MOCK_OVERLAY_VIEW_CONTROLLER_NAME = "OverlayViewController"; + private static final int OVERLAY_VIEW_CONTROLLER_1_Z_ORDER = 0; + private static final int OVERLAY_VIEW_CONTROLLER_2_Z_ORDER = 1; + private static final int OVERLAY_PANEL_VIEW_CONTROLLER_Z_ORDER = 2; private OverlayViewGlobalStateController mOverlayViewGlobalStateController; private ViewGroup mBaseLayout; @@ -54,7 +62,11 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { @Mock private OverlayViewMediator mOverlayViewMediator; @Mock - private OverlayViewController mOverlayViewController; + private OverlayViewController mOverlayViewController1; + @Mock + private OverlayViewController mOverlayViewController2; + @Mock + private OverlayPanelViewController mOverlayPanelViewController; @Mock private Runnable mRunnable; @@ -62,14 +74,15 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { public void setUp() { MockitoAnnotations.initMocks(/* testClass= */ this); + mBaseLayout = (ViewGroup) LayoutInflater.from(mContext).inflate( + R.layout.overlay_view_global_state_controller_test, /* root= */ null); + + when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); + mOverlayViewGlobalStateController = new OverlayViewGlobalStateController( mCarNavigationBarController, mSystemUIOverlayWindowController); verify(mSystemUIOverlayWindowController).attach(); - - mBaseLayout = new FrameLayout(mContext); - - when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); } @Test @@ -87,182 +100,445 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { } @Test - public void showView_nothingAlreadyShown_navigationBarsHidden() { - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + public void showView_nothingAlreadyShown_shouldShowNavBarFalse_navigationBarsHidden() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); verify(mCarNavigationBarController).hideBars(); } @Test - public void showView_nothingAlreadyShown_windowIsExpanded() { - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + public void showView_nothingAlreadyShown_shouldShowNavBarTrue_navigationBarsShown() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mCarNavigationBarController).showBars(); + } + + @Test + public void showView_nothingAlreadyShown_windowIsSetVisible() { + setupOverlayViewController1(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); verify(mSystemUIOverlayWindowController).setWindowVisible(true); } @Test - public void showView_somethingAlreadyShown_navigationBarsHidden() { - mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME); + public void showView_nothingAlreadyShown_newHighestZOrder() { + setupOverlayViewController1(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController1); + } + + @Test + public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() { + setupOverlayViewController1(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey( + OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isTrue(); + } + + @Test + public void showView_newHighestZOrder() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - verify(mCarNavigationBarController, never()).hideBars(); + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController2); } @Test - public void showView_somethingAlreadyShown_windowIsExpanded() { - mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME); + public void showView_newHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + verify(mCarNavigationBarController).hideBars(); + } + + @Test + public void showView_newHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); + + verify(mCarNavigationBarController).showBars(); + } + + @Test + public void showView_newHighestZOrder_correctViewsShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray()) + .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER, + OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray()); + } + + @Test + public void showView_oldHighestZOrder() { + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController2); + } + + @Test + public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() { + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mCarNavigationBarController).hideBars(); + } + + @Test + public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() { + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + verify(mCarNavigationBarController).showBars(); + } + + @Test + public void showView_oldHighestZOrder_correctViewsShown() { + setupOverlayViewController1(); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.keySet().toArray()) + .isEqualTo(Arrays.asList(OVERLAY_VIEW_CONTROLLER_1_Z_ORDER, + OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray()); + } + + @Test + public void showView_somethingAlreadyShown_windowVisibleNotCalled() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); verify(mSystemUIOverlayWindowController, never()).setWindowVisible(true); } @Test public void showView_viewControllerNotInflated_inflateViewController() { - when(mOverlayViewController.isInflated()).thenReturn(false); + setupOverlayViewController2(); + when(mOverlayViewController2.isInflated()).thenReturn(false); - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - verify(mOverlayViewController).inflate(mBaseLayout); + verify(mOverlayViewController2).inflate(mBaseLayout); } @Test public void showView_viewControllerInflated_inflateViewControllerNotCalled() { - when(mOverlayViewController.isInflated()).thenReturn(true); + setupOverlayViewController2(); - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable); - verify(mOverlayViewController, never()).inflate(mBaseLayout); + verify(mOverlayViewController2, never()).inflate(mBaseLayout); } @Test - public void showView_showRunnableCalled() { - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + public void showView_panelViewController_inflateViewControllerNotCalled() { + setupOverlayPanelViewController(); - verify(mRunnable).run(); + mOverlayViewGlobalStateController.showView(mOverlayPanelViewController, mRunnable); + + verify(mOverlayPanelViewController, never()).inflate(mBaseLayout); + verify(mOverlayPanelViewController, never()).isInflated(); } @Test - public void showView_overlayViewControllerAddedToShownSet() { - mOverlayViewGlobalStateController.showView(mOverlayViewController, mRunnable); + public void showView_showRunnableCalled() { + setupOverlayViewController1(); + + mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); - assertThat(mOverlayViewGlobalStateController.mShownSet.contains( - mOverlayViewController.getClass().getName())).isTrue(); + verify(mRunnable).run(); } @Test public void hideView_viewControllerNotInflated_hideRunnableNotCalled() { - when(mOverlayViewController.isInflated()).thenReturn(false); + when(mOverlayViewController2.isInflated()).thenReturn(false); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); verify(mRunnable, never()).run(); } @Test public void hideView_nothingShown_hideRunnableNotCalled() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.clear(); + when(mOverlayViewController2.isInflated()).thenReturn(true); + mOverlayViewGlobalStateController.mZOrderMap.clear(); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); verify(mRunnable, never()).run(); } @Test public void hideView_viewControllerNotShown_hideRunnableNotCalled() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController2.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); verify(mRunnable, never()).run(); } @Test public void hideView_viewControllerShown_hideRunnableCalled() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); verify(mRunnable).run(); } @Test + public void hideView_viewControllerOnlyShown_noHighestZOrder() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isNull(); + } + + @Test public void hideView_viewControllerOnlyShown_nothingShown() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.isEmpty()).isTrue(); + } + + @Test + public void hideView_viewControllerOnlyShown_viewControllerNotShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey( + OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isFalse(); + } + + @Test + public void hideView_newHighestZOrder_twoViewsShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController1); + } + + @Test + public void hideView_newHighestZOrder_threeViewsShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + setupOverlayPanelViewController(); + setOverlayViewControllerAsShowing(mOverlayPanelViewController); + + mOverlayViewGlobalStateController.hideView(mOverlayPanelViewController, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController2); + } + + @Test + public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(false); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); + + verify(mCarNavigationBarController).hideBars(); + } + + @Test + public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController1.shouldShowNavigationBar()).thenReturn(true); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + verify(mCarNavigationBarController).showBars(); + } + + @Test + public void hideView_oldHighestZOrder() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); - assertThat(mOverlayViewGlobalStateController.mShownSet.isEmpty()).isTrue(); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + assertThat(mOverlayViewGlobalStateController.mHighestZOrder).isEqualTo( + mOverlayViewController2); } @Test - public void hideView_viewControllerNotOnlyShown_navigationBarNotShown() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); - mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME); + public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(false); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); - verify(mCarNavigationBarController, never()).showBars(); + verify(mCarNavigationBarController).hideBars(); + } + + @Test + public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); + when(mOverlayViewController2.shouldShowNavigationBar()).thenReturn(true); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); + + verify(mCarNavigationBarController).showBars(); } @Test public void hideView_viewControllerNotOnlyShown_windowNotCollapsed() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); - mOverlayViewGlobalStateController.mShownSet.add(MOCK_OVERLAY_VIEW_CONTROLLER_NAME); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + setupOverlayViewController2(); + setOverlayViewControllerAsShowing(mOverlayViewController2); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController2, mRunnable); verify(mSystemUIOverlayWindowController, never()).setWindowVisible(false); } @Test public void hideView_viewControllerOnlyShown_navigationBarShown() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); verify(mCarNavigationBarController).showBars(); } @Test public void hideView_viewControllerOnlyShown_windowCollapsed() { - when(mOverlayViewController.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.mShownSet.add( - mOverlayViewController.getClass().getName()); + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); - mOverlayViewGlobalStateController.hideView(mOverlayViewController, mRunnable); + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); verify(mSystemUIOverlayWindowController).setWindowVisible(false); } @Test public void inflateView_notInflated_inflates() { - when(mOverlayViewController.isInflated()).thenReturn(false); + when(mOverlayViewController2.isInflated()).thenReturn(false); - mOverlayViewGlobalStateController.inflateView(mOverlayViewController); + mOverlayViewGlobalStateController.inflateView(mOverlayViewController2); - verify(mOverlayViewController).inflate(mBaseLayout); + verify(mOverlayViewController2).inflate(mBaseLayout); } @Test public void inflateView_alreadyInflated_doesNotInflate() { - when(mOverlayViewController.isInflated()).thenReturn(true); + when(mOverlayViewController2.isInflated()).thenReturn(true); - mOverlayViewGlobalStateController.inflateView(mOverlayViewController); + mOverlayViewGlobalStateController.inflateView(mOverlayViewController2); + + verify(mOverlayViewController2, never()).inflate(mBaseLayout); + } + + private void setupOverlayViewController1() { + setupOverlayViewController(mOverlayViewController1, R.id.overlay_view_controller_stub_1, + R.id.overlay_view_controller_1); + } - verify(mOverlayViewController, never()).inflate(mBaseLayout); + private void setupOverlayViewController2() { + setupOverlayViewController(mOverlayViewController2, R.id.overlay_view_controller_stub_2, + R.id.overlay_view_controller_2); + } + + private void setupOverlayPanelViewController() { + setupOverlayViewController(mOverlayPanelViewController, R.id.overlay_view_controller_stub_3, + R.id.overlay_view_controller_3); + } + + private void setupOverlayViewController(OverlayViewController overlayViewController, + int stubId, int inflatedId) { + ViewStub viewStub = mBaseLayout.findViewById(stubId); + View layout; + if (viewStub == null) { + layout = mBaseLayout.findViewById(inflatedId); + } else { + layout = viewStub.inflate(); + } + when(overlayViewController.getLayout()).thenReturn(layout); + when(overlayViewController.isInflated()).thenReturn(true); + } + + private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) { + mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null); + Mockito.reset(mCarNavigationBarController, mSystemUIOverlayWindowController); + when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); } } |