1 package com.android.launcher3.popup; 2 3 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP; 4 import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP; 5 6 import android.app.ActivityOptions; 7 import android.content.Context; 8 import android.content.Intent; 9 import android.graphics.Rect; 10 import android.view.View; 11 import android.view.accessibility.AccessibilityNodeInfo; 12 import android.widget.ImageView; 13 import android.widget.TextView; 14 15 import androidx.annotation.Nullable; 16 17 import com.android.launcher3.AbstractFloatingView; 18 import com.android.launcher3.BaseDraggingActivity; 19 import com.android.launcher3.Launcher; 20 import com.android.launcher3.R; 21 import com.android.launcher3.model.WidgetItem; 22 import com.android.launcher3.model.data.ItemInfo; 23 import com.android.launcher3.model.data.WorkspaceItemInfo; 24 import com.android.launcher3.userevent.nano.LauncherLogProto.Action; 25 import com.android.launcher3.userevent.nano.LauncherLogProto.ControlType; 26 import com.android.launcher3.util.InstantAppResolver; 27 import com.android.launcher3.util.PackageManagerHelper; 28 import com.android.launcher3.util.PackageUserKey; 29 import com.android.launcher3.widget.WidgetsBottomSheet; 30 31 import java.util.List; 32 33 /** 34 * Represents a system shortcut for a given app. The shortcut should have a label and icon, and an 35 * onClickListener that depends on the item that the shortcut services. 36 * 37 * Example system shortcuts, defined as inner classes, include Widgets and AppInfo. 38 * @param <T> 39 */ 40 public abstract class SystemShortcut<T extends BaseDraggingActivity> extends ItemInfo 41 implements View.OnClickListener { 42 43 private final int mIconResId; 44 private final int mLabelResId; 45 private final int mAccessibilityActionId; 46 47 protected final T mTarget; 48 protected final ItemInfo mItemInfo; 49 SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo)50 public SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo) { 51 mIconResId = iconResId; 52 mLabelResId = labelResId; 53 mAccessibilityActionId = labelResId; 54 mTarget = target; 55 mItemInfo = itemInfo; 56 } 57 SystemShortcut(SystemShortcut<T> other)58 public SystemShortcut(SystemShortcut<T> other) { 59 mIconResId = other.mIconResId; 60 mLabelResId = other.mLabelResId; 61 mAccessibilityActionId = other.mAccessibilityActionId; 62 mTarget = other.mTarget; 63 mItemInfo = other.mItemInfo; 64 } 65 66 /** 67 * Should be in the left group of icons in app's context menu header. 68 */ isLeftGroup()69 public boolean isLeftGroup() { 70 return false; 71 } 72 setIconAndLabelFor(View iconView, TextView labelView)73 public void setIconAndLabelFor(View iconView, TextView labelView) { 74 iconView.setBackgroundResource(mIconResId); 75 labelView.setText(mLabelResId); 76 } 77 setIconAndContentDescriptionFor(ImageView view)78 public void setIconAndContentDescriptionFor(ImageView view) { 79 view.setImageResource(mIconResId); 80 view.setContentDescription(view.getContext().getText(mLabelResId)); 81 } 82 createAccessibilityAction(Context context)83 public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(Context context) { 84 return new AccessibilityNodeInfo.AccessibilityAction( 85 mAccessibilityActionId, context.getText(mLabelResId)); 86 } 87 hasHandlerForAction(int action)88 public boolean hasHandlerForAction(int action) { 89 return mAccessibilityActionId == action; 90 } 91 92 public interface Factory<T extends BaseDraggingActivity> { 93 getShortcut(T activity, ItemInfo itemInfo)94 @Nullable SystemShortcut<T> getShortcut(T activity, ItemInfo itemInfo); 95 } 96 97 public static final Factory<Launcher> WIDGETS = (launcher, itemInfo) -> { 98 if (itemInfo.getTargetComponent() == null) return null; 99 final List<WidgetItem> widgets = 100 launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey( 101 itemInfo.getTargetComponent().getPackageName(), itemInfo.user)); 102 if (widgets == null) { 103 return null; 104 } 105 return new Widgets(launcher, itemInfo); 106 }; 107 108 public static class Widgets extends SystemShortcut<Launcher> { Widgets(Launcher target, ItemInfo itemInfo)109 public Widgets(Launcher target, ItemInfo itemInfo) { 110 super(R.drawable.ic_widget, R.string.widget_button_text, target, itemInfo); 111 } 112 113 @Override onClick(View view)114 public void onClick(View view) { 115 AbstractFloatingView.closeAllOpenViews(mTarget); 116 WidgetsBottomSheet widgetsBottomSheet = 117 (WidgetsBottomSheet) mTarget.getLayoutInflater().inflate( 118 R.layout.widgets_bottom_sheet, mTarget.getDragLayer(), false); 119 widgetsBottomSheet.populateAndShow(mItemInfo); 120 mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, 121 ControlType.WIDGETS_BUTTON, view); 122 mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo) 123 .log(LAUNCHER_SYSTEM_SHORTCUT_WIDGETS_TAP); 124 } 125 } 126 127 public static final Factory<BaseDraggingActivity> APP_INFO = AppInfo::new; 128 129 public static class AppInfo extends SystemShortcut { 130 AppInfo(BaseDraggingActivity target, ItemInfo itemInfo)131 public AppInfo(BaseDraggingActivity target, ItemInfo itemInfo) { 132 super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label, target, 133 itemInfo); 134 } 135 136 @Override onClick(View view)137 public void onClick(View view) { 138 dismissTaskMenuView(mTarget); 139 Rect sourceBounds = mTarget.getViewBounds(view); 140 new PackageManagerHelper(mTarget).startDetailsActivityForInfo( 141 mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); 142 mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, 143 ControlType.APPINFO_TARGET, view); 144 mTarget.getStatsLogManager().logger().withItemInfo(mItemInfo) 145 .log(LAUNCHER_SYSTEM_SHORTCUT_APP_INFO_TAP); 146 } 147 } 148 149 public static final Factory<BaseDraggingActivity> INSTALL = (activity, itemInfo) -> { 150 boolean supportsWebUI = (itemInfo instanceof WorkspaceItemInfo) 151 && ((WorkspaceItemInfo) itemInfo).hasStatusFlag( 152 WorkspaceItemInfo.FLAG_SUPPORTS_WEB_UI); 153 boolean isInstantApp = false; 154 if (itemInfo instanceof com.android.launcher3.model.data.AppInfo) { 155 com.android.launcher3.model.data.AppInfo 156 appInfo = (com.android.launcher3.model.data.AppInfo) itemInfo; 157 isInstantApp = InstantAppResolver.newInstance(activity).isInstantApp(appInfo); 158 } 159 boolean enabled = supportsWebUI || isInstantApp; 160 if (!enabled) { 161 return null; 162 } 163 return new Install(activity, itemInfo); 164 }; 165 166 public static class Install extends SystemShortcut { 167 Install(BaseDraggingActivity target, ItemInfo itemInfo)168 public Install(BaseDraggingActivity target, ItemInfo itemInfo) { 169 super(R.drawable.ic_install_no_shadow, R.string.install_drop_target_label, 170 target, itemInfo); 171 } 172 173 @Override onClick(View view)174 public void onClick(View view) { 175 Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent( 176 mItemInfo.getTargetComponent().getPackageName()); 177 mTarget.startActivitySafely(view, intent, mItemInfo, null); 178 AbstractFloatingView.closeAllOpenViews(mTarget); 179 } 180 } 181 dismissTaskMenuView(BaseDraggingActivity activity)182 public static void dismissTaskMenuView(BaseDraggingActivity activity) { 183 AbstractFloatingView.closeOpenViews(activity, true, 184 AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); 185 } 186 } 187