From e138bd19557512b2b7faa08a47e2ab344184ac18 Mon Sep 17 00:00:00 2001 From: Manu Cornet Date: Tue, 15 Nov 2016 11:32:28 -0800 Subject: [PATCH] Change the task layout to better match mocks, add "in" animation This only adds an animation when transitioning into recents. "Out" animations will come later as they need to be run in parallel with launching the activity not to introduce any latency. Test: Open recents on sw600dp device, check recents layout/animations Bug: 32101881 Change-Id: I367f8e5c106cd06d2a7833c165ecb960a7821ed9 --- packages/SystemUI/AndroidManifest.xml | 2 +- .../res/layout-sw600dp/recents_grid.xml | 19 +- .../layout/recents_stack_action_button.xml | 3 +- packages/SystemUI/res/values/attrs.xml | 2 + packages/SystemUI/res/values/dimens.xml | 15 ++ packages/SystemUI/res/values/styles.xml | 24 ++ .../recents/grid/RecentsGridActivity.java | 211 +++++++++++++----- .../recents/grid/TaskGridLayoutAlgorithm.java | 152 ++++++++----- .../grid/TaskGridLayoutAlgorithmTest.java | 57 ++--- 9 files changed, 339 insertions(+), 146 deletions(-) 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());