From 7805d49764cd0f8eeff07c3de39ff87dbd544786 Mon Sep 17 00:00:00 2001 From: Sunny Goyal Date: Tue, 22 Oct 2019 15:22:59 -0700 Subject: [PATCH] Separating SystemShortcut and Factory > This makes easier to extend the factory and callbacks separately > Availability checks are only performed once when getting the shortcut Change-Id: I413541eabfb2b9e987c852d5171c6696b1853958 --- .../android/quickstep/TaskOverlayFactory.java | 27 +- .../quickstep/TaskShortcutFactory.java | 312 +++++++++++++++++ .../android/quickstep/TaskSystemShortcut.java | 327 ------------------ .../android/quickstep/views/TaskMenuView.java | 21 +- .../com/android/quickstep/views/TaskView.java | 28 +- .../popup/PopupContainerWithArrow.java | 10 +- .../launcher3/popup/RemoteActionShortcut.java | 104 +++--- .../launcher3/popup/SystemShortcut.java | 229 ++++++------ .../popup/SystemShortcutFactory.java | 19 +- 9 files changed, 517 insertions(+), 560 deletions(-) create mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java delete mode 100644 quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java index 17457aace6..298b0ffb93 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskOverlayFactory.java @@ -19,11 +19,11 @@ package com.android.quickstep; import static com.android.launcher3.util.MainThreadInitializedObject.forOverride; import android.graphics.Matrix; -import android.view.View; import com.android.launcher3.BaseActivity; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.R; +import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.MainThreadInitializedObject; import com.android.launcher3.util.ResourceBasedOverride; import com.android.quickstep.views.TaskThumbnailView; @@ -40,25 +40,24 @@ import java.util.List; public class TaskOverlayFactory implements ResourceBasedOverride { /** Note that these will be shown in order from top to bottom, if available for the task. */ - private static final TaskSystemShortcut[] MENU_OPTIONS = new TaskSystemShortcut[]{ - new TaskSystemShortcut.AppInfo(), - new TaskSystemShortcut.SplitScreen(), - new TaskSystemShortcut.Pin(), - new TaskSystemShortcut.Install(), - new TaskSystemShortcut.Freeform() + private static final TaskShortcutFactory[] MENU_OPTIONS = new TaskShortcutFactory[]{ + TaskShortcutFactory.APP_INFO, + TaskShortcutFactory.SPLIT_SCREEN, + TaskShortcutFactory.PIN, + TaskShortcutFactory.INSTALL, + TaskShortcutFactory.FREE_FORM }; public static final MainThreadInitializedObject INSTANCE = forOverride(TaskOverlayFactory.class, R.string.task_overlay_factory_class); - public List getEnabledShortcuts(TaskView taskView) { - final ArrayList shortcuts = new ArrayList<>(); + public List getEnabledShortcuts(TaskView taskView) { + final ArrayList shortcuts = new ArrayList<>(); final BaseDraggingActivity activity = BaseActivity.fromContext(taskView.getContext()); - for (TaskSystemShortcut menuOption : MENU_OPTIONS) { - View.OnClickListener onClickListener = - menuOption.getOnClickListener(activity, taskView); - if (onClickListener != null) { - shortcuts.add(menuOption); + for (TaskShortcutFactory menuOption : MENU_OPTIONS) { + SystemShortcut shortcut = menuOption.getShortcut(activity, taskView); + if (shortcut != null) { + shortcuts.add(shortcut); } } return shortcuts; diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java new file mode 100644 index 0000000000..a3a1d6d483 --- /dev/null +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskShortcutFactory.java @@ -0,0 +1,312 @@ +/* + * Copyright (C) 2018 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 static android.view.Display.DEFAULT_DISPLAY; + +import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; + +import android.app.Activity; +import android.app.ActivityOptions; +import android.content.ComponentName; +import android.content.Intent; +import android.graphics.Bitmap; +import android.graphics.Color; +import android.graphics.Rect; +import android.os.Handler; +import android.os.Looper; +import android.os.UserHandle; +import android.view.View; + +import com.android.launcher3.BaseDraggingActivity; +import com.android.launcher3.DeviceProfile; +import com.android.launcher3.R; +import com.android.launcher3.WorkspaceItemInfo; +import com.android.launcher3.popup.SystemShortcut; +import com.android.launcher3.popup.SystemShortcut.AppInfo; +import com.android.launcher3.userevent.nano.LauncherLogProto; +import com.android.launcher3.util.Executors; +import com.android.launcher3.util.InstantAppResolver; +import com.android.quickstep.views.RecentsView; +import com.android.quickstep.views.TaskThumbnailView; +import com.android.quickstep.views.TaskView; +import com.android.systemui.shared.recents.model.Task; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; +import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; +import com.android.systemui.shared.recents.view.RecentsTransition; +import com.android.systemui.shared.system.ActivityCompat; +import com.android.systemui.shared.system.ActivityManagerWrapper; +import com.android.systemui.shared.system.ActivityOptionsCompat; +import com.android.systemui.shared.system.WindowManagerWrapper; + +import java.util.Collections; +import java.util.List; +import java.util.function.Consumer; + +/** + * Represents a system shortcut that can be shown for a recent task. + */ +public interface TaskShortcutFactory { + + SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView view); + + static WorkspaceItemInfo dummyInfo(TaskView view) { + Task task = view.getTask(); + + WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(); + dummyInfo.intent = new Intent(); + ComponentName component = task.getTopComponent(); + dummyInfo.intent.setComponent(component); + dummyInfo.user = UserHandle.of(task.key.userId); + dummyInfo.title = TaskUtils.getTitle(view.getContext(), task); + return dummyInfo; + } + + TaskShortcutFactory APP_INFO = (activity, view) -> new AppInfo(activity, dummyInfo(view)); + + abstract class MultiWindowFactory implements TaskShortcutFactory { + + private final int mIconRes; + private final int mTextRes; + + MultiWindowFactory(int iconRes, int textRes) { + mIconRes = iconRes; + mTextRes = textRes; + } + + protected abstract boolean isAvailable(BaseDraggingActivity activity, int displayId); + protected abstract ActivityOptions makeLaunchOptions(Activity activity); + protected abstract boolean onActivityStarted(BaseDraggingActivity activity); + + @Override + public SystemShortcut getShortcut(BaseDraggingActivity activity, TaskView taskView) { + final Task task = taskView.getTask(); + if (!task.isDockable) { + return null; + } + if (!isAvailable(activity, task.key.displayId)) { + return null; + } + return new MultiWindowSystemShortcut(mIconRes, mTextRes, activity, taskView, this); + } + } + + class MultiWindowSystemShortcut extends SystemShortcut { + + private Handler mHandler; + + private final RecentsView mRecentsView; + private final TaskThumbnailView mThumbnailView; + private final TaskView mTaskView; + private final MultiWindowFactory mFactory; + + public MultiWindowSystemShortcut(int iconRes, int textRes, + BaseDraggingActivity activity, TaskView taskView, MultiWindowFactory factory) { + super(iconRes, textRes, activity, dummyInfo(taskView)); + + mHandler = new Handler(Looper.getMainLooper()); + mTaskView = taskView; + mRecentsView = activity.getOverviewPanel(); + mThumbnailView = taskView.getThumbnail(); + mFactory = factory; + } + + @Override + public void onClick(View view) { + Task.TaskKey taskKey = mTaskView.getTask().key; + final int taskId = taskKey.id; + + final View.OnLayoutChangeListener onLayoutChangeListener = + new View.OnLayoutChangeListener() { + @Override + public void onLayoutChange(View v, int l, int t, int r, int b, + int oldL, int oldT, int oldR, int oldB) { + mTaskView.getRootView().removeOnLayoutChangeListener(this); + mRecentsView.clearIgnoreResetTask(taskId); + + // Start animating in the side pages once launcher has been resized + mRecentsView.dismissTask(mTaskView, false, false); + } + }; + + final DeviceProfile.OnDeviceProfileChangeListener onDeviceProfileChangeListener = + new DeviceProfile.OnDeviceProfileChangeListener() { + @Override + public void onDeviceProfileChanged(DeviceProfile dp) { + mTarget.removeOnDeviceProfileChangeListener(this); + if (dp.isMultiWindowMode) { + mTaskView.getRootView().addOnLayoutChangeListener( + onLayoutChangeListener); + } + } + }; + + dismissTaskMenuView(mTarget); + + ActivityOptions options = mFactory.makeLaunchOptions(mTarget); + if (options != null + && ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId, + options)) { + if (!mFactory.onActivityStarted(mTarget)) { + return; + } + // Add a device profile change listener to kick off animating the side tasks + // once we enter multiwindow mode and relayout + mTarget.addOnDeviceProfileChangeListener(onDeviceProfileChangeListener); + + final Runnable animStartedListener = () -> { + // Hide the task view and wait for the window to be resized + // TODO: Consider animating in launcher and do an in-place start activity + // afterwards + mRecentsView.setIgnoreResetTask(taskId); + mTaskView.setAlpha(0f); + }; + + final int[] position = new int[2]; + mThumbnailView.getLocationOnScreen(position); + final int width = (int) (mThumbnailView.getWidth() * mTaskView.getScaleX()); + final int height = (int) (mThumbnailView.getHeight() * mTaskView.getScaleY()); + final Rect taskBounds = new Rect(position[0], position[1], + position[0] + width, position[1] + height); + + // Take the thumbnail of the task without a scrim and apply it back after + float alpha = mThumbnailView.getDimAlpha(); + mThumbnailView.setDimAlpha(0); + Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap( + taskBounds.width(), taskBounds.height(), mThumbnailView, 1f, + Color.BLACK); + mThumbnailView.setDimAlpha(alpha); + + AppTransitionAnimationSpecsFuture future = + new AppTransitionAnimationSpecsFuture(mHandler) { + @Override + public List composeSpecs() { + return Collections.singletonList(new AppTransitionAnimationSpecCompat( + taskId, thumbnail, taskBounds)); + } + }; + WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( + future, animStartedListener, mHandler, true /* scaleUp */, + taskKey.displayId); + } + } + } + + TaskShortcutFactory SPLIT_SCREEN = new MultiWindowFactory( + R.drawable.ic_split_screen, R.string.recent_task_option_split_screen) { + + @Override + protected boolean isAvailable(BaseDraggingActivity activity, int displayId) { + // Don't show menu-item if already in multi-window and the task is from + // the secondary display. + // TODO(b/118266305): Temporarily disable splitscreen for secondary display while new + // implementation is enabled + return !activity.getDeviceProfile().isMultiWindowMode + && (displayId == -1 || displayId == DEFAULT_DISPLAY); + } + + @Override + protected ActivityOptions makeLaunchOptions(Activity activity) { + final ActivityCompat act = new ActivityCompat(activity); + final int navBarPosition = WindowManagerWrapper.getInstance().getNavBarPosition( + act.getDisplayId()); + if (navBarPosition == WindowManagerWrapper.NAV_BAR_POS_INVALID) { + return null; + } + boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT; + return ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft); + } + + @Override + protected boolean onActivityStarted(BaseDraggingActivity activity) { + SystemUiProxy.INSTANCE.get(activity).onSplitScreenInvoked(); + activity.getUserEventDispatcher().logActionOnControl(TAP, + LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET); + return true; + } + }; + + TaskShortcutFactory FREE_FORM = new MultiWindowFactory( + R.drawable.ic_split_screen, R.string.recent_task_option_freeform) { + + @Override + protected boolean isAvailable(BaseDraggingActivity activity, int displayId) { + return ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity); + } + + @Override + protected ActivityOptions makeLaunchOptions(Activity activity) { + ActivityOptions activityOptions = ActivityOptionsCompat.makeFreeformOptions(); + // Arbitrary bounds only because freeform is in dev mode right now + Rect r = new Rect(50, 50, 200, 200); + activityOptions.setLaunchBounds(r); + return activityOptions; + } + + @Override + protected boolean onActivityStarted(BaseDraggingActivity activity) { + activity.returnToHomescreen(); + return true; + } + }; + + TaskShortcutFactory PIN = (activity, tv) -> { + if (!SystemUiProxy.INSTANCE.get(activity).isActive()) { + return null; + } + if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { + return null; + } + if (ActivityManagerWrapper.getInstance().isLockToAppActive()) { + // We shouldn't be able to pin while an app is locked. + return null; + } + return new PinSystemShortcut(activity, tv); + }; + + class PinSystemShortcut extends SystemShortcut { + + private static final String TAG = "PinSystemShortcut"; + + private final TaskView mTaskView; + + public PinSystemShortcut(BaseDraggingActivity target, TaskView tv) { + super(R.drawable.ic_pin, R.string.recent_task_option_pin, target, dummyInfo(tv)); + mTaskView = tv; + } + + @Override + public void onClick(View view) { + Consumer resultCallback = success -> { + if (success) { + SystemUiProxy.INSTANCE.get(mTarget).startScreenPinning( + mTaskView.getTask().key.id); + } else { + mTaskView.notifyTaskLaunchFailed(TAG); + } + }; + mTaskView.launchTask(true, resultCallback, Executors.MAIN_EXECUTOR.getHandler()); + dismissTaskMenuView(mTarget); + } + } + + TaskShortcutFactory INSTALL = (activity, view) -> + InstantAppResolver.newInstance(activity).isInstantApp(activity, + view.getTask().getTopComponent().getPackageName()) + ? new SystemShortcut.Install(activity, dummyInfo(view)) : null; + +} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java deleted file mode 100644 index 5a2e3ff821..0000000000 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/TaskSystemShortcut.java +++ /dev/null @@ -1,327 +0,0 @@ -/* - * Copyright (C) 2018 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 static android.view.Display.DEFAULT_DISPLAY; -import static com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch.TAP; - -import android.app.Activity; -import android.app.ActivityOptions; -import android.content.ComponentName; -import android.content.Intent; -import android.graphics.Bitmap; -import android.graphics.Color; -import android.graphics.Rect; -import android.os.Handler; -import android.os.Looper; -import android.os.UserHandle; -import android.view.View; - -import com.android.launcher3.BaseDraggingActivity; -import com.android.launcher3.DeviceProfile; -import com.android.launcher3.ItemInfo; -import com.android.launcher3.R; -import com.android.launcher3.WorkspaceItemInfo; -import com.android.launcher3.popup.SystemShortcut; -import com.android.launcher3.userevent.nano.LauncherLogProto; -import com.android.launcher3.util.InstantAppResolver; -import com.android.quickstep.views.RecentsView; -import com.android.quickstep.views.TaskThumbnailView; -import com.android.quickstep.views.TaskView; -import com.android.systemui.shared.recents.model.Task; -import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecCompat; -import com.android.systemui.shared.recents.view.AppTransitionAnimationSpecsFuture; -import com.android.systemui.shared.recents.view.RecentsTransition; -import com.android.systemui.shared.system.ActivityCompat; -import com.android.systemui.shared.system.ActivityManagerWrapper; -import com.android.systemui.shared.system.ActivityOptionsCompat; -import com.android.systemui.shared.system.WindowManagerWrapper; - -import java.util.Collections; -import java.util.List; -import java.util.function.Consumer; - -/** - * Represents a system shortcut that can be shown for a recent task. - */ -public class TaskSystemShortcut extends SystemShortcut { - - private static final String TAG = "TaskSystemShortcut"; - - protected T mSystemShortcut; - - public TaskSystemShortcut(T systemShortcut) { - super(systemShortcut); - mSystemShortcut = systemShortcut; - } - - protected TaskSystemShortcut(int iconResId, int labelResId) { - super(iconResId, labelResId); - } - - @Override - public View.OnClickListener getOnClickListener( - BaseDraggingActivity activity, ItemInfo itemInfo) { - return null; - } - - public View.OnClickListener getOnClickListener(BaseDraggingActivity activity, TaskView view) { - Task task = view.getTask(); - - WorkspaceItemInfo dummyInfo = new WorkspaceItemInfo(); - dummyInfo.intent = new Intent(); - ComponentName component = task.getTopComponent(); - dummyInfo.intent.setComponent(component); - dummyInfo.user = UserHandle.of(task.key.userId); - dummyInfo.title = TaskUtils.getTitle(activity, task); - - return getOnClickListenerForTask(activity, task, dummyInfo); - } - - protected View.OnClickListener getOnClickListenerForTask( - BaseDraggingActivity activity, Task task, ItemInfo dummyInfo) { - return mSystemShortcut.getOnClickListener(activity, dummyInfo); - } - - public static class AppInfo extends TaskSystemShortcut { - public AppInfo() { - super(new SystemShortcut.AppInfo()); - } - } - - public static abstract class MultiWindow extends TaskSystemShortcut { - - private Handler mHandler; - - public MultiWindow(int iconRes, int textRes) { - super(iconRes, textRes); - mHandler = new Handler(Looper.getMainLooper()); - } - - protected abstract boolean isAvailable(BaseDraggingActivity activity, int displayId); - protected abstract ActivityOptions makeLaunchOptions(Activity activity); - protected abstract boolean onActivityStarted(BaseDraggingActivity activity); - - @Override - public View.OnClickListener getOnClickListener( - BaseDraggingActivity activity, TaskView taskView) { - final Task task = taskView.getTask(); - final int taskId = task.key.id; - final int displayId = task.key.displayId; - if (!task.isDockable) { - return null; - } - if (!isAvailable(activity, displayId)) { - return null; - } - final RecentsView recentsView = activity.getOverviewPanel(); - - final TaskThumbnailView thumbnailView = taskView.getThumbnail(); - return (v -> { - final View.OnLayoutChangeListener onLayoutChangeListener = - new View.OnLayoutChangeListener() { - @Override - public void onLayoutChange(View v, int l, int t, int r, int b, - int oldL, int oldT, int oldR, int oldB) { - taskView.getRootView().removeOnLayoutChangeListener(this); - recentsView.clearIgnoreResetTask(taskId); - - // Start animating in the side pages once launcher has been resized - recentsView.dismissTask(taskView, false, false); - } - }; - - final DeviceProfile.OnDeviceProfileChangeListener onDeviceProfileChangeListener = - new DeviceProfile.OnDeviceProfileChangeListener() { - @Override - public void onDeviceProfileChanged(DeviceProfile dp) { - activity.removeOnDeviceProfileChangeListener(this); - if (dp.isMultiWindowMode) { - taskView.getRootView().addOnLayoutChangeListener( - onLayoutChangeListener); - } - } - }; - - dismissTaskMenuView(activity); - - ActivityOptions options = makeLaunchOptions(activity); - if (options != null - && ActivityManagerWrapper.getInstance().startActivityFromRecents(taskId, - options)) { - if (!onActivityStarted(activity)) { - return; - } - // Add a device profile change listener to kick off animating the side tasks - // once we enter multiwindow mode and relayout - activity.addOnDeviceProfileChangeListener(onDeviceProfileChangeListener); - - final Runnable animStartedListener = () -> { - // Hide the task view and wait for the window to be resized - // TODO: Consider animating in launcher and do an in-place start activity - // afterwards - recentsView.setIgnoreResetTask(taskId); - taskView.setAlpha(0f); - }; - - final int[] position = new int[2]; - thumbnailView.getLocationOnScreen(position); - final int width = (int) (thumbnailView.getWidth() * taskView.getScaleX()); - final int height = (int) (thumbnailView.getHeight() * taskView.getScaleY()); - final Rect taskBounds = new Rect(position[0], position[1], - position[0] + width, position[1] + height); - - // Take the thumbnail of the task without a scrim and apply it back after - float alpha = thumbnailView.getDimAlpha(); - thumbnailView.setDimAlpha(0); - Bitmap thumbnail = RecentsTransition.drawViewIntoHardwareBitmap( - taskBounds.width(), taskBounds.height(), thumbnailView, 1f, - Color.BLACK); - thumbnailView.setDimAlpha(alpha); - - AppTransitionAnimationSpecsFuture future = - new AppTransitionAnimationSpecsFuture(mHandler) { - @Override - public List composeSpecs() { - return Collections.singletonList(new AppTransitionAnimationSpecCompat( - taskId, thumbnail, taskBounds)); - } - }; - WindowManagerWrapper.getInstance().overridePendingAppTransitionMultiThumbFuture( - future, animStartedListener, mHandler, true /* scaleUp */, displayId); - } - }); - } - } - - public static class SplitScreen extends MultiWindow { - public SplitScreen() { - super(R.drawable.ic_split_screen, R.string.recent_task_option_split_screen); - } - - @Override - protected boolean isAvailable(BaseDraggingActivity activity, int displayId) { - // Don't show menu-item if already in multi-window and the task is from - // the secondary display. - // TODO(b/118266305): Temporarily disable splitscreen for secondary display while new - // implementation is enabled - return !activity.getDeviceProfile().isMultiWindowMode - && (displayId == -1 || displayId == DEFAULT_DISPLAY); - } - - @Override - protected ActivityOptions makeLaunchOptions(Activity activity) { - final ActivityCompat act = new ActivityCompat(activity); - final int navBarPosition = WindowManagerWrapper.getInstance().getNavBarPosition( - act.getDisplayId()); - if (navBarPosition == WindowManagerWrapper.NAV_BAR_POS_INVALID) { - return null; - } - boolean dockTopOrLeft = navBarPosition != WindowManagerWrapper.NAV_BAR_POS_LEFT; - return ActivityOptionsCompat.makeSplitScreenOptions(dockTopOrLeft); - } - - @Override - protected boolean onActivityStarted(BaseDraggingActivity activity) { - SystemUiProxy.INSTANCE.get(activity).onSplitScreenInvoked(); - activity.getUserEventDispatcher().logActionOnControl(TAP, - LauncherLogProto.ControlType.SPLIT_SCREEN_TARGET); - return true; - } - } - - public static class Freeform extends MultiWindow { - public Freeform() { - super(R.drawable.ic_split_screen, R.string.recent_task_option_freeform); - } - - @Override - protected boolean isAvailable(BaseDraggingActivity activity, int displayId) { - return ActivityManagerWrapper.getInstance().supportsFreeformMultiWindow(activity); - } - - @Override - protected ActivityOptions makeLaunchOptions(Activity activity) { - ActivityOptions activityOptions = ActivityOptionsCompat.makeFreeformOptions(); - // Arbitrary bounds only because freeform is in dev mode right now - Rect r = new Rect(50, 50, 200, 200); - activityOptions.setLaunchBounds(r); - return activityOptions; - } - - @Override - protected boolean onActivityStarted(BaseDraggingActivity activity) { - activity.returnToHomescreen(); - return true; - } - } - - public static class Pin extends TaskSystemShortcut { - - private static final String TAG = Pin.class.getSimpleName(); - - private Handler mHandler; - - public Pin() { - super(R.drawable.ic_pin, R.string.recent_task_option_pin); - mHandler = new Handler(Looper.getMainLooper()); - } - - @Override - public View.OnClickListener getOnClickListener( - BaseDraggingActivity activity, TaskView taskView) { - if (!SystemUiProxy.INSTANCE.get(activity).isActive()) { - return null; - } - if (!ActivityManagerWrapper.getInstance().isScreenPinningEnabled()) { - return null; - } - if (ActivityManagerWrapper.getInstance().isLockToAppActive()) { - // We shouldn't be able to pin while an app is locked. - return null; - } - return view -> { - Consumer resultCallback = success -> { - if (success) { - SystemUiProxy.INSTANCE.get(activity).startScreenPinning( - taskView.getTask().key.id); - } else { - taskView.notifyTaskLaunchFailed(TAG); - } - }; - taskView.launchTask(true, resultCallback, mHandler); - dismissTaskMenuView(activity); - }; - } - } - - public static class Install extends TaskSystemShortcut { - public Install() { - super(new SystemShortcut.Install()); - } - - @Override - protected View.OnClickListener getOnClickListenerForTask( - BaseDraggingActivity activity, Task task, ItemInfo itemInfo) { - if (InstantAppResolver.newInstance(activity).isInstantApp(activity, - task.getTopComponent().getPackageName())) { - return mSystemShortcut.createOnClickListener(activity, itemInfo); - } - return null; - } - } -} diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java index 07d079664a..b810c4a4e4 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskMenuView.java @@ -16,7 +16,6 @@ package com.android.quickstep.views; -import static com.android.launcher3.config.FeatureFlags.ENABLE_QUICKSTEP_LIVE_TILE; import static com.android.quickstep.views.TaskThumbnailView.DIM_ALPHA; import android.animation.Animator; @@ -26,7 +25,6 @@ import android.content.Context; import android.graphics.Rect; import android.graphics.drawable.Drawable; import android.util.AttributeSet; -import android.util.Log; import android.view.Gravity; import android.view.MotionEvent; import android.view.View; @@ -41,16 +39,13 @@ import com.android.launcher3.R; import com.android.launcher3.anim.AnimationSuccessListener; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.anim.RoundedRectRevealOutlineProvider; -import com.android.launcher3.testing.TestProtocol; +import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.util.Themes; import com.android.launcher3.views.BaseDragLayer; import com.android.quickstep.TaskOverlayFactory; -import com.android.quickstep.TaskSystemShortcut; import com.android.quickstep.TaskUtils; import com.android.quickstep.views.IconView.OnScaleUpdateListener; -import java.util.List; - /** * Contains options for a recent task when long-pressing its icon. */ @@ -197,22 +192,16 @@ public class TaskMenuView extends AbstractFloatingView { params.topMargin = (int) -mThumbnailTopMargin; mTaskIcon.setLayoutParams(params); - final BaseDraggingActivity activity = BaseDraggingActivity.fromContext(getContext()); - final List shortcuts = - TaskOverlayFactory.INSTANCE.get(getContext()).getEnabledShortcuts(taskView); - final int count = shortcuts.size(); - for (int i = 0; i < count; ++i) { - final TaskSystemShortcut menuOption = shortcuts.get(i); - addMenuOption(menuOption, menuOption.getOnClickListener(activity, taskView)); - } + TaskOverlayFactory.INSTANCE.get(getContext()).getEnabledShortcuts(taskView) + .forEach(this::addMenuOption); } - private void addMenuOption(TaskSystemShortcut menuOption, OnClickListener onClickListener) { + private void addMenuOption(SystemShortcut menuOption) { ViewGroup menuOptionView = (ViewGroup) mActivity.getLayoutInflater().inflate( R.layout.task_view_menu_option, this, false); menuOption.setIconAndLabelFor( menuOptionView.findViewById(R.id.icon), menuOptionView.findViewById(R.id.text)); - menuOptionView.setOnClickListener(onClickListener); + menuOptionView.setOnClickListener(menuOption); mOptionLayout.addView(menuOptionView); } diff --git a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java index bfb961320d..3af0f705d3 100644 --- a/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/recents_ui_overrides/src/com/android/quickstep/views/TaskView.java @@ -53,6 +53,7 @@ import com.android.launcher3.Utilities; import com.android.launcher3.anim.AnimatorPlaybackController; import com.android.launcher3.anim.Interpolators; import com.android.launcher3.logging.UserEventDispatcher; +import com.android.launcher3.popup.SystemShortcut; import com.android.launcher3.userevent.nano.LauncherLogProto; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Direction; import com.android.launcher3.userevent.nano.LauncherLogProto.Action.Touch; @@ -61,7 +62,6 @@ import com.android.launcher3.util.ViewPool.Reusable; import com.android.quickstep.RecentsModel; import com.android.quickstep.TaskIconCache; import com.android.quickstep.TaskOverlayFactory; -import com.android.quickstep.TaskSystemShortcut; import com.android.quickstep.TaskThumbnailCache; import com.android.quickstep.TaskUtils; import com.android.quickstep.util.TaskCornerRadius; @@ -713,15 +713,9 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { getContext().getText(R.string.accessibility_close_task))); final Context context = getContext(); - final List shortcuts = - TaskOverlayFactory.INSTANCE.get(getContext()).getEnabledShortcuts(this); - final int count = shortcuts.size(); - for (int i = 0; i < count; ++i) { - final TaskSystemShortcut menuOption = shortcuts.get(i); - OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, this); - if (onClickListener != null) { - info.addAction(menuOption.createAccessibilityAction(context)); - } + for (SystemShortcut s : TaskOverlayFactory.INSTANCE.get(getContext()) + .getEnabledShortcuts(this)) { + info.addAction(s.createAccessibilityAction(context)); } if (mDigitalWellBeingToast.hasLimit()) { @@ -752,16 +746,10 @@ public class TaskView extends FrameLayout implements PageCallbacks, Reusable { return true; } - final List shortcuts = - TaskOverlayFactory.INSTANCE.get(getContext()).getEnabledShortcuts(this); - final int count = shortcuts.size(); - for (int i = 0; i < count; ++i) { - final TaskSystemShortcut menuOption = shortcuts.get(i); - if (menuOption.hasHandlerForAction(action)) { - OnClickListener onClickListener = menuOption.getOnClickListener(mActivity, this); - if (onClickListener != null) { - onClickListener.onClick(this); - } + for (SystemShortcut s : TaskOverlayFactory.INSTANCE.get(getContext()) + .getEnabledShortcuts(this)) { + if (s.hasHandlerForAction(action)) { + s.onClick(this); return true; } } diff --git a/src/com/android/launcher3/popup/PopupContainerWithArrow.java b/src/com/android/launcher3/popup/PopupContainerWithArrow.java index 4833c26d82..8e5d852a31 100644 --- a/src/com/android/launcher3/popup/PopupContainerWithArrow.java +++ b/src/com/android/launcher3/popup/PopupContainerWithArrow.java @@ -382,8 +382,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, @Override public void onWidgetsBound() { ItemInfo itemInfo = (ItemInfo) mOriginalIcon.getTag(); - SystemShortcut widgetInfo = new SystemShortcut.Widgets(); - View.OnClickListener onClickListener = widgetInfo.getOnClickListener(mLauncher, itemInfo); + SystemShortcut widgetInfo = SystemShortcut.WIDGETS.getShortcut(mLauncher, itemInfo); View widgetsView = null; int count = mSystemShortcutContainer.getChildCount(); for (int i = 0; i < count; i++) { @@ -394,7 +393,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, } } - if (onClickListener != null && widgetsView == null) { + if (widgetInfo != null && widgetsView == null) { // We didn't have any widgets cached but now there are some, so enable the shortcut. if (mSystemShortcutContainer != this) { initializeSystemShortcut( @@ -407,7 +406,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, close(false); PopupContainerWithArrow.showForIcon(mOriginalIcon); } - } else if (onClickListener == null && widgetsView != null) { + } else if (widgetInfo == null && widgetsView != null) { // No widgets exist, but we previously added the shortcut so remove it. if (mSystemShortcutContainer != this) { mSystemShortcutContainer.removeView(widgetsView); @@ -430,8 +429,7 @@ public class PopupContainerWithArrow extends ArrowPopup implements DragSource, info.setIconAndContentDescriptionFor((ImageView) view); } view.setTag(info); - view.setOnClickListener(info.getOnClickListener(mLauncher, - (ItemInfo) mOriginalIcon.getTag())); + view.setOnClickListener(info); } /** diff --git a/src/com/android/launcher3/popup/RemoteActionShortcut.java b/src/com/android/launcher3/popup/RemoteActionShortcut.java index 5a5fbabacf..8751202538 100644 --- a/src/com/android/launcher3/popup/RemoteActionShortcut.java +++ b/src/com/android/launcher3/popup/RemoteActionShortcut.java @@ -16,13 +16,19 @@ package com.android.launcher3.popup; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; + +import android.annotation.TargetApi; import android.app.PendingIntent; import android.app.RemoteAction; +import android.content.Context; import android.content.Intent; -import android.os.Handler; -import android.os.Looper; +import android.os.Build; import android.util.Log; import android.view.View; +import android.view.accessibility.AccessibilityNodeInfo; +import android.widget.ImageView; +import android.widget.TextView; import android.widget.Toast; import com.android.launcher3.AbstractFloatingView; @@ -32,55 +38,75 @@ import com.android.launcher3.R; import com.android.launcher3.Utilities; import com.android.launcher3.userevent.nano.LauncherLogProto; +@TargetApi(Build.VERSION_CODES.Q) public class RemoteActionShortcut extends SystemShortcut { private static final String TAG = "RemoteActionShortcut"; private static final boolean DEBUG = Utilities.IS_DEBUG_DEVICE; private final RemoteAction mAction; - public RemoteActionShortcut(RemoteAction action) { - super(action.getIcon(), action.getTitle(), action.getContentDescription(), - R.id.action_remote_action_shortcut); + public RemoteActionShortcut(RemoteAction action, + BaseDraggingActivity activity, ItemInfo itemInfo) { + super(0, R.id.action_remote_action_shortcut, activity, itemInfo); mAction = action; } @Override - public View.OnClickListener getOnClickListener( - final BaseDraggingActivity activity, final ItemInfo itemInfo) { - return view -> { - AbstractFloatingView.closeAllOpenViews(activity); + public void setIconAndLabelFor(View iconView, TextView labelView) { + mAction.getIcon().loadDrawableAsync(iconView.getContext(), + iconView::setBackground, + MAIN_EXECUTOR.getHandler()); + labelView.setText(mAction.getTitle()); + } - final String actionIdentity = mAction.getTitle() + ", " + - itemInfo.getTargetComponent().getPackageName(); - try { - if (DEBUG) Log.d(TAG, "Sending action: " + actionIdentity); - mAction.getActionIntent().send( - activity, - 0, - new Intent().putExtra( - Intent.EXTRA_PACKAGE_NAME, - itemInfo.getTargetComponent().getPackageName()), - (pendingIntent, intent, resultCode, resultData, resultExtras) -> { - if (DEBUG) Log.d(TAG, "Action is complete: " + actionIdentity); - if (resultData != null && !resultData.isEmpty()) { - Log.e(TAG, "Remote action returned result: " + actionIdentity - + " : " + resultData); - Toast.makeText(activity, resultData, Toast.LENGTH_SHORT).show(); - } - }, - new Handler(Looper.getMainLooper())); - } catch (PendingIntent.CanceledException e) { - Log.e(TAG, "Remote action canceled: " + actionIdentity, e); - Toast.makeText(activity, activity.getString( - R.string.remote_action_failed, - mAction.getTitle()), - Toast.LENGTH_SHORT) - .show(); - } + @Override + public void setIconAndContentDescriptionFor(ImageView view) { + mAction.getIcon().loadDrawableAsync(view.getContext(), + view::setImageDrawable, + MAIN_EXECUTOR.getHandler()); + view.setContentDescription(mAction.getContentDescription()); + } - activity.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, - LauncherLogProto.ControlType.REMOTE_ACTION_SHORTCUT, view); - }; + @Override + public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(Context context) { + return new AccessibilityNodeInfo.AccessibilityAction( + R.id.action_remote_action_shortcut, mAction.getContentDescription()); + } + + @Override + public void onClick(View view) { + AbstractFloatingView.closeAllOpenViews(mTarget); + + final String actionIdentity = mAction.getTitle() + ", " + + mItemInfo.getTargetComponent().getPackageName(); + try { + if (DEBUG) Log.d(TAG, "Sending action: " + actionIdentity); + mAction.getActionIntent().send( + mTarget, + 0, + new Intent().putExtra( + Intent.EXTRA_PACKAGE_NAME, + mItemInfo.getTargetComponent().getPackageName()), + (pendingIntent, intent, resultCode, resultData, resultExtras) -> { + if (DEBUG) Log.d(TAG, "Action is complete: " + actionIdentity); + if (resultData != null && !resultData.isEmpty()) { + Log.e(TAG, "Remote action returned result: " + actionIdentity + + " : " + resultData); + Toast.makeText(mTarget, resultData, Toast.LENGTH_SHORT).show(); + } + }, + MAIN_EXECUTOR.getHandler()); + } catch (PendingIntent.CanceledException e) { + Log.e(TAG, "Remote action canceled: " + actionIdentity, e); + Toast.makeText(mTarget, mTarget.getString( + R.string.remote_action_failed, + mAction.getTitle()), + Toast.LENGTH_SHORT) + .show(); + } + + mTarget.getUserEventDispatcher().logActionOnControl(LauncherLogProto.Action.Touch.TAP, + LauncherLogProto.ControlType.REMOTE_ACTION_SHORTCUT, view); } @Override diff --git a/src/com/android/launcher3/popup/SystemShortcut.java b/src/com/android/launcher3/popup/SystemShortcut.java index a87b7b8971..222c6c962f 100644 --- a/src/com/android/launcher3/popup/SystemShortcut.java +++ b/src/com/android/launcher3/popup/SystemShortcut.java @@ -5,14 +5,13 @@ 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 androidx.annotation.Nullable; + import com.android.launcher3.AbstractFloatingView; import com.android.launcher3.BaseDraggingActivity; import com.android.launcher3.ItemInfo; @@ -39,41 +38,30 @@ import java.util.List; * Example system shortcuts, defined as inner classes, include Widgets and AppInfo. * @param */ -public abstract class SystemShortcut - extends ItemInfo { +public abstract class SystemShortcut extends ItemInfo + implements View.OnClickListener { + 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) { + protected final T mTarget; + protected final ItemInfo mItemInfo; + + public SystemShortcut(int iconResId, int labelResId, T target, ItemInfo itemInfo) { mIconResId = iconResId; mLabelResId = labelResId; mAccessibilityActionId = labelResId; - mIcon = null; - mLabel = null; - mContentDescription = null; + mTarget = target; + mItemInfo = itemInfo; } - 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) { + public SystemShortcut(SystemShortcut other) { mIconResId = other.mIconResId; mLabelResId = other.mLabelResId; - mIcon = other.mIcon; - mLabel = other.mLabel; - mContentDescription = other.mContentDescription; mAccessibilityActionId = other.mAccessibilityActionId; + mTarget = other.mTarget; + mItemInfo = other.mItemInfo; } /** @@ -84,150 +72,135 @@ public abstract class SystemShortcut } 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); - } + iconView.setBackgroundResource(mIconResId); + 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); + view.setImageResource(mIconResId); + view.setContentDescription(view.getContext().getText(mLabelResId)); } public AccessibilityNodeInfo.AccessibilityAction createAccessibilityAction(Context context) { - return new AccessibilityNodeInfo.AccessibilityAction(mAccessibilityActionId, - getContentDescription(context)); + return new AccessibilityNodeInfo.AccessibilityAction( + mAccessibilityActionId, context.getText(mLabelResId)); } public boolean hasHandlerForAction(int action) { return mAccessibilityActionId == action; } - public abstract View.OnClickListener getOnClickListener(T activity, ItemInfo itemInfo); + public interface Factory { + + @Nullable SystemShortcut getShortcut(T activity, ItemInfo itemInfo); + } + + public static final Factory WIDGETS = (launcher, itemInfo) -> { + if (itemInfo.getTargetComponent() == null) return null; + final List widgets = + launcher.getPopupDataProvider().getWidgetsForPackageUser(new PackageUserKey( + itemInfo.getTargetComponent().getPackageName(), itemInfo.user)); + if (widgets == null) { + return null; + } + return new Widgets(launcher, itemInfo); + }; public static class Widgets extends SystemShortcut { - public Widgets() { - super(R.drawable.ic_widget, R.string.widget_button_text); + public Widgets(Launcher target, ItemInfo itemInfo) { + super(R.drawable.ic_widget, R.string.widget_button_text, target, itemInfo); } @Override - public View.OnClickListener getOnClickListener(final Launcher launcher, - final ItemInfo itemInfo) { - if (itemInfo.getTargetComponent() == null) return null; - final List 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 void onClick(View view) { + AbstractFloatingView.closeAllOpenViews(mTarget); + WidgetsBottomSheet widgetsBottomSheet = + (WidgetsBottomSheet) mTarget.getLayoutInflater().inflate( + R.layout.widgets_bottom_sheet, mTarget.getDragLayer(), false); + widgetsBottomSheet.populateAndShow(mItemInfo); + mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.WIDGETS_BUTTON, view); } } + public static final Factory APP_INFO = AppInfo::new; + public static class AppInfo extends SystemShortcut { - public AppInfo() { - super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label); + + public AppInfo(BaseDraggingActivity target, ItemInfo itemInfo) { + super(R.drawable.ic_info_no_shadow, R.string.app_info_drop_target_label, target, + itemInfo); } @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 void onClick(View view) { + dismissTaskMenuView(mTarget); + Rect sourceBounds = mTarget.getViewBounds(view); + new PackageManagerHelper(mTarget).startDetailsActivityForInfo( + mItemInfo, sourceBounds, ActivityOptions.makeBasic().toBundle()); + mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.APPINFO_TARGET, view); } } + public static Factory INSTALL = (activity, 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 new Install(activity, itemInfo); + }; + public static class Install extends SystemShortcut { - public Install() { - super(R.drawable.ic_install_no_shadow, R.string.install_drop_target_label); + + public Install(BaseDraggingActivity target, ItemInfo itemInfo) { + super(R.drawable.ic_install_no_shadow, R.string.install_drop_target_label, + target, itemInfo); } @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 void onClick(View view) { + Intent intent = new PackageManagerHelper(view.getContext()).getMarketIntent( + mItemInfo.getTargetComponent().getPackageName()); + mTarget.startActivitySafely(view, intent, mItemInfo, null); + AbstractFloatingView.closeAllOpenViews(mTarget); } } + public static Factory DISMISS_PREDICTION = (launcher, itemInfo) -> { + if (!FeatureFlags.ENABLE_PREDICTION_DISMISS.get()) return null; + if (itemInfo.container != LauncherSettings.Favorites.CONTAINER_PREDICTION) return null; + return new DismissPrediction(launcher, itemInfo); + }; + public static class DismissPrediction extends SystemShortcut { - public DismissPrediction() { - super(R.drawable.ic_remove_no_shadow, R.string.dismiss_prediction_label); + public DismissPrediction(Launcher launcher, ItemInfo itemInfo) { + super(R.drawable.ic_remove_no_shadow, R.string.dismiss_prediction_label, launcher, + itemInfo); } @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); - }; + public void onClick(View view) { + PopupContainerWithArrow.closeAllOpenViews(mTarget); + mTarget.getUserEventDispatcher().logActionOnControl(Action.Touch.TAP, + ControlType.DISMISS_PREDICTION, ContainerType.DEEPSHORTCUTS); + AppLaunchTracker.INSTANCE.get(view.getContext()).onDismissApp( + mItemInfo.getTargetComponent(), + mItemInfo.user, + AppLaunchTracker.CONTAINER_PREDICTIONS); } } - protected static void dismissTaskMenuView(BaseDraggingActivity activity) { + public static void dismissTaskMenuView(BaseDraggingActivity activity) { AbstractFloatingView.closeOpenViews(activity, true, AbstractFloatingView.TYPE_ALL & ~AbstractFloatingView.TYPE_REBIND_SAFE); } diff --git a/src/com/android/launcher3/popup/SystemShortcutFactory.java b/src/com/android/launcher3/popup/SystemShortcutFactory.java index dfcc2f8224..8b8a4d0190 100644 --- a/src/com/android/launcher3/popup/SystemShortcutFactory.java +++ b/src/com/android/launcher3/popup/SystemShortcutFactory.java @@ -34,25 +34,24 @@ public class SystemShortcutFactory implements ResourceBasedOverride { forOverride(SystemShortcutFactory.class, R.string.system_shortcut_factory_class); /** Note that these are in order of priority. */ - private final SystemShortcut[] mAllShortcuts; + private final SystemShortcut.Factory[] mAllFactories; @SuppressWarnings("unused") public SystemShortcutFactory() { - this(new SystemShortcut.AppInfo(), - new SystemShortcut.Widgets(), - new SystemShortcut.Install(), - new SystemShortcut.DismissPrediction()); + this(SystemShortcut.APP_INFO, SystemShortcut.WIDGETS, SystemShortcut.INSTALL, + SystemShortcut.DISMISS_PREDICTION); } - protected SystemShortcutFactory(SystemShortcut... shortcuts) { - mAllShortcuts = shortcuts; + protected SystemShortcutFactory(SystemShortcut.Factory... factories) { + mAllFactories = factories; } public @NonNull List getEnabledShortcuts(Launcher launcher, ItemInfo info) { List systemShortcuts = new ArrayList<>(); - for (SystemShortcut systemShortcut : mAllShortcuts) { - if (systemShortcut.getOnClickListener(launcher, info) != null) { - systemShortcuts.add(systemShortcut); + for (SystemShortcut.Factory factory : mAllFactories) { + SystemShortcut shortcut = factory.getShortcut(launcher, info); + if (shortcut != null) { + systemShortcuts.add(shortcut); } }