diff --git a/packages/SystemUI/AndroidManifest.xml b/packages/SystemUI/AndroidManifest.xml index 0b5383acf4d21..d232e00d02e2d 100644 --- a/packages/SystemUI/AndroidManifest.xml +++ b/packages/SystemUI/AndroidManifest.xml @@ -297,7 +297,7 @@ android:screenOrientation="behind" android:resizeableActivity="true" android:configChanges="orientation|screenSize|smallestScreenSize|screenLayout" - android:theme="@style/RecentsTheme.Wallpaper"> + android:theme="@style/RecentsTheme.Grid"> diff --git a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml index cff770ae049ab..1a054a5347258 100644 --- a/packages/SystemUI/res/layout-sw600dp/recents_grid.xml +++ b/packages/SystemUI/res/layout-sw600dp/recents_grid.xml @@ -13,22 +13,11 @@ See the License for the specific language governing permissions and limitations under the License. --> - - - - \ No newline at end of file + \ No newline at end of file diff --git a/packages/SystemUI/res/layout/recents_stack_action_button.xml b/packages/SystemUI/res/layout/recents_stack_action_button.xml index 541000b78f8b6..34b4e1771af54 100644 --- a/packages/SystemUI/res/layout/recents_stack_action_button.xml +++ b/packages/SystemUI/res/layout/recents_stack_action_button.xml @@ -33,4 +33,5 @@ android:fontFamily="sans-serif-medium" android:background="@drawable/recents_stack_action_background" android:visibility="invisible" - android:forceHasOverlappingRendering="false" /> + android:forceHasOverlappingRendering="false" + style="?attr/clearAllStyle" /> diff --git a/packages/SystemUI/res/values/attrs.xml b/packages/SystemUI/res/values/attrs.xml index ad65f82ab956f..a2298663740e2 100644 --- a/packages/SystemUI/res/values/attrs.xml +++ b/packages/SystemUI/res/values/attrs.xml @@ -30,6 +30,8 @@ + + diff --git a/packages/SystemUI/res/values/dimens.xml b/packages/SystemUI/res/values/dimens.xml index 12f7881c11d9b..2f7174a6a89e3 100644 --- a/packages/SystemUI/res/values/dimens.xml +++ b/packages/SystemUI/res/values/dimens.xml @@ -697,4 +697,19 @@ 48dp + + + + 15dp + 70dp + 15dp + 90dp + + 0dp + 30dp + 15dp + 0dp + + 15dp + diff --git a/packages/SystemUI/res/values/styles.xml b/packages/SystemUI/res/values/styles.xml index 6661f076d8481..78fc9f979999b 100644 --- a/packages/SystemUI/res/values/styles.xml +++ b/packages/SystemUI/res/values/styles.xml @@ -34,6 +34,30 @@ @null true true + @style/ClearAllButtonDefaultMargins + + + + + + + + diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java index e1e654d58be75..71c21489554b0 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java +++ b/packages/SystemUI/src/com/android/systemui/recents/grid/RecentsGridActivity.java @@ -20,16 +20,22 @@ import static android.app.ActivityManager.StackId.INVALID_STACK_ID; import android.app.Activity; import android.content.Intent; import android.content.res.Configuration; +import android.content.res.Resources; +import android.graphics.Point; import android.graphics.Rect; import android.os.Bundle; +import android.util.DisplayMetrics; import android.view.Gravity; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.view.ViewTreeObserver; import android.view.WindowManager; +import android.view.animation.Animation; +import android.view.animation.AnimationSet; +import android.view.animation.DecelerateInterpolator; +import android.view.animation.ScaleAnimation; +import android.view.animation.TranslateAnimation; import android.widget.FrameLayout; -import android.widget.LinearLayout; import android.widget.TextView; import com.android.internal.logging.MetricsLogger; @@ -61,17 +67,23 @@ import com.android.systemui.recents.model.TaskStack; import com.android.systemui.recents.views.TaskView; import java.util.ArrayList; -import java.util.List; +import java.util.Arrays; /** * The main grid recents activity started by the RecentsImpl. */ -public class RecentsGridActivity extends Activity implements ViewTreeObserver.OnPreDrawListener { +public class RecentsGridActivity extends Activity { + public final static int MAX_VISIBLE_TASKS = 9; + private final static String TAG = "RecentsGridActivity"; + private final static int TITLE_BAR_HEIGHT_DP = 64; + + private ArrayList mMargins = new ArrayList<>(); private TaskStack mTaskStack; - private List mTasks = new ArrayList<>(); - private List mTaskViews = new ArrayList<>(); + private ArrayList mTasks = new ArrayList<>(); + private ArrayList mTaskViews = new ArrayList<>(); + private ArrayList mTaskViewRects; private FrameLayout mRecentsView; private TextView mEmptyView; private View mClearAllButton; @@ -80,6 +92,10 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On private Rect mDisplayRect = new Rect(); private LayoutInflater mInflater; private boolean mTouchExplorationEnabled; + private Point mScreenSize; + private int mTitleBarHeightPx; + private int mStatusBarHeightPx; + private int mNavigationBarHeightPx; @Override public void onCreate(Bundle savedInstanceState) { @@ -87,12 +103,28 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On setContentView(R.layout.recents_grid); SystemServicesProxy ssp = Recents.getSystemServices(); + Resources res = getResources(); + Integer[] margins = { + res.getDimensionPixelSize(R.dimen.recents_grid_margin_left), + res.getDimensionPixelSize(R.dimen.recents_grid_margin_top), + res.getDimensionPixelSize(R.dimen.recents_grid_margin_right), + res.getDimensionPixelSize(R.dimen.recents_grid_margin_bottom), + }; + mMargins.addAll(Arrays.asList(margins)); + mInflater = LayoutInflater.from(this); Configuration appConfiguration = Utilities.getAppConfiguration(this); mDisplayRect = ssp.getDisplayRect(); mLastDisplayOrientation = appConfiguration.orientation; mLastDisplayDensity = appConfiguration.densityDpi; mTouchExplorationEnabled = ssp.isTouchExplorationEnabled(); + mScreenSize = new Point(); + getWindowManager().getDefaultDisplay().getRealSize(mScreenSize); + DisplayMetrics metrics = res.getDisplayMetrics(); + mTitleBarHeightPx = (int) (TITLE_BAR_HEIGHT_DP * + ((float) metrics.densityDpi / DisplayMetrics.DENSITY_DEFAULT)); + mStatusBarHeightPx = res.getDimensionPixelSize(R.dimen.status_bar_height); + mNavigationBarHeightPx = res.getDimensionPixelSize(R.dimen.navigation_bar_height); mRecentsView = (FrameLayout) findViewById(R.id.recents_view); mRecentsView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE | @@ -100,8 +132,7 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION); getWindow().getAttributes().privateFlags |= WindowManager.LayoutParams.PRIVATE_FLAG_FORCE_DECOR_VIEW_VISIBILITY; - LinearLayout recentsContainer = (LinearLayout) findViewById(R.id.recents_container); - mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, recentsContainer, false); + mEmptyView = (TextView) mInflater.inflate(R.layout.recents_empty, mRecentsView, false); mClearAllButton = findViewById(R.id.button); FrameLayout.LayoutParams emptyViewLayoutParams = new FrameLayout.LayoutParams( @@ -111,8 +142,8 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On mRecentsView.addView(mEmptyView); mClearAllButton.setVisibility(View.VISIBLE); - LinearLayout.LayoutParams lp = - (LinearLayout.LayoutParams) mClearAllButton.getLayoutParams(); + FrameLayout.LayoutParams lp = + (FrameLayout.LayoutParams) mClearAllButton.getLayoutParams(); lp.gravity = Gravity.END; mClearAllButton.setOnClickListener(v -> { @@ -154,6 +185,57 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On return null; } + /** + * Starts animations for each task view to either enlarge it to the size of the screen (when + * launching a task), or (if {@code reverse} is true, to reduce it from the size of the screen + * back to its place in the recents layout (when opening recents). + * @param animationListener An animation listener for executing code before or after the + * animations run. + * @param reverse Whether the blow-up animations should be run in reverse. + */ + private void startBlowUpAnimations(Animation.AnimationListener animationListener, + boolean reverse) { + if (mTaskViews.size() == 0) { + return; + } + int screenWidth = mLastDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE + ? mScreenSize.x : mScreenSize.y; + int screenHeight = mLastDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE + ? mScreenSize.y : mScreenSize.x; + screenHeight -= mStatusBarHeightPx + mNavigationBarHeightPx; + for (int i = 0; i < mTaskViews.size(); i++) { + View tv = mTaskViews.get(i); + AnimationSet animations = new AnimationSet(true /* shareInterpolator */); + animations.setInterpolator(new DecelerateInterpolator()); + if (i == 0 && animationListener != null) { + animations.setAnimationListener(animationListener); + } + animations.setFillBefore(reverse); + animations.setFillAfter(!reverse); + Rect initialRect = mTaskViewRects.get(mTaskViewRects.size() - 1 - i); + int xDelta = - initialRect.left; + int yDelta = - initialRect.top - mTitleBarHeightPx + mStatusBarHeightPx; + TranslateAnimation translate = new TranslateAnimation( + reverse ? xDelta : 0, reverse ? 0 : xDelta, + reverse ? yDelta : 0, reverse ? 0 : yDelta); + translate.setDuration(250); + animations.addAnimation(translate); + + + float xScale = (float) screenWidth / (float) initialRect.width(); + float yScale = (float) screenHeight / + ((float) initialRect.height() - mTitleBarHeightPx); + ScaleAnimation scale = new ScaleAnimation( + reverse ? xScale : 1, reverse ? 1 : xScale, + reverse ? yScale : 1, reverse ? 1 : yScale, + Animation.ABSOLUTE, 0, Animation.ABSOLUTE, mStatusBarHeightPx); + scale.setDuration(300); + animations.addAnimation(scale); + + tv.startAnimation(animations); + } + } + private void updateControlVisibility() { boolean empty = (mTasks.size() == 0); mClearAllButton.setVisibility(empty ? View.INVISIBLE : View.VISIBLE); @@ -163,7 +245,7 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On } } - private void updateRecentsTasks() { + private void updateModel() { RecentsTaskLoader loader = Recents.getTaskLoader(); RecentsTaskLoadPlan plan = RecentsImpl.consumeInstanceLoadPlan(); if (plan == null) { @@ -174,29 +256,66 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On 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; + loadOpts.numVisibleTasks = MAX_VISIBLE_TASKS; + loadOpts.numVisibleTaskThumbnails = MAX_VISIBLE_TASKS; loader.loadTasks(this, plan, loadOpts); mTasks = mTaskStack.getStackTasks(); + } - updateControlVisibility(); - - clearTaskViews(); + private void updateViews() { + int screenWidth = mLastDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE + ? mScreenSize.x : mScreenSize.y; + int screenHeight = mLastDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE + ? mScreenSize.y : mScreenSize.x; + int paddingPixels = getResources().getDimensionPixelSize( + R.dimen.recents_grid_inter_task_padding); + mTaskViewRects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + mTasks.size(), screenWidth, screenHeight, getAppRectRatio(), paddingPixels, + mMargins, mTitleBarHeightPx); + boolean recycleViews = (mTaskViews.size() == mTasks.size()); + if (!recycleViews) { + clearTaskViews(); + } for (int i = 0; i < mTasks.size(); i++) { Task task = mTasks.get(i); - TaskView taskView = createView(); + // We keep the same ordering in the model as other Recents flavors (older tasks are + // first in the stack) so that the logic can be similar, but we reverse the order + // when placing views on the screen so that most recent tasks are displayed first. + Rect rect = mTaskViewRects.get(mTaskViewRects.size() - 1 - i); + TaskView taskView; + if (recycleViews) { + taskView = mTaskViews.get(i); + } else { + taskView = createView(); + } taskView.onTaskBound(task, mTouchExplorationEnabled, mLastDisplayOrientation, mDisplayRect); Recents.getTaskLoader().loadTaskData(task); taskView.setTouchEnabled(true); // Show dismiss button right away. taskView.startNoUserInteractionAnimation(); - mTaskViews.add(taskView); + taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height())); + taskView.setTranslationX(rect.left); + taskView.setTranslationY(rect.top); + if (!recycleViews) { + mRecentsView.addView(taskView); + mTaskViews.add(taskView); + } + } + updateControlVisibility(); + } + + private float getAppRectRatio() { + if (mLastDisplayOrientation == Configuration.ORIENTATION_LANDSCAPE) { + return (float) mScreenSize.x / + (float) (mScreenSize.y - mStatusBarHeightPx - mNavigationBarHeightPx); + } else { + return (float) mScreenSize.y / + (float) (mScreenSize.x - mStatusBarHeightPx - mNavigationBarHeightPx); } } @@ -204,13 +323,23 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On protected void onStart() { super.onStart(); EventBus.getDefault().send(new RecentsVisibilityChangedEvent(this, true)); - mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); - } + updateModel(); + updateViews(); + if (mTaskViews.size() > 0) { + mTaskViews.get(mTaskViews.size() - 1).bringToFront(); + } + startBlowUpAnimations(new Animation.AnimationListener() { + @Override + public void onAnimationStart(Animation animation) { } - @Override - public void onResume() { - super.onResume(); - updateRecentsTasks(); + @Override + public void onAnimationEnd(Animation animation) { + updateViews(); + } + + @Override + public void onAnimationRepeat(Animation animation) { } + }, true /* reverse */); } @Override @@ -237,37 +366,13 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On // Notify of the config change. Configuration newDeviceConfiguration = Utilities.getAppConfiguration(this); mDisplayRect = Recents.getSystemServices().getDisplayRect(); - mRecentsView.getViewTreeObserver().addOnPreDrawListener(this); - mRecentsView.requestLayout(); int numStackTasks = mTaskStack.getStackTaskCount(); EventBus.getDefault().send(new ConfigurationChangedEvent(false /* fromMultiWindow */, mLastDisplayOrientation != newDeviceConfiguration.orientation, mLastDisplayDensity != newDeviceConfiguration.densityDpi, numStackTasks > 0)); mLastDisplayOrientation = newDeviceConfiguration.orientation; mLastDisplayDensity = newDeviceConfiguration.densityDpi; - } - - @Override - public boolean onPreDraw() { - mRecentsView.getViewTreeObserver().removeOnPreDrawListener(this); - int width = mRecentsView.getWidth(); - int height = mRecentsView.getHeight(); - - List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - mTasks.size(), width, height, false /* allowLineOfThree */, 30 /* padding */); - removeTaskViews(); - for (int i = 0; i < rects.size(); i++) { - Rect rect = rects.get(i); - // We keep the same ordering in the model as other Recents flavors (older tasks are - // first in the stack) so that the logic can be similar, but we reverse the order - // when placing views on the screen so that most recent tasks are displayed first. - View taskView = mTaskViews.get(rects.size() - 1 - i); - taskView.setLayoutParams(new FrameLayout.LayoutParams(rect.width(), rect.height())); - taskView.setTranslationX(rect.left); - taskView.setTranslationY(rect.top); - mRecentsView.addView(taskView); - } - return true; + updateViews(); } void dismissRecentsToHome() { @@ -360,7 +465,8 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On EventBus.getDefault().send(new DeleteTaskDataEvent(tasks.get(i))); } mTasks = new ArrayList<>(); - updateRecentsTasks(); + updateModel(); + updateViews(); MetricsLogger.action(this, MetricsEvent.OVERVIEW_DISMISS_ALL); } @@ -390,6 +496,9 @@ public class RecentsGridActivity extends Activity implements ViewTreeObserver.On } public final void onBusEvent(LaunchTaskEvent event) { + event.taskView.bringToFront(); startActivity(event.task.key.baseIntent); + // Eventually we should start blow-up animations here, but we need to make sure it's done + // in parallel with starting the activity so that we don't introduce unneeded latency. } } diff --git a/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java b/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java index 057aa5497bf4b..648f2f023fdff 100644 --- a/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java +++ b/packages/SystemUI/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithm.java @@ -19,66 +19,111 @@ import android.graphics.Rect; import android.util.Log; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; class TaskGridLayoutAlgorithm { - private static final String TAG = "TaskGridLayoutAlgorithm"; - - static List getRectsForTaskCount(int count, int containerWidth, int containerHeight, - boolean allowLineOfThree, int padding) { - return getRectsForTaskCount(count, containerWidth, containerHeight, allowLineOfThree, - padding, null); + public enum VerticalGravity { + START, END, CENTER } - static List getRectsForTaskCount(int count, int containerWidth, int containerHeight, - boolean allowLineOfThree, int padding, Rect preCalculatedTile) { - int singleLineMaxCount = allowLineOfThree ? 3 : 2; - List rects = new ArrayList<>(count); + public static final List 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 getRectsForTaskCount(int count, int containerWidth, int containerHeight, + float screenRatio, int padding, List margins, int titleBarHeight) { + return getRectsForTaskCount(count, containerWidth, containerHeight, screenRatio, padding, + margins, titleBarHeight, null, VerticalGravity.CENTER); + } + + private static ArrayList getRectsForTaskCount(int count, int containerWidth, + int containerHeight, float screenRatio, int padding, List margins, + int titleBarHeight, Rect preCalculatedTile, VerticalGravity gravity) { + ArrayList 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, 9); + count = Math.min(count, RecentsGridActivity.MAX_VISIBLE_TASKS); 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)); - } + if (count <= 3) { + // Base case: single line. + int taskWidth, taskHeight; + if (preCalculatedTile != null) { + taskWidth = preCalculatedTile.width(); + taskHeight = preCalculatedTile.height(); } 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)); + // 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 rectsA = getRectsForTaskCount( - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, - null); - List rectsB = getRectsForTaskCount( - count - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, - padding, rectsA.get(0)); - for (Rect rect : rectsB) { - rect.offset(0, lineHeight + padding); + List rectsA = getRectsForTaskCount(lineTaskCount, containerWidth, lineHeight, + screenRatio, padding, ZERO_MARGIN, titleBarHeight, null, VerticalGravity.END); + List 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); @@ -86,19 +131,22 @@ class TaskGridLayoutAlgorithm { // Three lines. int lineHeight = (containerHeight - 2 * padding) / 3; int lineTaskCount = (int) Math.ceil((double) count / 3); - List rectsA = getRectsForTaskCount( - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, null); - List rectsB = getRectsForTaskCount( - lineTaskCount, containerWidth, lineHeight, true /* allowLineOfThree */, padding, - rectsA.get(0)); - List rectsC = getRectsForTaskCount( - count - (2 * lineTaskCount), containerWidth, lineHeight, - true /* allowLineOfThree */, padding, rectsA.get(0)); - for (Rect rect : rectsB) { - rect.offset(0, lineHeight + padding); + List rectsA = getRectsForTaskCount(lineTaskCount, containerWidth, lineHeight, + screenRatio, padding, ZERO_MARGIN, titleBarHeight, null, VerticalGravity.END); + List rectsB = getRectsForTaskCount(lineTaskCount, containerWidth, lineHeight, + screenRatio, padding, ZERO_MARGIN, titleBarHeight, rectsA.get(0), + VerticalGravity.END); + List 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 (Rect rect : rectsC) { - rect.offset(0, 2 * (lineHeight + padding)); + 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); diff --git a/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java b/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java index 74b6127448701..a9f811b2cee6b 100644 --- a/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java +++ b/packages/SystemUI/tests/src/com/android/systemui/recents/grid/TaskGridLayoutAlgorithmTest.java @@ -19,39 +19,44 @@ import android.graphics.Rect; import android.test.suitebuilder.annotation.SmallTest; import com.android.systemui.SysuiTestCase; +import java.util.ArrayList; +import java.util.Arrays; import java.util.List; import static junit.framework.Assert.assertEquals; import static junit.framework.Assert.assertTrue; +import org.junit.Test; + @SmallTest public class TaskGridLayoutAlgorithmTest extends SysuiTestCase { - public void testMethodName_ExpectedBehavior() { - assertTrue(true); - } + private static final List ZERO_MARGIN = TaskGridLayoutAlgorithm.ZERO_MARGIN; + @Test public void testOneTile() { List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - 1, 1000, 500, false /* allowLineOfThree */, 0 /* padding */); + 1, 1000, 1000, 1 /* screenRatio */, 0 /* padding */, ZERO_MARGIN, 0); assertEquals(1, rects.size()); Rect singleRect = rects.get(0); assertEquals(1000, singleRect.width()); } + @Test public void testTwoTilesLandscape() { List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - 2, 1200, 500, false /* allowLineOfThree */, 0 /* padding */); + 2, 1200, 500, 1.2f /* screenRatio */, 0 /* padding */, ZERO_MARGIN, 0); assertEquals(2, rects.size()); for (Rect rect : rects) { assertEquals(600, rect.width()); - assertEquals(500, rect.height()); + assertEquals(499, rect.height()); } } + @Test public void testTwoTilesLandscapeWithPadding() { List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - 2, 1200, 500, false /* allowLineOfThree */, 10 /* padding */); + 2, 1200, 500, 1.19f /* screenRatio */, 10 /* padding */, ZERO_MARGIN, 0); assertEquals(2, rects.size()); Rect rectA = rects.get(0); Rect rectB = rects.get(1); @@ -60,46 +65,46 @@ public class TaskGridLayoutAlgorithmTest extends SysuiTestCase { assertEquals(605, rectB.left); } + @Test public void testTwoTilesPortrait() { List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - 2, 500, 1200, false /* allowLineOfThree */, 0 /* padding */); + 2, 500, 1200, 1 /* screenRatio */, 0 /* padding */, ZERO_MARGIN, 0); assertEquals(2, rects.size()); for (Rect rect : rects) { - assertEquals(500, rect.width()); - assertEquals(600, rect.height()); - } - } - - public void testThreeTiles() { - List 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.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); } + @Test + public void testThreeTiles() { + List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( + 3, 1200, 500, 2 /* screenRatio */, 0 /* padding */, ZERO_MARGIN, 0); + assertEquals(3, rects.size()); + for (Rect rect : rects) { + assertEquals(400, rect.width()); + assertEquals(200, rect.height()); + } + } + + @Test public void testFourTiles() { List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - 4, 1200, 500, false /* allowLineOfThree */, 0 /* padding */); + 4, 1200, 500, 2.4f /* screenRatio */, 0 /* padding */, ZERO_MARGIN, 0); assertEquals(4, rects.size()); for (Rect rect : rects) { assertEquals(600, rect.width()); - assertEquals(250, rect.height()); + assertEquals(249, rect.height()); } Rect rectD = rects.get(3); assertEquals(600, rectD.left); assertEquals(250, rectD.top); } + @Test public void testNineTiles() { List rects = TaskGridLayoutAlgorithm.getRectsForTaskCount( - 9, 1200, 600, false /* allowLineOfThree */, 0 /* padding */); + 9, 1200, 600, 2 /* screenRatio */, 0 /* padding */, ZERO_MARGIN, 0); assertEquals(9, rects.size()); for (Rect rect : rects) { assertEquals(400, rect.width());