diff --git a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java index ab61b443df976..2dad5f872e73e 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/keyguard/CarKeyguardViewController.java @@ -218,6 +218,14 @@ public class CarKeyguardViewController extends OverlayViewController implements } } + @Override + public void setOccluded(boolean occluded, boolean animate) { + getOverlayViewGlobalStateController().setOccluded(occluded); + if (!occluded) { + reset(/* hideBouncerWhenShowing= */ false); + } + } + @Override public void onCancelClicked() { if (mBouncer == null) return; @@ -314,11 +322,6 @@ public class CarKeyguardViewController extends OverlayViewController implements // no-op } - @Override - public void setOccluded(boolean occluded, boolean animate) { - // no-op - } - @Override public boolean shouldDisableWindowAnimationsForUnlock() { return false; 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 30e26578bd733..3969f92c690aa 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewController.java @@ -138,4 +138,11 @@ public class OverlayViewController { protected boolean shouldShowNavigationBar() { return false; } + + /** + * Returns {@code true} if this view should be hidden during the occluded state. + */ + protected boolean shouldShowWhenOccluded() { + 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 70260b0d4cef2..8e94109643131 100644 --- a/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java +++ b/packages/CarSystemUI/src/com/android/systemui/car/window/OverlayViewGlobalStateController.java @@ -24,7 +24,9 @@ import androidx.annotation.VisibleForTesting; import com.android.systemui.car.navigationbar.CarNavigationBarController; import java.util.HashMap; +import java.util.HashSet; import java.util.Map; +import java.util.Set; import java.util.SortedMap; import java.util.TreeMap; @@ -47,11 +49,16 @@ public class OverlayViewGlobalStateController { private static final int UNKNOWN_Z_ORDER = -1; private final SystemUIOverlayWindowController mSystemUIOverlayWindowController; private final CarNavigationBarController mCarNavigationBarController; + + private boolean mIsOccluded; + @VisibleForTesting Map mZOrderMap; @VisibleForTesting SortedMap mZOrderVisibleSortedMap; @VisibleForTesting + Set mViewsHiddenForOcclusion; + @VisibleForTesting OverlayViewController mHighestZOrder; @Inject @@ -63,6 +70,7 @@ public class OverlayViewGlobalStateController { mCarNavigationBarController = carNavigationBarController; mZOrderMap = new HashMap<>(); mZOrderVisibleSortedMap = new TreeMap<>(); + mViewsHiddenForOcclusion = new HashSet<>(); } /** @@ -91,6 +99,10 @@ public class OverlayViewGlobalStateController { */ public void showView(OverlayViewController viewController, @Nullable Runnable show) { debugLog(); + if (mIsOccluded && !viewController.shouldShowWhenOccluded()) { + mViewsHiddenForOcclusion.add(viewController); + return; + } if (mZOrderVisibleSortedMap.isEmpty()) { setWindowVisible(true); } @@ -147,6 +159,10 @@ public class OverlayViewGlobalStateController { */ public void hideView(OverlayViewController viewController, @Nullable Runnable hide) { debugLog(); + if (mIsOccluded && mViewsHiddenForOcclusion.contains(viewController)) { + mViewsHiddenForOcclusion.remove(viewController); + return; + } if (!viewController.isInflated()) { Log.d(TAG, "Content cannot be hidden since it isn't inflated: " + viewController.getClass().getName()); @@ -240,6 +256,43 @@ public class OverlayViewGlobalStateController { return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN(); } + /** + * Set the OverlayViewWindow to be in occluded or unoccluded state. When OverlayViewWindow is + * occluded, all views mounted to it that are not configured to be shown during occlusion will + * be hidden. + */ + public void setOccluded(boolean occluded) { + if (occluded) { + // Hide views before setting mIsOccluded to true so the regular hideView logic is used, + // not the one used during occlusion. + hideViewsForOcclusion(); + mIsOccluded = true; + } else { + mIsOccluded = false; + // show views after setting mIsOccluded to false so the regular showView logic is used, + // not the one used during occlusion. + showViewsHiddenForOcclusion(); + } + } + + private void hideViewsForOcclusion() { + HashSet viewsCurrentlyShowing = new HashSet<>( + mZOrderVisibleSortedMap.values()); + viewsCurrentlyShowing.forEach(overlayController -> { + if (!overlayController.shouldShowWhenOccluded()) { + hideView(overlayController, overlayController::hideInternal); + mViewsHiddenForOcclusion.add(overlayController); + } + }); + } + + private void showViewsHiddenForOcclusion() { + mViewsHiddenForOcclusion.forEach(overlayViewController -> { + showView(overlayViewController, overlayViewController::showInternal); + }); + mViewsHiddenForOcclusion.clear(); + } + private void debugLog() { if (!DEBUG) { return; @@ -250,5 +303,8 @@ public class OverlayViewGlobalStateController { Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap); Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size()); Log.d(TAG, "mZOrderMap: " + mZOrderMap); + Log.d(TAG, "mIsOccluded: " + mIsOccluded); + Log.d(TAG, "mViewsHiddenForOcclusion: " + mViewsHiddenForOcclusion); + Log.d(TAG, "mViewsHiddenForOcclusion.size(): " + mViewsHiddenForOcclusion.size()); } } 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 38836d85e8d47..189e240169c3d 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 @@ -22,6 +22,7 @@ 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.reset; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @@ -168,6 +169,18 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase { any()); } + @Test + public void setOccludedFalse_currentlyOccluded_bouncerReset() { + when(mBouncer.isSecure()).thenReturn(true); + mCarKeyguardViewController.show(/* options= */ null); + mCarKeyguardViewController.setOccluded(/* occluded= */ true, /* animate= */ false); + reset(mBouncer); + + mCarKeyguardViewController.setOccluded(/* occluded= */ false, /* animate= */ false); + + verify(mBouncer).show(/* resetSecuritySelection= */ true); + } + @Test public void onCancelClicked_callsCancelClickedListener() { when(mBouncer.isSecure()).thenReturn(true); 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 9e6e616e3ccfc..cba42e5a9be43 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 @@ -490,6 +490,81 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase { verify(mSystemUIOverlayWindowController).setWindowVisible(false); } + @Test + public void setOccludedTrue_viewToHideWhenOccludedVisible_viewHidden() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false); + + mOverlayViewGlobalStateController.setOccluded(true); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue( + mOverlayViewController1)).isFalse(); + } + + @Test + public void setOccludedTrue_viewToNotHideWhenOccludedVisible_viewShown() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true); + + mOverlayViewGlobalStateController.setOccluded(true); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue( + mOverlayViewController1)).isTrue(); + } + + @Test + public void hideViewAndThenSetOccludedTrue_viewHiddenForOcclusion_viewHiddenAfterOcclusion() { + setupOverlayViewController1(); + setOverlayViewControllerAsShowing(mOverlayViewController1); + when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false); + mOverlayViewGlobalStateController.setOccluded(true); + + mOverlayViewGlobalStateController.hideView(mOverlayViewController1, /* runnable= */ null); + mOverlayViewGlobalStateController.setOccluded(false); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue( + mOverlayViewController1)).isFalse(); + } + + @Test + public void setOccludedTrueAndThenShowView_viewToNotHideForOcclusion_viewShown() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(true); + + mOverlayViewGlobalStateController.setOccluded(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue( + mOverlayViewController1)).isTrue(); + } + + @Test + public void setOccludedTrueAndThenShowView_viewToHideForOcclusion_viewHidden() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false); + + mOverlayViewGlobalStateController.setOccluded(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue( + mOverlayViewController1)).isFalse(); + } + + @Test + public void setOccludedFalse_viewShownAfterSetOccludedTrue_viewToHideForOcclusion_viewShown() { + setupOverlayViewController1(); + when(mOverlayViewController1.shouldShowWhenOccluded()).thenReturn(false); + mOverlayViewGlobalStateController.setOccluded(true); + setOverlayViewControllerAsShowing(mOverlayViewController1); + + mOverlayViewGlobalStateController.setOccluded(false); + + assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsValue( + mOverlayViewController1)).isTrue(); + } + @Test public void inflateView_notInflated_inflates() { when(mOverlayViewController2.isInflated()).thenReturn(false);