diff --git a/packages/SystemUI/res/values/dimens_grid.xml b/packages/SystemUI/res/values/dimens_grid.xml new file mode 100644 index 0000000000000..43e152aa26831 --- /dev/null +++ b/packages/SystemUI/res/values/dimens_grid.xml @@ -0,0 +1,23 @@ + + + + 32dp + 84dp + 20dp + + diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java index 493e6187c83e4..c1f4c8a4c1dde 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackAnimationHelper.java @@ -157,7 +157,7 @@ public class TaskStackAnimationHelper { // Get the current transform for the task, which will be used to position it offscreen stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, - null); + null, mStackView.useGridLayout()); if (hideTask) { tv.setVisibility(View.INVISIBLE); @@ -230,7 +230,7 @@ public class TaskStackAnimationHelper { // Get the current transform for the task, which will be updated to the final transform // to animate to depending on how recents was invoked stackLayout.getStackTransform(task, stackScroller.getStackScroll(), mTmpTransform, - null); + null, mStackView.useGridLayout()); if (launchState.launchedFromApp && !launchState.launchedViaDockGesture) { if (task.isLaunchTarget) { diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java index 571c0f67e18e9..3c9731024e341 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackLayoutAlgorithm.java @@ -38,7 +38,7 @@ import com.android.systemui.recents.misc.SystemServicesProxy; import com.android.systemui.recents.misc.Utilities; import com.android.systemui.recents.model.Task; import com.android.systemui.recents.model.TaskStack; - +import com.android.systemui.recents.views.grid.TaskGridLayoutAlgorithm; import java.io.PrintWriter; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; @@ -326,7 +326,7 @@ public class TaskStackLayoutAlgorithm { @ViewDebug.ExportedProperty(category="recents") int mMinTranslationZ; @ViewDebug.ExportedProperty(category="recents") - int mMaxTranslationZ; + public int mMaxTranslationZ; // Optimization, allows for quick lookup of task -> index private SparseIntArray mTaskIndexMap = new SparseIntArray(); @@ -334,6 +334,7 @@ public class TaskStackLayoutAlgorithm { // The freeform workspace layout FreeformWorkspaceLayoutAlgorithm mFreeformLayoutAlgorithm; + TaskGridLayoutAlgorithm mTaskGridLayoutAlgorithm; // The transform to place TaskViews at the front and back of the stack respectively TaskViewTransform mBackOfStackTransform = new TaskViewTransform(); @@ -344,6 +345,7 @@ public class TaskStackLayoutAlgorithm { mContext = context; mCb = cb; mFreeformLayoutAlgorithm = new FreeformWorkspaceLayoutAlgorithm(context); + mTaskGridLayoutAlgorithm = new TaskGridLayoutAlgorithm(context); reloadOnConfigurationChange(context); } @@ -377,6 +379,7 @@ public class TaskStackLayoutAlgorithm { R.dimen.recents_layout_initial_bottom_offset_tablet, R.dimen.recents_layout_initial_bottom_offset_tablet); mFreeformLayoutAlgorithm.reloadOnConfigurationChange(context); + mTaskGridLayoutAlgorithm.reloadOnConfigurationChange(context); mMinMargin = res.getDimensionPixelSize(R.dimen.recents_layout_min_margin); mBaseTopMargin = getDimensionForDevice(context, R.dimen.recents_layout_top_margin_phone, @@ -470,6 +473,9 @@ public class TaskStackLayoutAlgorithm { updateFrontBackTransforms(); } + + // Initialize the grid layout + mTaskGridLayoutAlgorithm.initialize(displayRect, windowRect); } /** @@ -825,24 +831,30 @@ public class TaskStackLayoutAlgorithm { * is what the view is measured and laid out with. */ public TaskViewTransform getStackTransform(Task task, float stackScroll, - TaskViewTransform transformOut, TaskViewTransform frontTransform) { + TaskViewTransform transformOut, TaskViewTransform frontTransform, + boolean useGridLayout) { return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform, - false /* forceUpdate */, false /* ignoreTaskOverrides */); + false /* forceUpdate */, false /* ignoreTaskOverrides */, useGridLayout); } public TaskViewTransform getStackTransform(Task task, float stackScroll, TaskViewTransform transformOut, TaskViewTransform frontTransform, - boolean ignoreTaskOverrides) { + boolean ignoreTaskOverrides, boolean useGridLayout) { return getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform, - false /* forceUpdate */, ignoreTaskOverrides); + false /* forceUpdate */, ignoreTaskOverrides, useGridLayout); } public TaskViewTransform getStackTransform(Task task, float stackScroll, int focusState, TaskViewTransform transformOut, TaskViewTransform frontTransform, boolean forceUpdate, - boolean ignoreTaskOverrides) { + boolean ignoreTaskOverrides, boolean useGridLayout) { if (mFreeformLayoutAlgorithm.isTransformAvailable(task, this)) { mFreeformLayoutAlgorithm.getTransform(task, transformOut, this); return transformOut; + } else if (useGridLayout) { + int taskIndex = mTaskIndexMap.get(task.key.id); + int taskCount = mTaskIndexMap.size(); + mTaskGridLayoutAlgorithm.getTransform(taskIndex, taskCount, transformOut, this); + return transformOut; } else { // Return early if we have an invalid index int nonOverrideTaskProgress = mTaskIndexMap.get(task.key.id, -1); @@ -867,7 +879,7 @@ public class TaskStackLayoutAlgorithm { Rect windowOverrideRect) { TaskViewTransform transform = getStackTransform(task, stackScroll, mFocusState, transformOut, frontTransform, true /* forceUpdate */, - false /* ignoreTaskOverrides */); + false /* ignoreTaskOverrides */, false /* useGridLayout */); return transformToScreenCoordinates(transform, windowOverrideRect); } 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 1174e20570fa1..57fde67410859 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java +++ b/packages/SystemUI/src/com/android/systemui/recents/views/TaskStackView.java @@ -159,6 +159,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal private int mTaskCornerRadiusPx; private int mDividerSize; private int mStartTimerIndicatorDuration; + private boolean mDraggingOverDockState; @ViewDebug.ExportedProperty(category="recents") private boolean mTaskViewsClipDirty = true; @@ -500,13 +501,13 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Calculate the current and (if necessary) the target transform for the task transform = mLayoutAlgorithm.getStackTransform(task, curStackScroll, - taskTransforms.get(i), frontTransform, ignoreTaskOverrides); + taskTransforms.get(i), frontTransform, ignoreTaskOverrides, useGridLayout()); if (useTargetStackScroll && !transform.visible) { // If we have a target stack scroll and the task is not currently visible, then we // just update the transform at the new scroll // TODO: Optimize this - transformAtTarget = mLayoutAlgorithm.getStackTransform(task, - targetStackScroll, new TaskViewTransform(), frontTransformAtTarget); + transformAtTarget = mLayoutAlgorithm.getStackTransform(task, targetStackScroll, + new TaskViewTransform(), frontTransformAtTarget, useGridLayout()); if (transformAtTarget.visible) { transform.copyFrom(transformAtTarget); } @@ -737,7 +738,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } else { mLayoutAlgorithm.getStackTransform(task, mStackScroller.getStackScroll(), focusState, transform, null, true /* forceUpdate */, - false /* ignoreTaskOverrides */); + false /* ignoreTaskOverrides */, useGridLayout()); } transform.visible = true; } @@ -754,7 +755,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Task task = tasks.get(i); TaskViewTransform transform = transformsOut.get(i); mLayoutAlgorithm.getStackTransform(task, stackScroll, focusState, transform, null, - true /* forceUpdate */, ignoreTaskOverrides); + true /* forceUpdate */, ignoreTaskOverrides, useGridLayout()); transform.visible = true; } } @@ -1840,7 +1841,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal // Enlarge the dragged view slightly float finalScale = event.taskView.getScaleX() * DRAG_SCALE_FACTOR; mLayoutAlgorithm.getStackTransform(event.task, getScroller().getStackScroll(), - mTmpTransform, null); + mTmpTransform, null, useGridLayout()); mTmpTransform.scale = finalScale; mTmpTransform.translationZ = mLayoutAlgorithm.mMaxTranslationZ + 1; mTmpTransform.dimAlpha = 0f; @@ -1861,6 +1862,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal Interpolators.FAST_OUT_SLOW_IN); boolean ignoreTaskOverrides = false; if (event.dropTarget instanceof TaskStack.DockState) { + mDraggingOverDockState = true; // Calculate the new task stack bounds that matches the window size that Recents will // have after the drop final TaskStack.DockState dockState = (TaskStack.DockState) event.dropTarget; @@ -1880,6 +1882,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal updateLayoutAlgorithm(true /* boundScroll */); ignoreTaskOverrides = true; } else { + mDraggingOverDockState = false; // Restore the pre-drag task stack bounds, but ensure that we don't layout the dragging // task view, so add it back to the ignore set after updating the layout removeIgnoreTask(event.task); @@ -1890,6 +1893,7 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal } public final void onBusEvent(final DragEndEvent event) { + mDraggingOverDockState = false; // We don't handle drops on the dock regions if (event.dropTarget instanceof TaskStack.DockState) { // However, we do need to reset the overrides, since the last state of this task stack @@ -2128,6 +2132,20 @@ public class TaskStackView extends FrameLayout implements TaskStack.TaskStackCal return -1; } + /** + * Check whether we should use the grid layout. + * We use the grid layout for Recents iff all the following is true: + * 1. Grid-mode is enabled. + * 2. The activity is not in multi-window mode. + * 3. The user is not dragging a task view over the dock state. + * @return True if we should use the grid layout. + */ + public boolean useGridLayout() { + return Recents.getConfiguration().isGridEnabled + && !((RecentsActivity) mContext).isInMultiWindowMode() + && !mDraggingOverDockState; + } + /** * Reads current system flags related to accessibility and screen pinning. */ diff --git a/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java new file mode 100644 index 0000000000000..8d1bec80c5614 --- /dev/null +++ b/packages/SystemUI/src/com/android/systemui/recents/views/grid/TaskGridLayoutAlgorithm.java @@ -0,0 +1,88 @@ +/* + * Copyright (C) 2016 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.grid; + +import android.content.Context; +import android.content.res.Resources; +import android.graphics.Rect; +import com.android.systemui.R; +import com.android.systemui.recents.misc.Utilities; +import com.android.systemui.recents.views.TaskStackLayoutAlgorithm; +import com.android.systemui.recents.views.TaskViewTransform; + +public class TaskGridLayoutAlgorithm { + + private int mPaddingLeftRight; + private int mPaddingTopBottom; + private int mPaddingTaskView; + + private Rect mDisplayRect; + private Rect mWindowRect; + + private Rect mTaskGridRect; + + public TaskGridLayoutAlgorithm(Context context) { + reloadOnConfigurationChange(context); + } + + public void reloadOnConfigurationChange(Context context) { + Resources res = context.getResources(); + mPaddingLeftRight = res.getDimensionPixelSize(R.dimen.recents_grid_padding_left_right); + mPaddingTopBottom = res.getDimensionPixelSize(R.dimen.recents_grid_padding_top_bottom); + mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view); + + mTaskGridRect = new Rect(); + } + + public TaskViewTransform getTransform(int taskIndex, int taskAmount, + TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) { + + int taskPerLine = taskAmount < 2 ? 1 : ( + taskAmount < 5 ? 2 : 3); + + int taskWidth = (mDisplayRect.width() - mPaddingLeftRight * 2 + - mPaddingTaskView * (taskPerLine - 1)) / taskPerLine; + int taskHeight = taskWidth * mDisplayRect.height() / mDisplayRect.width(); + mTaskGridRect.set(0, 0, taskWidth, taskHeight); + + int xIndex = taskIndex % taskPerLine; + int yIndex = taskIndex / taskPerLine; + int x = mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex; + int y = mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex; + float z = stackLayout.mMaxTranslationZ; + + float dimAlpha = 0f; + float viewOutlineAlpha = 0f; + + // Fill out the transform + transformOut.scale = 1f; + transformOut.alpha = 1f; + transformOut.translationZ = z; + transformOut.dimAlpha = dimAlpha; + transformOut.viewOutlineAlpha = viewOutlineAlpha; + transformOut.rect.set(mTaskGridRect); + transformOut.rect.offset(x, y); + Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); + transformOut.visible = true; + return transformOut; + } + + public void initialize(Rect displayRect, Rect windowRect) { + mDisplayRect = displayRect; + mWindowRect = windowRect; + } +} \ No newline at end of file