Merge "adding the new Material U App Shortcut Popup design" into tm-qpr-dev

This commit is contained in:
Charlie Anderson
2023-02-15 15:11:49 +00:00
committed by Android (Google) Code Review
17 changed files with 461 additions and 75 deletions

View File

@@ -15,6 +15,7 @@
*/
package com.android.launcher3.taskbar;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.util.SplitConfigurationOptions.getLogEventForPosition;
import android.content.Intent;
@@ -56,6 +57,7 @@ import com.android.quickstep.util.LogUtils;
import java.io.PrintWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;
import java.util.function.Predicate;
import java.util.stream.Collectors;
@@ -152,9 +154,28 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
return null;
}
final PopupContainerWithArrow<BaseTaskbarContext> container =
(PopupContainerWithArrow<BaseTaskbarContext>) context.getLayoutInflater().inflate(
R.layout.popup_container, context.getDragLayer(), false);
PopupContainerWithArrow<BaseTaskbarContext> container;
int deepShortcutCount = mPopupDataProvider.getShortcutCountForItem(item);
// TODO(b/198438631): add support for INSTALL shortcut factory
List<SystemShortcut> systemShortcuts = getSystemShortcuts()
.map(s -> s.getShortcut(context, item, icon))
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (ENABLE_MATERIAL_U_POPUP.get()) {
container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
R.layout.popup_container_material_u, context.getDragLayer(), false);
container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
} else {
container = (PopupContainerWithArrow) context.getLayoutInflater().inflate(
R.layout.popup_container, context.getDragLayer(), false);
container.populateAndShow(
icon,
deepShortcutCount,
mPopupDataProvider.getNotificationKeysForItem(item),
systemShortcuts);
}
container.addOnAttachStateChangeListener(
new PopupLiveUpdateHandler<BaseTaskbarContext>(context, container) {
@Override
@@ -165,15 +186,6 @@ public class TaskbarPopupController implements TaskbarControllers.LoggableTaskba
// TODO (b/198438631): configure for taskbar/context
container.setPopupItemDragHandler(new TaskbarPopupItemDragHandler());
mControllers.taskbarDragController.addDragListener(container);
container.populateAndShow(icon,
mPopupDataProvider.getShortcutCountForItem(item),
mPopupDataProvider.getNotificationKeysForItem(item),
// TODO (b/198438631): add support for INSTALL shortcut factory
getSystemShortcuts()
.map(s -> s.getShortcut(context, item, icon))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
container.requestFocus();
// Make focusable to receive back events

View File

@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<shape xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle">
<solid android:color="?attr/popupColorPrimary"/>
<corners android:radius="@dimen/dialogCornerRadius"/>
</shape>

View File

@@ -0,0 +1,24 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/deep_shortcuts_container"
android:background="@drawable/popup_background_material_u"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="@string/popup_container_iterate_children"
android:elevation="@dimen/deep_shortcuts_elevation"
android:orientation="vertical"/>

View File

@@ -0,0 +1,50 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.launcher3.shortcuts.DeepShortcutView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:launcher="http://schemas.android.com/apk/res-auto"
android:id="@+id/deep_shortcut_material"
android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="@dimen/bg_popup_item_height"
android:elevation="@dimen/deep_shortcuts_elevation"
android:background="@drawable/middle_item_primary"
android:theme="@style/PopupItem" >
<com.android.launcher3.shortcuts.DeepShortcutTextView
style="@style/BaseIcon"
android:id="@+id/bubble_text"
android:background="?android:attr/selectableItemBackground"
android:gravity="start|center_vertical"
android:textAlignment="viewStart"
android:paddingStart="@dimen/deep_shortcuts_text_padding_start"
android:paddingEnd="@dimen/popup_padding_end"
android:drawablePadding="@dimen/deep_shortcut_drawable_padding"
android:singleLine="true"
android:ellipsize="end"
android:textSize="14sp"
android:textColor="?android:attr/textColorPrimary"
launcher:layoutHorizontal="true"
launcher:iconDisplay="shortcut_popup"
launcher:iconSizeOverride="@dimen/deep_shortcut_icon_size" />
<View
android:id="@+id/icon"
android:layout_width="@dimen/deep_shortcut_icon_size"
android:layout_height="@dimen/deep_shortcut_icon_size"
android:layout_marginStart="@dimen/popup_padding_start"
android:layout_gravity="start|center_vertical"
android:background="@drawable/ic_deepshortcut_placeholder"/>
</com.android.launcher3.shortcuts.DeepShortcutView>

View File

@@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.launcher3.popup.PopupContainerWithArrow
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/popup_container"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"/>

View File

@@ -18,6 +18,7 @@
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="@dimen/bg_popup_item_width"
android:layout_height="wrap_content"
android:id="@+id/system_shortcut"
android:minHeight="@dimen/bg_popup_item_height"
android:elevation="@dimen/deep_shortcuts_elevation"
android:background="@drawable/middle_item_primary"

View File

@@ -26,7 +26,7 @@
android:clipToPadding="true">
<Space android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/separator"/>
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/separator"/>
</LinearLayout>

View File

@@ -0,0 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/system_shortcut_icons"
android:tag="@string/popup_container_iterate_children"
android:layout_width="match_parent"
android:layout_height="@dimen/system_shortcut_header_height"
android:orientation="horizontal"
android:gravity="end|center_vertical"
android:background="@drawable/popup_background_material_u"
android:elevation="@dimen/deep_shortcuts_elevation">
<Space android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1"
android:id="@+id/separator"/>
</LinearLayout>

View File

@@ -0,0 +1,25 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/system_shortcuts_container"
android:background="@drawable/popup_background_material_u"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:tag="@string/popup_container_iterate_children"
android:elevation="@dimen/deep_shortcuts_elevation"
android:orientation="vertical"/>

View File

@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright (C) 2023 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.
-->
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/widget_shortcut_container"
android:background="@drawable/popup_background_material_u"
android:layout_width="match_parent"
android:layout_height="@dimen/system_shortcut_header_height"
android:orientation="horizontal"
android:gravity="end|center_vertical"
android:elevation="@dimen/deep_shortcuts_elevation"
android:tag="@string/popup_container_iterate_children"
android:clipToPadding="true"/>

View File

@@ -348,7 +348,7 @@
<dimen name="developer_options_filter_margins">10dp</dimen>
<!-- Theming related -->
<dimen name="default_dialog_corner_radius">8dp</dimen>
<dimen name="default_dialog_corner_radius">26dp</dimen>
<dimen name="dialogCornerRadius">@dimen/default_dialog_corner_radius</dimen>
<!-- Onboarding bottomsheet related -->

View File

@@ -3211,7 +3211,7 @@ public class Launcher extends StatefulActivity<LauncherState>
}
@Override
public boolean shouldUseColorExtractionForPopup() {
public boolean canUseMultipleShadesForPopup() {
return getTopOpenViewWithType(this, TYPE_FOLDER) == null
&& getStateManager().getState() != LauncherState.ALL_APPS;
}

View File

@@ -21,6 +21,7 @@ import static androidx.core.content.ContextCompat.getColorStateList;
import static com.android.launcher3.anim.Interpolators.ACCELERATED_EASE;
import static com.android.launcher3.anim.Interpolators.DECELERATED_EASE;
import static com.android.launcher3.anim.Interpolators.LINEAR;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import android.animation.Animator;
import android.animation.AnimatorListenerAdapter;
@@ -116,7 +117,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
private final String mIterateChildrenTag;
private final int[] mColorIds;
protected final int[] mColorIds;
public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
@@ -125,8 +126,8 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
mActivityContext = ActivityContext.lookupContext(context);
mIsRtl = Utilities.isRtl(getResources());
int backgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
mArrowColor = backgroundColor;
int popupPrimaryColor = Themes.getAttrColor(context, R.attr.popupColorPrimary);
mArrowColor = popupPrimaryColor;
mElevation = getResources().getDimension(R.dimen.deep_shortcuts_elevation);
// Initialize arrow view
@@ -143,18 +144,18 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
int smallerRadius = resources.getDimensionPixelSize(R.dimen.popup_smaller_radius);
mRoundedTop = new GradientDrawable();
mRoundedTop.setColor(backgroundColor);
mRoundedTop.setColor(popupPrimaryColor);
mRoundedTop.setCornerRadii(new float[] { mOutlineRadius, mOutlineRadius, mOutlineRadius,
mOutlineRadius, smallerRadius, smallerRadius, smallerRadius, smallerRadius});
mRoundedBottom = new GradientDrawable();
mRoundedBottom.setColor(backgroundColor);
mRoundedBottom.setColor(popupPrimaryColor);
mRoundedBottom.setCornerRadii(new float[] { smallerRadius, smallerRadius, smallerRadius,
smallerRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius, mOutlineRadius});
mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children);
if (mActivityContext.shouldUseColorExtractionForPopup()) {
if (!ENABLE_MATERIAL_U_POPUP.get() && mActivityContext.canUseMultipleShadesForPopup()) {
mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second,
R.color.popup_shade_third};
} else {
@@ -241,15 +242,23 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
mlp.bottomMargin = 0;
if (colors != null) {
backgroundColor = colors[numVisibleChild % colors.length];
if (!ENABLE_MATERIAL_U_POPUP.get()) {
backgroundColor = colors[numVisibleChild % colors.length];
}
if (ENABLE_MATERIAL_U_POPUP.get() && isShortcutContainer(view)) {
setChildColor(view, colors[0], colorAnimator);
mArrowColor = colors[0];
}
}
// Arrow color matches the first child or the last child.
if (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this)) {
if (!ENABLE_MATERIAL_U_POPUP.get()
&& (mIsAboveIcon || (numVisibleChild == 0 && viewGroup == this))) {
mArrowColor = backgroundColor;
}
if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) {
if (view instanceof ViewGroup && isShortcutContainer(view)) {
assignMarginsAndBackgrounds((ViewGroup) view, backgroundColor);
numVisibleChild++;
continue;
@@ -286,6 +295,13 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
return view instanceof DeepShortcutView;
}
/**
* Returns {@code true} if view is a layout container of shortcuts
*/
boolean isShortcutContainer(View view) {
return mIterateChildrenTag.equals(view.getTag());
}
/**
* Sets the background color of the child.
*/
@@ -308,7 +324,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
*/
protected void reorderAndShow(int viewsToFlip) {
setupForDisplay();
boolean reverseOrder = mIsAboveIcon;
boolean reverseOrder = !ENABLE_MATERIAL_U_POPUP.get() && mIsAboveIcon;
if (reverseOrder) {
reverseOrder(viewsToFlip);
}
@@ -634,7 +650,7 @@ public abstract class ArrowPopup<T extends Context & ActivityContext>
for (int i = group.getChildCount() - 1; i >= 0; --i) {
View view = group.getChildAt(i);
if (view.getVisibility() == VISIBLE && view instanceof ViewGroup) {
if (mIterateChildrenTag.equals(view.getTag())) {
if (isShortcutContainer(view)) {
fadeInChildViews((ViewGroup) view, alphaValues, startDelay, duration, out);
continue;
}

View File

@@ -17,12 +17,16 @@
package com.android.launcher3.popup;
import static com.android.launcher3.LauncherSettings.Favorites.CONTAINER_SHORTCUTS;
import static com.android.launcher3.Utilities.ATLEAST_P;
import static com.android.launcher3.Utilities.squaredHypot;
import static com.android.launcher3.Utilities.squaredTouchSlop;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS;
import static com.android.launcher3.popup.PopupPopulator.MAX_SHORTCUTS_IF_NOTIFICATIONS;
import static com.android.launcher3.util.Executors.MODEL_EXECUTOR;
import static java.util.Collections.emptyList;
import android.animation.AnimatorSet;
import android.animation.LayoutTransition;
import android.annotation.TargetApi;
@@ -39,6 +43,8 @@ import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import androidx.annotation.LayoutRes;
import com.android.launcher3.AbstractFloatingView;
import com.android.launcher3.BaseDraggingActivity;
import com.android.launcher3.BubbleTextView;
@@ -82,20 +88,20 @@ import java.util.stream.Collectors;
public class PopupContainerWithArrow<T extends Context & ActivityContext>
extends ArrowPopup<T> implements DragSource, DragController.DragListener {
private final List<DeepShortcutView> mShortcuts = new ArrayList<>();
private final List<DeepShortcutView> mDeepShortcuts = new ArrayList<>();
private final PointF mInterceptTouchDown = new PointF();
private final int mStartDragThreshold;
private static final int SHORTCUT_COLLAPSE_THRESHOLD = 6;
private BubbleTextView mOriginalIcon;
private int mNumNotifications;
private NotificationContainer mNotificationContainer;
private int mContainerWidth;
private ViewGroup mWidgetContainer;
private ViewGroup mDeepShortcutContainer;
private ViewGroup mSystemShortcutContainer;
protected PopupItemDragHandler mPopupItemDragHandler;
@@ -211,19 +217,27 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
return null;
}
final PopupContainerWithArrow<Launcher> container =
(PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
container.configureForLauncher(launcher);
PopupContainerWithArrow<Launcher> container;
PopupDataProvider popupDataProvider = launcher.getPopupDataProvider();
container.populateAndShow(icon,
popupDataProvider.getShortcutCountForItem(item),
popupDataProvider.getNotificationKeysForItem(item),
launcher.getSupportedShortcuts()
.map(s -> s.getShortcut(launcher, item, icon))
.filter(Objects::nonNull)
.collect(Collectors.toList()));
int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
List<SystemShortcut> systemShortcuts = launcher.getSupportedShortcuts()
.map(s -> s.getShortcut(launcher, item, icon))
.filter(Objects::nonNull)
.collect(Collectors.toList());
if (ENABLE_MATERIAL_U_POPUP.get()) {
container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container_material_u, launcher.getDragLayer(), false);
container.populateAndShowRowsMaterialU(icon, deepShortcutCount, systemShortcuts);
} else {
container = (PopupContainerWithArrow) launcher.getLayoutInflater().inflate(
R.layout.popup_container, launcher.getDragLayer(), false);
container.populateAndShow(
icon,
deepShortcutCount,
popupDataProvider.getNotificationKeysForItem(item),
systemShortcuts);
}
container.configureForLauncher(launcher);
launcher.refreshAndBindWidgetsForPackageUser(PackageUserKey.fromItemInfo(item));
container.requestFocus();
return container;
@@ -246,7 +260,7 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
initializeSystemShortcut(R.layout.system_shortcut, this, shortcuts.get(0));
return;
}
mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons, this);
mSystemShortcutContainer = inflateAndAdd(R.layout.system_shortcut_icons_container, this);
for (SystemShortcut shortcut : shortcuts) {
initializeSystemShortcut(
R.layout.system_shortcut_icon_only, mSystemShortcutContainer,
@@ -281,17 +295,7 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
mDeepShortcutContainer = findViewById(R.id.deep_shortcuts_container);
}
if (hasDeepShortcuts) {
// Remove the widget shortcut fom the list
List<SystemShortcut> systemShortcuts = shortcuts
.stream()
.filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
.collect(Collectors.toList());
Optional<SystemShortcut.Widgets> widgetShortcutOpt = shortcuts
.stream()
.filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
.map(SystemShortcut.Widgets.class::cast)
.findFirst();
List<SystemShortcut> systemShortcuts = getNonWidgetSystemShortcuts(shortcuts);
// if there are deep shortcuts, we might want to increase the width of shortcuts to fit
// horizontally laid out system shortcuts.
mContainerWidth = Math.max(mContainerWidth,
@@ -304,10 +308,10 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
for (int i = shortcutCount; i > 0; i--) {
DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut, mDeepShortcutContainer);
v.getLayoutParams().width = mContainerWidth;
mShortcuts.add(v);
mDeepShortcuts.add(v);
}
updateHiddenShortcuts();
Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(shortcuts);
if (widgetShortcutOpt.isPresent()) {
if (mWidgetContainer == null) {
mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container,
@@ -327,21 +331,151 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
}
reorderAndShow(viewsToFlip);
showPopupContainer((ItemInfo) originalIcon.getTag(), notificationKeys);
}
ItemInfo originalItemInfo = (ItemInfo) originalIcon.getTag();
if (android.os.Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
setAccessibilityPaneTitle(getTitleForAccessibility());
/**
* Populate and show shortcuts for the Launcher U app shortcut design.
* Will inflate the container and shortcut View instances for the popup container.
* @param originalIcon App icon that the popup is shown for
* @param deepShortcutCount Number of DeepShortcutView instances to add to container
* @param systemShortcuts List of SystemShortcuts to add to container
*/
public void populateAndShowRowsMaterialU(final BubbleTextView originalIcon,
int deepShortcutCount, List<SystemShortcut> systemShortcuts) {
mOriginalIcon = originalIcon;
mContainerWidth = getResources().getDimensionPixelSize(R.dimen.bg_popup_item_width);
if (deepShortcutCount > 0) {
addAllShortcutsMaterialU(deepShortcutCount, systemShortcuts);
} else if (!systemShortcuts.isEmpty()) {
addSystemShortcutsMaterialU(systemShortcuts,
R.layout.system_shortcut_rows_container_material_u,
R.layout.system_shortcut);
}
mOriginalIcon.setForceHideDot(true);
// no reversing needed for U design
reorderAndShow(0);
showPopupContainer((ItemInfo) originalIcon.getTag(), /* notificationKeys= */ emptyList());
}
/**
* Animates and loads shortcuts on background thread for this popup container
*/
private void showPopupContainer(ItemInfo originalItemInfo,
List<NotificationKeyData> notificationKeys) {
if (ATLEAST_P) {
setAccessibilityPaneTitle(getTitleForAccessibility());
}
mOriginalIcon.setForceHideDot(true);
// All views are added. Animate layout from now on.
setLayoutTransition(new LayoutTransition());
// Load the shortcuts on a background thread and update the container as it animates.
MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(PopupPopulator.createUpdateRunnable(
mActivityContext, originalItemInfo, new Handler(Looper.getMainLooper()),
this, mShortcuts, notificationKeys));
this, mDeepShortcuts, notificationKeys));
}
/**
* Adds any Deep Shortcuts, System Shortcuts and the Widget Shortcut to their respective
* containers
* @param deepShortcutCount number of DeepShortcutView instances
* @param systemShortcuts List of SystemShortcuts
*/
private void addAllShortcutsMaterialU(int deepShortcutCount,
List<SystemShortcut> systemShortcuts) {
if (deepShortcutCount + systemShortcuts.size() <= SHORTCUT_COLLAPSE_THRESHOLD) {
// add all system shortcuts including widgets shortcut to same container
addSystemShortcutsMaterialU(systemShortcuts,
R.layout.system_shortcut_rows_container_material_u,
R.layout.system_shortcut);
addDeepShortcutsMaterialU(deepShortcutCount);
return;
}
List<SystemShortcut> nonWidgetSystemShortcuts =
getNonWidgetSystemShortcuts(systemShortcuts);
// If total shortcuts over threshold, collapse system shortcuts to single row
addSystemShortcutsMaterialU(nonWidgetSystemShortcuts,
R.layout.system_shortcut_icons_container_material_u,
R.layout.system_shortcut_icon_only);
// May need to recalculate row width
mContainerWidth = Math.max(mContainerWidth,
nonWidgetSystemShortcuts.size() * getResources()
.getDimensionPixelSize(R.dimen.system_shortcut_header_icon_touch_size));
// Add widget shortcut to separate container
Optional<SystemShortcut.Widgets> widgetShortcutOpt = getWidgetShortcut(systemShortcuts);
if (widgetShortcutOpt.isPresent()) {
mWidgetContainer = inflateAndAdd(R.layout.widget_shortcut_container_material_u,
this);
initializeWidgetShortcut(mWidgetContainer, widgetShortcutOpt.get());
}
addDeepShortcutsMaterialU(deepShortcutCount);
}
/**
* Finds the first instance of the Widgets Shortcut from the SystemShortcut List
* @param systemShortcuts List of SystemShortcut instances to search
* @return Optional Widgets SystemShortcut
*/
private static Optional<SystemShortcut.Widgets> getWidgetShortcut(
List<SystemShortcut> systemShortcuts) {
return systemShortcuts
.stream()
.filter(shortcut -> shortcut instanceof SystemShortcut.Widgets)
.map(SystemShortcut.Widgets.class::cast)
.findFirst();
}
/**
* Returns list of [systemShortcuts] without the Widgets shortcut instance if found
* @param systemShortcuts list of SystemShortcuts to filter from
* @return systemShortcuts without the Widgets Shortcut
*/
private static List<SystemShortcut> getNonWidgetSystemShortcuts(
List<SystemShortcut> systemShortcuts) {
return systemShortcuts
.stream()
.filter(shortcut -> !(shortcut instanceof SystemShortcut.Widgets))
.collect(Collectors.toList());
}
/**
* Inflates the given systemShortcutContainerLayout as a container, and populates with
* the systemShortcuts as views using the systemShortcutLayout
* @param systemShortcuts List of SystemShortcut to inflate as Views
* @param systemShortcutContainerLayout Layout Resource for the Container of shortcut Views
* @param systemShortcutLayout Layout Resource for the individual shortcut Views
*/
private void addSystemShortcutsMaterialU(List<SystemShortcut> systemShortcuts,
@LayoutRes int systemShortcutContainerLayout, @LayoutRes int systemShortcutLayout) {
if (systemShortcuts.size() == 0) {
return;
}
mSystemShortcutContainer = inflateAndAdd(systemShortcutContainerLayout, this);
for (SystemShortcut shortcut : systemShortcuts) {
initializeSystemShortcut(systemShortcutLayout, mSystemShortcutContainer, shortcut);
}
}
/**
* Inflates and adds [deepShortcutCount] number of DeepShortcutView for the to a new container
* @param deepShortcutCount number of DeepShortcutView instances to add
*/
private void addDeepShortcutsMaterialU(int deepShortcutCount) {
mDeepShortcutContainer = inflateAndAdd(R.layout.deep_shortcut_container, this);
for (int i = deepShortcutCount; i > 0; i--) {
DeepShortcutView v = inflateAndAdd(R.layout.deep_shortcut_material_u,
mDeepShortcutContainer);
v.getLayoutParams().width = mContainerWidth;
mDeepShortcuts.add(v);
}
updateHiddenShortcuts();
}
protected NotificationContainer getNotificationContainer() {
@@ -391,9 +525,9 @@ public class PopupContainerWithArrow<T extends Context & ActivityContext>
int allowedCount = mNotificationContainer != null
? MAX_SHORTCUTS_IF_NOTIFICATIONS : MAX_SHORTCUTS;
int total = mShortcuts.size();
int total = mDeepShortcuts.size();
for (int i = 0; i < total; i++) {
DeepShortcutView view = mShortcuts.get(i);
DeepShortcutView view = mDeepShortcuts.get(i);
view.setVisibility(i >= allowedCount ? GONE : VISIBLE);
}
}

View File

@@ -18,6 +18,7 @@ package com.android.launcher3.secondarydisplay;
import static android.view.View.MeasureSpec.EXACTLY;
import static android.view.View.MeasureSpec.makeMeasureSpec;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.popup.SystemShortcut.APP_INFO;
import android.content.Context;
@@ -203,14 +204,22 @@ public class SecondaryDragLayer extends BaseDragLayer<SecondaryDisplayLauncher>
systemShortcuts.add(mPinnedAppsAdapter.getSystemShortcut(item, v));
}
systemShortcuts.add(APP_INFO.getShortcut(mActivity, item, v));
final PopupContainerWithArrow container =
(PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
R.layout.popup_container, mActivity.getDragLayer(), false);
container.populateAndShow((BubbleTextView) v,
popupDataProvider.getShortcutCountForItem(item),
Collections.emptyList(), systemShortcuts);
int deepShortcutCount = popupDataProvider.getShortcutCountForItem(item);
final PopupContainerWithArrow<SecondaryDisplayLauncher> container;
if (ENABLE_MATERIAL_U_POPUP.get()) {
container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
R.layout.popup_container_material_u, mActivity.getDragLayer(), false);
container.populateAndShowRowsMaterialU((BubbleTextView) v, deepShortcutCount,
systemShortcuts);
} else {
container = (PopupContainerWithArrow) mActivity.getLayoutInflater().inflate(
R.layout.popup_container, mActivity.getDragLayer(), false);
container.populateAndShow(
(BubbleTextView) v,
deepShortcutCount,
Collections.emptyList(),
systemShortcuts);
}
container.requestFocus();
if (!FeatureFlags.SECONDARY_DRAG_N_DROP_TO_PIN.get() || !mActivity.isAppDrawerShown()) {

View File

@@ -199,9 +199,9 @@ public interface ActivityContext {
}
/**
* Returns {@code true} if popups should use color extraction.
* Returns {@code true} if popups can use a range of color shades instead of a singular color.
*/
default boolean shouldUseColorExtractionForPopup() {
default boolean canUseMultipleShadesForPopup() {
return true;
}

View File

@@ -15,12 +15,16 @@
*/
package com.android.launcher3.views;
import static androidx.core.content.ContextCompat.getColorStateList;
import static com.android.launcher3.config.FeatureFlags.ENABLE_MATERIAL_U_POPUP;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.IGNORE;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SETTINGS_BUTTON_TAP_OR_LONGPRESS;
import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_WIDGETSTRAY_BUTTON_TAP_OR_LONGPRESS;
import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.graphics.Rect;
import android.graphics.RectF;
import android.graphics.drawable.Drawable;
@@ -31,6 +35,7 @@ import android.view.MotionEvent;
import android.view.View;
import android.view.View.OnClickListener;
import android.view.View.OnLongClickListener;
import android.view.ViewGroup;
import android.widget.Toast;
import androidx.annotation.Nullable;
@@ -139,6 +144,16 @@ public class OptionsPopupView extends ArrowPopup<Launcher>
mTargetRect.roundOut(outPos);
}
@Override
public void assignMarginsAndBackgrounds(ViewGroup viewGroup) {
if (ENABLE_MATERIAL_U_POPUP.get()) {
assignMarginsAndBackgrounds(viewGroup,
getColorStateList(getContext(), mColorIds[0]).getDefaultColor());
} else {
assignMarginsAndBackgrounds(viewGroup, Color.TRANSPARENT);
}
}
public static OptionsPopupView show(ActivityContext launcher, RectF targetRect,
List<OptionItem> items, boolean shouldAddArrow) {
return show(launcher, targetRect, items, shouldAddArrow, 0 /* width */);