diff --git a/Android.bp b/Android.bp index d04dca0dfc..f79c18657b 100644 --- a/Android.bp +++ b/Android.bp @@ -258,8 +258,8 @@ android_library { "go/quickstep/res", ], static_libs: [ - "Launcher3CommonDepsLib", "QuickstepResLib", + "Launcher3CommonDepsLib", ], manifest: "quickstep/AndroidManifest-launcher.xml", additional_manifests: [ @@ -278,16 +278,15 @@ android_library { srcs: [ ":launcher-src-no-build-config", ], - resource_dirs: [ - "quickstep/res", - ], + resource_dirs: [], libs: [ "framework-statsd", ], static_libs: [ + "QuickstepResLib", "SystemUI-statsd", "SystemUISharedLib", - "Launcher3CommonDepsLib" + "Launcher3CommonDepsLib", ], manifest: "quickstep/AndroidManifest.xml", platform_apis: true, diff --git a/quickstep/res/drawable/task_menu_item_bg.xml b/quickstep/res/drawable/task_menu_item_bg.xml index b6a8b909ee..16c13ebebc 100644 --- a/quickstep/res/drawable/task_menu_item_bg.xml +++ b/quickstep/res/drawable/task_menu_item_bg.xml @@ -15,7 +15,8 @@ limitations under the License. --> - - - + + + diff --git a/quickstep/res/layout/task_menu_with_arrow.xml b/quickstep/res/layout/task_menu_with_arrow.xml new file mode 100644 index 0000000000..38573fd1e5 --- /dev/null +++ b/quickstep/res/layout/task_menu_with_arrow.xml @@ -0,0 +1,33 @@ + + + + + + + \ No newline at end of file diff --git a/quickstep/res/layout/task_view_menu_option.xml b/quickstep/res/layout/task_view_menu_option.xml index 5978b97dd4..8a8fc36b84 100644 --- a/quickstep/res/layout/task_view_menu_option.xml +++ b/quickstep/res/layout/task_view_menu_option.xml @@ -18,7 +18,7 @@ xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" - android:orientation="vertical" + android:orientation="horizontal" android:paddingTop="@dimen/task_card_menu_option_vertical_padding" android:paddingBottom="@dimen/task_card_menu_option_vertical_padding" android:background="@drawable/task_menu_item_bg" diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index 98d43f1bbc..8649a1d56c 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -27,7 +27,7 @@ 22dp 4dp 2dp - 200dp + 234dp 48dp 16dp @@ -90,7 +90,7 @@ 8dp 8dp 3dp - 12dp + 16dp 10dp diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/src/com/android/quickstep/views/TaskMenuView.java index 77ac373827..2690a2a054 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/src/com/android/quickstep/views/TaskMenuView.java @@ -270,15 +270,9 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange BaseDragLayer.LayoutParams params = (BaseDragLayer.LayoutParams) getLayoutParams(); int padding = getResources() .getDimensionPixelSize(R.dimen.task_menu_vertical_padding); - if (deviceProfile.overviewShowAsGrid) { - // TODO(b/193432925) temporary so it doesn't look terrible on large screen - params.width = - getContext().getResources().getDimensionPixelSize(R.dimen.task_menu_width_grid); - } else { - params.width = orientationHandler - .getTaskMenuWidth(taskContainer.getThumbnailView(), - deviceProfile) - (2 * padding); - } + params.width = orientationHandler + .getTaskMenuWidth(taskContainer.getThumbnailView(), + deviceProfile) - (2 * padding); // Gravity set to Left instead of Start as sTempRect.left measures Left distance not Start params.gravity = Gravity.LEFT; setLayoutParams(params); diff --git a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt index 9b86c73170..39a6fc4668 100644 --- a/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt +++ b/quickstep/src/com/android/quickstep/views/TaskMenuViewWithArrow.kt @@ -1,14 +1,150 @@ package com.android.quickstep.views -import android.util.Log +import android.animation.AnimatorSet +import android.animation.ObjectAnimator +import android.content.Context +import android.graphics.Rect +import android.graphics.drawable.ShapeDrawable +import android.graphics.drawable.shapes.RectShape +import android.util.AttributeSet +import android.view.MotionEvent +import android.view.View +import android.view.ViewGroup +import android.widget.LinearLayout +import com.android.launcher3.BaseDraggingActivity +import com.android.launcher3.DeviceProfile +import com.android.launcher3.R +import com.android.launcher3.popup.ArrowPopup +import com.android.launcher3.popup.SystemShortcut +import com.android.launcher3.util.Themes +import com.android.quickstep.TaskOverlayFactory +import com.android.quickstep.views.TaskView.TaskIdAttributeContainer -// TODO(http://b/193432925) -class TaskMenuViewWithArrow { +class TaskMenuViewWithArrow : ArrowPopup { companion object { const val TAG = "TaskMenuViewWithArrow" - fun logSomething() { - Log.d(TAG, "It worked!") + fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean { + val activity = BaseDraggingActivity + .fromContext(taskContainer.taskView.context) + val taskMenuViewWithArrow = activity.layoutInflater + .inflate(R.layout.task_menu_with_arrow, activity.dragLayer, false) as TaskMenuViewWithArrow<*> + + return taskMenuViewWithArrow.populateAndShowForTask(taskContainer) } } + + constructor(context: Context) : super(context) + constructor(context: Context, attrs: AttributeSet) : super(context, attrs) + constructor(context: Context, attrs: AttributeSet, defStyleAttr: Int) : super(context, attrs, defStyleAttr) + + init { + clipToOutline = true + } + + private val menuWidth = context.resources.getDimensionPixelSize(R.dimen.task_menu_width_grid) + + private lateinit var taskView: TaskView + private lateinit var optionLayout: LinearLayout + private lateinit var taskContainer: TaskIdAttributeContainer + + override fun isOfType(type: Int): Boolean = type and TYPE_TASK_MENU != 0 + + override fun getTargetObjectLocation(outPos: Rect?) { + popupContainer.getDescendantRectRelativeToSelf(taskView.iconView, outPos) + } + + override fun onControllerInterceptTouchEvent(ev: MotionEvent?): Boolean { + if (ev?.action == MotionEvent.ACTION_DOWN) { + if (!popupContainer.isEventOverView(this, ev)) { + close(true) + return true + } + } + return false + } + + override fun onFinishInflate() { + super.onFinishInflate() + optionLayout = findViewById(R.id.menu_option_layout) + } + + private fun populateAndShowForTask(taskContainer: TaskIdAttributeContainer): Boolean { + if (isAttachedToWindow) { + return false + } + + taskView = taskContainer.taskView + this.taskContainer = taskContainer + if (!populateMenu()) return false + show() + return true + } + + /** @return true if successfully able to populate task view menu, false otherwise + */ + private fun populateMenu(): Boolean { + // Icon may not be loaded + if (taskContainer.task.icon == null) return false + + addMenuOptions() + return true + } + + private fun addMenuOptions() { + // Add the options + TaskOverlayFactory + .getEnabledShortcuts(taskView, mActivityContext.deviceProfile, taskContainer) + .forEach { this.addMenuOption(it) } + + // Add the spaces between items + val divider = ShapeDrawable(RectShape()) + divider.paint.color = resources.getColor(android.R.color.transparent) + val dividerSpacing = resources.getDimension(R.dimen.task_menu_spacing).toInt() + optionLayout.showDividers = SHOW_DIVIDER_MIDDLE + + // Set the orientation, which makes the menu show + val recentsView: RecentsView<*, *> = mActivityContext.getOverviewPanel() + val orientationHandler = recentsView.pagedOrientationHandler + val deviceProfile: DeviceProfile = mActivityContext.deviceProfile + orientationHandler.setTaskOptionsMenuLayoutOrientation( + deviceProfile, + optionLayout, + dividerSpacing, + divider + ) + } + + private fun addMenuOption(menuOption: SystemShortcut<*>) { + val menuOptionView = mActivityContext.layoutInflater.inflate( + R.layout.task_view_menu_option, this, false + ) as LinearLayout + menuOption.setIconAndLabelFor( + menuOptionView.findViewById(R.id.icon), + menuOptionView.findViewById(R.id.text) + ) + val lp = menuOptionView.layoutParams as LayoutParams + lp.width = menuWidth + menuOptionView.setOnClickListener { view: View? -> menuOption.onClick(view) } + optionLayout.addView(menuOptionView) + } + + override fun assignMarginsAndBackgrounds(viewGroup: ViewGroup) { + assignMarginsAndBackgrounds(this, Themes.getAttrColor(context, com.android.internal.R.attr.colorSurface)) + } + + override fun onCreateOpenAnimation(anim: AnimatorSet) { + anim.play( + ObjectAnimator.ofFloat( + taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, + TaskView.MAX_PAGE_SCRIM_ALPHA + ) + ) + } + + override fun onCreateCloseAnimation(anim: AnimatorSet) { + anim.play( + ObjectAnimator.ofFloat(taskContainer.thumbnailView, TaskThumbnailView.DIM_ALPHA, 0f) + ) + } } \ No newline at end of file diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index f88b243cab..df1817ed1c 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -824,9 +824,11 @@ public class TaskView extends FrameLayout implements Reusable { } protected boolean showTaskMenuWithContainer(IconView iconView) { - // TODO(http://b/193432925) - if (DEBUG) TaskMenuViewWithArrow.Companion.logSomething(); - return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]); + if (mActivity.getDeviceProfile().overviewShowAsGrid) { + return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]); + } else { + return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]); + } } protected void setIcon(IconView iconView, Drawable icon) { diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 223091485c..5a1e4bf27e 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -234,7 +234,7 @@ public abstract class ArrowPopup * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColorIds}. * Otherwise, we will use this color for all child views. */ - private void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) { + protected void assignMarginsAndBackgrounds(ViewGroup viewGroup, int backgroundColor) { int[] colors = null; if (backgroundColor == Color.TRANSPARENT) { // Lazily get the colors so they match the current wallpaper colors. @@ -445,7 +445,7 @@ public abstract class ArrowPopup animateOpen(); } - private void setupForDisplay() { + protected void setupForDisplay() { setVisibility(View.INVISIBLE); mIsOpen = true; getPopupContainer().addView(this); @@ -482,7 +482,7 @@ public abstract class ArrowPopup mArrow.setVisibility(show && shouldAddArrow() ? VISIBLE : INVISIBLE); } - private void addArrow() { + protected void addArrow() { getPopupContainer().addView(mArrow); mArrow.setX(getX() + getArrowLeft()); @@ -686,12 +686,13 @@ public abstract class ArrowPopup return getChildCount() > 0 ? getChildAt(0) : this; } - private void animateOpen() { + protected void animateOpen() { setVisibility(View.VISIBLE); mOpenCloseAnimator = getOpenCloseAnimator(true, OPEN_DURATION, OPEN_FADE_START_DELAY, OPEN_FADE_DURATION, OPEN_CHILD_FADE_START_DELAY, OPEN_CHILD_FADE_DURATION, DECELERATED_EASE); + onCreateOpenAnimation(mOpenCloseAnimator); mOpenCloseAnimator.addListener(new AnimatorListenerAdapter() { @Override public void onAnimationEnd(Animator animation) { @@ -784,6 +785,11 @@ public abstract class ArrowPopup mOpenCloseAnimator.start(); } + /** + * Called when creating the open transition allowing subclass can add additional animations. + */ + protected void onCreateOpenAnimation(AnimatorSet anim) { } + /** * Called when creating the close transition allowing subclass can add additional animations. */