FreeformWorkspaceLayoutAlgorithm.java revision f0d1c44a59a10707baa0cca8dd377302260710c1
1/* 2 * Copyright (C) 2014 The Android Open Source Project 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17package com.android.systemui.recents.views; 18 19import android.graphics.Bitmap; 20import android.graphics.Rect; 21import android.util.Log; 22import com.android.systemui.recents.misc.Utilities; 23import com.android.systemui.recents.model.Task; 24 25import java.util.HashMap; 26import java.util.List; 27 28/** 29 * The layout logic for the contents of the freeform workspace. 30 */ 31public class FreeformWorkspaceLayoutAlgorithm { 32 33 private static final String TAG = "FreeformWorkspaceLayoutAlgorithm"; 34 private static final boolean DEBUG = false; 35 36 // The number of cells in the freeform workspace 37 private int mFreeformCellXCount; 38 private int mFreeformCellYCount; 39 40 // The width and height of the cells in the freeform workspace 41 private int mFreeformCellWidth; 42 private int mFreeformCellHeight; 43 44 // Optimization, allows for quick lookup of task -> index 45 private HashMap<Task.TaskKey, Integer> mTaskIndexMap = new HashMap<>(); 46 47 /** 48 * Updates the layout for each of the freeform workspace tasks. This is called after the stack 49 * layout is updated. 50 */ 51 public void update(List<Task> freeformTasks, TaskStackLayoutAlgorithm stackLayout) { 52 mTaskIndexMap.clear(); 53 54 int numFreeformTasks = stackLayout.mNumFreeformTasks; 55 if (!freeformTasks.isEmpty()) { 56 // Calculate the cell width/height depending on the number of freeform tasks 57 mFreeformCellXCount = Math.max(1, (int) Math.ceil(Math.sqrt(numFreeformTasks))); 58 mFreeformCellYCount = Math.max(1, (int) Math.ceil((float) numFreeformTasks / 59 mFreeformCellXCount)); 60 // For now, make the cells square 61 mFreeformCellWidth = Math.min(stackLayout.mFreeformRect.width() / mFreeformCellXCount, 62 stackLayout.mFreeformRect.height() / mFreeformCellYCount); 63 mFreeformCellHeight = mFreeformCellWidth; 64 65 // Put each of the tasks in the progress map at a fixed index (does not need to actually 66 // map to a scroll position, just by index) 67 int taskCount = freeformTasks.size(); 68 for (int i = taskCount - 1; i >= 0; i--) { 69 Task task = freeformTasks.get(i); 70 mTaskIndexMap.put(task.key, taskCount - i - 1); 71 } 72 73 if (DEBUG) { 74 Log.d(TAG, "mFreeformCellXCount: " + mFreeformCellXCount); 75 Log.d(TAG, "mFreeformCellYCount: " + mFreeformCellYCount); 76 Log.d(TAG, "mFreeformCellWidth: " + mFreeformCellWidth); 77 Log.d(TAG, "mFreeformCellHeight: " + mFreeformCellHeight); 78 } 79 } 80 } 81 82 /** 83 * Returns whether the transform is available for the given task. 84 */ 85 public boolean isTransformAvailable(Task task, TaskStackLayoutAlgorithm stackLayout) { 86 if (stackLayout.mNumFreeformTasks == 0 || task == null) { 87 return false; 88 } 89 return mTaskIndexMap.containsKey(task.key); 90 } 91 92 /** 93 * Returns the transform for the given task. Any rect returned will be offset by the actual 94 * transform for the freeform workspace. 95 */ 96 public TaskViewTransform getTransform(Task task, TaskViewTransform transformOut, 97 TaskStackLayoutAlgorithm stackLayout) { 98 if (mTaskIndexMap.containsKey(task.key)) { 99 Rect taskRect = stackLayout.mTaskRect; 100 int taskIndex = mTaskIndexMap.get(task.key); 101 int topOffset = (stackLayout.mFreeformRect.top - taskRect.top); 102 int x = taskIndex % mFreeformCellXCount; 103 int y = taskIndex / mFreeformCellXCount; 104 105 Bitmap thumbnail = task.thumbnail; 106 float thumbnailScale = 1f; 107 float thumbnailWidth = mFreeformCellWidth; 108 float thumbnailHeight = mFreeformCellHeight; 109 if (thumbnail != null) { 110 int bitmapWidth = task.thumbnail.getWidth(); 111 int bitmapHeight = task.thumbnail.getHeight(); 112 thumbnailScale = Math.min((float) mFreeformCellWidth / bitmapWidth, 113 (float) mFreeformCellHeight / bitmapHeight); 114 thumbnailWidth = bitmapWidth * thumbnailScale; 115 thumbnailHeight = bitmapHeight * thumbnailScale; 116 } 117 int scaleXOffset = (int) (((1f - thumbnailScale) * thumbnailWidth) / 2); 118 int scaleYOffset = (int) (((1f - thumbnailScale) * thumbnailHeight) / 2); 119 transformOut.scale = thumbnailScale * 0.9f; 120 transformOut.translationX = x * mFreeformCellWidth - scaleXOffset; 121 transformOut.translationY = topOffset + y * mFreeformCellHeight - scaleYOffset; 122 transformOut.translationZ = stackLayout.mMaxTranslationZ; 123 transformOut.rect.set(stackLayout.mTaskRect); 124 transformOut.rect.offset(transformOut.translationX, transformOut.translationY); 125 Utilities.scaleRectAboutCenter(transformOut.rect, transformOut.scale); 126 transformOut.visible = true; 127 transformOut.p = 1f; 128 129 if (DEBUG) { 130 Log.d(TAG, "getTransform: " + task.key + ", " + transformOut); 131 } 132 return transformOut; 133 } 134 return null; 135 } 136} 137