TaskGridLayoutAlgorithm.java revision 8f34df423d9f65c692d9bcf59d224e0f938f78ac
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 550a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He /** 560a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * When the amount of tasks is determined, the size and position of every task view can be 570a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * decided. Each instance of TaskGridRectInfo store the task view information for a certain 580a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * amount of tasks. 590a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He */ 600a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He class TaskGridRectInfo { 610a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He Rect size; 620a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int[] xOffsets; 630a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int[] yOffsets; 640a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 650a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He public TaskGridRectInfo(int taskCount) { 660a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He size = new Rect(); 670a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He xOffsets = new int[taskCount]; 680a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He yOffsets = new int[taskCount]; 690a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 700a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int layoutTaskCount = Math.min(MAX_LAYOUT_TASK_COUNT, taskCount); 710a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 720a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int tasksPerLine = layoutTaskCount < 2 ? 1 : ( 730a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He layoutTaskCount < 5 ? 2 : ( 740a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He layoutTaskCount < 7 ? 3 : 4)); 750a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int lines = layoutTaskCount < 3 ? 1 : 2; 760a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 770a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskWidth, taskHeight; 780a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int maxTaskWidth = (mDisplayRect.width() - 2 * mPaddingLeftRight 790a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (tasksPerLine - 1) * mPaddingTaskView) / tasksPerLine; 800a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int maxTaskHeight = (mDisplayRect.height() - 2 * mPaddingTopBottom 810a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (lines - 1) * mPaddingTaskView) / lines; 820a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 830a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He if (maxTaskHeight >= maxTaskWidth / mAppAspectRatio + mTitleBarHeight) { 840a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Width bound. 850a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskWidth = maxTaskWidth; 860a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskHeight = (int) (maxTaskWidth / mAppAspectRatio + mTitleBarHeight); 870a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } else { 880a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Height bound. 890a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskHeight = maxTaskHeight; 900a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He taskWidth = (int) ((taskHeight - mTitleBarHeight) * mAppAspectRatio); 910a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 920a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He size.set(0, 0, taskWidth, taskHeight); 930a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 940a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int emptySpaceX = mDisplayRect.width() - 2 * mPaddingLeftRight 950a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (tasksPerLine * taskWidth) - (tasksPerLine - 1) * mPaddingTaskView; 960a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int emptySpaceY = mDisplayRect.height() - 2 * mPaddingTopBottom 970a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He - (lines * taskHeight) - (lines - 1) * mPaddingTaskView; 980a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He for (int taskIndex = 0; taskIndex < taskCount; taskIndex++) { 990a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // We also need to invert the index in order to display the most recent tasks first. 1000a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskLayoutIndex = taskCount - taskIndex - 1; 1010a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1020a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int xIndex = taskLayoutIndex % tasksPerLine; 1030a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int yIndex = taskLayoutIndex / tasksPerLine; 1040a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He xOffsets[taskIndex] = 1050a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He emptySpaceX / 2 + mPaddingLeftRight + (taskWidth + mPaddingTaskView) * xIndex; 1060a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He yOffsets[taskIndex] = 1070a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He emptySpaceY / 2 + mPaddingTopBottom + (taskHeight + mPaddingTaskView) * yIndex; 1080a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1090a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1100a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 1110a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1120a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He /** 1130a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * We can find task view sizes and positions from mTaskGridRectInfoList[k - 1] when there 1140a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He * are k tasks. 1150a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He */ 1160a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He TaskGridRectInfo[] mTaskGridRectInfoList; 1170a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 118bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public TaskGridLayoutAlgorithm(Context context) { 119bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet reloadOnConfigurationChange(context); 120bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 121bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 122bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void reloadOnConfigurationChange(Context context) { 123bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Resources res = context.getResources(); 124bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mPaddingLeftRight = res.getDimensionPixelSize(R.dimen.recents_grid_padding_left_right); 125bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mPaddingTopBottom = res.getDimensionPixelSize(R.dimen.recents_grid_padding_top_bottom); 126bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mPaddingTaskView = res.getDimensionPixelSize(R.dimen.recents_grid_padding_task_view); 127bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 128bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mTaskGridRect = new Rect(); 129bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mTitleBarHeight = res.getDimensionPixelSize(R.dimen.recents_grid_task_view_header_height); 130bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 131bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet WindowManager windowManager = (WindowManager) context 132bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet .getSystemService(Context.WINDOW_SERVICE); 133bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet windowManager.getDefaultDisplay().getRealSize(mScreenSize); 134bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 135bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet updateAppAspectRatio(); 136bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 137bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 138bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public TaskViewTransform getTransform(int taskIndex, int taskCount, 139bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet TaskViewTransform transformOut, TaskStackLayoutAlgorithm stackLayout) { 140bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 1410a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He TaskGridRectInfo gridInfo = mTaskGridRectInfoList[taskCount - 1]; 1420a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRect.set(gridInfo.size); 143bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 1440a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int x = gridInfo.xOffsets[taskIndex]; 1450a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int y = gridInfo.yOffsets[taskIndex]; 146bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float z = stackLayout.mMaxTranslationZ; 147bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 148bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float dimAlpha = 0f; 149bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet float viewOutlineAlpha = 0f; 1500a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // We also need to invert the index in order to display the most recent tasks first. 1510a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He int taskLayoutIndex = taskCount - taskIndex - 1; 152bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet boolean isTaskViewVisible = (taskLayoutIndex < MAX_LAYOUT_TASK_COUNT); 153bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 154bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet // Fill out the transform 155bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.scale = 1f; 156bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.alpha = isTaskViewVisible ? 1f : 0f; 157bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.translationZ = z; 158bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.dimAlpha = dimAlpha; 159bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.viewOutlineAlpha = viewOutlineAlpha; 160bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.rect.set(mTaskGridRect); 161bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.rect.offset(x, y); 162bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); 163bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet // We only show the 8 most recent tasks. 164bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet transformOut.visible = isTaskViewVisible; 165bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet return transformOut; 166bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 167bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 168bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void initialize(Rect displayRect, Rect windowRect) { 169bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mDisplayRect = displayRect; 170bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mWindowRect = windowRect; 1710a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He 1720a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // Pre-calculate the positions and offsets of task views so that we can reuse them directly 1730a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He // in the future. 1740a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRectInfoList = new TaskGridRectInfo[MAX_LAYOUT_TASK_COUNT]; 1750a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He for (int i = 0; i < MAX_LAYOUT_TASK_COUNT; i++) { 1760a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He mTaskGridRectInfoList[i] = new TaskGridRectInfo(i + 1); 1770a5e2d6b93af0638f9dccb3bad43266b8fc261adJiaquan He } 178bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 179bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 180bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public void setSystemInsets(Rect systemInsets) { 181bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mSystemInsets = systemInsets; 182bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet updateAppAspectRatio(); 183bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 184bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 185bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet private void updateAppAspectRatio() { 186bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet int usableWidth = mScreenSize.x - mSystemInsets.left - mSystemInsets.right; 187bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet int usableHeight = mScreenSize.y - mSystemInsets.top - mSystemInsets.bottom; 188bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet mAppAspectRatio = (float) usableWidth / (float) usableHeight; 189bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 190bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet 191bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet public Rect getStackActionButtonRect() { 192bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet Rect buttonRect = new Rect(mDisplayRect); 193bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.right -= mPaddingLeftRight; 194bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.left += mPaddingLeftRight; 195bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet buttonRect.bottom = buttonRect.top + mPaddingTopBottom; 196bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet return buttonRect; 197bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet } 1988f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He 1998f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He public Rect getTaskGridRect() { 2008f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He return mTaskGridRect; 2018f34df423d9f65c692d9bcf59d224e0f938f78acJiaquan He } 202bf8e290376b8ee6d04c330b22f5275e82103def3Manu Cornet} 203