Restore focus history properly
Fixes: 171573648
Test: manually tested the dialog in Launcher
Change-Id: Id6079e3cf1a25d38dcdc1cb609cd07c33292788a
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java
index 3ccbd88..b20758a 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusArea.java
@@ -480,16 +480,26 @@
@Override
public void onWindowFocusChanged(boolean hasWindowFocus) {
// To ensure the focus is initialized properly in rotary mode when there is a window focus
- // change, this FocusArea will grab the focus from the currently focused view if one of this
- // FocusArea's descendants is a better focus candidate than the currently focused view.
+ // change, this FocusArea will grab the focus if nothing is focused or the currently
+ // focused view's FocusLevel is lower than REGULAR_FOCUS.
if (hasWindowFocus && !isInTouchMode()) {
- maybeAdjustFocus();
+ maybeInitFocus();
}
super.onWindowFocusChanged(hasWindowFocus);
}
/**
- * Focuses on another view in this FocusArea if the view is a better focus candidate than the
+ * Focuses on another view in this FocusArea if nothing is focused or the currently focused
+ * view's FocusLevel is lower than REGULAR_FOCUS.
+ */
+ private boolean maybeInitFocus() {
+ View root = getRootView();
+ View focus = root.findFocus();
+ return ViewUtils.initFocus(root, focus);
+ }
+
+ /**
+ * Focuses on a view in this FocusArea if the view is a better focus candidate than the
* currently focused view.
*/
private boolean maybeAdjustFocus() {
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java
index 2cddee6..aac5c03 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/FocusParkingView.java
@@ -160,7 +160,9 @@
}
private void updateFocusedView(@Nullable View focusedView) {
- mFocusCache.setFocusedView(mFocusedView, SystemClock.uptimeMillis());
+ if (mFocusedView != null) {
+ mFocusCache.setFocusedView(mFocusedView, SystemClock.uptimeMillis());
+ }
mFocusedView = focusedView;
mScrollableContainer = ViewUtils.getAncestorScrollableContainer(focusedView);
}
@@ -201,7 +203,7 @@
} else if (isFocused()) {
// When FocusParkingView is focused and the window just gets focused, transfer the view
// focus to a non-FocusParkingView in the window.
- restoreFocusInRoot(/* checkForTouchMode= */ true, /* checkFocusHistory= */ false);
+ restoreFocusInRoot(/* checkForTouchMode= */ true);
}
super.onWindowFocusChanged(hasWindowFocus);
}
@@ -215,8 +217,7 @@
public boolean performAccessibilityAction(int action, Bundle arguments) {
switch (action) {
case ACTION_RESTORE_DEFAULT_FOCUS:
- return restoreFocusInRoot(
- /* checkForTouchMode= */ false, /* checkFocusHistory= */ true);
+ return restoreFocusInRoot(/* checkForTouchMode= */ false);
case ACTION_HIDE_IME:
InputMethodManager inputMethodManager =
getContext().getSystemService(InputMethodManager.class);
@@ -239,7 +240,7 @@
}
// Find a better target to focus instead of focusing this FocusParkingView when the
// framework wants to focus it.
- return restoreFocusInRoot(/* checkForTouchMode= */ true, /* checkFocusHistory= */ false);
+ return restoreFocusInRoot(/* checkForTouchMode= */ true);
}
@Override
@@ -249,7 +250,7 @@
}
// Find a better target to focus instead of focusing this FocusParkingView when the
// framework wants to focus it.
- return restoreFocusInRoot(/* checkForTouchMode= */ true, /* checkFocusHistory= */ false);
+ return restoreFocusInRoot(/* checkForTouchMode= */ true);
}
/**
@@ -261,7 +262,7 @@
mShouldRestoreFocus = shouldRestoreFocus;
}
- private boolean restoreFocusInRoot(boolean checkForTouchMode, boolean checkFocusHistory) {
+ private boolean restoreFocusInRoot(boolean checkForTouchMode) {
// Don't do anything in touch mode if checkForTouchMode is true.
if (checkForTouchMode && isInTouchMode()) {
return false;
@@ -274,9 +275,7 @@
}
// Otherwise try to find the best target view to focus.
- View cachedFocusedView = checkFocusHistory
- ? mFocusCache.getFocusedView(SystemClock.uptimeMillis())
- : null;
+ View cachedFocusedView = mFocusCache.getFocusedView(SystemClock.uptimeMillis());
if (ViewUtils.adjustFocus(
getRootView(), cachedFocusedView, mDefaultFocusOverridesHistory)) {
return true;
diff --git a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/ViewUtils.java b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/ViewUtils.java
index a23e641..bc5a583 100644
--- a/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/ViewUtils.java
+++ b/car-ui-lib/car-ui-lib/src/main/java/com/android/car/ui/utils/ViewUtils.java
@@ -174,6 +174,21 @@
}
/**
+ * If the {@code currentFocus}'s FocusLevel is lower than REGULAR_FOCUS, adjusts focus within
+ * {@code root}. See {@link #adjustFocus(View, int)}. Otherwise no-op.
+ *
+ * @return whether the focus has changed
+ */
+ public static boolean initFocus(@NonNull View root, @Nullable View currentFocus) {
+ @FocusLevel int currentLevel = getFocusLevel(currentFocus);
+ if (currentLevel >= REGULAR_FOCUS) {
+ return false;
+ }
+ return adjustFocus(root, currentLevel, /* cachedFocusedView= */ null,
+ /* defaultFocusOverridesHistory= */ false);
+ }
+
+ /**
* Searches the {@code root}'s descendants for a view with the highest {@link FocusLevel}. If
* the view's FocusLevel is higher than {@code currentLevel}, focuses on the view.
*