blob: 648f2f023fdff71ae7e25dc74229d909e0fd31f3 [file] [log] [blame]
/*
* Copyright (C) 2016 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.android.systemui.recents.grid;
import android.graphics.Rect;
import android.util.Log;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
class TaskGridLayoutAlgorithm {
public enum VerticalGravity {
START, END, CENTER
}
public static final List<Integer> ZERO_MARGIN = new ArrayList<>();
static {
Integer[] zero = {0, 0, 0, 0};
ZERO_MARGIN.addAll(Arrays.asList(zero));
}
private static final String TAG = "TaskGridLayoutAlgorithm";
/**
* Calculates the adequate rectangles for the specified number of tasks to be layed out on
* the screen.
* @param count The number of task views to layout.
* @param containerWidth The width of the whole area containing those tasks.
* @param containerHeight The height of the whole area containing those tasks.
* @param screenRatio The ratio of the device's screen, so that tasks have the same aspect
* ratio (ignoring the title bar).
* @param padding The amount of padding, in pixels, in between task views.
* @param margins The amount of space to be left blank around the area on the left, top, right
* and bottom.
* @param titleBarHeight The height, in pixels, of the task views title bar.
* @return A list of rectangles to be used for layout.
*/
static ArrayList<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight,
float screenRatio, int padding, List<Integer> margins, int titleBarHeight) {
return getRectsForTaskCount(count, containerWidth, containerHeight, screenRatio, padding,
margins, titleBarHeight, null, VerticalGravity.CENTER);
}
private static ArrayList<Rect> getRectsForTaskCount(int count, int containerWidth,
int containerHeight, float screenRatio, int padding, List<Integer> margins,
int titleBarHeight, Rect preCalculatedTile, VerticalGravity gravity) {
ArrayList<Rect> rects = new ArrayList<>(count);
boolean landscape = (containerWidth > containerHeight);
containerWidth -= margins.get(0) + margins.get(2);
containerHeight -= margins.get(1) + margins.get(3);
// We support at most 9 tasks in this layout.
count = Math.min(count, RecentsGridActivity.MAX_VISIBLE_TASKS);
if (count == 0) {
return rects;
}
if (count <= 3) {
// Base case: single line.
int taskWidth, taskHeight;
if (preCalculatedTile != null) {
taskWidth = preCalculatedTile.width();
taskHeight = preCalculatedTile.height();
} else {
// Divide available width in equal parts.
int maxTaskWidth = (containerWidth - (count - 1) * padding) / count;
int maxTaskHeight = containerHeight;
if (maxTaskHeight >= maxTaskWidth / screenRatio + titleBarHeight) {
// Width bound.
taskWidth = maxTaskWidth;
taskHeight = (int) (maxTaskWidth / screenRatio + titleBarHeight);
} else {
// Height bound.
taskHeight = maxTaskHeight;
taskWidth = (int) ((taskHeight - titleBarHeight) * screenRatio);
}
}
int emptySpaceX = containerWidth - (count * taskWidth) - (count - 1) * padding;
int emptySpaceY = containerHeight - taskHeight;
for (int i = 0; i < count; i++) {
int left = emptySpaceX / 2 + i * taskWidth + i * padding;
int top;
switch (gravity) {
case CENTER:
top = emptySpaceY / 2;
break;
case END:
top = emptySpaceY;
break;
case START:
default:
top = 0;
break;
}
Rect rect = new Rect(left, top, left + taskWidth, top + taskHeight);
rect.offset(margins.get(0), margins.get(1));
rects.add(rect);
}
} else if (count < 7) {
// Two lines.
int lineHeight = (containerHeight - padding) / 2;
int lineTaskCount = (int) Math.ceil((double) count / 2);
List<Rect> rectsA = getRectsForTaskCount(lineTaskCount, containerWidth, lineHeight,
screenRatio, padding, ZERO_MARGIN, titleBarHeight, null, VerticalGravity.END);
List<Rect> rectsB = getRectsForTaskCount(count - lineTaskCount, containerWidth,
lineHeight, screenRatio, padding, ZERO_MARGIN, titleBarHeight, rectsA.get(0),
VerticalGravity.START);
for (int i = 0; i < rectsA.size(); i++) {
rectsA.get(i).offset(margins.get(0), margins.get(1));
}
for (int i = 0; i < rectsB.size(); i++) {
rectsB.get(i).offset(margins.get(0), margins.get(1) + lineHeight + padding);
}
rects.addAll(rectsA);
rects.addAll(rectsB);
} else {
// Three lines.
int lineHeight = (containerHeight - 2 * padding) / 3;
int lineTaskCount = (int) Math.ceil((double) count / 3);
List<Rect> rectsA = getRectsForTaskCount(lineTaskCount, containerWidth, lineHeight,
screenRatio, padding, ZERO_MARGIN, titleBarHeight, null, VerticalGravity.END);
List<Rect> rectsB = getRectsForTaskCount(lineTaskCount, containerWidth, lineHeight,
screenRatio, padding, ZERO_MARGIN, titleBarHeight, rectsA.get(0),
VerticalGravity.END);
List<Rect> rectsC = getRectsForTaskCount(count - (2 * lineTaskCount), containerWidth,
lineHeight, screenRatio, padding, ZERO_MARGIN, titleBarHeight, rectsA.get(0),
VerticalGravity.START);
for (int i = 0; i < rectsA.size(); i++) {
rectsA.get(i).offset(margins.get(0), margins.get(1));
}
for (int i = 0; i < rectsB.size(); i++) {
rectsB.get(i).offset(margins.get(0), margins.get(1) + lineHeight + padding);
}
for (int i = 0; i < rectsC.size(); i++) {
rectsC.get(i).offset(margins.get(0), margins.get(1) + 2 * (lineHeight + padding));
}
rects.addAll(rectsA);
rects.addAll(rectsB);
rects.addAll(rectsC);
}
return rects;
}
}