DO NOT MERGE Add generic rotary support for sysui overlay window

Bug: 181138897
Test: manual
Change-Id: I353d9587fce09c5dff7328b5dec7e973230f2a9c
This commit is contained in:
Heemin Seog
2021-02-26 14:03:01 -08:00
parent d8c231ef99
commit e076c2344e
14 changed files with 239 additions and 88 deletions

View File

@@ -14,10 +14,7 @@
~ limitations under the License. ~ limitations under the License.
--> -->
<!-- Car customizations <com.android.car.ui.FocusArea
Car has solid black background instead of a transparent one
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/keyguard_container" android:id="@+id/keyguard_container"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -66,7 +66,6 @@
android:src="@drawable/ic_backspace" android:src="@drawable/ic_backspace"
android:clickable="true" android:clickable="true"
android:tint="@android:color/white" android:tint="@android:color/white"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/keyboardview_keycode_delete" /> android:contentDescription="@string/keyboardview_keycode_delete" />
<com.android.keyguard.NumPadKey <com.android.keyguard.NumPadKey
android:id="@+id/key0" android:id="@+id/key0"
@@ -77,7 +76,6 @@
style="@style/NumPadKeyButton.LastRow" style="@style/NumPadKeyButton.LastRow"
android:src="@drawable/ic_done" android:src="@drawable/ic_done"
android:tint="@android:color/white" android:tint="@android:color/white"
android:background="@drawable/ripple_drawable"
android:contentDescription="@string/keyboardview_keycode_enter" /> android:contentDescription="@string/keyboardview_keycode_enter" />
</merge> </merge>

View File

@@ -17,10 +17,8 @@
<resources> <resources>
<dimen name="num_pad_margin_left">112dp</dimen> <dimen name="num_pad_margin_left">112dp</dimen>
<dimen name="num_pad_margin_right">144dp</dimen> <dimen name="num_pad_margin_right">144dp</dimen>
<dimen name="num_pad_key_width">80dp</dimen> <dimen name="num_pad_key_width">120dp</dimen>
<dimen name="num_pad_key_height">80dp</dimen> <dimen name="num_pad_key_height">80dp</dimen>
<dimen name="num_pad_key_margin_horizontal">@*android:dimen/car_padding_5</dimen>
<dimen name="num_pad_key_margin_bottom">@*android:dimen/car_padding_5</dimen>
<dimen name="pin_entry_height">@dimen/num_pad_key_height</dimen> <dimen name="pin_entry_height">@dimen/num_pad_key_height</dimen>
<dimen name="divider_height">1dp</dimen> <dimen name="divider_height">1dp</dimen>
<dimen name="key_enter_margin_top">128dp</dimen> <dimen name="key_enter_margin_top">128dp</dimen>

View File

@@ -23,12 +23,11 @@
<item name="android:layout_width">@dimen/num_pad_key_width</item> <item name="android:layout_width">@dimen/num_pad_key_width</item>
<item name="android:layout_height">@dimen/num_pad_key_height</item> <item name="android:layout_height">@dimen/num_pad_key_height</item>
<item name="android:layout_marginBottom">@dimen/num_pad_key_margin_bottom</item> <item name="android:layout_marginBottom">@dimen/num_pad_key_margin_bottom</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="textView">@id/pinEntry</item> <item name="textView">@id/pinEntry</item>
</style> </style>
<style name="NumPadKeyButton.MiddleColumn"> <style name="NumPadKeyButton.MiddleColumn">
<item name="android:layout_marginStart">@dimen/num_pad_key_margin_horizontal</item>
<item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
</style> </style>
<style name="NumPadKeyButton.LastRow"> <style name="NumPadKeyButton.LastRow">
@@ -36,12 +35,10 @@
</style> </style>
<style name="NumPadKeyButton.LastRow.MiddleColumn"> <style name="NumPadKeyButton.LastRow.MiddleColumn">
<item name="android:layout_marginStart">@dimen/num_pad_key_margin_horizontal</item>
<item name="android:layout_marginEnd">@dimen/num_pad_key_margin_horizontal</item>
</style> </style>
<style name="KeyguardButton" parent="@android:style/Widget.DeviceDefault.Button"> <style name="KeyguardButton" parent="@android:style/Widget.DeviceDefault.Button">
<item name="android:background">@drawable/keyguard_button_background</item> <item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:textColor">@color/button_text</item> <item name="android:textColor">@color/button_text</item>
<item name="android:textAllCaps">false</item> <item name="android:textAllCaps">false</item>
</style> </style>

View File

@@ -14,29 +14,36 @@
See the License for the specific language governing permissions and See the License for the specific language governing permissions and
limitations under the License. limitations under the License.
--> -->
<com.android.systemui.car.userswitcher.UserSwitcherContainer
<com.android.car.ui.FocusArea
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/container" android:id="@+id/user_switcher_container"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/car_user_switcher_background_color" android:gravity="center">
android:orientation="vertical"> <com.android.systemui.car.userswitcher.UserSwitcherContainer
android:id="@+id/container"
<include
layout="@layout/car_status_bar_header"
android:layout_alignParentTop="true"
android:theme="@android:style/Theme"/>
<FrameLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent"
<com.android.systemui.car.userswitcher.UserGridRecyclerView android:background="@color/car_user_switcher_background_color"
android:id="@+id/user_grid" android:orientation="vertical">
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>
</FrameLayout>
</com.android.systemui.car.userswitcher.UserSwitcherContainer> <include
layout="@layout/car_status_bar_header"
android:layout_alignParentTop="true"
android:theme="@android:style/Theme"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<com.android.systemui.car.userswitcher.UserGridRecyclerView
android:id="@+id/user_grid"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginTop="@dimen/car_user_switcher_margin_top"/>
</FrameLayout>
</com.android.systemui.car.userswitcher.UserSwitcherContainer>
</com.android.car.ui.FocusArea>

View File

@@ -22,10 +22,6 @@
android:layout_height="match_parent" android:layout_height="match_parent"
android:background="@color/notification_shade_background_color"> android:background="@color/notification_shade_background_color">
<com.android.car.ui.FocusParkingView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<View <View
android:id="@+id/glass_pane" android:id="@+id/glass_pane"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -37,20 +33,15 @@
app:layout_constraintTop_toTopOf="parent" app:layout_constraintTop_toTopOf="parent"
/> />
<com.android.car.ui.FocusArea <androidx.recyclerview.widget.RecyclerView
android:layout_width="0dp" android:id="@+id/notifications"
android:layout_height="0dp" android:layout_width="match_parent"
android:orientation="vertical" android:layout_height="match_parent"
android:paddingBottom="@dimen/notification_shade_list_padding_bottom"
app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent" app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent" app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"> app:layout_constraintTop_toTopOf="parent"/>
<androidx.recyclerview.widget.RecyclerView
android:id="@+id/notifications"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/notification_shade_list_padding_bottom"/>
</com.android.car.ui.FocusArea>
<include layout="@layout/notification_handle_bar"/> <include layout="@layout/notification_handle_bar"/>

View File

@@ -14,7 +14,7 @@
~ See the License for the specific language governing permissions and ~ See the License for the specific language governing permissions and
~ limitations under the License. ~ limitations under the License.
--> -->
<FrameLayout <com.android.car.ui.FocusArea
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/notification_container" android:id="@+id/notification_container"
android:layout_width="match_parent" android:layout_width="match_parent"

View File

@@ -22,25 +22,29 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<com.android.car.ui.FocusParkingView
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<ViewStub android:id="@+id/notification_panel_stub" <ViewStub android:id="@+id/notification_panel_stub"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout="@layout/notification_panel_container" android:layout="@layout/notification_panel_container"
android:layout_marginBottom="@dimen/car_bottom_navigation_bar_height"/> android:layout_marginBottom="@dimen/car_bottom_navigation_bar_height"/>
<ViewStub android:id="@+id/keyguard_stub" <ViewStub android:id="@+id/keyguard_stub"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout="@layout/keyguard_container" /> android:layout="@layout/keyguard_container" />
<ViewStub android:id="@+id/fullscreen_user_switcher_stub" <ViewStub android:id="@+id/fullscreen_user_switcher_stub"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout="@layout/car_fullscreen_user_switcher"/> android:layout="@layout/car_fullscreen_user_switcher"/>
<ViewStub android:id="@+id/user_switching_dialog_stub" <ViewStub android:id="@+id/user_switching_dialog_stub"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:layout="@layout/car_user_switching_dialog"/> android:layout="@layout/car_user_switching_dialog"/>
</FrameLayout> </FrameLayout>

View File

@@ -147,6 +147,11 @@ public class CarKeyguardViewController extends OverlayViewController implements
registerUserSwitchedListener(); registerUserSwitchedListener();
} }
@Override
protected int getFocusAreaViewId() {
return R.id.keyguard_container;
}
@Override @Override
protected boolean shouldShowNavigationBarInsets() { protected boolean shouldShowNavigationBarInsets() {
return true; return true;

View File

@@ -218,6 +218,11 @@ public class NotificationPanelViewController extends OverlayPanelViewController
mNotificationVisibilityLogger.stop(); mNotificationVisibilityLogger.stop();
} }
@Override
protected int getFocusAreaViewId() {
return R.id.notification_container;
}
@Override @Override
protected boolean shouldShowNavigationBarInsets() { protected boolean shouldShowNavigationBarInsets() {
return true; return true;

View File

@@ -76,7 +76,7 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController
} }
if (event.getAction() == KeyEvent.ACTION_UP && getLayout().isVisibleToUser()) { if (event.getAction() == KeyEvent.ACTION_UP && getLayout().isVisibleToUser()) {
getLayout().setVisibility(View.GONE); stop();
} }
return true; return true;
}); });
@@ -91,6 +91,11 @@ public class FullScreenUserSwitcherViewController extends OverlayViewController
registerCarUserManagerIfPossible(); registerCarUserManagerIfPossible();
} }
@Override
protected int getFocusAreaViewId() {
return R.id.user_switcher_container;
}
@Override @Override
protected boolean shouldFocusWindow() { protected boolean shouldFocusWindow() {
return true; return true;

View File

@@ -17,12 +17,17 @@
package com.android.systemui.car.window; package com.android.systemui.car.window;
import static android.view.WindowInsets.Type.statusBars; import static android.view.WindowInsets.Type.statusBars;
import static android.view.accessibility.AccessibilityNodeInfo.ACTION_FOCUS;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.view.ViewStub; import android.view.ViewStub;
import android.view.WindowInsets; import android.view.WindowInsets;
import androidx.annotation.IdRes;
import com.android.car.ui.FocusArea;
/** /**
* Owns a {@link View} that is present in SystemUIOverlayWindow. * Owns a {@link View} that is present in SystemUIOverlayWindow.
*/ */
@@ -128,6 +133,66 @@ public class OverlayViewController {
return mOverlayViewGlobalStateController; return mOverlayViewGlobalStateController;
} }
/** Returns whether the view controlled by this controller is visible. */
public final boolean isVisible() {
return mLayout.getVisibility() == View.VISIBLE;
}
/**
* Returns the ID of the focus area that should receive focus when this view is the
* topmost view or {@link View#NO_ID} if there is no focus area.
*/
@IdRes
protected int getFocusAreaViewId() {
return View.NO_ID;
}
/** Returns whether the view controlled by this controller has rotary focus. */
protected final boolean hasRotaryFocus() {
return !mLayout.isInTouchMode() && mLayout.hasFocus();
}
/**
* Sets whether this view allows rotary focus. This should be set to {@code true} for the
* topmost layer in the overlay window and {@code false} for the others.
*/
public void setAllowRotaryFocus(boolean allowRotaryFocus) {
if (!isInflated()) {
return;
}
if (!(mLayout instanceof ViewGroup)) {
return;
}
ViewGroup viewGroup = (ViewGroup) mLayout;
viewGroup.setDescendantFocusability(allowRotaryFocus
? ViewGroup.FOCUS_BEFORE_DESCENDANTS
: ViewGroup.FOCUS_BLOCK_DESCENDANTS);
}
/**
* Refreshes the rotary focus in this view if we are in rotary mode. If the view already has
* rotary focus, it leaves the focus alone. Returns {@code true} if a new view was focused.
*/
public boolean refreshRotaryFocusIfNeeded() {
if (mLayout.isInTouchMode()) {
return false;
}
if (hasRotaryFocus()) {
return false;
}
View view = mLayout.findViewById(getFocusAreaViewId());
if (view == null || !(view instanceof FocusArea)) {
return mLayout.requestFocus();
}
FocusArea focusArea = (FocusArea) view;
return focusArea.performAccessibilityAction(ACTION_FOCUS, /* arguments= */ null);
}
/** /**
* Returns {@code true} if heads up notifications should be displayed over this view. * Returns {@code true} if heads up notifications should be displayed over this view.
*/ */

View File

@@ -29,6 +29,7 @@ import androidx.annotation.VisibleForTesting;
import java.util.HashMap; import java.util.HashMap;
import java.util.HashSet; import java.util.HashSet;
import java.util.Map; import java.util.Map;
import java.util.Objects;
import java.util.Set; import java.util.Set;
import java.util.SortedMap; import java.util.SortedMap;
import java.util.TreeMap; import java.util.TreeMap;
@@ -120,6 +121,7 @@ public class OverlayViewGlobalStateController {
refreshWindowFocus(); refreshWindowFocus();
refreshNavigationBarVisibility(); refreshNavigationBarVisibility();
refreshStatusBarVisibility(); refreshStatusBarVisibility();
refreshRotaryFocusIfNeeded();
Log.d(TAG, "Content shown: " + viewController.getClass().getName()); Log.d(TAG, "Content shown: " + viewController.getClass().getName());
debugLog(); debugLog();
@@ -193,6 +195,7 @@ public class OverlayViewGlobalStateController {
refreshWindowFocus(); refreshWindowFocus();
refreshNavigationBarVisibility(); refreshNavigationBarVisibility();
refreshStatusBarVisibility(); refreshStatusBarVisibility();
refreshRotaryFocusIfNeeded();
if (mZOrderVisibleSortedMap.isEmpty()) { if (mZOrderVisibleSortedMap.isEmpty()) {
setWindowVisible(false); setWindowVisible(false);
@@ -254,6 +257,17 @@ public class OverlayViewGlobalStateController {
} }
} }
private void refreshRotaryFocusIfNeeded() {
for (OverlayViewController controller : mZOrderVisibleSortedMap.values()) {
boolean isTop = Objects.equals(controller, mHighestZOrder);
controller.setAllowRotaryFocus(isTop);
}
if (!mZOrderVisibleSortedMap.isEmpty()) {
mHighestZOrder.refreshRotaryFocusIfNeeded();
}
}
/** Returns {@code true} is the window is visible. */ /** Returns {@code true} is the window is visible. */
public boolean isWindowVisible() { public boolean isWindowVisible() {
return mSystemUIOverlayWindowController.isWindowVisible(); return mSystemUIOverlayWindowController.isWindowVisible();

View File

@@ -214,6 +214,16 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
verify(mSystemUIOverlayWindowController).setWindowVisible(true); verify(mSystemUIOverlayWindowController).setWindowVisible(true);
} }
@Test
public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() {
setupOverlayViewController1();
mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey(
OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isTrue();
}
@Test @Test
public void showView_nothingAlreadyShown_newHighestZOrder() { public void showView_nothingAlreadyShown_newHighestZOrder() {
setupOverlayViewController1(); setupOverlayViewController1();
@@ -225,13 +235,12 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
} }
@Test @Test
public void showView_nothingAlreadyShown_newHighestZOrder_isVisible() { public void showView_nothingAlreadyShown_descendantsFocusable() {
setupOverlayViewController1(); setupOverlayViewController1();
mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
assertThat(mOverlayViewGlobalStateController.mZOrderVisibleSortedMap.containsKey( verify(mOverlayViewController1).setAllowRotaryFocus(true);
OVERLAY_VIEW_CONTROLLER_1_Z_ORDER)).isTrue();
} }
@Test @Test
@@ -331,6 +340,30 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray()); OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
} }
@Test
public void showView_newHighestZOrder_topDescendantsFocusable() {
setupOverlayViewController1();
setOverlayViewControllerAsShowing(mOverlayViewController1);
setupOverlayViewController2();
mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
verify(mOverlayViewController1).setAllowRotaryFocus(false);
verify(mOverlayViewController2).setAllowRotaryFocus(true);
}
@Test
public void showView_newHighestZOrder_refreshTopFocus() {
setupOverlayViewController1();
setOverlayViewControllerAsShowing(mOverlayViewController1);
setupOverlayViewController2();
mOverlayViewGlobalStateController.showView(mOverlayViewController2, mRunnable);
verify(mOverlayViewController1, never()).refreshRotaryFocusIfNeeded();
verify(mOverlayViewController2).refreshRotaryFocusIfNeeded();
}
@Test @Test
public void showView_oldHighestZOrder() { public void showView_oldHighestZOrder() {
setupOverlayViewController2(); setupOverlayViewController2();
@@ -345,9 +378,9 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
@Test @Test
public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() { public void showView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarsHidden() {
setupOverlayViewController2(); setupOverlayViewController2();
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true); when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true);
when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false); when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -360,11 +393,12 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
@Test @Test
public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() { public void showView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarsShown() {
setupOverlayViewController2(); setupOverlayViewController2();
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false); when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false);
when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true); when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true);
reset(mWindowInsetsController);
mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
@@ -374,9 +408,9 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
@Test @Test
public void showView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarsHidden() { public void showView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarsHidden() {
setupOverlayViewController2(); setupOverlayViewController2();
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true); when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true);
when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false); when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -389,11 +423,12 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
@Test @Test
public void showView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarsShown() { public void showView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarsShown() {
setupOverlayViewController2(); setupOverlayViewController2();
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true); when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false); when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false);
when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true); when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true);
reset(mWindowInsetsController);
mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable); mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
@@ -425,6 +460,30 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray()); OVERLAY_VIEW_CONTROLLER_2_Z_ORDER).toArray());
} }
@Test
public void showView_oldHighestZOrder_topDescendantsFocusable() {
setupOverlayViewController1();
setupOverlayViewController2();
setOverlayViewControllerAsShowing(mOverlayViewController2);
mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mOverlayViewController1).setAllowRotaryFocus(false);
verify(mOverlayViewController2).setAllowRotaryFocus(true);
}
@Test
public void showView_oldHighestZOrder_refreshTopFocus() {
setupOverlayViewController1();
setupOverlayViewController2();
setOverlayViewControllerAsShowing(mOverlayViewController2);
mOverlayViewGlobalStateController.showView(mOverlayViewController1, mRunnable);
verify(mOverlayViewController1, never()).refreshRotaryFocusIfNeeded();
verify(mOverlayViewController2).refreshRotaryFocusIfNeeded();
}
@Test @Test
public void showView_somethingAlreadyShown_windowVisibleNotCalled() { public void showView_somethingAlreadyShown_windowVisibleNotCalled() {
setupOverlayViewController1(); setupOverlayViewController1();
@@ -577,10 +636,10 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { public void hideView_newHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false); when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(false);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -593,10 +652,10 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() { public void hideView_newHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true); when(mOverlayViewController1.shouldShowNavigationBarInsets()).thenReturn(true);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -609,10 +668,10 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_newHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() { public void hideView_newHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false); when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(false);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -625,10 +684,10 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_newHighestZOrder_shouldShowStatusBarTrue_statusBarShown() { public void hideView_newHighestZOrder_shouldShowStatusBarTrue_statusBarShown() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true); when(mOverlayViewController1.shouldShowStatusBarInsets()).thenReturn(true);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -668,10 +727,10 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() { public void hideView_oldHighestZOrder_shouldShowNavBarFalse_navigationBarHidden() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false); when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(false);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -684,11 +743,12 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() { public void hideView_oldHighestZOrder_shouldShowNavBarTrue_navigationBarShown() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true); when(mOverlayViewController2.shouldShowNavigationBarInsets()).thenReturn(true);
reset(mWindowInsetsController);
mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
@@ -699,10 +759,10 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() { public void hideView_oldHighestZOrder_shouldShowStatusBarFalse_statusBarHidden() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false); when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(false);
reset(mWindowInsetsController); reset(mWindowInsetsController);
@@ -715,11 +775,12 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
public void hideView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarShown() { public void hideView_oldHighestZOrder_shouldShowStatusBarTrue_statusBarShown() {
setupOverlayViewController1(); setupOverlayViewController1();
setupOverlayViewController2(); setupOverlayViewController2();
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
setOverlayViewControllerAsShowing(mOverlayViewController1); setOverlayViewControllerAsShowing(mOverlayViewController1);
setOverlayViewControllerAsShowing(mOverlayViewController2); setOverlayViewControllerAsShowing(mOverlayViewController2);
when(mOverlayViewController1.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldFocusWindow()).thenReturn(true);
when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true); when(mOverlayViewController2.shouldShowStatusBarInsets()).thenReturn(true);
reset(mWindowInsetsController);
mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable); mOverlayViewGlobalStateController.hideView(mOverlayViewController1, mRunnable);
@@ -917,7 +978,11 @@ public class OverlayViewGlobalStateControllerTest extends SysuiTestCase {
private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) { private void setOverlayViewControllerAsShowing(OverlayViewController overlayViewController) {
mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null); mOverlayViewGlobalStateController.showView(overlayViewController, /* show= */ null);
View layout = overlayViewController.getLayout();
reset(mSystemUIOverlayWindowController); reset(mSystemUIOverlayWindowController);
reset(overlayViewController);
when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout); when(mSystemUIOverlayWindowController.getBaseLayout()).thenReturn(mBaseLayout);
when(overlayViewController.getLayout()).thenReturn(layout);
when(overlayViewController.isInflated()).thenReturn(true);
} }
} }