TaskGridLayoutAlgorithm.java revision 776f6bacd67d27e033598f8c8c079bab9d0dd183
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; 26c0e181394431fb13420f7bd0415231075cb1b469Jiaquan Heimport com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent; 27c0e181394431fb13420f7bd0415231075cb1b469Jiaquan Heimport com.android.systemui.recents.events.ui.focus.NavigateTaskViewEvent.Direction; 28bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.misc.Utilities; 29bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.views.TaskStackLayoutAlgorithm; 30bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetimport com.android.systemui.recents.views.TaskViewTransform; 31bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 32bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornetpublic class TaskGridLayoutAlgorithm { 33bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 34bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private final String TAG = "TaskGridLayoutAlgorithm"; 35883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He public static final int MAX_LAYOUT_TASK_COUNT = 8; 36bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 37bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The horizontal padding around the whole recents view. */ 38bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mPaddingLeftRight; 39bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The vertical padding around the whole recents view. */ 40bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mPaddingTopBottom; 41bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The padding between task views. */ 42bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mPaddingTaskView; 43bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 44bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Rect mWindowRect; 45bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Point mScreenSize = new Point(); 46bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 47bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Rect mTaskGridRect; 48bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 49bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The height, in pixels, of each task view's title bar. */ 50bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private int mTitleBarHeight; 51bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 52bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet /** The aspect ratio of each task thumbnail, without the title bar. */ 53bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private float mAppAspectRatio; 54bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private Rect mSystemInsets = new Rect(); 55bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 5621f495f07b1b9ace99986a110d01a763847687b1Jiaquan He /** The thickness of the focused task view frame. */ 5721f495f07b1b9ace99986a110d01a763847687b1Jiaquan He private int mFocusedFrameThickness; 5821f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 590a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He /** 600a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * When the amount of tasks is determined, the size and position of every task view can be 610a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * decided. Each instance of TaskGridRectInfo store the task view information for a certain 620a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * amount of tasks. 630a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He */ 640a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He class TaskGridRectInfo { 650a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He Rect size; 660a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int[] xOffsets; 670a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int[] yOffsets; 68c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int tasksPerLine; 69c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int lines; 700a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 71c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet TaskGridRectInfo(int taskCount) { 720a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He size = new Rect(); 730a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He xOffsets = new int[taskCount]; 740a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He yOffsets = new int[taskCount]; 750a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 760a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount); 77776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet tasksPerLine = getTasksPerLine(layoutTaskCount); 78776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet lines = layoutTaskCount < 4 ? 1 : 2; 790a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 80c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // A couple of special cases. 81c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet boolean landscapeWindow = mWindowRect.width() > mWindowRect.height(); 82c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet boolean landscapeTaskView = mAppAspectRatio > 1; 83c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // If we're in portrait but task views are landscape, show more lines of fewer tasks. 84c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet if (!landscapeWindow && landscapeTaskView) { 85c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet tasksPerLine = layoutTaskCount < 2 ? 1 : 2; 86c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet lines = layoutTaskCount < 3 ? 1 : ( 87c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet layoutTaskCount < 5 ? 2 : ( 88c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet layoutTaskCount < 7 ? 3 : 4)); 89c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet } 90c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // If we're in landscape but task views are portrait, show fewer lines of more tasks. 91c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet if (landscapeWindow && !landscapeTaskView) { 92c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet tasksPerLine = layoutTaskCount < 7 ? layoutTaskCount : 6; 93c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet lines = layoutTaskCount < 7 ? 1 : 2; 94c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet } 95c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet 960a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskWidth, taskHeight; 97c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int maxTaskWidth = (mWindowRect.width() - 2 * mPaddingLeftRight 980a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (tasksPerLine - 1) * mPaddingTaskView) / tasksPerLine; 99c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int maxTaskHeight = (mWindowRect.height() - 2 * mPaddingTopBottom 1000a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (lines - 1) * mPaddingTaskView) / lines; 1010a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1020a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) { 1030a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Width bound. 1040a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskWidth = maxTaskWidth; 10590f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He // Here we should round the height to the nearest integer. 10690f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight + 0.5); 1070a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } else { 1080a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Height bound. 1090a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskHeight = maxTaskHeight; 11090f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He // Here we should round the width to the nearest integer. 11190f4f5290b971aefcf7cab306b3e95168ed53585Jiaquan He taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio + 0.5); 1120a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1130a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He size.set(0, 0, taskWidth, taskHeight); 1140a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 115c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int emptySpaceX = mWindowRect.width() - 2 * mPaddingLeftRight 1160a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (tasksPerLine * taskWidth) - (tasksPerLine - 1) * mPaddingTaskView; 117c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet int emptySpaceY = mWindowRect.height() - 2 * mPaddingTopBottom 1180a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (lines * taskHeight) - (lines - 1) * mPaddingTaskView; 1190a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He for (int taskIndex = 0; taskIndex < taskCount; taskIndex++) { 1200a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // We also need to invert the index in order to display the most recent tasks first. 1210a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskLayoutIndex = taskCount - taskIndex - 1; 1220a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1230a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int xIndex = taskLayoutIndex % tasksPerLine; 1240a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int yIndex = taskLayoutIndex / tasksPerLine; 125c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet xOffsets[taskIndex] = mWindowRect.left + 1260a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He emptySpaceX / 2 + mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex; 127c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet yOffsets[taskIndex] = mWindowRect.top + 1280a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex; 1290a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1300a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 131776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet 132776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet private int getTasksPerLine(int taskCount) { 133776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet switch(taskCount) { 134776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 0: 135776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 0; 136776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 1: 137776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 1; 138776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 2: 139776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 4: 140776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 2; 141776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 3: 142776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 5: 143776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 6: 144776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 3; 145776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 7: 146776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet case 8: 147776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet return 4; 148776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet default: 149776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet throw new IllegalArgumentException("Unsupported task count " + taskCount); 150776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet } 151776f6bacd67d27e033598f8c8c079bab9d0dd183Manu Cornet } 1520a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1530a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1540a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He /** 1550a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * We can find task view sizes and positions from mTaskGridRectInfoList[k - 1] when there 1560a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * are k tasks. 1570a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He */ 158c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet private TaskGridRectInfo[] mTaskGridRectInfoList; 1590a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 160bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public TaskGridLayoutAlgorithm(Context context) { 161bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet reloadOnConfigurationChange(context); 162bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 163bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 164bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void reloadOnConfigurationChange(Context context) { 165bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Resources res = context.getResources(); 166bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view); 16721f495f07b1b9ace99986a110d01a763847687b1Jiaquan He mFocusedFrameThickness = res.getDimensionPixelSize( 16821f495f07b1b9ace99986a110d01a763847687b1Jiaquan He R.dimen.recents_grid_task_view_focused_frame_thickness); 16921f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 170bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mTaskGridRect = new Rect(); 171bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height); 172bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 173bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet WindowManager windowManager = (WindowManager) context 174bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet .getSystemService(Context.WINDOW_SERVICE); 175bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet windowManager.getDefaultDisplay().getRealSize(mScreenSize); 176bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 177bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet updateAppAspectRatio(); 178bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 179bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 180883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He /** 181883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * Returns the proper task view transform of a certain task view, according to its index and the 182883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * amount of task views. 183883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param taskIndex The index of the task view whose transform we want. It's never greater 184883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * than {@link MAX_LAYOUT_TASK_COUNT}. 185883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param taskCount The current amount of task views. 186883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param transformOut The result transform that this method returns. 187883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @param stackLayout The base stack layout algorithm. 188883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He * @return The expected transform of the (taskIndex)th task view. 189883887eac908b4b0145f06c52de00f76e8c833dfJiaquan He */ 190bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public TaskViewTransform getTransform(int taskIndex, int taskCount, 191bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) { 192244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He if (taskCount == 0) { 193244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He transformOut.reset(); 194244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He return transformOut; 195244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He } 196bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 1970a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 1980a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRect.set(gridInfo.size); 199bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 2000a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int x = gridInfo.xOffsets[taskIndex]; 2010a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int y = gridInfo.yOffsets[taskIndex]; 202bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float z = stackLayout.mMaxTranslationZ; 203bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 20415fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He // We always set the dim alpha to 0, since we don't want grid task views to dim. 205bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float dimAlpha = 0f; 20615fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He // We always set the alpha of the view outline to 1, to make sure the shadow is visible. 20715fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He float viewOutlineAlpha = 1f; 20815fa3246d8091e6ab3956fd0a833fdd8daa9d6fbJiaquan He 2090a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // We also need to invert the index in order to display the most recent tasks first. 2100a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskLayoutIndex = taskCount - taskIndex - 1; 211244bac6c8bb8c7ef621786b42cf26dafaa417829Jiaquan He boolean isTaskViewVisible = taskLayoutIndex < MAX_LAYOUT_TASK_COUNT; 212bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 213bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet // Fill out the transform 214bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.scale = 1f; 215bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.alpha = isTaskViewVisible ? 1f : 0f; 216bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.translationZ = z; 217bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.dimAlpha = dimAlpha; 218bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.viewOutlineAlpha = viewOutlineAlpha; 219bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.rect.set(mTaskGridRect); 220bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.rect.offset(x, y); 221bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); 222bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet // We only show the 8 most recent tasks. 223bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.visible = isTaskViewVisible; 224bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet return transformOut; 225bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 226bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 227c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He /** 228c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * Return the proper task index to focus for arrow key navigation. 229c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @param taskCount The amount of tasks. 230c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @param currentFocusedIndex The index of the currently focused task. 231c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @param direction The direction we're navigating. 232c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He * @return The index of the task that should get the focus. 233c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He */ 234c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He public int navigateFocus(int taskCount, int currentFocusedIndex, Direction direction) { 235c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He if (taskCount < 1 || taskCount > MAX_LAYOUT_TASK_COUNT) { 236c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He return -1; 237c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 238c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He if (currentFocusedIndex == -1) { 239c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He return 0; 240c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 241c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int newIndex = currentFocusedIndex; 242c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He final TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 243c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He final int currentLine = (taskCount - 1 - currentFocusedIndex) / gridInfo.tasksPerLine; 244c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He switch (direction) { 245c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case UP: 246c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex += gridInfo.tasksPerLine; 247c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex >= taskCount ? currentFocusedIndex : newIndex; 248c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 249c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case DOWN: 250c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex -= gridInfo.tasksPerLine; 251c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex < 0 ? currentFocusedIndex : newIndex; 252c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 253c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case LEFT: 254c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex++; 255c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He final int leftMostIndex = (taskCount - 1) - currentLine * gridInfo.tasksPerLine; 256c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex > leftMostIndex ? currentFocusedIndex : newIndex; 257c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 258c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He case RIGHT: 259c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex--; 260c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He int rightMostIndex = 261c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He (taskCount - 1) - (currentLine + 1) * gridInfo.tasksPerLine + 1; 262c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He rightMostIndex = rightMostIndex < 0 ? 0 : rightMostIndex; 263c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He newIndex = newIndex < rightMostIndex ? currentFocusedIndex : newIndex; 264c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He break; 265c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 266c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He return newIndex; 267c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He } 268c0e181394431fb13420f7bd0415231075cb1b469Jiaquan He 269c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet public void initialize(Rect windowRect) { 270bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mWindowRect = windowRect; 271c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet // Define paddings in terms of percentage of the total area. 272c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet mPaddingLeftRight = (int) (0.025f * Math.min(mWindowRect.width(), mWindowRect.height())); 273c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet mPaddingTopBottom = (int) (0.1 * mWindowRect.height()); 2740a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 2750a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Pre-calculate the positions and offsets of task views so that we can reuse them directly 2760a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // in the future. 2770a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRectInfoList = new TaskGridRectInfo[MAX_LAYOUT_TASK_COUNT]; 2780a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He for (int i = 0; i < MAX_LAYOUT_TASK_COUNT; i++) { 2790a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRectInfoList[i] = new TaskGridRectInfo(i + 1); 2800a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 281bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 282bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 283bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void setSystemInsets(Rect systemInsets) { 284bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mSystemInsets = systemInsets; 285bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet updateAppAspectRatio(); 286bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 287bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 288bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private void updateAppAspectRatio() { 289bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet int usableWidth = mScreenSize.x - mSystemInsets.left - mSystemInsets.right; 290bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet int usableHeight = mScreenSize.y - mSystemInsets.top - mSystemInsets.bottom; 291bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mAppAspectRatio = (float) usableWidth / (float) usableHeight; 292bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 293bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 294bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public Rect getStackActionButtonRect() { 295c0432c63de3def1f00f93aedee8050c30c2dc291Manu Cornet Rect buttonRect = new Rect(mWindowRect); 296bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.right -= mPaddingLeftRight; 297bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.left += mPaddingLeftRight; 298bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.bottom = buttonRect.top + mPaddingTopBottom; 299bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet return buttonRect; 300bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 3018f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He 30221f495f07b1b9ace99986a110d01a763847687b1Jiaquan He public void updateTaskGridRect(int taskCount) { 30321f495f07b1b9ace99986a110d01a763847687b1Jiaquan He if (taskCount > 0) { 30421f495f07b1b9ace99986a110d01a763847687b1Jiaquan He TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 30521f495f07b1b9ace99986a110d01a763847687b1Jiaquan He mTaskGridRect.set(gridInfo.size); 30621f495f07b1b9ace99986a110d01a763847687b1Jiaquan He } 30721f495f07b1b9ace99986a110d01a763847687b1Jiaquan He } 30821f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 3098f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He public Rect getTaskGridRect() { 3108f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He return mTaskGridRect; 3118f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He } 31221f495f07b1b9ace99986a110d01a763847687b1Jiaquan He 31321f495f07b1b9ace99986a110d01a763847687b1Jiaquan He public int getFocusFrameThickness() { 31421f495f07b1b9ace99986a110d01a763847687b1Jiaquan He return mFocusedFrameThickness; 31521f495f07b1b9ace99986a110d01a763847687b1Jiaquan He } 316bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet} 317