Merge "Add occlusion logic to OverlayViewGlobalStateController and CarKeyguardViewController" into rvc-dev am: 8920f765c9
Original change: https://googleplex-android-review.googlesource.com/c/platform/frameworks/base/+/11635056 Change-Id: I933587da3fde8c5c0f4bfcd86d25d77d2836272f
This commit is contained in:
@@ -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
|
@Override
|
||||||
public void onCancelClicked() {
|
public void onCancelClicked() {
|
||||||
if (mBouncer == null) return;
|
if (mBouncer == null) return;
|
||||||
@@ -314,11 +322,6 @@ public class CarKeyguardViewController extends OverlayViewController implements
|
|||||||
// no-op
|
// no-op
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public void setOccluded(boolean occluded, boolean animate) {
|
|
||||||
// no-op
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public boolean shouldDisableWindowAnimationsForUnlock() {
|
public boolean shouldDisableWindowAnimationsForUnlock() {
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -138,4 +138,11 @@ public class OverlayViewController {
|
|||||||
protected boolean shouldShowNavigationBar() {
|
protected boolean shouldShowNavigationBar() {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns {@code true} if this view should be hidden during the occluded state.
|
||||||
|
*/
|
||||||
|
protected boolean shouldShowWhenOccluded() {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,9 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import com.android.systemui.car.navigationbar.CarNavigationBarController;
|
import com.android.systemui.car.navigationbar.CarNavigationBarController;
|
||||||
|
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.HashSet;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
|
import java.util.Set;
|
||||||
import java.util.SortedMap;
|
import java.util.SortedMap;
|
||||||
import java.util.TreeMap;
|
import java.util.TreeMap;
|
||||||
|
|
||||||
@@ -47,11 +49,16 @@ public class OverlayViewGlobalStateController {
|
|||||||
private static final int UNKNOWN_Z_ORDER = -1;
|
private static final int UNKNOWN_Z_ORDER = -1;
|
||||||
private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
|
private final SystemUIOverlayWindowController mSystemUIOverlayWindowController;
|
||||||
private final CarNavigationBarController mCarNavigationBarController;
|
private final CarNavigationBarController mCarNavigationBarController;
|
||||||
|
|
||||||
|
private boolean mIsOccluded;
|
||||||
|
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
Map<OverlayViewController, Integer> mZOrderMap;
|
Map<OverlayViewController, Integer> mZOrderMap;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
|
SortedMap<Integer, OverlayViewController> mZOrderVisibleSortedMap;
|
||||||
@VisibleForTesting
|
@VisibleForTesting
|
||||||
|
Set<OverlayViewController> mViewsHiddenForOcclusion;
|
||||||
|
@VisibleForTesting
|
||||||
OverlayViewController mHighestZOrder;
|
OverlayViewController mHighestZOrder;
|
||||||
|
|
||||||
@Inject
|
@Inject
|
||||||
@@ -63,6 +70,7 @@ public class OverlayViewGlobalStateController {
|
|||||||
mCarNavigationBarController = carNavigationBarController;
|
mCarNavigationBarController = carNavigationBarController;
|
||||||
mZOrderMap = new HashMap<>();
|
mZOrderMap = new HashMap<>();
|
||||||
mZOrderVisibleSortedMap = new TreeMap<>();
|
mZOrderVisibleSortedMap = new TreeMap<>();
|
||||||
|
mViewsHiddenForOcclusion = new HashSet<>();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -91,6 +99,10 @@ public class OverlayViewGlobalStateController {
|
|||||||
*/
|
*/
|
||||||
public void showView(OverlayViewController viewController, @Nullable Runnable show) {
|
public void showView(OverlayViewController viewController, @Nullable Runnable show) {
|
||||||
debugLog();
|
debugLog();
|
||||||
|
if (mIsOccluded && !viewController.shouldShowWhenOccluded()) {
|
||||||
|
mViewsHiddenForOcclusion.add(viewController);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (mZOrderVisibleSortedMap.isEmpty()) {
|
if (mZOrderVisibleSortedMap.isEmpty()) {
|
||||||
setWindowVisible(true);
|
setWindowVisible(true);
|
||||||
}
|
}
|
||||||
@@ -147,6 +159,10 @@ public class OverlayViewGlobalStateController {
|
|||||||
*/
|
*/
|
||||||
public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
|
public void hideView(OverlayViewController viewController, @Nullable Runnable hide) {
|
||||||
debugLog();
|
debugLog();
|
||||||
|
if (mIsOccluded && mViewsHiddenForOcclusion.contains(viewController)) {
|
||||||
|
mViewsHiddenForOcclusion.remove(viewController);
|
||||||
|
return;
|
||||||
|
}
|
||||||
if (!viewController.isInflated()) {
|
if (!viewController.isInflated()) {
|
||||||
Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
|
Log.d(TAG, "Content cannot be hidden since it isn't inflated: "
|
||||||
+ viewController.getClass().getName());
|
+ viewController.getClass().getName());
|
||||||
@@ -240,6 +256,43 @@ public class OverlayViewGlobalStateController {
|
|||||||
return mZOrderVisibleSortedMap.isEmpty() || mHighestZOrder.shouldShowHUN();
|
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<OverlayViewController> 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() {
|
private void debugLog() {
|
||||||
if (!DEBUG) {
|
if (!DEBUG) {
|
||||||
return;
|
return;
|
||||||
@@ -250,5 +303,8 @@ public class OverlayViewGlobalStateController {
|
|||||||
Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
|
Log.d(TAG, "mZOrderVisibleSortedMap: " + mZOrderVisibleSortedMap);
|
||||||
Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
|
Log.d(TAG, "mZOrderMap.size(): " + mZOrderMap.size());
|
||||||
Log.d(TAG, "mZOrderMap: " + mZOrderMap);
|
Log.d(TAG, "mZOrderMap: " + mZOrderMap);
|
||||||
|
Log.d(TAG, "mIsOccluded: " + mIsOccluded);
|
||||||
|
Log.d(TAG, "mViewsHiddenForOcclusion: " + mViewsHiddenForOcclusion);
|
||||||
|
Log.d(TAG, "mViewsHiddenForOcclusion.size(): " + mViewsHiddenForOcclusion.size());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,7 @@ import static org.mockito.ArgumentMatchers.eq;
|
|||||||
import static org.mockito.Mockito.inOrder;
|
import static org.mockito.Mockito.inOrder;
|
||||||
import static org.mockito.Mockito.mock;
|
import static org.mockito.Mockito.mock;
|
||||||
import static org.mockito.Mockito.never;
|
import static org.mockito.Mockito.never;
|
||||||
|
import static org.mockito.Mockito.reset;
|
||||||
import static org.mockito.Mockito.verify;
|
import static org.mockito.Mockito.verify;
|
||||||
import static org.mockito.Mockito.when;
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
@@ -168,6 +169,18 @@ public class CarKeyguardViewControllerTest extends SysuiTestCase {
|
|||||||
any());
|
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
|
@Test
|
||||||
public void onCancelClicked_callsCancelClickedListener() {
|
public void onCancelClicked_callsCancelClickedListener() {
|
||||||
when(mBouncer.isSecure()).thenReturn(true);
|
when(mBouncer.isSecure()).thenReturn(true);
|
||||||
|
|||||||
@@ -490,6 +490,81 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
|
|||||||
verify(mSystemUIOverlayWindowController).setWindowVisible(false);
|
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
|
@Test
|
||||||
public void inflateView_notInflated_inflates() {
|
public void inflateView_notInflated_inflates() {
|
||||||
when(mOverlayViewController2.isInflated()).thenReturn(false);
|
when(mOverlayViewController2.isInflated()).thenReturn(false);
|
||||||
|
|||||||
Reference in New Issue
Block a user