Added open, dismiss and split screen as custom accessibility actions

In overview with talkback, swiping would select the individual apps
instead of the open and dismiss views. The open and dismiss actions
are changed to accessibility custom actions with the additional action
to split the current app into multi-window mode.

Test: manual - used talkback with running all three actions in
landscape and portrait
Fixes: 29360763
Change-Id: Ie0bec99b849c5754d45577c66b17fa6b0c7e985c
This commit is contained in:
Matthew Ng
2017-01-19 11:04:50 -08:00
parent e961992ed3
commit b7035f3a47
8 changed files with 195 additions and 43 deletions

View File

@@ -297,4 +297,11 @@
If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
<integer name="config_warningTemperature">-1</integer>
<!-- Accessibility actions -->
<item type="id" name="action_split_task_to_left" />
<item type="id" name="action_split_task_to_right" />
<item type="id" name="action_split_task_to_top" />
<item type="id" name="action_open" />
<item type="id" name="action_dimiss" />
</resources>

View File

@@ -786,6 +786,16 @@
<string name="recents_multistack_add_stack_dialog_split_vertical">Split Vertical</string>
<!-- Recents: MultiStack add stack split custom radio button. [CHAR LIMIT=NONE] -->
<string name="recents_multistack_add_stack_dialog_split_custom">Split Custom</string>
<!-- Recents: Accessibility dismiss label -->
<string name="recents_accessibility_dismissed">Dismiss</string>
<!-- Recents: Accessibility open label -->
<string name="recents_accessibility_open">Open</string>
<!-- Recents: Accessibility split to the top -->
<string name="recents_accessibility_split_screen_top">Split screen to the top</string>
<!-- Recents: Accessibility split to the left -->
<string name="recents_accessibility_split_screen_left">Split screen to the left</string>
<!-- Recents: Accessibility split to the right -->
<string name="recents_accessibility_split_screen_right">Split screen to the right</string>
<!-- Fully qualified activity class names to be blacklisted in Recents, add package names into overlay as needed -->
<string-array name="recents_blacklist_array">

View File

@@ -17,12 +17,33 @@
package com.android.systemui.recents;
import android.content.Context;
import android.content.res.Configuration;
import android.content.res.Resources;
import android.graphics.Rect;
import android.os.SystemProperties;
import com.android.systemui.R;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.TaskStack;
/**
* Represents the dock regions for each orientation.
*/
class DockRegion {
public static TaskStack.DockState[] PHONE_LANDSCAPE = {
// We only allow docking to the left in landscape for now on small devices
TaskStack.DockState.LEFT
};
public static TaskStack.DockState[] PHONE_PORTRAIT = {
// We only allow docking to the top for now on small devices
TaskStack.DockState.TOP
};
public static TaskStack.DockState[] TABLET_LANDSCAPE = {
TaskStack.DockState.LEFT,
TaskStack.DockState.RIGHT
};
public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
}
/**
* Application resources that can be retrieved from the application context and are not specifically
@@ -63,12 +84,14 @@ public class RecentsConfiguration {
// Recents will layout task views in a grid mode when there's enough space in the screen.
public boolean isGridEnabled;
private final Context mAppContext;
public RecentsConfiguration(Context context) {
// Load only resources that can not change after the first load either through developer
// settings or via multi window
SystemServicesProxy ssp = Recents.getSystemServices();
Context appContext = context.getApplicationContext();
Resources res = appContext.getResources();
mAppContext = context.getApplicationContext();
Resources res = mAppContext.getResources();
fakeShadows = res.getBoolean(R.bool.config_recents_fake_shadows);
svelteLevel = res.getInteger(R.integer.recents_svelte_level);
isGridEnabled = SystemProperties.getBoolean("ro.recents.grid", false);
@@ -86,4 +109,20 @@ public class RecentsConfiguration {
public RecentsActivityLaunchState getLaunchState() {
return mLaunchState;
}
/**
* Returns the preferred dock states for the current orientation.
* @return a list of dock states for device and its orientation
*/
public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
boolean isLandscape = mAppContext.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
RecentsConfiguration config = Recents.getConfiguration();
if (config.isLargeScreen) {
return isLandscape ? DockRegion.TABLET_LANDSCAPE : DockRegion.TABLET_PORTRAIT;
} else {
return isLandscape ? DockRegion.PHONE_LANDSCAPE : DockRegion.PHONE_PORTRAIT;
}
}
}

View File

@@ -30,10 +30,17 @@ public class DragStartEvent extends EventBus.Event {
public final Task task;
public final TaskView taskView;
public final Point tlOffset;
public final boolean isUserTouchInitiated;
public DragStartEvent(Task task, TaskView taskView, Point tlOffset) {
this(task, taskView, tlOffset, true);
}
public DragStartEvent(Task task, TaskView taskView, Point tlOffset,
boolean isUserTouchInitiated) {
this.task = task;
this.taskView = taskView;
this.tlOffset = tlOffset;
this.isUserTouchInitiated = isUserTouchInitiated;
}
}

View File

@@ -454,7 +454,7 @@ public class RecentsView extends FrameLayout {
}
public final void onBusEvent(DragStartEvent event) {
updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
updateVisibleDockRegions(Recents.getConfiguration().getDockStatesForCurrentOrientation(),
true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
TaskStack.DockState.NONE.viewState.hintTextAlpha,
true /* animateAlpha */, false /* animateBounds */);
@@ -471,7 +471,8 @@ public class RecentsView extends FrameLayout {
public final void onBusEvent(DragDropTargetChangedEvent event) {
if (event.dropTarget == null || !(event.dropTarget instanceof TaskStack.DockState)) {
updateVisibleDockRegions(mTouchHandler.getDockStatesForCurrentOrientation(),
updateVisibleDockRegions(
Recents.getConfiguration().getDockStatesForCurrentOrientation(),
true /* isDefaultDockState */, TaskStack.DockState.NONE.viewState.dockAreaAlpha,
TaskStack.DockState.NONE.viewState.hintTextAlpha,
true /* animateAlpha */, true /* animateBounds */);

View File

@@ -28,7 +28,6 @@ import android.view.ViewDebug;
import com.android.internal.policy.DividerSnapAlgorithm;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
@@ -44,25 +43,6 @@ import com.android.systemui.recents.model.TaskStack;
import java.util.ArrayList;
/**
* Represents the dock regions for each orientation.
*/
class DockRegion {
public static TaskStack.DockState[] PHONE_LANDSCAPE = {
// We only allow docking to the left in landscape for now on small devices
TaskStack.DockState.LEFT
};
public static TaskStack.DockState[] PHONE_PORTRAIT = {
// We only allow docking to the top for now on small devices
TaskStack.DockState.TOP
};
public static TaskStack.DockState[] TABLET_LANDSCAPE = {
TaskStack.DockState.LEFT,
TaskStack.DockState.RIGHT
};
public static TaskStack.DockState[] TABLET_PORTRAIT = PHONE_PORTRAIT;
}
/**
* Handles touch events for a RecentsView.
*/
@@ -110,20 +90,6 @@ public class RecentsViewTouchHandler {
mDropTargets.add(target);
}
/**
* Returns the preferred dock states for the current orientation.
*/
public TaskStack.DockState[] getDockStatesForCurrentOrientation() {
boolean isLandscape = mRv.getResources().getConfiguration().orientation ==
Configuration.ORIENTATION_LANDSCAPE;
RecentsConfiguration config = Recents.getConfiguration();
if (config.isLargeScreen) {
return isLandscape ? DockRegion.TABLET_LANDSCAPE : DockRegion.TABLET_PORTRAIT;
} else {
return isLandscape ? DockRegion.PHONE_LANDSCAPE : DockRegion.PHONE_PORTRAIT;
}
}
/**
* Returns the set of visible dock states for this current drag.
*/
@@ -162,10 +128,14 @@ public class RecentsViewTouchHandler {
mRv.getLocationInWindow(recentsViewLocation);
mTaskViewOffset.set(mTaskView.getLeft() - recentsViewLocation[0] + event.tlOffset.x,
mTaskView.getTop() - recentsViewLocation[1] + event.tlOffset.y);
float x = mDownPos.x - mTaskViewOffset.x;
float y = mDownPos.y - mTaskViewOffset.y;
mTaskView.setTranslationX(x);
mTaskView.setTranslationY(y);
// Change space coordinates relative to the view to RecentsView when user initiates a touch
if (event.isUserTouchInitiated) {
float x = mDownPos.x - mTaskViewOffset.x;
float y = mDownPos.y - mTaskViewOffset.y;
mTaskView.setTranslationX(x);
mTaskView.setTranslationY(y);
}
mVisibleDockStates.clear();
if (ActivityManager.supportsMultiWindow() && !ssp.hasDockedTask()
@@ -176,7 +146,8 @@ public class RecentsViewTouchHandler {
EventBus.getDefault().send(new ShowIncompatibleAppOverlayEvent());
} else {
// Add the dock state drop targets (these take priority)
TaskStack.DockState[] dockStates = getDockStatesForCurrentOrientation();
TaskStack.DockState[] dockStates = Recents.getConfiguration()
.getDockStatesForCurrentOrientation();
for (TaskStack.DockState dockState : dockStates) {
registerDropTargetForCurrentDrag(dockState);
dockState.update(mRv.getContext());

View File

@@ -183,6 +183,7 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
setOutlineProvider(mViewBounds);
setOnLongClickListener(this);
setAccessibilityDelegate(new TaskViewAccessibilityDelegate(this));
}
/** Set callback */
@@ -256,6 +257,11 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
}
@Override
public void addChildrenForAccessibility(ArrayList<View> outChildren) {
// Prevent any children from being focusable during talkback
}
@Override
public boolean hasOverlappingRendering() {
return false;

View File

@@ -0,0 +1,111 @@
/*
* Copyright (C) 2017 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License
*/
package com.android.systemui.recents.views;
import android.app.ActivityManager;
import android.content.Context;
import android.content.res.Configuration;
import android.graphics.Point;
import android.os.Bundle;
import android.util.SparseArray;
import android.view.View;
import android.view.accessibility.AccessibilityNodeInfo;
import android.view.accessibility.AccessibilityNodeInfo.AccessibilityAction;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.ui.dragndrop.DragEndEvent;
import com.android.systemui.recents.events.ui.dragndrop.DragStartEvent;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.TaskStack;
public class TaskViewAccessibilityDelegate extends View.AccessibilityDelegate {
private static final String TAG = "TaskViewAccessibilityDelegate";
private final TaskView mTaskView;
protected static final int OPEN = R.id.action_open;
protected static final int DIMISS = R.id.action_dimiss;
protected static final int SPLIT_TASK_TOP = R.id.action_split_task_to_top;
protected static final int SPLIT_TASK_LEFT = R.id.action_split_task_to_left;
protected static final int SPLIT_TASK_RIGHT = R.id.action_split_task_to_right;
protected final SparseArray<AccessibilityAction> mActions = new SparseArray<>();
public TaskViewAccessibilityDelegate(TaskView taskView) {
mTaskView = taskView;
Context context = taskView.getContext();
mActions.put(OPEN, new AccessibilityAction(OPEN,
context.getString(R.string.recents_accessibility_open)));
mActions.put(DIMISS, new AccessibilityAction(DIMISS,
context.getString(R.string.recents_accessibility_dismissed)));
mActions.put(SPLIT_TASK_TOP, new AccessibilityAction(SPLIT_TASK_TOP,
context.getString(R.string.recents_accessibility_split_screen_top)));
mActions.put(SPLIT_TASK_LEFT, new AccessibilityAction(SPLIT_TASK_LEFT,
context.getString(R.string.recents_accessibility_split_screen_left)));
mActions.put(SPLIT_TASK_RIGHT, new AccessibilityAction(SPLIT_TASK_RIGHT,
context.getString(R.string.recents_accessibility_split_screen_right)));
}
@Override
public void onInitializeAccessibilityNodeInfo(View host, AccessibilityNodeInfo info) {
super.onInitializeAccessibilityNodeInfo(host, info);
info.addAction(mActions.get(OPEN));
info.addAction(mActions.get(DIMISS));
if (ActivityManager.supportsSplitScreenMultiWindow()
&& !Recents.getSystemServices().hasDockedTask()) {
TaskStack.DockState[] dockStates = Recents.getConfiguration()
.getDockStatesForCurrentOrientation();
for (TaskStack.DockState dockState: dockStates) {
if (dockState == TaskStack.DockState.TOP) {
info.addAction(mActions.get(SPLIT_TASK_TOP));
} else if (dockState == TaskStack.DockState.LEFT) {
info.addAction(mActions.get(SPLIT_TASK_LEFT));
} else if (dockState == TaskStack.DockState.RIGHT) {
info.addAction(mActions.get(SPLIT_TASK_RIGHT));
}
}
}
}
@Override
public boolean performAccessibilityAction(View host, int action, Bundle args) {
if (action == OPEN) {
mTaskView.onClick(host);
} else if (action == DIMISS) {
mTaskView.dismissTask();
} else if (action == SPLIT_TASK_TOP) {
simulateDragIntoMultiwindow(TaskStack.DockState.TOP);
} else if (action == SPLIT_TASK_LEFT) {
simulateDragIntoMultiwindow(TaskStack.DockState.LEFT);
} else if (action == SPLIT_TASK_RIGHT) {
simulateDragIntoMultiwindow(TaskStack.DockState.RIGHT);
} else {
return super.performAccessibilityAction(host, action, args);
}
return true;
}
/** Simulate a user drag event to split the screen to the respected side */
private void simulateDragIntoMultiwindow(TaskStack.DockState dockState) {
int orientation = Utilities.getAppConfiguration(mTaskView.getContext()).orientation;
EventBus.getDefault().send(new DragStartEvent(mTaskView.getTask(), mTaskView,
new Point(0,0), false /* isUserTouchInitiated */));
EventBus.getDefault().send(new DragEndEvent(mTaskView.getTask(), mTaskView, dockState));
}
}