Merge "Added open, dismiss and split screen as custom accessibility actions"

This commit is contained in:
TreeHugger Robot
2017-01-20 23:54:08 +00:00
committed by Android (Google) Code Review
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

@@ -794,6 +794,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));
}
}