DO NOT MERGE - 2-dimensional Recents activity.

This is a simple first version in the spirit of small, incremental CLs.
It is fully functional but the following will come in later changes:

* Split screen support
* Potential animations
* Alt-tab behavior
* Relayout on orientation changes

The new activity is only started when a specific system property is set.

Test: Tested new activity behavior on local Ryu. Added tests for layout logic.
Bug: 32101881
Merged-In: I550f6e7ea0de3937dbf80e5f0294676cfe567d47
Change-Id: I46a537646e98b312d831510e1d331948888ae5ce
This commit is contained in:
Manu Cornet
2016-11-11 11:36:08 -08:00
parent 8da11f44ef
commit c13df1eb30
8 changed files with 642 additions and 2 deletions

View File

@@ -267,6 +267,22 @@
</intent-filter>
</activity>
<activity android:name=".recents.grid.RecentsGridActivity"
android:label="@string/accessibility_desc_recent_apps"
android:exported="false"
android:launchMode="singleInstance"
android:excludeFromRecents="true"
android:stateNotNeeded="true"
android:resumeWhilePausing="true"
android:screenOrientation="behind"
android:resizeableActivity="true"
android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout"
android:theme="@style/RecentsTheme.Wallpaper">
<intent-filter>
<action android:name="com.android.systemui.recents.TOGGLE_RECENTS" />
</intent-filter>
</activity>
<activity android:name=".recents.tv.RecentsTvActivity"
android:label="@string/accessibility_desc_recent_apps"
android:exported="false"

View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- 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.
-->
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
android:id="@+id/recents_container">
<include layout="@layout/recents_stack_action_button" />
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/recents_view"
android:layout_marginLeft="12dp"
android:layout_marginTop="10dp"
android:layout_marginRight="12dp"
android:layout_marginBottom="5dp"
android:gravity="center">
</FrameLayout>
</LinearLayout>

View File

@@ -57,6 +57,7 @@ import com.android.systemui.recents.events.component.ShowUserToastEvent;
import com.android.systemui.recents.events.ui.RecentsDrawnEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.grid.RecentsGridImpl;
import com.android.systemui.recents.tv.RecentsTvImpl;
import com.android.systemui.stackdivider.Divider;
@@ -83,6 +84,7 @@ public class Recents extends SystemUI
static {
RECENTS_ACTIVITIES.add(RecentsImpl.RECENTS_ACTIVITY);
RECENTS_ACTIVITIES.add(RecentsTvImpl.RECENTS_TV_ACTIVITY);
RECENTS_ACTIVITIES.add(RecentsGridImpl.RECENTS_MOSAIC_ACTIVITY);
}
// Purely for experimentation
@@ -205,6 +207,8 @@ public class Recents extends SystemUI
getSystemService(Context.UI_MODE_SERVICE);
if (uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION) {
mImpl = new RecentsTvImpl(mContext);
} else if (SystemProperties.getBoolean("ro.recents.grid", false) == true) {
mImpl = new RecentsGridImpl(mContext);
} else {
mImpl = new RecentsImpl(mContext);
}

View File

@@ -0,0 +1,317 @@
/*
* 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.app.Activity;
import android.content.Intent;
import android.content.res.Configuration;
import android.graphics.Rect;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.view.ViewTreeObserver;
import android.widget.FrameLayout;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.android.internal.logging.MetricsLogger;
import com.android.internal.logging.MetricsProto.MetricsEvent;
import com.android.systemui.R;
import com.android.systemui.recents.Recents;
import com.android.systemui.recents.RecentsActivity;
import com.android.systemui.recents.RecentsActivityLaunchState;
import com.android.systemui.recents.RecentsConfiguration;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.ConfigurationChangedEvent;
import com.android.systemui.recents.events.activity.HideRecentsEvent;
import com.android.systemui.recents.events.activity.LaunchNextTaskRequestEvent;
import com.android.systemui.recents.events.activity.LaunchTaskEvent;
import com.android.systemui.recents.events.activity.ToggleRecentsEvent;
import com.android.systemui.recents.events.component.RecentsVisibilityChangedEvent;
import com.android.systemui.recents.events.ui.AllTaskViewsDismissedEvent;
import com.android.systemui.recents.events.ui.DeleteTaskDataEvent;
import com.android.systemui.recents.events.ui.DismissAllTaskViewsEvent;
import com.android.systemui.recents.events.ui.DismissTaskViewEvent;
import com.android.systemui.recents.events.ui.TaskViewDismissedEvent;
import com.android.systemui.recents.misc.SystemServicesProxy;
import com.android.systemui.recents.misc.Utilities;
import com.android.systemui.recents.model.RecentsTaskLoadPlan;
import com.android.systemui.recents.model.RecentsTaskLoader;
import com.android.systemui.recents.model.Task;
import com.android.systemui.recents.model.TaskStack;
import com.android.systemui.recents.views.TaskView;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/**
* The main grid recents activity started by the RecentsImpl.
*/
public class RecentsGridActivity extends Activity implements ViewTreeObserver.OnPreDrawListener {
private final static String TAG = "RecentsGridActivity";
private TaskStack mTaskStack;
private List<Task> mTasks = new ArrayList<>();
private List<View> mTaskViews = new ArrayList<>();
private FrameLayout mRecentsView;
private TextView mEmptyView;
private View mClearAllButton;
private int mDisplayOrientation = Configuration.ORIENTATION_UNDEFINED;
private Rect mDisplayRect = new Rect();
private LayoutInflater mInflater;
private boolean mTouchExplorationEnabled;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.recents_grid);
SystemServicesProxy ssp = Recents.getSystemServices();
mInflater = LayoutInflater.from(this);
mDisplayOrientation = Utilities.getAppConfiguration(this).orientation;
mDisplayRect = ssp.getDisplayRect();
mTouchExplorationEnabled = ssp.isTouchExplorationEnabled();
mRecentsView = (FrameLayout) findViewById(R.id.recents_view);
LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container);
mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false);
mClearAllButton = findViewById(R.id.button);
FrameLayout.LayoutParams emptyViewLayoutParams = new FrameLayout.LayoutParams(
FrameLayout.LayoutParams.MATCH_PARENT, FrameLayout.LayoutParams.WRAP_CONTENT);
emptyViewLayoutParams.gravity = Gravity.CENTER_VERTICAL | Gravity.CENTER_HORIZONTAL;
mEmptyView.setLayoutParams(emptyViewLayoutParams);
mRecentsView.addView(mEmptyView);
mClearAllButton.setVisibility(View.VISIBLE);
LinearLayout.LayoutParams lp =
(LinearLayout.LayoutParams) mClearAllButton.getLayoutParams();
lp.gravity = Gravity.END;
mClearAllButton.setOnClickListener(v -> {
EventBus.getDefault().send(new DismissAllTaskViewsEvent());
});
mRecentsView.setOnClickListener(v -> {
EventBus.getDefault().send(new HideRecentsEvent(
false /* triggeredFromAltTab */, false /* triggeredFromHomeKey */));
});
EventBus.getDefault().register(this, RecentsActivity.EVENT_BUS_PRIORITY);
}
private TaskView createView() {
return (TaskView) mInflater.inflate(R.layout.recents_task_view, mRecentsView, false);
}
private void clearTaskViews() {
for (View taskView : mTaskViews) {
ViewGroup parent = (ViewGroup) taskView.getParent();
if (parent != null) {
parent.removeView(taskView);
}
}
mTaskViews.clear();
}
private void updateControlVisibility() {
boolean empty = (mTasks.size() == 0);
mClearAllButton.setVisibility(empty ? View.INVISIBLE : View.VISIBLE);
mEmptyView.setVisibility(empty ? View.VISIBLE : View.INVISIBLE);
if (empty) {
mEmptyView.bringToFront();
}
}
private void updateRecentsTasks() {
RecentsTaskLoader loader = Recents.getTaskLoader();
RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan();
if (plan == null) {
plan = loader.createLoadPlan(this);
}
RecentsConfiguration config = Recents.getConfiguration();
RecentsActivityLaunchState launchState = config.getLaunchState();
if (!plan.hasTasks()) {
loader.preloadTasks(plan, -1, !launchState.launchedFromHome);
}
int numVisibleTasks = 9;
mTaskStack = plan.getTaskStack();
RecentsTaskLoadPlan.Options loadOpts = new RecentsTaskLoadPlan.Options();
loadOpts.runningTaskId = launchState.launchedToTaskId;
loadOpts.numVisibleTasks = numVisibleTasks;
loadOpts.numVisibleTaskThumbnails = numVisibleTasks;
loader.loadTasks(this, plan, loadOpts);
List<Task> stackTasks = mTaskStack.getStackTasks();
Collections.reverse(stackTasks);
mTasks = stackTasks;
updateControlVisibility();
clearTaskViews();
for (int i = 0; i < mTasks.size(); i++) {
Task task = mTasks.get(i);
TaskView taskView = createView();
taskView.onTaskBound(task, mTouchExplorationEnabled, mDisplayOrientation, mDisplayRect);
Recents.getTaskLoader().loadTaskData(task);
taskView.setTouchEnabled(true);
// Show dismiss button right away.
taskView.startNoUserInteractionAnimation();
mTaskViews.add(taskView);
}
}
@Override
protected void onStart() {
super.onStart();
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true));
mRecentsView.getViewTreeObserver().addOnPreDrawListener(this);
}
@Override
public void onResume() {
super.onResume();
updateRecentsTasks();
}
@Override
protected void onStop() {
super.onStop();
EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, false));
}
@Override
protected void onDestroy() {
super.onDestroy();
EventBus.getDefault().unregister(this);
}
@Override
public void onBackPressed() {
// Back behaves like the recents button so just trigger a toggle event.
EventBus.getDefault().send(new ToggleRecentsEvent());
}
@Override
public boolean onPreDraw() {
mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this);
int width = mRecentsView.getWidth();
int height = mRecentsView.getHeight();
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
mTasks.size(), width, height, false /* allowLineOfThree */, 30 /* padding */);
for (int i = 0; i < rects.size(); i++) {
Rect rect = rects.get(i);
View taskView = mTaskViews.get(i);
taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height()));
taskView.setTranslationX(rect.left);
taskView.setTranslationY(rect.top);
mRecentsView.addView(taskView);
}
return true;
}
void dismissRecentsToHome() {
Intent startMain = new Intent(Intent.ACTION_MAIN);
startMain.addCategory(Intent.CATEGORY_HOME);
startActivity(startMain);
}
/**** EventBus events ****/
public final void onBusEvent(HideRecentsEvent event) {
if (event.triggeredFromAltTab) {
// Do nothing for now.
} else if (event.triggeredFromHomeKey) {
dismissRecentsToHome();
}
}
public final void onBusEvent(ToggleRecentsEvent event) {
// Always go back home for simplicity for now. If recents is entered from another app, this
// code will eventually need to go back to the original app.
dismissRecentsToHome();
}
public final void onBusEvent(DismissTaskViewEvent event) {
int taskIndex = mTaskViews.indexOf(event.taskView);
if (taskIndex != -1) {
mTasks.remove(taskIndex);
((ViewGroup) event.taskView.getParent()).removeView(event.taskView);
mTaskViews.remove(taskIndex);
EventBus.getDefault().send(
new TaskViewDismissedEvent(event.taskView.getTask(), event.taskView, null));
}
}
public final void onBusEvent(TaskViewDismissedEvent event) {
mRecentsView.announceForAccessibility(this.getString(
R.string.accessibility_recents_item_dismissed, event.task.title));
updateControlVisibility();
EventBus.getDefault().send(new DeleteTaskDataEvent(event.task));
MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS,
event.task.key.getComponent().toString());
}
public final void onBusEvent(DeleteTaskDataEvent event) {
// Remove any stored data from the loader.
RecentsTaskLoader loader = Recents.getTaskLoader();
loader.deleteTaskData(event.task, false);
// Remove the task from activity manager.
SystemServicesProxy ssp = Recents.getSystemServices();
ssp.removeTask(event.task.key.id);
}
public final void onBusEvent(final DismissAllTaskViewsEvent event) {
// Keep track of the tasks which will have their data removed.
ArrayList<Task> tasks = new ArrayList<>(mTaskStack.getStackTasks());
mRecentsView.announceForAccessibility(this.getString(
R.string.accessibility_recents_all_items_dismissed));
mTaskStack.removeAllTasks();
for (int i = tasks.size() - 1; i >= 0; i--) {
EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i)));
}
mTasks = new ArrayList<>();
updateRecentsTasks();
MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS_ALL);
}
public final void onBusEvent(AllTaskViewsDismissedEvent event) {
SystemServicesProxy ssp = Recents.getSystemServices();
if (!ssp.hasDockedTask()) {
dismissRecentsToHome();
}
}
public final void onBusEvent(LaunchNextTaskRequestEvent event) {
// Always go back home for simplicity for now. Quick switch will be supported soon.
EventBus.getDefault().send(new HideRecentsEvent(false, true));
}
public final void onBusEvent(LaunchTaskEvent event) {
startActivity(event.task.key.baseIntent);
}
}

View File

@@ -0,0 +1,48 @@
/*
* 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.app.ActivityManager;
import android.content.Context;
import android.content.Intent;
import android.os.UserHandle;
import com.android.systemui.recents.RecentsImpl;
import com.android.systemui.recents.events.EventBus;
import com.android.systemui.recents.events.activity.RecentsActivityStartingEvent;
public class RecentsGridImpl extends RecentsImpl {
public static final String RECENTS_MOSAIC_ACTIVITY =
"com.android.systemui.recents.grid.RecentsGridActivity";
public RecentsGridImpl(Context context) {
super(context);
}
@Override
protected void startRecentsActivity(ActivityManager.RunningTaskInfo runningTask,
boolean isHomeStackVisible, boolean animate, int growTarget) {
Intent intent = new Intent();
intent.setClassName(RECENTS_PACKAGE, RECENTS_MOSAIC_ACTIVITY);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK
| Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS
| Intent.FLAG_ACTIVITY_TASK_ON_HOME);
mContext.startActivityAsUser(intent, UserHandle.CURRENT);
EventBus.getDefault().send(new RecentsActivityStartingEvent());
}
}

View File

@@ -0,0 +1,110 @@
/*
* 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.List;
class TaskGridLayoutAlgorithm {
private static final String TAG = "TaskGridLayoutAlgorithm";
static List<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight,
boolean allowLineOfThree, int padding) {
return getRectsForTaskCount(count, containerWidth, containerHeight, allowLineOfThree,
padding, null);
}
static List<Rect> getRectsForTaskCount(int count, int containerWidth, int containerHeight,
boolean allowLineOfThree, int padding, Rect preCalculatedTile) {
int singleLineMaxCount = allowLineOfThree ? 3 : 2;
List<Rect> rects = new ArrayList<>(count);
boolean landscape = (containerWidth > containerHeight);
// We support at most 9 tasks in this layout.
count = Math.min(count, 9);
if (count == 0) {
return rects;
}
if (count <= singleLineMaxCount) {
if (landscape) {
// Single line.
int taskWidth = 0;
int emptySpace = 0;
if (preCalculatedTile != null) {
taskWidth = preCalculatedTile.width();
emptySpace = containerWidth - (count * taskWidth) - (count - 1) * padding;
} else {
// Divide available space in equal parts.
taskWidth = (containerWidth - (count - 1) * padding) / count;
}
for (int i = 0; i < count; i++) {
int left = emptySpace / 2 + i * taskWidth + i * padding;
rects.add(new Rect(left, 0, left + taskWidth, containerHeight));
}
} else {
// Single column. Divide available space in equal parts.
int taskHeight = (containerHeight - (count - 1) * padding) / count;
for (int i = 0; i < count; i++) {
int top = i * taskHeight + i * padding;
rects.add(new Rect(0, top, containerWidth, top + taskHeight));
}
}
} 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, true /* allowLineOfThree */, padding,
null);
List<Rect> rectsB = getRectsForTaskCount(
count - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */,
padding, rectsA.get(0));
for (Rect rect : rectsB) {
rect.offset(0, 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, true /* allowLineOfThree */, padding, null);
List<Rect> rectsB = getRectsForTaskCount(
lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding,
rectsA.get(0));
List<Rect> rectsC = getRectsForTaskCount(
count - (2 * lineTaskCount), containerWidth, lineHeight,
true /* allowLineOfThree */, padding, rectsA.get(0));
for (Rect rect : rectsB) {
rect.offset(0, lineHeight + padding);
}
for (Rect rect : rectsC) {
rect.offset(0, 2 * (lineHeight + padding));
}
rects.addAll(rectsA);
rects.addAll(rectsB);
rects.addAll(rectsC);
}
return rects;
}
}

View File

@@ -360,12 +360,12 @@ public class TaskView extends FixedSizeFrameLayout implements Task.TaskCallbacks
}
/** Enables/disables handling touch on this task view. */
void setTouchEnabled(boolean enabled) {
public void setTouchEnabled(boolean enabled) {
setOnClickListener(enabled ? this : null);
}
/** Animates this task view if the user does not interact with the stack after a certain time. */
void startNoUserInteractionAnimation() {
public void startNoUserInteractionAnimation() {
mHeaderView.startNoUserInteractionAnimation();
}

View File

@@ -0,0 +1,112 @@
/*
* 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.test.suitebuilder.annotation.SmallTest;
import com.android.systemui.SysuiTestCase;
import java.util.List;
import static junit.framework.Assert.assertEquals;
import static junit.framework.Assert.assertTrue;
@SmallTest
public class TaskGridLayoutAlgorithmTest extends SysuiTestCase {
public void testOneTile() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
1, 1000, 500, false /* allowLineOfThree */, 0 /* padding */);
assertEquals(1, rects.size());
Rect singleRect = rects.get(0);
assertEquals(1000, singleRect.width());
}
public void testTwoTilesLandscape() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
2, 1200, 500, false /* allowLineOfThree */, 0 /* padding */);
assertEquals(2, rects.size());
for (Rect rect : rects) {
assertEquals(600, rect.width());
assertEquals(500, rect.height());
}
}
public void testTwoTilesLandscapeWithPadding() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
2, 1200, 500, false /* allowLineOfThree */, 10 /* padding */);
assertEquals(2, rects.size());
Rect rectA = rects.get(0);
Rect rectB = rects.get(1);
assertEquals(595, rectA.width());
assertEquals(595, rectB.width());
assertEquals(605, rectB.left);
}
public void testTwoTilesPortrait() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
2, 500, 1200, false /* allowLineOfThree */, 0 /* padding */);
assertEquals(2, rects.size());
for (Rect rect : rects) {
assertEquals(500, rect.width());
assertEquals(600, rect.height());
}
}
public void testThreeTiles() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
3, 1200, 500, false /* allowLineOfThree */, 0 /* padding */);
assertEquals(3, rects.size());
for (Rect rect : rects) {
assertEquals(600, rect.width());
assertEquals(250, rect.height());
}
// The third tile should be on the second line, in the middle.
Rect rectC = rects.get(2);
assertEquals(300, rectC.left);
assertEquals(250, rectC.top);
}
public void testFourTiles() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
4, 1200, 500, false /* allowLineOfThree */, 0 /* padding */);
assertEquals(4, rects.size());
for (Rect rect : rects) {
assertEquals(600, rect.width());
assertEquals(250, rect.height());
}
Rect rectD = rects.get(3);
assertEquals(600, rectD.left);
assertEquals(250, rectD.top);
}
public void testNineTiles() {
List<Rect> rects = TaskGridLayoutAlgorithm.getRectsForTaskCount(
9, 1200, 600, false /* allowLineOfThree */, 0 /* padding */);
assertEquals(9, rects.size());
for (Rect rect : rects) {
assertEquals(400, rect.width());
assertEquals(200, rect.height());
}
Rect rectE = rects.get(4);
assertEquals(400, rectE.left);
assertEquals(200, rectE.top);
Rect rectI = rects.get(8);
assertEquals(800, rectI.left);
assertEquals(400, rectI.top);
}
}