diff --git a/packages/SystemUI/res/values/config.xml b/packages/SystemUI/res/values/config.xml
index 50ef392fe0f14..ac86439665b32 100644
--- a/packages/SystemUI/res/values/config.xml
+++ b/packages/SystemUI/res/values/config.xml
@@ -297,4 +297,11 @@
If < 0, uses the value from HardwarePropertiesManager#getDeviceTemperatures. -->
-1
+
+
+
+
+
+
+
diff --git a/packages/SystemUI/res/values/strings.xml b/packages/SystemUI/res/values/strings.xml
index 34a0397eca8bb..4956232d08f69 100644
--- a/packages/SystemUI/res/values/strings.xml
+++ b/packages/SystemUI/res/values/strings.xml
@@ -786,6 +786,16 @@
Split Vertical
Split Custom
+
+ Dismiss
+
+ Open
+
+ Split screen to the top
+
+ Split screen to the left
+
+ Split screen to the right
diff --git a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
index 711f0c679b6de..ff8d4bf68cc6f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/RecentsConfiguration.java
@@ -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;
+ }
+ }
+
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
index b368bd353ad84..e57fa2d86a66f 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/events/ui/dragndrop/DragStartEvent.java
@@ -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;
}
}
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
index ee79330f816a2..8f9c457c255ba 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsView.java
@@ -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 */);
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
index d3ec9845856a4..db0c95eb59979 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/RecentsViewTouchHandler.java
@@ -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());
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 36d5f838a0705..3e4316f44facf 100644
--- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskView.java
@@ -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 outChildren) {
+ // Prevent any children from being focusable during talkback
+ }
+
@Override
public boolean hasOverlappingRendering() {
return false;
diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
new file mode 100644
index 0000000000000..759daf1e0f124
--- /dev/null
+++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskViewAccessibilityDelegate.java
@@ -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 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));
+ }
+}