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