From f00098805c2af4dc7abc51fe7a5e77b04a5fb0fe Mon Sep 17 00:00:00 2001 From: Winson Date: Wed, 1 Jun 2016 12:22:55 -0700 Subject: [PATCH] Fixing several issues with accessibility - Only reset the focused task if the task that we removed actually had accessibility focus. - Only reset the focused task on scroll if we are not in touch exploration mode - Ensure the focused view has accessibility focus when entering recents in touch exploration mode - Instead of using the focused task, query for the accessibility focused task view when setting the focused task in response to the scroll gesture. In addition, use this accessibility focused task to determine whether we need to add the accessibility actions - No longer explicitly requesting accessibility focus on view focus - Removing some unused code Bug: 29046351 Change-Id: I5701a408bd919e47990f0d2fc6e4686eb9530d8e --- .../systemui/recents/misc/Utilities.java | 21 ++++ .../systemui/recents/views/TaskStackView.java | 108 ++++++++++-------- .../views/TaskStackViewTouchHandler.java | 4 +- .../systemui/recents/views/TaskView.java | 10 +- 4 files changed, 88 insertions(+), 55 deletions(-) diff --git a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java index 9fb8bd557b90e..2c5c437bfab0b 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java +++ b/packages/SystemUI/src/com/android/systemui/recents/misc/Utilities.java @@ -34,6 +34,7 @@ import android.util.IntProperty; import android.util.Property; import android.util.TypedValue; import android.view.View; +import android.view.ViewGroup; import android.view.ViewParent; import android.view.ViewStub; @@ -284,6 +285,26 @@ public class Utilities { Trace.traceEnd(Trace.TRACE_TAG_VIEW); } + /** + * Returns whether this view, or one of its descendants have accessibility focus. + */ + public static boolean isDescendentAccessibilityFocused(View v) { + if (v.isAccessibilityFocused()) { + return true; + } + + if (v instanceof ViewGroup) { + ViewGroup vg = (ViewGroup) v; + int childCount = vg.getChildCount(); + for (int i = 0; i < childCount; i++) { + if (isDescendentAccessibilityFocused(vg.getChildAt(i))) { + return true; + } + } + } + return false; + } + /** * Returns the application configuration, which is independent of the activity's current * configuration in multiwindow. diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java index 231360e46ae97..586a8bcd89202 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -44,6 +44,7 @@ import android.view.ViewGroup; import android.view.accessibility.AccessibilityEvent; import android.view.accessibility.AccessibilityNodeInfo; import android.widget.FrameLayout; +import android.widget.ScrollView; import com.android.internal.logging.MetricsLogger; import com.android.internal.logging.MetricsProto.MetricsEvent; @@ -170,7 +171,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal @ViewDebug.ExportedProperty(category="recents") private boolean mEnterAnimationComplete = false; @ViewDebug.ExportedProperty(category="recents") - private boolean mTouchExplorationEnabled; + boolean mTouchExplorationEnabled; @ViewDebug.ExportedProperty(category="recents") boolean mScreenPinningEnabled; @@ -579,7 +580,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (task.isFreeformTask() || (transform != null && transform.visible)) { mTmpTaskViewMap.put(task.key, tv); } else { - if (mTouchExplorationEnabled) { + if (mTouchExplorationEnabled && Utilities.isDescendentAccessibilityFocused(tv)) { lastFocusedTaskIndex = taskIndex; resetFocusedTask(task); } @@ -630,12 +631,14 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Update the focus if the previous focused task was returned to the view pool if (lastFocusedTaskIndex != -1) { - if (lastFocusedTaskIndex < visibleTaskRange[1]) { - setFocusedTask(visibleTaskRange[1], false /* scrollToTask */, - true /* requestViewFocus */); - } else { - setFocusedTask(visibleTaskRange[0], false /* scrollToTask */, - true /* requestViewFocus */); + int newFocusedTaskIndex = (lastFocusedTaskIndex < visibleTaskRange[1]) + ? visibleTaskRange[1] + : visibleTaskRange[0]; + setFocusedTask(newFocusedTaskIndex, false /* scrollToTask */, + true /* requestViewFocus */); + TaskView focusedTaskView = getChildViewForTask(mFocusedTask); + if (focusedTaskView != null) { + focusedTaskView.requestAccessibilityFocus(); } } } @@ -938,24 +941,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * focus. */ public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated) { - setRelativeFocusedTask(forward, stackTasksOnly, animated, false); - } - - /** - * Sets the focused task relative to the currently focused task. - * - * @param forward whether to go to the next task in the stack (along the curve) or the previous - * @param stackTasksOnly if set, will ensure that the traversal only goes along stack tasks, and - * if the currently focused task is not a stack task, will set the focus - * to the first visible stack task - * @param animated determines whether to actually draw the highlight along with the change in - * focus. - * @param cancelWindowAnimations if set, will attempt to cancel window animations if a scroll - * happens. - */ - public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated, - boolean cancelWindowAnimations) { - setRelativeFocusedTask(forward, stackTasksOnly, animated, cancelWindowAnimations, 0); + setRelativeFocusedTask(forward, stackTasksOnly, animated, false, 0); } /** @@ -972,13 +958,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal * @param timerIndicatorDuration the duration to initialize the auto-advance timer indicator */ public void setRelativeFocusedTask(boolean forward, boolean stackTasksOnly, boolean animated, - boolean cancelWindowAnimations, - int timerIndicatorDuration) { - int newIndex = mStack.indexOfStackTask(mFocusedTask); - if (mFocusedTask != null) { + boolean cancelWindowAnimations, int timerIndicatorDuration) { + Task focusedTask = getFocusedTask(); + int newIndex = mStack.indexOfStackTask(focusedTask); + if (focusedTask != null) { if (stackTasksOnly) { List tasks = mStack.getStackTasks(); - if (mFocusedTask.isFreeformTask()) { + if (focusedTask.isFreeformTask()) { // Try and focus the front most stack task TaskView tv = getFrontMostTaskView(stackTasksOnly); if (tv != null) { @@ -1054,6 +1040,25 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return mFocusedTask; } + /** + * Returns the accessibility focused task. + */ + Task getAccessibilityFocusedTask() { + List taskViews = getTaskViews(); + int taskViewCount = taskViews.size(); + for (int i = 0; i < taskViewCount; i++) { + TaskView tv = taskViews.get(i); + if (Utilities.isDescendentAccessibilityFocused(tv)) { + return tv.getTask(); + } + } + TaskView frontTv = getFrontMostTaskView(true /* stackTasksOnly */); + if (frontTv != null) { + return frontTv.getTask(); + } + return null; + } + @Override public void onInitializeAccessibilityEvent(AccessibilityEvent event) { super.onInitializeAccessibilityEvent(event); @@ -1078,21 +1083,23 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal super.onInitializeAccessibilityNodeInfo(info); List taskViews = getTaskViews(); int taskViewCount = taskViews.size(); - if (taskViewCount > 1 && mFocusedTask != null) { + if (taskViewCount > 1) { + // Find the accessibility focused task + Task focusedTask = getAccessibilityFocusedTask(); info.setScrollable(true); - int focusedTaskIndex = mStack.indexOfStackTask(mFocusedTask); + int focusedTaskIndex = mStack.indexOfStackTask(focusedTask); if (focusedTaskIndex > 0) { - info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); - } - if (focusedTaskIndex < mStack.getTaskCount() - 1) { info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD); } + if (0 <= focusedTaskIndex && focusedTaskIndex < mStack.getTaskCount() - 1) { + info.addAction(AccessibilityNodeInfo.ACTION_SCROLL_FORWARD); + } } } @Override public CharSequence getAccessibilityClassName() { - return TaskStackView.class.getName(); + return ScrollView.class.getName(); } @Override @@ -1100,14 +1107,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal if (super.performAccessibilityAction(action, arguments)) { return true; } - switch (action) { - case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { - setRelativeFocusedTask(true, false /* stackTasksOnly */, false /* animated */); - return true; - } - case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { - setRelativeFocusedTask(false, false /* stackTasksOnly */, false /* animated */); - return true; + Task focusedTask = getAccessibilityFocusedTask(); + int taskIndex = mStack.indexOfStackTask(focusedTask); + if (0 <= taskIndex && taskIndex < mStack.getTaskCount()) { + switch (action) { + case AccessibilityNodeInfo.ACTION_SCROLL_FORWARD: { + setFocusedTask(taskIndex + 1, true /* scrollToTask */, true /* requestViewFocus */, + 0); + return true; + } + case AccessibilityNodeInfo.ACTION_SCROLL_BACKWARD: { + setFocusedTask(taskIndex - 1, true /* scrollToTask */, true /* requestViewFocus */, + 0); + return true; + } } } return false; @@ -1489,6 +1502,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal unbindTaskView(tv, task); // Reset the view properties and view state + tv.clearAccessibilityFocus(); tv.resetViewProperties(); tv.setFocusedState(false, false /* requestViewFocus */); tv.setClipViewInStack(false); @@ -1949,6 +1963,10 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal RecentsActivityLaunchState launchState = config.getLaunchState(); setFocusedTask(mStack.indexOfStackTask(mFocusedTask), false /* scrollToTask */, launchState.launchedWithAltTab); + TaskView focusedTaskView = getChildViewForTask(mFocusedTask); + if (mTouchExplorationEnabled && focusedTaskView != null) { + focusedTaskView.requestAccessibilityFocus(); + } } EventBus.getDefault().send(new EnterRecentsTaskStackAnimationCompletedEvent()); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java index b554a467c7ce7..67a2595c90cd9 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackViewTouchHandler.java @@ -343,7 +343,9 @@ class TaskStackViewTouchHandler implements SwipeHelper.Callback { } // Reset the focused task after the user has scrolled - mSv.resetFocusedTask(mSv.getFocusedTask()); + if (!mSv.mTouchExplorationEnabled) { + mSv.resetFocusedTask(mSv.getFocusedTask()); + } } else if (mActiveTaskView == null) { // This tap didn't start on a task. maybeHideRecentsFromBackgroundTap((int) ev.getX(), (int) ev.getY()); diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java index 612c41d07a047..4ecdd77880011 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java @@ -133,8 +133,6 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks @ViewDebug.ExportedProperty(deepExport=true, prefix="task_") private Task mTask; @ViewDebug.ExportedProperty(category="recents") - private boolean mTaskDataLoaded; - @ViewDebug.ExportedProperty(category="recents") private boolean mClipViewInStack = true; @ViewDebug.ExportedProperty(category="recents") private boolean mTouchExplorationEnabled; @@ -451,16 +449,12 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks * Explicitly sets the focused state of this task. */ public void setFocusedState(boolean isFocused, boolean requestViewFocus) { - SystemServicesProxy ssp = Recents.getSystemServices(); if (isFocused) { if (requestViewFocus && !isFocused()) { requestFocus(); } - if (requestViewFocus && !isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) { - requestAccessibilityFocus(); - } } else { - if (isAccessibilityFocused() && ssp.isTouchExplorationEnabled()) { + if (isAccessibilityFocused() && mTouchExplorationEnabled) { clearAccessibilityFocus(); } } @@ -622,7 +616,6 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks // Update each of the views to the new task data mThumbnailView.onTaskDataLoaded(thumbnailInfo); mHeaderView.onTaskDataLoaded(); - mTaskDataLoaded = true; } @Override @@ -631,7 +624,6 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks mTask.removeCallback(this); mThumbnailView.unbindFromTask(); mHeaderView.unbindFromTask(mTouchExplorationEnabled); - mTaskDataLoaded = false; } @Override