| package com.android.launcher3.popup; |
| |
| |
| import android.app.ActivityOptions; |
| import android.content.Context; |
| import android.content.Intent; |
| import android.graphics.Rect; |
| import android.graphics.drawable.Icon; |
| import android.os.Handler; |
| import android.os.Looper; |
| import android.view.View; |
| import android.view.accessibility.AccessibilityNodeInfo; |
| import android.widget.ImageView; |
| import android.widget.TextView; |
| |
| import com.android.launcher3.AbstractFloatingView; |
| import com.android.launcher3.BaseDraggingActivity; |
| import com.android.launcher3.ItemInfo; |
| import com.android.launcher3.Launcher; |
| import com.android.launcher3.LauncherSettings; |
| import com.android.launcher3.R; |
| import com.android.launcher3.WorkspaceItemInfo; |
| import com.android.launcher3.config.FeatureFlags; |
| import com.android.launcher3.model.AppLaunchTracker; |
| import com.android.launcher3.model.WidgetItem; |
| import com.android.launcher3.userevent.nano.LauncherLogProto.Action; |
| import com.android.launcher3.userevent.nano.LauncherLogProto.ContainerType; |
| import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; |
| import com.android.launcher3.util.InstantAppResolver; |
| import com.android.launcher3.util.PackageManagerHelper; |
| import com.android.launcher3.util.PackageUserKey; |
| import com.android.launcher3.widget.WidgetsBottomSheet; |
| |
| import java.util.List; |
| /** |
| * Represents a system shortcut for a given app. The shortcut should have a label and icon, and an |
| * onClickListener that depends on the item that the shortcut services. |
| * |
| * Example system shortcuts, defined as inner classes, include Widgets and AppInfo. |
| * @param <T> |
| */ |
| public abstract class SystemShortcut<T extends BaseDraggingActivity> |
| extends ItemInfo { |
| private final int mIconResId; |
| private final int mLabelResId; |
| private final Icon mIcon; |
| private final CharSequence mLabel; |
| private final CharSequence mContentDescription; |
| private final int mAccessibilityActionId; |
| |
| public SystemShortcut(int iconResId, int labelResId) { |
| mIconResId = iconResId; |
| mLabelResId = labelResId; |
| mAccessibilityActionId = labelResId; |
| mIcon = null; |
| mLabel = null; |
| mContentDescription = null; |
| } |
| |
| public SystemShortcut(Icon icon, CharSequence label, CharSequence contentDescription, |
| int accessibilityActionId) { |
| mIcon = icon; |
| mLabel = label; |
| mContentDescription = contentDescription; |
| mAccessibilityActionId = accessibilityActionId; |
| mIconResId = 0; |
| mLabelResId = 0; |
| } |
| |
| public SystemShortcut(SystemShortcut other) { |
| mIconResId = other.mIconResId; |
| mLabelResId = other.mLabelResId; |
| mIcon = other.mIcon; |
| mLabel = other.mLabel; |
| mContentDescription = other.mContentDescription; |
| mAccessibilityActionId = other.mAccessibilityActionId; |
| } |
| |
| /** |
| * Should be in the left group of icons in app's context menu header. |
| */ |
| public boolean isLeftGroup() { |
| return false; |
| } |
| |
| public void setIconAndLabelFor(View iconView, TextView labelView) { |
| if (mIcon != null) { |
| mIcon.loadDrawableAsync(iconView.getContext(), |
| iconView::setBackground, |
| new Handler(Looper.getMainLooper())); |
| } else { |
| iconView.setBackgroundResource(mIconResId); |
| } |
| |
| if (mLabel != null) { |
| labelView.setText(mLabel); |
| } else { |
| labelView.setText(mLabelResId); |
| } |
| } |
| |
| public void setIconAndContentDescriptionFor(ImageView view) { |
| if (mIcon != null) { |
| mIcon.loadDrawableAsync(view.getContext(), |
| view::setImageDrawable, |
| new Handler(Looper.getMainLooper())); |
| } else { |
| view.setImageResource(mIconResId); |
| } |
| |
| view.setContentDescription(getContentDescription(view.getContext())); |
| } |
| |
| private CharSequence getContentDescription(Context context) { |
| return mContentDescription != null ? mContentDescription : context.getText(mLabelResId); |
| } |
| |
| public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(Context context) { |
| return new AccessibilityNodeInfo.AccessibilityAction(mAccessibilityActionId, |
| getContentDescription(context)); |
| } |
| |
| public boolean hasHandlerForAction(int action) { |
| return mAccessibilityActionId == action; |
| } |
| |
| public abstract View.OnClickListener getOnClickListener(T activity, ItemInfo itemInfo); |
| |
| public static class Widgets extends SystemShortcut<Launcher> { |
| |
| public Widgets() { |
| super(R.drawable.ic_widget, R.string.widget_button_text); |
| } |
| |
| @Override |
| public View.OnClickListener getOnClickListener(final Launcher launcher, |
| final ItemInfo itemInfo) { |
| if (itemInfo.getTargetComponent() == null) return null; |
| final List<WidgetItem> widgets = |
| launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey( |
| itemInfo.getTargetComponent().getPackageName(), itemInfo.user)); |
| if (widgets == null) { |
| return null; |
| } |
| return (view) -> { |
| AbstractFloatingView.closeAllOpenViews(launcher); |
| WidgetsBottomSheet widgetsBottomSheet = |
| (WidgetsBottomSheet) launcher.getLayoutInflater().inflate( |
| R.layout.widgets_bottom_sheet, launcher.getDragLayer(), false); |
| widgetsBottomSheet.populateAndShow(itemInfo); |
| launcher.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, |
| ControlType.WIDGETS_BUTTON, view); |
| }; |
| } |
| } |
| |
| public static class AppInfo extends SystemShortcut { |
| public AppInfo() { |
| super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label); |
| } |
| |
| @Override |
| public View.OnClickListener getOnClickListener( |
| BaseDraggingActivity activity, ItemInfo itemInfo) { |
| return (view) -> { |
| dismissTaskMenuView(activity); |
| Rect sourceBounds = activity.getViewBounds(view); |
| new PackageManagerHelper(activity).startDetailsActivityForInfo( |
| itemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); |
| activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, |
| ControlType.APPINFO_TARGET, view); |
| }; |
| } |
| } |
| |
| public static class Install extends SystemShortcut { |
| public Install() { |
| super(R.drawable.ic_install_no_shadow, R.string.install_drop_target_label); |
| } |
| |
| @Override |
| public View.OnClickListener getOnClickListener( |
| BaseDraggingActivity activity, ItemInfo itemInfo) { |
| boolean supportsWebUI = (itemInfo instanceof WorkspaceItemInfo) && |
| ((WorkspaceItemInfo) itemInfo).hasStatusFlag(WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI); |
| boolean isInstantApp = false; |
| if (itemInfo instanceof com.android.launcher3.AppInfo) { |
| com.android.launcher3.AppInfo appInfo = (com.android.launcher3.AppInfo) itemInfo; |
| isInstantApp = InstantAppResolver.newInstance(activity).isInstantApp(appInfo); |
| } |
| boolean enabled = supportsWebUI || isInstantApp; |
| if (!enabled) { |
| return null; |
| } |
| return createOnClickListener(activity, itemInfo); |
| } |
| |
| public View.OnClickListener createOnClickListener( |
| BaseDraggingActivity activity, ItemInfo itemInfo) { |
| return view -> { |
| Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent( |
| itemInfo.getTargetComponent().getPackageName()); |
| activity.startActivitySafely(view, intent, itemInfo, null); |
| AbstractFloatingView.closeAllOpenViews(activity); |
| }; |
| } |
| } |
| |
| public static class DismissPrediction extends SystemShortcut<Launcher> { |
| public DismissPrediction() { |
| super(R.drawable.ic_remove_no_shadow, R.string.dismiss_prediction_label); |
| } |
| |
| @Override |
| public View.OnClickListener getOnClickListener(Launcher activity, ItemInfo itemInfo) { |
| if (!FeatureFlags.ENABLE_PREDICTION_DISMISS.get()) return null; |
| if (itemInfo.container != LauncherSettings.Favorites.CONTAINER_PREDICTION) return null; |
| return (view) -> { |
| PopupContainerWithArrow.closeAllOpenViews(activity); |
| activity.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, |
| ControlType.DISMISS_PREDICTION, ContainerType.DEEPSHORTCUTS); |
| AppLaunchTracker.INSTANCE.get(view.getContext()) |
| .onDismissApp(itemInfo.getTargetComponent(), |
| itemInfo.user, |
| AppLaunchTracker.CONTAINER_PREDICTIONS); |
| }; |
| } |
| } |
| |
| protected static void dismissTaskMenuView(BaseDraggingActivity activity) { |
| AbstractFloatingView.closeOpenViews(activity, true, |
| AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); |
| } |
| } |