Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c0a1acde authored by Jiaquan He's avatar Jiaquan He
Browse files

Add a grid-based layout algorithm for Recents.

This commit adds a layout algorithm for Recents so that task views are
layouted in a grid mode, to take full use of the screen space.

Change-Id: Ia0e388ea2e8a6ae348ed002a830212e8fea546fc
parent 5a2eb833
Loading
Loading
Loading
Loading
+23 −0
Original line number Diff line number Diff line
<?xml version="1.0" encoding="utf-8"?>
<!--
 * 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.
*/
-->
<resources>
  <dimen name="recents_grid_padding_left_right">32dp</dimen>
  <dimen name="recents_grid_padding_top_bottom">84dp</dimen>
  <dimen name="recents_grid_padding_task_view">20dp</dimen>
</resources>
+2 −2
Original line number Diff line number Diff line
@@ -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) {
+20 −8
Original line number Diff line number Diff line
@@ -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);
    }

+24 −6
Original line number Diff line number Diff line
@@ -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.
     */
+88 −0
Original line number Diff line number Diff line
/*
 * 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