diff --git a/src/com/android/launcher3/Launcher.java b/src/com/android/launcher3/Launcher.java index 8a3518561f..409ee83782 100644 --- a/src/com/android/launcher3/Launcher.java +++ b/src/com/android/launcher3/Launcher.java @@ -23,9 +23,11 @@ import static android.view.View.IMPORTANT_FOR_ACCESSIBILITY_NO; import static android.view.accessibility.AccessibilityEvent.TYPE_WINDOW_STATE_CHANGED; import static com.android.launcher3.AbstractFloatingView.TYPE_ALL; +import static com.android.launcher3.AbstractFloatingView.TYPE_FOLDER; import static com.android.launcher3.AbstractFloatingView.TYPE_ICON_SURFACE; import static com.android.launcher3.AbstractFloatingView.TYPE_REBIND_SAFE; import static com.android.launcher3.AbstractFloatingView.TYPE_SNACKBAR; +import static com.android.launcher3.AbstractFloatingView.getTopOpenViewWithType; import static com.android.launcher3.LauncherAnimUtils.SPRING_LOADED_EXIT_DELAY; import static com.android.launcher3.LauncherState.ALL_APPS; import static com.android.launcher3.LauncherState.FLAG_CLOSE_POPUPS; @@ -2901,13 +2903,26 @@ public class Launcher extends StatefulActivity implements Launche * Shows the default options popup */ public void showDefaultOptions(float x, float y) { + OptionsPopupView.show(this, getPopupTarget(x, y), OptionsPopupView.getOptions(this), + false); + } + + /** + * Returns target rectangle for anchoring a popup menu. + */ + protected RectF getPopupTarget(float x, float y) { float halfSize = getResources().getDimension(R.dimen.options_menu_thumb_size) / 2; if (x < 0 || y < 0) { x = mDragLayer.getWidth() / 2; y = mDragLayer.getHeight() / 2; } - RectF target = new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize); - OptionsPopupView.show(this, target, OptionsPopupView.getOptions(this), false); + return new RectF(x - halfSize, y - halfSize, x + halfSize, y + halfSize); + } + + @Override + public boolean shouldUseColorExtractionForPopup() { + return getTopOpenViewWithType(this, TYPE_FOLDER) == null + && getStateManager().getState() != LauncherState.ALL_APPS; } @Override diff --git a/src/com/android/launcher3/popup/ArrowPopup.java b/src/com/android/launcher3/popup/ArrowPopup.java index 112a24e37f..117ae4212b 100644 --- a/src/com/android/launcher3/popup/ArrowPopup.java +++ b/src/com/android/launcher3/popup/ArrowPopup.java @@ -51,21 +51,20 @@ import android.widget.FrameLayout; import androidx.annotation.NonNull; import com.android.launcher3.AbstractFloatingView; -import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.InsettableFrameLayout; import com.android.launcher3.Launcher; -import com.android.launcher3.LauncherState; import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.Workspace; import com.android.launcher3.dragndrop.DragLayer; import com.android.launcher3.shortcuts.DeepShortcutView; -import com.android.launcher3.statemanager.StatefulActivity; import com.android.launcher3.util.Themes; +import com.android.launcher3.views.ActivityContext; import com.android.launcher3.views.BaseDragLayer; import com.android.launcher3.widget.LocalColorExtractor; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collections; import java.util.List; @@ -74,7 +73,7 @@ import java.util.List; * * @param The activity on with the popup shows */ -public abstract class ArrowPopup> +public abstract class ArrowPopup extends AbstractFloatingView { // Duration values (ms) for popup open and close animations. @@ -98,7 +97,7 @@ public abstract class ArrowPopup> protected final LayoutInflater mInflater; private final float mOutlineRadius; - protected final T mLauncher; + protected final T mActivityContext; protected final boolean mIsRtl; private final int mArrowOffsetVertical; @@ -131,13 +130,13 @@ public abstract class ArrowPopup> private final String mIterateChildrenTag; - private final int[] mColors; + private final int[] mColorIds; public ArrowPopup(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); mInflater = LayoutInflater.from(context); mOutlineRadius = Themes.getDialogCornerRadius(context); - mLauncher = BaseDraggingActivity.fromContext(context); + mActivityContext = ActivityContext.lookupContext(context); mIsRtl = Utilities.isRtl(getResources()); mBackgroundColor = Themes.getAttrColor(context, R.attr.popupColorPrimary); @@ -169,22 +168,18 @@ public abstract class ArrowPopup> mIterateChildrenTag = getContext().getString(R.string.popup_container_iterate_children); - boolean isAboveAnotherSurface = getTopOpenViewWithType(mLauncher, TYPE_FOLDER) != null - || mLauncher.getStateManager().getState() == LauncherState.ALL_APPS; - if (!isAboveAnotherSurface && Utilities.ATLEAST_S && ENABLE_LOCAL_COLOR_POPUPS.get()) { + boolean shouldUseColorExtraction = mActivityContext.shouldUseColorExtractionForPopup(); + if (shouldUseColorExtraction && Utilities.ATLEAST_S && ENABLE_LOCAL_COLOR_POPUPS.get()) { mColorExtractors = new ArrayList<>(); } else { mColorExtractors = null; } - if (isAboveAnotherSurface) { - mColors = new int[] { - getColorStateList(context, R.color.popup_shade_first).getDefaultColor()}; + if (shouldUseColorExtraction) { + mColorIds = new int[]{R.color.popup_shade_first, R.color.popup_shade_second, + R.color.popup_shade_third}; } else { - mColors = new int[] { - getColorStateList(context, R.color.popup_shade_first).getDefaultColor(), - getColorStateList(context, R.color.popup_shade_second).getDefaultColor(), - getColorStateList(context, R.color.popup_shade_third).getDefaultColor()}; + mColorIds = new int[]{R.color.popup_shade_first}; } } @@ -236,17 +231,22 @@ public abstract class ArrowPopup> } /** - * @param backgroundColor When Color.TRANSPARENT, we get color from {@link #mColors}. + * @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) { - final boolean getColorFromColorArray = backgroundColor == Color.TRANSPARENT; + int[] colors = null; + if (backgroundColor == Color.TRANSPARENT) { + // Lazily get the colors so they match the current wallpaper colors. + colors = Arrays.stream(mColorIds).map( + r -> getColorStateList(getContext(), r).getDefaultColor()).toArray(); + } int count = viewGroup.getChildCount(); int totalVisibleShortcuts = 0; for (int i = 0; i < count; i++) { View view = viewGroup.getChildAt(i); - if (view.getVisibility() == VISIBLE && view instanceof DeepShortcutView) { + if (view.getVisibility() == VISIBLE && isShortcutOrWrapper(view)) { totalVisibleShortcuts++; } } @@ -266,9 +266,8 @@ public abstract class ArrowPopup> MarginLayoutParams mlp = (MarginLayoutParams) lastView.getLayoutParams(); mlp.bottomMargin = 0; - - if (getColorFromColorArray) { - backgroundColor = mColors[numVisibleChild % mColors.length]; + if (colors != null) { + backgroundColor = colors[numVisibleChild % colors.length]; } if (view instanceof ViewGroup && mIterateChildrenTag.equals(view.getTag())) { @@ -277,7 +276,7 @@ public abstract class ArrowPopup> continue; } - if (view instanceof DeepShortcutView) { + if (isShortcutOrWrapper(view)) { if (totalVisibleShortcuts == 1) { view.setBackgroundResource(R.drawable.single_item_primary); } else if (totalVisibleShortcuts > 1) { @@ -310,6 +309,12 @@ public abstract class ArrowPopup> measure(MeasureSpec.UNSPECIFIED, MeasureSpec.UNSPECIFIED); } + /** + * Returns {@code true} if the child is a shortcut or wraps a shortcut. + */ + protected boolean isShortcutOrWrapper(View view) { + return view instanceof DeepShortcutView; + } @TargetApi(Build.VERSION_CODES.S) private int getExtractedColor(SparseIntArray colors) { @@ -427,7 +432,7 @@ public abstract class ArrowPopup> /** * Shows the popup at the desired location. */ - protected void show() { + public void show() { setupForDisplay(); onInflationComplete(false); assignMarginsAndBackgrounds(this); @@ -807,6 +812,6 @@ public abstract class ArrowPopup> } protected BaseDragLayer getPopupContainer() { - return mLauncher.getDragLayer(); + return mActivityContext.getDragLayer(); } } diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 454dc6e651..e340b21d53 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -151,7 +151,7 @@ public class PopupContainerWithArrow> public OnClickListener getItemClickListener() { return (view) -> { - mLauncher.getItemOnClickListener().onClick(view); + mActivityContext.getItemOnClickListener().onClick(view); close(true); }; } @@ -326,7 +326,7 @@ public class PopupContainerWithArrow> // Load the shortcuts on a background thread and update the container as it animates. MODEL_EXECUTOR.getHandler().postAtFrontOfQueue(PopupPopulator.createUpdateRunnable( - mLauncher, originalItemInfo, new Handler(Looper.getMainLooper()), + mActivityContext, originalItemInfo, new Handler(Looper.getMainLooper()), this, mShortcuts, notificationKeys)); } @@ -439,7 +439,7 @@ public class PopupContainerWithArrow> private void updateNotificationHeader() { ItemInfoWithIcon itemInfo = (ItemInfoWithIcon) mOriginalIcon.getTag(); - DotInfo dotInfo = mLauncher.getDotInfoForItem(itemInfo); + DotInfo dotInfo = mActivityContext.getDotInfoForItem(itemInfo); if (mNotificationContainer != null && dotInfo != null) { mNotificationContainer.updateHeader(dotInfo.getNotificationCount()); } @@ -481,7 +481,7 @@ public class PopupContainerWithArrow> @Override protected void closeComplete() { super.closeComplete(); - PopupContainerWithArrow openPopup = getOpen(mLauncher); + PopupContainerWithArrow openPopup = getOpen(mActivityContext); if (openPopup == null || openPopup.mOriginalIcon != mOriginalIcon) { mOriginalIcon.setTextVisibility(mOriginalIcon.shouldTextBeVisible()); mOriginalIcon.setForceHideDot(false); diff --git a/src/com/android/launcher3/views/ActivityContext.java b/src/com/android/launcher3/views/ActivityContext.java index ebcd379f74..e07d71e3af 100644 --- a/src/com/android/launcher3/views/ActivityContext.java +++ b/src/com/android/launcher3/views/ActivityContext.java @@ -115,6 +115,13 @@ public interface ActivityContext { return StatsLogManager.newInstance((Context) this); } + /** + * Returns {@code true} if popups should use color extraction. + */ + default boolean shouldUseColorExtractionForPopup() { + return true; + } + /** * Returns whether we can show the IME for elements hosted by this ActivityContext. */ diff --git a/src/com/android/launcher3/views/OptionsPopupView.java b/src/com/android/launcher3/views/OptionsPopupView.java index 257b18fcfb..33ab0d28fb 100644 --- a/src/com/android/launcher3/views/OptionsPopupView.java +++ b/src/com/android/launcher3/views/OptionsPopupView.java @@ -59,7 +59,7 @@ import java.util.List; /** * Popup shown on long pressing an empty space in launcher */ -public class OptionsPopupView extends ArrowPopup +public class OptionsPopupView extends ArrowPopup implements OnClickListener, OnLongClickListener { private final ArrayMap mItemMap = new ArrayMap<>(); @@ -74,6 +74,10 @@ public class OptionsPopupView extends ArrowPopup super(context, attrs, defStyleAttr); } + public void setTargetRect(RectF targetRect) { + mTargetRect = targetRect; + } + @Override public void onClick(View view) { handleViewClick(view); @@ -90,7 +94,7 @@ public class OptionsPopupView extends ArrowPopup return false; } if (item.eventId.getId() > 0) { - mLauncher.getStatsLogManager().logger().log(item.eventId); + mActivityContext.getStatsLogManager().logger().log(item.eventId); } if (item.clickListener.onLongClick(view)) { close(true);