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 19cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggiimport static com.android.systemui.recents.views.TaskStackLayoutAlgorithm.*; 20cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi 21bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.content.Context; 22bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.content.res.Resources; 23bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.graphics.Point; 24bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.graphics.Rect; 25bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport android.view.WindowManager; 26bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 27bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.R; 28c0e181394431fb13420f7bd0415231075cb1b469Jiaquan Heimport com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; 29c0e181394431fb13420f7bd0415231075cb1b469Jiaquan Heimport com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction; 30bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.misc.Utilities; 31cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggiimport com.android.systemui.recents.model.Task; 32bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.views.TaskStackLayoutAlgorithm; 33bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.views.TaskViewTransform; 34bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 35cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggiimport java.util.ArrayList; 36cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi 37bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetpublic class TaskGridLayoutAlgorithm { 38bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 39bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private final String TAG = "TaskGridLayoutAlgorithm"; 40883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He public static final int MAX_LAYOUT_TASK_COUNT = 8; 41bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 42bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The horizontal padding around the whole recents view. */ 43bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mPaddingLeftRight; 44bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The vertical padding around the whole recents view. */ 45bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mPaddingTopBottom; 46bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The padding between task views. */ 47bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mPaddingTaskView; 48bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 49bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Rect mWindowRect; 50bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Point mScreenSize = new Point(); 51bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 52bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Rect mTaskGridRect; 53bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 54bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The height, in pixels, of each task view's title bar. */ 55bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mTitleBarHeight; 56bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 57bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The aspect ratio of each task thumbnail, without the title bar. */ 58bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private float mAppAspectRatio; 59bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Rect mSystemInsets = new Rect(); 60bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 6121f495f07b1b9ace99986a110d01a763847687b1Jiaquan He /** The thickness of the focused task view frame. */ 6221f495f07b1b9ace99986a110d01a763847687b1Jiaquan He private int mFocusedFrameThickness; 6321f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 640a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He /** 650a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * When the amount of tasks is determined, the size and position of every task view can be 660a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * decided. Each instance of TaskGridRectInfo store the task view information for a certain 670a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * amount of tasks. 680a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He */ 690a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He class TaskGridRectInfo { 700a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He Rect size; 710a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int[] xOffsets; 720a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int[] yOffsets; 73c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int tasksPerLine; 74c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int lines; 750a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 76c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet TaskGridRectInfo(int taskCount) { 770a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He size = new Rect(); 780a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He xOffsets = new int[taskCount]; 790a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He yOffsets = new int[taskCount]; 800a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 810a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount); 82776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet tasksPerLine = getTasksPerLine(layoutTaskCount); 83776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet lines = layoutTaskCount < 4 ? 1 : 2; 840a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 85c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // A couple of special cases. 86c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet boolean landscapeWindow = mWindowRect.width() > mWindowRect.height(); 87c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet boolean landscapeTaskView = mAppAspectRatio > 1; 88c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // If we're in portrait but task views are landscape, show more lines of fewer tasks. 89c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet if (!landscapeWindow && landscapeTaskView) { 90c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet tasksPerLine = layoutTaskCount < 2 ? 1 : 2; 91c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet lines = layoutTaskCount < 3 ? 1 : ( 92c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet layoutTaskCount < 5 ? 2 : ( 93c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet layoutTaskCount < 7 ? 3 : 4)); 94c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet } 95c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // If we're in landscape but task views are portrait, show fewer lines of more tasks. 96c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet if (landscapeWindow && !landscapeTaskView) { 97c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet tasksPerLine = layoutTaskCount < 7 ? layoutTaskCount : 6; 98c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet lines = layoutTaskCount < 7 ? 1 : 2; 99c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet } 100c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet 1010a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskWidth, taskHeight; 102c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int maxTaskWidth = (mWindowRect.width() - 2 * mPaddingLeftRight 1030a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (tasksPerLine - 1) * mPaddingTaskView) / tasksPerLine; 104c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int maxTaskHeight = (mWindowRect.height() - 2 * mPaddingTopBottom 1050a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (lines - 1) * mPaddingTaskView) / lines; 1060a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1070a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) { 1080a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Width bound. 1090a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskWidth = maxTaskWidth; 11090f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He // Here we should round the height to the nearest integer. 11190f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight + 0.5); 1120a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } else { 1130a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Height bound. 1140a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskHeight = maxTaskHeight; 11590f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He // Here we should round the width to the nearest integer. 11690f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio + 0.5); 1170a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1180a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He size.set(0, 0, taskWidth, taskHeight); 1190a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 120c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int emptySpaceX = mWindowRect.width() - 2 * mPaddingLeftRight 1210a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (tasksPerLine * taskWidth) - (tasksPerLine - 1) * mPaddingTaskView; 122c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int emptySpaceY = mWindowRect.height() - 2 * mPaddingTopBottom 1230a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (lines * taskHeight) - (lines - 1) * mPaddingTaskView; 1240a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He for (int taskIndex = 0; taskIndex < taskCount; taskIndex++) { 1250a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // We also need to invert the index in order to display the most recent tasks first. 1260a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskLayoutIndex = taskCount - taskIndex - 1; 1270a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1280a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int xIndex = taskLayoutIndex % tasksPerLine; 1290a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int yIndex = taskLayoutIndex / tasksPerLine; 130c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet xOffsets[taskIndex] = mWindowRect.left + 1310a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He emptySpaceX / 2 + mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex; 132c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet yOffsets[taskIndex] = mWindowRect.top + 1330a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex; 1340a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1350a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 136776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet 137776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet private int getTasksPerLine(int taskCount) { 138776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet switch(taskCount) { 139776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 0: 140776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 0; 141776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 1: 142776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 1; 143776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 2: 144776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 4: 145776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 2; 146776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 3: 147776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 5: 148776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 6: 149776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 3; 150776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 7: 151776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 8: 152776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 4; 153776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet default: 154776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet throw new IllegalArgumentException("Unsupported task count " + taskCount); 155776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet } 156776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet } 1570a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1580a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1590a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He /** 1600a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * We can find task view sizes and positions from mTaskGridRectInfoList[k - 1] when there 1610a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * are k tasks. 1620a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He */ 163c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet private TaskGridRectInfo[] mTaskGridRectInfoList; 1640a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 165bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public TaskGridLayoutAlgorithm(Context context) { 166bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet reloadOnConfigurationChange(context); 167bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 168bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 169bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void reloadOnConfigurationChange(Context context) { 170bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Resources res = context.getResources(); 171bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view); 17221f495f07b1b9ace99986a110d01a763847687b1Jiaquan He mFocusedFrameThickness = res.getDimensionPixelSize( 17321f495f07b1b9ace99986a110d01a763847687b1Jiaquan He R.dimen.recents_grid_task_view_focused_frame_thickness); 17421f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 175bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mTaskGridRect = new Rect(); 176bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height); 177bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 178bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet WindowManager windowManager = (WindowManager) context 179bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet .getSystemService(Context.WINDOW_SERVICE); 180bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet windowManager.getDefaultDisplay().getRealSize(mScreenSize); 181bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 182bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet updateAppAspectRatio(); 183bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 184bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 185883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He /** 186883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * Returns the proper task view transform of a certain task view, according to its index and the 187883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * amount of task views. 188883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param taskIndex The index of the task view whose transform we want. It's never greater 189883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * than {@link MAX_LAYOUT_TASK_COUNT}. 190883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param taskCount The current amount of task views. 191883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param transformOut The result transform that this method returns. 192883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param stackLayout The base stack layout algorithm. 193883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @return The expected transform of the (taskIndex)th task view. 194883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He */ 195bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public TaskViewTransform getTransform(int taskIndex, int taskCount, 196bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) { 197244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He if (taskCount == 0) { 198244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He transformOut.reset(); 199244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He return transformOut; 200244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He } 201bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 2020a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 2030a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRect.set(gridInfo.size); 204bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 2050a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int x = gridInfo.xOffsets[taskIndex]; 2060a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int y = gridInfo.yOffsets[taskIndex]; 207bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float z = stackLayout.mMaxTranslationZ; 208bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 20915fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He // We always set the dim alpha to 0, since we don't want grid task views to dim. 210bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float dimAlpha = 0f; 21115fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He // We always set the alpha of the view outline to 1, to make sure the shadow is visible. 21215fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He float viewOutlineAlpha = 1f; 21315fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He 2140a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // We also need to invert the index in order to display the most recent tasks first. 2150a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskLayoutIndex = taskCount - taskIndex - 1; 216244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He boolean isTaskViewVisible = taskLayoutIndex < MAX_LAYOUT_TASK_COUNT; 217bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 218bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet // Fill out the transform 219bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.scale = 1f; 220bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.alpha = isTaskViewVisible ? 1f : 0f; 221bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.translationZ = z; 222bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.dimAlpha = dimAlpha; 223bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.viewOutlineAlpha = viewOutlineAlpha; 224bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.rect.set(mTaskGridRect); 225bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.rect.offset(x, y); 226bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); 227bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet // We only show the 8 most recent tasks. 228bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.visible = isTaskViewVisible; 229bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet return transformOut; 230bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 231bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 232c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He /** 233c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * Return the proper task index to focus for arrow key navigation. 234c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @param taskCount The amount of tasks. 235c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @param currentFocusedIndex The index of the currently focused task. 236c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @param direction The direction we're navigating. 237c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @return The index of the task that should get the focus. 238c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He */ 239c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He public int navigateFocus(int taskCount, int currentFocusedIndex, Direction direction) { 240c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He if (taskCount < 1 || taskCount > MAX_LAYOUT_TASK_COUNT) { 241c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He return -1; 242c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 243c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He if (currentFocusedIndex == -1) { 244c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He return 0; 245c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 246c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int newIndex = currentFocusedIndex; 247c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He final TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 248c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He final int currentLine = (taskCount - 1 - currentFocusedIndex) / gridInfo.tasksPerLine; 249c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He switch (direction) { 250c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case UP: 251c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex += gridInfo.tasksPerLine; 252c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex >= taskCount ? currentFocusedIndex : newIndex; 253c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 254c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case DOWN: 255c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex -= gridInfo.tasksPerLine; 256c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex < 0 ? currentFocusedIndex : newIndex; 257c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 258c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case LEFT: 259c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex++; 260c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He final int leftMostIndex = (taskCount - 1) - currentLine * gridInfo.tasksPerLine; 261c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex > leftMostIndex ? currentFocusedIndex : newIndex; 262c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 263c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case RIGHT: 264c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex--; 265c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int rightMostIndex = 266c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He (taskCount - 1) - (currentLine + 1) * gridInfo.tasksPerLine + 1; 267c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He rightMostIndex = rightMostIndex < 0 ? 0 : rightMostIndex; 268c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex < rightMostIndex ? currentFocusedIndex : newIndex; 269c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 270c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 271c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He return newIndex; 272c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 273c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He 274c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet public void initialize(Rect windowRect) { 275bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mWindowRect = windowRect; 276c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // Define paddings in terms of percentage of the total area. 277c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet mPaddingLeftRight = (int) (0.025f * Math.min(mWindowRect.width(), mWindowRect.height())); 278c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet mPaddingTopBottom = (int) (0.1 * mWindowRect.height()); 2790a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 2800a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Pre-calculate the positions and offsets of task views so that we can reuse them directly 2810a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // in the future. 2820a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRectInfoList = new TaskGridRectInfo[MAX_LAYOUT_TASK_COUNT]; 2830a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He for (int i = 0; i < MAX_LAYOUT_TASK_COUNT; i++) { 2840a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRectInfoList[i] = new TaskGridRectInfo(i + 1); 2850a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 286bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 287bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 288bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void setSystemInsets(Rect systemInsets) { 289bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mSystemInsets = systemInsets; 290bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet updateAppAspectRatio(); 291bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 292bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 293bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private void updateAppAspectRatio() { 294bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet int usableWidth = mScreenSize.x - mSystemInsets.left - mSystemInsets.right; 295bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet int usableHeight = mScreenSize.y - mSystemInsets.top - mSystemInsets.bottom; 296bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mAppAspectRatio = (float) usableWidth / (float) usableHeight; 297bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 298bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 299bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public Rect getStackActionButtonRect() { 300c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet Rect buttonRect = new Rect(mWindowRect); 301bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.right -= mPaddingLeftRight; 302bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.left += mPaddingLeftRight; 303bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.bottom = buttonRect.top + mPaddingTopBottom; 304bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet return buttonRect; 305bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 3068f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He 30721f495f07b1b9ace99986a110d01a763847687b1Jiaquan He public void updateTaskGridRect(int taskCount) { 30821f495f07b1b9ace99986a110d01a763847687b1Jiaquan He if (taskCount > 0) { 30921f495f07b1b9ace99986a110d01a763847687b1Jiaquan He TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 31021f495f07b1b9ace99986a110d01a763847687b1Jiaquan He mTaskGridRect.set(gridInfo.size); 31121f495f07b1b9ace99986a110d01a763847687b1Jiaquan He } 31221f495f07b1b9ace99986a110d01a763847687b1Jiaquan He } 31321f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 3148f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He public Rect getTaskGridRect() { 3158f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He return mTaskGridRect; 3168f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He } 31721f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 31821f495f07b1b9ace99986a110d01a763847687b1Jiaquan He public int getFocusFrameThickness() { 31921f495f07b1b9ace99986a110d01a763847687b1Jiaquan He return mFocusedFrameThickness; 32021f495f07b1b9ace99986a110d01a763847687b1Jiaquan He } 321cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi 322cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi public VisibilityReport computeStackVisibilityReport(ArrayList<Task> tasks) { 323cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi int visibleCount = Math.min(TaskGridLayoutAlgorithm.MAX_LAYOUT_TASK_COUNT, tasks.size()); 324cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi return new VisibilityReport(visibleCount, visibleCount); 325cdef591e52e691a6f57e367caa5670fdc4ee1a8aJorim Jaggi } 326bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet} 327