TaskGridLayoutAlgorithm.java revision bf8e290376b8ee6d04c330b22f5275e82103def3
1bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet/*
2bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * Copyright (C) 2016 The Android Open Source Project
3bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet *
4bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * Licensed under the Apache License, Version 2.0 (the "License");
5bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * you may not use this file except in compliance with the License.
6bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * You may obtain a copy of the License at
7bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet *
8bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet *      http://www.apache.org/licenses/LICENSE-2.0
9bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet *
10bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * Unless required by applicable law or agreed to in writing, software
11bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * distributed under the License is distributed on an "AS IS" BASIS,
12bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * See the License for the specific language governing permissions and
14bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet * limitations under the License.
15bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet */
16bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
17bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetpackage com.android.systemui.recents.views.grid;
18bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
19bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.content.Context;
20bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.content.res.Resources;
21bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.graphics.Point;
22bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.graphics.Rect;
23bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.view.WindowManager;
24bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
25bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.R;
26bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.misc.Utilities;
27bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.views.TaskStackLayoutAlgorithm;
28bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.views.TaskViewTransform;
29bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
30bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetpublic class TaskGridLayoutAlgorithm  {
31bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
32bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private final String TAG = "TaskGridLayoutAlgorithm";
33bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private final int MAX_LAYOUT_TASK_COUNT = 8;
34bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
35bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    /** The horizontal padding around the whole recents view. */
36bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private int mPaddingLeftRight;
37bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    /** The vertical padding around the whole recents view. */
38bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private int mPaddingTopBottom;
39bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    /** The padding between task views. */
40bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private int mPaddingTaskView;
41bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
42bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private Rect mDisplayRect;
43bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private Rect mWindowRect;
44bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private Point mScreenSize = new Point();
45bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
46bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private Rect mTaskGridRect;
47bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
48bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    /** The height, in pixels, of each task view's title bar. */
49bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private int mTitleBarHeight;
50bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
51bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    /** The aspect ratio of each task thumbnail, without the title bar. */
52bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private float mAppAspectRatio;
53bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private Rect mSystemInsets = new Rect();
54bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
55bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    public TaskGridLayoutAlgorithm(Context context) {
56bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        reloadOnConfigurationChange(context);
57bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
58bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
59bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    public void reloadOnConfigurationChange(Context context) {
60bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        Resources res = context.getResources();
61bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mPaddingLeftRight = res.getDimensionPixelSize(R.dimen.recents_grid_padding_left_right);
62bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mPaddingTopBottom = res.getDimensionPixelSize(R.dimen.recents_grid_padding_top_bottom);
63bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view);
64bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
65bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mTaskGridRect = new Rect();
66bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height);
67bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
68bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        WindowManager windowManager = (WindowManager) context
69bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                .getSystemService(Context.WINDOW_SERVICE);
70bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        windowManager.getDefaultDisplay().getRealSize(mScreenSize);
71bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
72bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        updateAppAspectRatio();
73bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
74bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
75bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    public TaskViewTransform getTransform(int taskIndex, int taskCount,
76bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) {
77bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
78bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount);
79bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
80bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        // We also need to invert the index in order to display the most recent tasks first.
81bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int taskLayoutIndex = taskCount - taskIndex - 1;
82bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
83bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int tasksPerLine = layoutTaskCount < 2 ? 1 : (
84bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                layoutTaskCount < 5 ? 2 : (
85bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                        layoutTaskCount < 7 ? 3 : 4));
86bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int lines = layoutTaskCount < 3 ? 1 : 2;
87bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
88bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int taskWidth, taskHeight;
89bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int maxTaskWidth = (mDisplayRect.width() - 2 * mPaddingLeftRight
90bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                - (tasksPerLine - 1) * mPaddingTaskView) / tasksPerLine;
91bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int maxTaskHeight = (mDisplayRect.height() - 2 * mPaddingTopBottom
92bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                - (lines - 1) * mPaddingTaskView) / lines;
93bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
94bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) {
95bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet            // Width bound.
96bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet            taskWidth = maxTaskWidth;
97bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet            taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight);
98bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        } else {
99bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet            // Height bound.
100bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet            taskHeight = maxTaskHeight;
101bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet            taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio);
102bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        }
103bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int emptySpaceX = mDisplayRect.width() - 2 * mPaddingLeftRight
104bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                - (tasksPerLine * taskWidth) - (tasksPerLine - 1) * mPaddingTaskView;
105bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int emptySpaceY = mDisplayRect.height() - 2 * mPaddingTopBottom
106bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet                - (lines * taskHeight) - (lines - 1) * mPaddingTaskView;
107bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
108bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mTaskGridRect.set(0, 0, taskWidth, taskHeight);
109bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
110bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int xIndex = taskLayoutIndex % tasksPerLine;
111bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int yIndex = taskLayoutIndex / tasksPerLine;
112bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int x = emptySpaceX / 2 + mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex;
113bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int y = emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex;
114bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        float z = stackLayout.mMaxTranslationZ;
115bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
116bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        float dimAlpha = 0f;
117bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        float viewOutlineAlpha = 0f;
118bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        boolean isTaskViewVisible = (taskLayoutIndex < MAX_LAYOUT_TASK_COUNT);
119bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
120bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        // Fill out the transform
121bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.scale = 1f;
122bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.alpha = isTaskViewVisible ? 1f : 0f;
123bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.translationZ = z;
124bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.dimAlpha = dimAlpha;
125bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.viewOutlineAlpha = viewOutlineAlpha;
126bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.rect.set(mTaskGridRect);
127bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.rect.offset(x, y);
128bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale);
129bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        // We only show the 8 most recent tasks.
130bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        transformOut.visible = isTaskViewVisible;
131bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        return transformOut;
132bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
133bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
134bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    public void initialize(Rect displayRect, Rect windowRect) {
135bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mDisplayRect = displayRect;
136bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mWindowRect = windowRect;
137bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
138bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
139bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    public void setSystemInsets(Rect systemInsets) {
140bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mSystemInsets = systemInsets;
141bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        updateAppAspectRatio();
142bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
143bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
144bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    private void updateAppAspectRatio() {
145bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int usableWidth = mScreenSize.x - mSystemInsets.left - mSystemInsets.right;
146bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        int usableHeight = mScreenSize.y - mSystemInsets.top - mSystemInsets.bottom;
147bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        mAppAspectRatio = (float) usableWidth / (float) usableHeight;
148bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
149bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet
150bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    public Rect getStackActionButtonRect() {
151bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        Rect buttonRect = new Rect(mDisplayRect);
152bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        buttonRect.right -= mPaddingLeftRight;
153bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        buttonRect.left += mPaddingLeftRight;
154bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        buttonRect.bottom = buttonRect.top + mPaddingTopBottom;
155bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet        return buttonRect;
156bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet    }
157bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet}
158