launcher: use a different task menu for foldables
Foldables use a different menu from phones, positioned either to the right or left of the app icon, and display an arrow. Since TaskMenuView is very specific for handhelds, it was cleaner to create another class to handle foldables case extending from ArrowPopup. This creates a working menu, the correct style will come in later CLs. Bug: 193432925 Test: open Overview and tap the app icon Fixes: 205298731 Test: atest NexusLauncherTests Change-Id: I7a5c1fb4800a309f40fadb2df0f6c3a4c3f42679
This commit is contained in:
parent
2e2f49e8a5
commit
c335ad28a2
|
@ -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,
|
||||
|
|
|
@ -15,7 +15,8 @@
|
|||
limitations under the License.
|
||||
-->
|
||||
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<solid android:color="?android:attr/colorPrimary"/>
|
||||
<corners android:radius="@dimen/task_menu_item_corner_radius"/>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:androidprv="http://schemas.android.com/apk/prv/res/android">
|
||||
<solid android:color="?androidprv:attr/colorSurface" />
|
||||
<corners android:radius="@dimen/task_menu_item_corner_radius" />
|
||||
</shape>
|
||||
|
|
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
Copyright (C) 2021 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.
|
||||
-->
|
||||
<com.android.quickstep.views.TaskMenuViewWithArrow
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:animateLayoutChanges="true"
|
||||
android:background="@drawable/task_menu_bg"
|
||||
android:orientation="vertical"
|
||||
android:visibility="invisible">
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/menu_option_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:showDividers="middle" />
|
||||
|
||||
</com.android.quickstep.views.TaskMenuViewWithArrow>
|
|
@ -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"
|
||||
|
|
|
@ -27,7 +27,7 @@
|
|||
<dimen name="task_menu_corner_radius">22dp</dimen>
|
||||
<dimen name="task_menu_item_corner_radius">4dp</dimen>
|
||||
<dimen name="task_menu_spacing">2dp</dimen>
|
||||
<dimen name="task_menu_width_grid">200dp</dimen>
|
||||
<dimen name="task_menu_width_grid">234dp</dimen>
|
||||
<dimen name="overview_proactive_row_height">48dp</dimen>
|
||||
<dimen name="overview_proactive_row_bottom_margin">16dp</dimen>
|
||||
|
||||
|
@ -91,7 +91,7 @@
|
|||
<dimen name="task_menu_vertical_padding">8dp</dimen>
|
||||
<dimen name="task_card_margin">8dp</dimen>
|
||||
<dimen name="task_card_menu_shadow_height">3dp</dimen>
|
||||
<dimen name="task_menu_option_start_margin">12dp</dimen>
|
||||
<dimen name="task_menu_option_start_margin">16dp</dimen>
|
||||
<!-- Copied from framework resource:
|
||||
docked_stack_divider_thickness - 2 * docked_stack_divider_insets -->
|
||||
<dimen name="multi_window_task_divider_size">10dp</dimen>
|
||||
|
|
|
@ -0,0 +1,39 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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 com.android.launcher3.R;
|
||||
|
||||
/**
|
||||
* Bridge class to allow using resources in Kotlin.
|
||||
* <br/>
|
||||
* TODO(b/204069723) Can't use resources directly in Kotlin
|
||||
*/
|
||||
public class KtR {
|
||||
public static final class id {
|
||||
public static int menu_option_layout = R.id.menu_option_layout;
|
||||
}
|
||||
|
||||
public static final class dimen {
|
||||
public static int task_menu_spacing = R.dimen.task_menu_spacing;
|
||||
}
|
||||
|
||||
public static final class layout {
|
||||
public static int task_menu_with_arrow = R.layout.task_menu_with_arrow;
|
||||
public static int task_view_menu_option = R.layout.task_view_menu_option;
|
||||
}
|
||||
}
|
|
@ -118,7 +118,11 @@ public class GroupedTaskView extends TaskView {
|
|||
}
|
||||
|
||||
protected boolean showTaskMenuWithContainer(IconView iconView) {
|
||||
return TaskMenuView.showForTask(mTaskIdAttributeContainer[iconView == mIconView ? 0 : 1]);
|
||||
if (mActivity.getDeviceProfile().overviewShowAsGrid) {
|
||||
return TaskMenuViewWithArrow.Companion.showForTask(mTaskIdAttributeContainer[0]);
|
||||
} else {
|
||||
return TaskMenuView.showForTask(mTaskIdAttributeContainer[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public void updateSplitBoundsConfig(StagedSplitBounds stagedSplitBounds) {
|
||||
|
|
|
@ -34,7 +34,6 @@ import android.util.AttributeSet;
|
|||
import android.view.Gravity;
|
||||
import android.view.MotionEvent;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.view.ViewOutlineProvider;
|
||||
import android.view.ViewTreeObserver.OnScrollChangedListener;
|
||||
import android.widget.LinearLayout;
|
||||
|
@ -270,15 +269,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);
|
||||
|
@ -349,13 +342,4 @@ public class TaskMenuView extends AbstractFloatingView implements OnScrollChange
|
|||
return new RoundedRectRevealOutlineProvider(radius, radius, fromRect, toRect);
|
||||
}
|
||||
|
||||
public View findMenuItemByText(String text) {
|
||||
for (int i = mOptionLayout.getChildCount() - 1; i >= 0; --i) {
|
||||
final ViewGroup menuOptionView = (ViewGroup) mOptionLayout.getChildAt(i);
|
||||
if (text.equals(menuOptionView.<TextView>findViewById(R.id.text).getText())) {
|
||||
return menuOptionView;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,14 +1,167 @@
|
|||
/*
|
||||
* Copyright (C) 2021 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.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.KtR
|
||||
import com.android.quickstep.TaskOverlayFactory
|
||||
import com.android.quickstep.views.TaskView.TaskIdAttributeContainer
|
||||
|
||||
// TODO(http://b/193432925)
|
||||
class TaskMenuViewWithArrow {
|
||||
class TaskMenuViewWithArrow<T : BaseDraggingActivity> : ArrowPopup<T> {
|
||||
companion object {
|
||||
const val TAG = "TaskMenuViewWithArrow"
|
||||
|
||||
fun logSomething() {
|
||||
Log.d(TAG, "It worked!")
|
||||
fun showForTask(taskContainer: TaskIdAttributeContainer): Boolean {
|
||||
val activity = BaseDraggingActivity
|
||||
.fromContext<BaseDraggingActivity>(taskContainer.taskView.context)
|
||||
val taskMenuViewWithArrow = activity.layoutInflater
|
||||
.inflate(KtR.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(KtR.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(KtR.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(
|
||||
KtR.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)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -95,7 +95,6 @@ import com.android.quickstep.util.CancellableTask;
|
|||
import com.android.quickstep.util.LauncherSplitScreenListener;
|
||||
import com.android.quickstep.util.RecentsOrientedState;
|
||||
import com.android.quickstep.util.TaskCornerRadius;
|
||||
import com.android.quickstep.util.TaskViewSimulator;
|
||||
import com.android.quickstep.util.TransformParams;
|
||||
import com.android.quickstep.views.TaskThumbnailView.PreviewPositionHelper;
|
||||
import com.android.systemui.shared.recents.model.Task;
|
||||
|
@ -839,9 +838,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) {
|
||||
|
|
|
@ -234,7 +234,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
|
|||
* @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<T extends Context & ActivityContext>
|
|||
animateOpen();
|
||||
}
|
||||
|
||||
private void setupForDisplay() {
|
||||
protected void setupForDisplay() {
|
||||
setVisibility(View.INVISIBLE);
|
||||
mIsOpen = true;
|
||||
getPopupContainer().addView(this);
|
||||
|
@ -482,7 +482,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
|
|||
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<T extends Context & ActivityContext>
|
|||
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<T extends Context & ActivityContext>
|
|||
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.
|
||||
*/
|
||||
|
|
Loading…
Reference in New Issue