Merge "Update getBoundsInScreen() method" into rvc-qpr-dev
diff --git a/src/com/android/car/rotary/Navigator.java b/src/com/android/car/rotary/Navigator.java
index 9c8c841..c4e44c1 100644
--- a/src/com/android/car/rotary/Navigator.java
+++ b/src/com/android/car/rotary/Navigator.java
@@ -78,13 +78,7 @@
}
// Find the HUN window, if any.
- AccessibilityWindowInfo hunWindow = null;
- for (AccessibilityWindowInfo window : windows) {
- if (isHunWindow(window)) {
- hunWindow = window;
- break;
- }
- }
+ AccessibilityWindowInfo hunWindow = findHunWindow(windows);
if (hunWindow == null) {
return null;
}
@@ -103,6 +97,16 @@
return targetFocusArea;
}
+ @Nullable
+ AccessibilityWindowInfo findHunWindow(@NonNull List<AccessibilityWindowInfo> windows) {
+ for (AccessibilityWindowInfo window : windows) {
+ if (isHunWindow(window)) {
+ return window;
+ }
+ }
+ return null;
+ }
+
/**
* Returns the target focusable for a rotate. The caller is responsible for recycling the node
* in the result.
diff --git a/src/com/android/car/rotary/RotaryService.java b/src/com/android/car/rotary/RotaryService.java
index 79e03cf..475fb9f 100644
--- a/src/com/android/car/rotary/RotaryService.java
+++ b/src/com/android/car/rotary/RotaryService.java
@@ -55,8 +55,8 @@
import android.car.input.RotaryEvent;
import android.content.ContentResolver;
import android.content.Context;
-import android.content.res.Resources;
import android.content.SharedPreferences;
+import android.content.res.Resources;
import android.database.ContentObserver;
import android.graphics.PixelFormat;
import android.hardware.display.DisplayManager;
@@ -127,6 +127,13 @@
*/
private static final int SHIFT_DETENTS = 10;
+ /**
+ * A value to indicate that it isn't one of the nudge directions. (i.e.
+ * {@link View#FOCUS_LEFT}, {@link View#FOCUS_UP}, {@link View#FOCUS_RIGHT}, or
+ * {@link View#FOCUS_DOWN}).
+ */
+ private static final int INVALID_NUDGE_DIRECTION = -1;
+
private static final String SHARED_PREFS = "com.android.car.rotary.RotaryService";
private static final String TOUCH_INPUT_METHOD_PREFIX = "TOUCH_INPUT_METHOD_";
@@ -213,6 +220,13 @@
private UserManager mUserManager;
/**
+ * The direction of the HUN. If there is no focused node, or the focused node is outside the
+ * HUN, nudging to this direction will focus on a node inside the HUN.
+ */
+ @View.FocusRealDirection
+ private int mHunNudgeDirection;
+
+ /**
* Possible actions to do after receiving {@link AccessibilityEvent#TYPE_VIEW_SCROLLED}.
*
* @see #injectScrollEvent
@@ -329,6 +343,7 @@
int displayWidth = windowManager.getCurrentWindowMetrics().getBounds().width();
int hunRight = displayWidth - hunMarginHorizontal;
boolean showHunOnBottom = res.getBoolean(R.bool.config_showHeadsUpNotificationOnBottom);
+ mHunNudgeDirection = showHunOnBottom ? View.FOCUS_DOWN : View.FOCUS_UP;
mIgnoreViewClickedMs = res.getInteger(R.integer.ignore_view_clicked_ms);
mAfterScrollTimeoutMs = res.getInteger(R.integer.after_scroll_timeout_ms);
@@ -346,6 +361,11 @@
if (isValidIme(defaultTouchInputMethod)) {
mTouchInputMethod = mPrefs.getString(
TOUCH_INPUT_METHOD_PREFIX + mUserManager.getUserName(), defaultTouchInputMethod);
+ // Set the DEFAULT_INPUT_METHOD in case Android defaults to the rotary_input_method.
+ // TODO(b/169423887): Figure out how to configure the default IME through Android
+ // without needing to do this.
+ Settings.Secure.putString(
+ getContentResolver(), DEFAULT_INPUT_METHOD, mTouchInputMethod);
}
String rotaryInputMethod = res.getString(R.string.rotary_input_method);
if (isValidIme(rotaryInputMethod)) {
@@ -1012,17 +1032,19 @@
return;
}
+ List<AccessibilityWindowInfo> windows = getWindows();
+
// Don't call initFocus() when handling ACTION_UP nudge events as this event will typically
// arrive before the TYPE_VIEW_FOCUSED event when we delegate focusing to a FocusArea, and
// will cause us to focus a nearby view when we discover that mFocusedNode is no longer
// focused.
- if (initFocus()) {
+ if (initFocus(windows, direction)) {
+ Utils.recycleWindows(windows);
return;
}
// If the focused node is not in direct manipulation mode, try to move the focus to another
// node.
- List<AccessibilityWindowInfo> windows = getWindows();
boolean success = nudgeTo(windows, direction);
Utils.recycleWindows(windows);
@@ -1387,6 +1409,21 @@
* {@link #mFocusedNode} is guaranteed to not be {@code null}.
*/
private boolean initFocus() {
+ return initFocus(null, INVALID_NUDGE_DIRECTION);
+ }
+
+ /**
+ * Similar to above, but also checks for heads-up notifications if given a valid nudge direction
+ * which may be relevant when we're trying to focus the HUNs when coming from touch mode.
+ *
+ * @param windows the windows currently available to the Accessibility Service
+ * @param direction the direction of the nudge that was received (can be
+ * {@link #INVALID_NUDGE_DIRECTION})
+ * @return whether the event was consumed by this method. When {@code false},
+ * {@link #mFocusedNode} is guaranteed to not be {@code null}.
+ */
+ private boolean initFocus(@Nullable List<AccessibilityWindowInfo> windows, int direction) {
+ boolean prevInRotaryMode = mInRotaryMode;
refreshSavedNodes();
setInRotaryMode(true);
if (mFocusedNode != null) {
@@ -1405,6 +1442,14 @@
// focused any more. In this case we should set mFocusedNode to null.
setFocusedNode(null);
}
+
+ // If we were not in rotary mode before and we can focus the HUNs window for the given
+ // nudge, focus the window and ensure that there is no previously touched node.
+ if (!prevInRotaryMode && windows != null && focusHunsWindow(windows, direction)) {
+ setLastTouchedNode(null);
+ return true;
+ }
+
if (mLastTouchedNode != null && focusLastTouchedNode()) {
return true;
}
@@ -1484,6 +1529,30 @@
return result;
}
+ private boolean focusHunsWindow(@NonNull List<AccessibilityWindowInfo> windows, int direction) {
+ if (direction != mHunNudgeDirection) {
+ return false;
+ }
+
+ AccessibilityWindowInfo hunWindow = mNavigator.findHunWindow(windows);
+ if (hunWindow == null) {
+ L.d("No HUN window to focus");
+ return false;
+ }
+
+ AccessibilityNodeInfo hunRoot = hunWindow.getRoot();
+ if (hunRoot == null) {
+ L.d("No root in HUN Window to focus");
+ return false;
+ }
+
+ boolean success = restoreDefaultFocus(hunRoot);
+ hunRoot.recycle();
+ hunWindow.recycle();
+ L.d("HUN window focus " + (success ? "successful" : "failed"));
+ return success;
+ }
+
/**
* Focuses the last touched node, if any.
*