Merge "Smarter task laying out based off onMeasure" into ub-launcher3-master
diff --git a/go/quickstep/res/layout/icon_recents_root_view.xml b/go/quickstep/res/layout/icon_recents_root_view.xml
index 6300882..6dc293f 100644
--- a/go/quickstep/res/layout/icon_recents_root_view.xml
+++ b/go/quickstep/res/layout/icon_recents_root_view.xml
@@ -29,7 +29,6 @@
android:id="@+id/recent_task_recycler_view"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_weight="1"
android:scrollbars="none"/>
<Button
android:id="@+id/clear_all_button"
diff --git a/go/quickstep/res/layout/task_item_view.xml b/go/quickstep/res/layout/task_item_view.xml
index 2198237..1483d4c 100644
--- a/go/quickstep/res/layout/task_item_view.xml
+++ b/go/quickstep/res/layout/task_item_view.xml
@@ -17,25 +17,23 @@
<com.android.quickstep.views.TaskItemView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
- android:layout_height="wrap_content"
+ android:layout_height="match_parent"
android:orientation="horizontal">
- <FrameLayout
+ <com.android.quickstep.views.TaskThumbnailIconView
android:id="@+id/task_icon_and_thumbnail"
android:layout_width="match_parent"
android:layout_height="match_parent"
- android:layout_gravity="center_vertical"
- android:layout_marginHorizontal="8dp">
+ android:layout_marginHorizontal="8dp"
+ android:layout_marginTop="16dp">
<ImageView
android:id="@+id/task_thumbnail"
- android:layout_width="wrap_content"
- android:layout_height="match_parent"
- android:layout_gravity="top|start"/>
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
<ImageView
android:id="@+id/task_icon"
- android:layout_width="wrap_content"
- android:layout_height="wrap_content"
- android:layout_gravity="bottom|end"/>
- </FrameLayout>
+ android:layout_width="match_parent"
+ android:layout_height="match_parent"/>
+ </com.android.quickstep.views.TaskThumbnailIconView>
<TextView
android:id="@+id/task_label"
android:layout_width="wrap_content"
diff --git a/go/quickstep/src/com/android/quickstep/TaskAdapter.java b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
index f1fc9de..7e7f278 100644
--- a/go/quickstep/src/com/android/quickstep/TaskAdapter.java
+++ b/go/quickstep/src/com/android/quickstep/TaskAdapter.java
@@ -15,11 +15,6 @@
*/
package com.android.quickstep;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
-import static com.android.quickstep.views.TaskLayoutUtils.getTaskHeight;
-import static com.android.quickstep.views.TaskLayoutUtils.getTaskTopMargin;
-
import android.view.LayoutInflater;
import android.view.ViewGroup;
@@ -45,13 +40,11 @@
private static final String TAG = "TaskAdapter";
private final TaskListLoader mLoader;
- private final DeviceProfile mDeviceProfile;
private TaskActionController mTaskActionController;
private boolean mIsShowingLoadingUi;
- public TaskAdapter(@NonNull TaskListLoader loader, DeviceProfile dp) {
+ public TaskAdapter(@NonNull TaskListLoader loader) {
mLoader = loader;
- mDeviceProfile = dp;
}
public void setActionController(TaskActionController taskActionController) {
@@ -74,11 +67,6 @@
public TaskHolder onCreateViewHolder(ViewGroup parent, int viewType) {
TaskItemView itemView = (TaskItemView) LayoutInflater.from(parent.getContext())
.inflate(R.layout.task_item_view, parent, false);
- ViewGroup.MarginLayoutParams itemViewParams =
- (ViewGroup.MarginLayoutParams) itemView.getLayoutParams();
- itemViewParams.width = MATCH_PARENT;
- itemViewParams.height = getTaskHeight(mDeviceProfile);
- itemViewParams.topMargin = getTaskTopMargin(mDeviceProfile);
TaskHolder holder = new TaskHolder(itemView);
itemView.setOnClickListener(view -> mTaskActionController.launchTask(holder));
return holder;
diff --git a/go/quickstep/src/com/android/quickstep/TaskLayoutManager.java b/go/quickstep/src/com/android/quickstep/TaskLayoutManager.java
new file mode 100644
index 0000000..ecb2499
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/TaskLayoutManager.java
@@ -0,0 +1,42 @@
+/*
+ * Copyright (C) 2019 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.quickstep;
+
+import android.content.Context;
+import android.view.View;
+
+import androidx.annotation.NonNull;
+import androidx.recyclerview.widget.LinearLayoutManager;
+
+/**
+ * Layout manager for task list that restricts child height based off the max number of tasks the
+ * recycler view should hold and the height of the recycler view.
+ */
+public final class TaskLayoutManager extends LinearLayoutManager {
+
+ public TaskLayoutManager(Context context, int vertical, boolean b) {
+ super(context, vertical, b);
+ }
+
+ @Override
+ public void measureChildWithMargins(@NonNull View child, int widthUsed, int heightUsed) {
+ // Request child view takes up 1 / MAX_TASKS of the total view height.
+ int heightUsedByView = (int) (getHeight() *
+ (TaskAdapter.MAX_TASKS_TO_DISPLAY - 1.0f) / TaskAdapter.MAX_TASKS_TO_DISPLAY);
+ super.measureChildWithMargins(child, widthUsed, heightUsedByView);
+ }
+}
diff --git a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
index 2c4abc5..712b9dc 100644
--- a/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
+++ b/go/quickstep/src/com/android/quickstep/views/IconRecentsView.java
@@ -43,7 +43,6 @@
import androidx.annotation.Nullable;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.ItemTouchHelper;
-import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.recyclerview.widget.RecyclerView.AdapterDataObserver;
import androidx.recyclerview.widget.RecyclerView.OnChildAttachStateChangeListener;
@@ -56,6 +55,7 @@
import com.android.quickstep.TaskActionController;
import com.android.quickstep.TaskAdapter;
import com.android.quickstep.TaskHolder;
+import com.android.quickstep.TaskLayoutManager;
import com.android.quickstep.TaskListLoader;
import com.android.quickstep.TaskSwipeCallback;
@@ -121,7 +121,7 @@
mContext = context;
mDeviceProfile = activity.getDeviceProfile();
mTaskLoader = new TaskListLoader(mContext);
- mTaskAdapter = new TaskAdapter(mTaskLoader, mDeviceProfile);
+ mTaskAdapter = new TaskAdapter(mTaskLoader);
mTaskActionController = new TaskActionController(mTaskLoader, mTaskAdapter);
mTaskAdapter.setActionController(mTaskActionController);
}
@@ -135,7 +135,7 @@
recyclerViewParams.height = getTaskListHeight(mDeviceProfile);
mTaskRecyclerView.setAdapter(mTaskAdapter);
mTaskRecyclerView.setLayoutManager(
- new LinearLayoutManager(mContext, VERTICAL, true /* reverseLayout */));
+ new TaskLayoutManager(mContext, VERTICAL, true /* reverseLayout */));
ItemTouchHelper helper = new ItemTouchHelper(
new TaskSwipeCallback(mTaskActionController));
helper.attachToRecyclerView(mTaskRecyclerView);
@@ -170,6 +170,8 @@
updateContentViewVisibility();
}
});
+ // TODO: Move clear all button to recycler view so that it can scroll off screen.
+ // TODO: Move layout param logic into onMeasure
mClearAllView = findViewById(R.id.clear_all_button);
MarginLayoutParams clearAllParams =
(MarginLayoutParams) mClearAllView.getLayoutParams();
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
index 4392c68..572747b 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskItemView.java
@@ -15,8 +15,6 @@
*/
package com.android.quickstep.views;
-import static android.view.ViewGroup.LayoutParams.MATCH_PARENT;
-
import android.content.Context;
import android.content.res.Resources;
import android.graphics.Bitmap;
@@ -25,8 +23,6 @@
import android.util.AttributeSet;
import android.util.FloatProperty;
import android.view.View;
-import android.view.ViewGroup;
-import android.widget.FrameLayout;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
@@ -43,7 +39,6 @@
private static final String EMPTY_LABEL = "";
private static final String DEFAULT_LABEL = "...";
- private static final float SUBITEM_FRAME_RATIO = .6f;
private final Drawable mDefaultIcon;
private final Drawable mDefaultThumbnail;
private final TaskLayerDrawable mIconDrawable;
@@ -51,7 +46,6 @@
private TextView mLabelView;
private ImageView mIconView;
private ImageView mThumbnailView;
- private FrameLayout mThumbnailIconFrame;
private float mContentTransitionProgress;
/**
@@ -86,7 +80,6 @@
mLabelView = findViewById(R.id.task_label);
mThumbnailView = findViewById(R.id.task_thumbnail);
mIconView = findViewById(R.id.task_icon);
- mThumbnailIconFrame = findViewById(R.id.task_icon_and_thumbnail);
mThumbnailView.setImageDrawable(mThumbnailDrawable);
mIconView.setImageDrawable(mIconDrawable);
@@ -95,31 +88,6 @@
CONTENT_TRANSITION_PROGRESS.setValue(this, 1.0f);
}
- @Override
- public void setLayoutParams(ViewGroup.LayoutParams params) {
- super.setLayoutParams(params);
-
- // TODO: Rather than setting child layout params, make custom views and override onMeasure.
- if (mThumbnailIconFrame == null
- || mIconView == null
- || mThumbnailView == null) {
- // Views not initialized yet.
- return;
- }
-
- int frameSize = params.height;
- ViewGroup.LayoutParams frameParams = mThumbnailIconFrame.getLayoutParams();
- frameParams.width = frameSize;
-
- int frameSubItemWidth = (int) (SUBITEM_FRAME_RATIO * frameSize);
- ViewGroup.LayoutParams thumbnailParams = mThumbnailView.getLayoutParams();
- thumbnailParams.width = frameSubItemWidth;
-
- ViewGroup.LayoutParams iconParams = mIconView.getLayoutParams();
- iconParams.width = frameSubItemWidth;
- iconParams.height = frameSubItemWidth;
- }
-
/**
* Resets task item view to empty, loading UI.
*/
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskLayoutUtils.java b/go/quickstep/src/com/android/quickstep/views/TaskLayoutUtils.java
index 1b50707..5bb30ad 100644
--- a/go/quickstep/src/com/android/quickstep/views/TaskLayoutUtils.java
+++ b/go/quickstep/src/com/android/quickstep/views/TaskLayoutUtils.java
@@ -26,23 +26,9 @@
private static final float BUTTON_TO_DEVICE_HEIGHT_RATIO = 36.0f/569;
private static final float BUTTON_WIDTH_TO_HEIGHT_RATIO = 53.0f/18;
private static final float BUTTON_MARGIN_TO_BUTTON_HEIGHT_RATIO = 5.0f/9;
- private static final float TASK_TO_DEVICE_HEIGHT_RATIO = 15.0f/19;
- private static final float TASK_MARGIN_TO_TASK_HEIGHT_RATIO = 4.0f/15;
private TaskLayoutUtils() {}
- public static int getTaskHeight(DeviceProfile dp) {
- return (int) (TASK_TO_DEVICE_HEIGHT_RATIO * getTaskItemSpace(dp));
- }
-
- public static int getTaskTopMargin(DeviceProfile dp) {
- return (int) (TASK_MARGIN_TO_TASK_HEIGHT_RATIO * getTaskHeight(dp));
- }
-
- private static int getTaskItemSpace(DeviceProfile dp) {
- return getTaskListHeight(dp) / TaskAdapter.MAX_TASKS_TO_DISPLAY;
- }
-
public static int getTaskListHeight(DeviceProfile dp) {
int clearAllSpace = getClearAllButtonHeight(dp) + 2 * getClearAllButtonTopBottomMargin(dp);
return getDeviceLongWidth(dp) - clearAllSpace;
diff --git a/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java b/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java
new file mode 100644
index 0000000..b1c60dd
--- /dev/null
+++ b/go/quickstep/src/com/android/quickstep/views/TaskThumbnailIconView.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright (C) 2019 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.quickstep.views;
+
+import android.content.Context;
+import android.graphics.Rect;
+import android.util.AttributeSet;
+import android.view.Gravity;
+import android.view.View;
+import android.view.ViewGroup;
+
+import com.android.launcher3.R;
+
+/**
+ * Square view that holds thumbnail and icon and shrinks them appropriately so that both fit nicely
+ * within the view. Side length is determined by height.
+ */
+final class TaskThumbnailIconView extends ViewGroup {
+ private final Rect mTmpFrameRect = new Rect();
+ private final Rect mTmpChildRect = new Rect();
+ private View mThumbnailView;
+ private View mIconView;
+ private static final float SUBITEM_FRAME_RATIO = .6f;
+
+ public TaskThumbnailIconView(Context context, AttributeSet attrs) {
+ super(context, attrs);
+ }
+
+ @Override
+ protected void onFinishInflate() {
+ super.onFinishInflate();
+ mThumbnailView = findViewById(R.id.task_thumbnail);
+ mIconView = findViewById(R.id.task_icon);
+ }
+
+ @Override
+ protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
+ int height = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
+ int width = height;
+ setMeasuredDimension(width, height);
+
+ int subItemSize = (int) (SUBITEM_FRAME_RATIO * height);
+ if (mThumbnailView.getVisibility() != GONE) {
+ int thumbnailHeightSpec = MeasureSpec.makeMeasureSpec(height, MeasureSpec.EXACTLY);
+ int thumbnailWidthSpec = MeasureSpec.makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
+ measureChild(mThumbnailView, thumbnailWidthSpec, thumbnailHeightSpec);
+ }
+ if (mIconView.getVisibility() != GONE) {
+ int iconHeightSpec = MeasureSpec.makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
+ int iconWidthSpec = MeasureSpec.makeMeasureSpec(subItemSize, MeasureSpec.EXACTLY);
+ measureChild(mIconView, iconWidthSpec, iconHeightSpec);
+ }
+ }
+
+ @Override
+ protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
+ mTmpFrameRect.left = getPaddingLeft();
+ mTmpFrameRect.right = right - left - getPaddingRight();
+ mTmpFrameRect.top = getPaddingTop();
+ mTmpFrameRect.bottom = bottom - top - getPaddingBottom();
+
+ // Layout the thumbnail to the top-start corner of the view
+ if (mThumbnailView.getVisibility() != GONE) {
+ final int width = mThumbnailView.getMeasuredWidth();
+ final int height = mThumbnailView.getMeasuredHeight();
+
+ final int thumbnailGravity = Gravity.TOP | Gravity.START;
+ Gravity.apply(thumbnailGravity, width, height, mTmpFrameRect, mTmpChildRect);
+
+ mThumbnailView.layout(mTmpChildRect.left, mTmpChildRect.top,
+ mTmpChildRect.right, mTmpChildRect.bottom);
+ }
+
+ // Layout the icon to the bottom-end corner of the view
+ if (mIconView.getVisibility() != GONE) {
+ final int width = mIconView.getMeasuredWidth();
+ final int height = mIconView.getMeasuredHeight();
+
+ int thumbnailGravity = Gravity.BOTTOM | Gravity.END;
+ Gravity.apply(thumbnailGravity, width, height, mTmpFrameRect, mTmpChildRect);
+
+ mIconView.layout(mTmpChildRect.left, mTmpChildRect.top,
+ mTmpChildRect.right, mTmpChildRect.bottom);
+ }
+ }
+}