From 5512003c0d3e39f524f6ecc991026d7c4307b124 Mon Sep 17 00:00:00 2001 From: Jordan Demeulenaere Date: Wed, 8 May 2024 14:50:52 +0200 Subject: [PATCH 01/12] Delay TransitionAnimator.onAnimationEnd by one frame (2/4) Bug: 330672236 Test: atest ActivityTransitionAnimatorTest Test: atest DialogTransitionAnimatorTest Flag: N/A Change-Id: I81e85df79256d013f6c3ef5cb58a5d96c0c7deec --- .../src/com/android/launcher3/QuickstepTransitionManager.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java index 0697f47cda..72aaa9000a 100644 --- a/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java +++ b/quickstep/src/com/android/launcher3/QuickstepTransitionManager.java @@ -58,6 +58,7 @@ import static com.android.launcher3.config.FeatureFlags.SEPARATE_RECENTS_ACTIVIT import static com.android.launcher3.model.data.ItemInfo.NO_MATCHING_ID; import static com.android.launcher3.testing.shared.TestProtocol.WALLPAPER_OPEN_ANIMATION_FINISHED_MESSAGE; import static com.android.launcher3.util.DisplayController.isTransientTaskbar; +import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.ORDERED_BG_EXECUTOR; import static com.android.launcher3.util.MultiPropertyFactory.MULTI_PROPERTY_VALUE; import static com.android.launcher3.util.window.RefreshRateTracker.getSingleFrameMs; @@ -1881,7 +1882,7 @@ public class QuickstepTransitionManager implements OnDeviceProfileChangeListener return new ContainerAnimationRunner( new ActivityTransitionAnimator.AnimationDelegate( - controller, callback, listener)); + MAIN_EXECUTOR, controller, callback, listener)); } /** From cc54eb490772044eb348f1f659d2b7e031a4e35f Mon Sep 17 00:00:00 2001 From: helencheuk Date: Fri, 26 Apr 2024 16:06:02 +0100 Subject: [PATCH 02/12] Add focus outline to AppPairIcon Bug: 327470960 Test: Manual Flag: ACONFIG com.android.launcher3.enable_focus_outline Trunkfood Change-Id: I6a9c6abc3441b5f40bb4f352a844cecad4a1474b --- src/com/android/launcher3/apppairs/AppPairIcon.java | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/com/android/launcher3/apppairs/AppPairIcon.java b/src/com/android/launcher3/apppairs/AppPairIcon.java index 1f73241ed0..32445ecddb 100644 --- a/src/com/android/launcher3/apppairs/AppPairIcon.java +++ b/src/com/android/launcher3/apppairs/AppPairIcon.java @@ -30,6 +30,8 @@ import androidx.annotation.Nullable; import com.android.launcher3.BubbleTextView; import com.android.launcher3.DeviceProfile; +import com.android.launcher3.Flags; +import com.android.launcher3.Launcher; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.Reorderable; @@ -85,6 +87,11 @@ public class AppPairIcon extends FrameLayout implements DraggableView, Reorderab : activity.getLayoutInflater(); AppPairIcon icon = (AppPairIcon) inflater.inflate(resId, group, false); + if (Flags.enableFocusOutline() && activity instanceof Launcher) { + icon.setOnFocusChangeListener(((Launcher) activity).getFocusHandler()); + icon.setDefaultFocusHighlightEnabled(false); + } + // Sort contents, so that left-hand app comes first appPairInfo.getContents().sort(Comparator.comparingInt(a -> a.rank)); From c9eda41c318598ffc984217f5ed224b833ad50f6 Mon Sep 17 00:00:00 2001 From: Anushree Ganjam Date: Tue, 7 May 2024 15:54:14 -0700 Subject: [PATCH 03/12] Hardcode the className instead of class.getSimpleName(). class.getSimpleName() causes issues with obfuscation. Bug: 332171918 Test: Manual Flag: NA Change-Id: I5119a7ba0e4e27d8745c94df67881934fed282a4 --- .../appprediction/PredictionRowView.java | 2 +- .../HotseatPredictionController.java | 2 +- .../popup/QuickstepSystemShortcut.java | 2 +- .../launcher3/splitscreen/SplitShortcut.kt | 2 +- .../statehandlers/DepthController.java | 2 +- .../taskbar/FallbackTaskbarUIController.java | 5 + .../taskbar/LauncherTaskbarUIController.java | 5 + .../TaskbarLauncherStateController.java | 2 +- .../taskbar/TaskbarNavButtonController.java | 2 +- .../taskbar/TaskbarStashController.java | 2 +- .../taskbar/TaskbarUIController.java | 7 +- .../launcher3/taskbar/TaskbarView.java | 2 +- .../taskbar/TaskbarViewController.java | 2 +- .../taskbar/bubbles/BubbleBarController.java | 2 +- .../taskbar/bubbles/BubbleBarView.java | 2 +- .../bubbles/BubbleBarViewController.java | 2 +- .../bubbles/BubbleDismissController.java | 2 +- .../bubbles/BubbleStashController.java | 2 +- .../com/android/quickstep/SystemUiProxy.java | 2 +- .../quickstep/util/SplitSelectDataHolder.kt | 194 ++++++++++-------- .../util/SwipePipToHomeAnimator.java | 2 +- .../util/TaskKeyByLastActiveTimeCache.java | 2 +- .../quickstep/views/DesktopTaskView.java | 2 +- .../views/DigitalWellBeingToast.java | 2 +- .../quickstep/views/GroupedTaskView.java | 2 +- .../com/android/quickstep/views/TaskView.java | 2 +- src/com/android/launcher3/DevicePaddings.java | 2 +- src/com/android/launcher3/PagedView.java | 2 +- .../launcher3/model/data/ItemInfo.java | 3 +- .../launcher3/pm/PackageInstallInfo.java | 3 +- .../responsive/HotseatSpecsProvider.kt | 2 +- .../responsive/ResponsiveCellSpecsProvider.kt | 12 +- .../launcher3/responsive/ResponsiveSpec.kt | 2 +- .../responsive/ResponsiveSpecsProvider.kt | 3 +- .../launcher3/touch/ItemClickHandler.java | 2 +- .../android/launcher3/views/ArrowTipView.java | 2 +- .../launcher3/views/FloatingIconView.java | 2 +- 37 files changed, 165 insertions(+), 125 deletions(-) diff --git a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java index 70e01f53a0..a16031d804 100644 --- a/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java +++ b/quickstep/src/com/android/launcher3/appprediction/PredictionRowView.java @@ -286,7 +286,7 @@ public class PredictionRowView } public void dump(String prefix, PrintWriter writer) { - writer.println(prefix + this.getClass().getSimpleName()); + writer.println(prefix + "PredictionRowView"); writer.println(prefix + "\tmPredictionsEnabled: " + mPredictionsEnabled); writer.println(prefix + "\tmPredictionUiUpdatePaused: " + mPredictionUiUpdatePaused); writer.println(prefix + "\tmNumPredictedAppsPerRow: " + mNumPredictedAppsPerRow); diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 1c5a75dd1c..866dbe584c 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -521,7 +521,7 @@ public class HotseatPredictionController implements DragController.DragListener, } public void dump(String prefix, PrintWriter writer) { - writer.println(prefix + this.getClass().getSimpleName()); + writer.println(prefix + "HotseatPredictionController"); writer.println(prefix + "\tFlags: " + getStateString(mPauseFlags)); writer.println(prefix + "\tmHotSeatItemsCount: " + mHotSeatItemsCount); writer.println(prefix + "\tmPredictedItems: " + mPredictedItems); diff --git a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java index 184ea717cd..fe9ade9896 100644 --- a/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java +++ b/quickstep/src/com/android/launcher3/popup/QuickstepSystemShortcut.java @@ -25,7 +25,7 @@ import com.android.launcher3.util.SplitConfigurationOptions.SplitPositionOption; /** {@link SystemShortcut.Factory} implementation to create workspace split shortcuts */ public interface QuickstepSystemShortcut { - String TAG = QuickstepSystemShortcut.class.getSimpleName(); + String TAG = "QuickstepSystemShortcut"; static SystemShortcut.Factory getSplitSelectShortcutByPosition( SplitPositionOption position) { diff --git a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt index 2b6f77f231..c94edceb43 100644 --- a/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt +++ b/quickstep/src/com/android/launcher3/splitscreen/SplitShortcut.kt @@ -45,7 +45,7 @@ abstract class SplitShortcut( ) : SystemShortcut(iconResId, labelResId, target, itemInfo, originalView) where T : Context?, T : ActivityContext? { - private val TAG = SystemShortcut::class.java.simpleName + private val TAG = "SplitShortcut" // Initiate splitscreen from the Home screen or Home All Apps protected val splitSelectSource: SplitSelectSource? diff --git a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java index 882682dc4a..747612d823 100644 --- a/quickstep/src/com/android/launcher3/statehandlers/DepthController.java +++ b/quickstep/src/com/android/launcher3/statehandlers/DepthController.java @@ -182,7 +182,7 @@ public class DepthController extends BaseDepthController implements StateHandler } public void dump(String prefix, PrintWriter writer) { - writer.println(prefix + this.getClass().getSimpleName()); + writer.println(prefix + "DepthController"); writer.println(prefix + "\tmMaxBlurRadius=" + mMaxBlurRadius); writer.println(prefix + "\tmCrossWindowBlursEnabled=" + mCrossWindowBlursEnabled); writer.println(prefix + "\tmSurface=" + mSurface); diff --git a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java index c0ecc6151a..06d9ee6c96 100644 --- a/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/FallbackTaskbarUIController.java @@ -133,4 +133,9 @@ public class FallbackTaskbarUIController extends TaskbarUIController { protected TISBindHelper getTISBindHelper() { return mRecentsActivity.getTISBindHelper(); } + + @Override + protected String getTaskbarUIControllerName() { + return "FallbackTaskbarUIController"; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java index 2ce6a41cb9..4f021224c3 100644 --- a/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/LauncherTaskbarUIController.java @@ -446,4 +446,9 @@ public class LauncherTaskbarUIController extends TaskbarUIController { mTaskbarLauncherStateController.dumpLogs(prefix + "\t", pw); } + + @Override + protected String getTaskbarUIControllerName() { + return "LauncherTaskbarUIController"; + } } diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java index ee21eacb8c..6ea52cb888 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarLauncherStateController.java @@ -65,7 +65,7 @@ import java.util.StringJoiner; */ public class TaskbarLauncherStateController { - private static final String TAG = TaskbarLauncherStateController.class.getSimpleName(); + private static final String TAG = "TaskbarLauncherStateController"; private static final boolean DEBUG = false; /** Launcher activity is visible and focused. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java index ade4649dab..13a68a04a7 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarNavButtonController.java @@ -66,7 +66,7 @@ public class TaskbarNavButtonController implements TaskbarControllers.LoggableTa /** Allow some time in between the long press for back and recents. */ static final int SCREEN_PIN_LONG_PRESS_THRESHOLD = 200; static final int SCREEN_PIN_LONG_PRESS_RESET = SCREEN_PIN_LONG_PRESS_THRESHOLD + 100; - private static final String TAG = TaskbarNavButtonController.class.getSimpleName(); + private static final String TAG = "TaskbarNavButtonController"; private long mLastScreenPinLongPress; private boolean mScreenPinned; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java index 4da77627f7..f764a835f6 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarStashController.java @@ -78,7 +78,7 @@ import java.util.function.IntPredicate; * create a cohesive animation between stashed/unstashed states. */ public class TaskbarStashController implements TaskbarControllers.LoggableTaskbarController { - private static final String TAG = TaskbarStashController.class.getSimpleName(); + private static final String TAG = "TaskbarStashController"; private static final boolean DEBUG = false; public static final int FLAG_IN_APP = 1 << 0; diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index 32e4097de4..6abd5a9c75 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -55,7 +55,6 @@ import java.util.stream.Stream; * Base class for providing different taskbar UI */ public class TaskbarUIController { - public static final TaskbarUIController DEFAULT = new TaskbarUIController(); // Initialized in init. @@ -91,6 +90,10 @@ public class TaskbarUIController { */ protected void onIconLayoutBoundsChanged() { } + protected String getTaskbarUIControllerName() { + return "TaskbarUIController"; + } + /** Called when an icon is launched. */ @CallSuper public void onTaskbarIconLaunched(ItemInfo item) { @@ -207,7 +210,7 @@ public class TaskbarUIController { pw.println(String.format( "%sTaskbarUIController: using an instance of %s", prefix, - getClass().getSimpleName())); + getTaskbarUIControllerName())); } /** diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java index 77f8a8a088..df7a7ba84a 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarView.java @@ -71,7 +71,7 @@ import java.util.function.Predicate; */ public class TaskbarView extends FrameLayout implements FolderIcon.FolderIconParent, Insettable, DeviceProfile.OnDeviceProfileChangeListener { - private static final String TAG = TaskbarView.class.getSimpleName(); + private static final String TAG = "TaskbarView"; private static final Rect sTmpRect = new Rect(); diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java index e0b446e5a9..0ee3d7f361 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarViewController.java @@ -79,7 +79,7 @@ import java.util.function.Predicate; */ public class TaskbarViewController implements TaskbarControllers.LoggableTaskbarController { - private static final String TAG = TaskbarViewController.class.getSimpleName(); + private static final String TAG = "TaskbarViewController"; private static final Runnable NO_OP = () -> { }; diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index 8c83508ad9..4c126f8966 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -94,7 +94,7 @@ import java.util.concurrent.Executors; */ public class BubbleBarController extends IBubblesListener.Stub { - private static final String TAG = BubbleBarController.class.getSimpleName(); + private static final String TAG = "BubbleBarController"; private static final boolean DEBUG = false; /** diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java index 4334807021..d08015e0ca 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarView.java @@ -76,7 +76,7 @@ import java.util.function.Consumer; */ public class BubbleBarView extends FrameLayout { - private static final String TAG = BubbleBarView.class.getSimpleName(); + private static final String TAG = "BubbleBarView"; // TODO: (b/273594744) calculate the amount of space we have and base the max on that // if it's smaller than 5. diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java index ac02f1fe5e..cd8eaf9a5e 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarViewController.java @@ -55,7 +55,7 @@ import java.util.function.Consumer; */ public class BubbleBarViewController { - private static final String TAG = BubbleBarViewController.class.getSimpleName(); + private static final String TAG = "BubbleBarViewController"; private static final float APP_ICON_SMALL_DP = 44f; private static final float APP_ICON_MEDIUM_DP = 48f; private static final float APP_ICON_LARGE_DP = 52f; diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java index a40f33c595..0e6fa3c5e8 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleDismissController.java @@ -40,7 +40,7 @@ import com.android.wm.shell.common.magnetictarget.MagnetizedObject; * @see BubbleDragController */ public class BubbleDismissController { - private static final String TAG = BubbleDismissController.class.getSimpleName(); + private static final String TAG = "BubbleDismissController"; private static final float FLING_TO_DISMISS_MIN_VELOCITY = 6000f; private final TaskbarActivityContext mActivity; private final TaskbarDragLayer mDragLayer; diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java index d0462aa3da..5d01b9bd08 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleStashController.java @@ -42,7 +42,7 @@ import com.android.wm.shell.shared.animation.PhysicsAnimator; */ public class BubbleStashController { - private static final String TAG = BubbleStashController.class.getSimpleName(); + private static final String TAG = "BubbleStashController"; /** * How long to stash/unstash. diff --git a/quickstep/src/com/android/quickstep/SystemUiProxy.java b/quickstep/src/com/android/quickstep/SystemUiProxy.java index 0ad60b7f1e..4d3fe41f5d 100644 --- a/quickstep/src/com/android/quickstep/SystemUiProxy.java +++ b/quickstep/src/com/android/quickstep/SystemUiProxy.java @@ -111,7 +111,7 @@ import java.util.List; * Holds the reference to SystemUI. */ public class SystemUiProxy implements ISystemUiProxy, NavHandle, SafeCloseable { - private static final String TAG = SystemUiProxy.class.getSimpleName(); + private static final String TAG = "SystemUiProxy"; public static final MainThreadInitializedObject INSTANCE = new MainThreadInitializedObject<>(SystemUiProxy::new); diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt index 06edb14a1f..8258ab81af 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt +++ b/quickstep/src/com/android/quickstep/util/SplitSelectDataHolder.kt @@ -38,36 +38,40 @@ import com.android.quickstep.util.SplitSelectDataHolder.Companion.SplitLaunchTyp import java.io.PrintWriter /** - * Holds/transforms/signs/seals/delivers information for the transient state of the user - * selecting a first app to start split with and then choosing a second app. - * This class DOES NOT associate itself with drag-and-drop split screen starts because they come - * from the bad part of town. + * Holds/transforms/signs/seals/delivers information for the transient state of the user selecting a + * first app to start split with and then choosing a second app. This class DOES NOT associate + * itself with drag-and-drop split screen starts because they come from the bad part of town. * * After setting the correct fields for initial/second.* variables, this converts them into the - * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary - * data back via [getSplitLaunchData]. Note: there should be only one "initial" field and one - * "second" field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are - * always passed in together as a set, and are converted to a single [PendingIntent] or + * correct [PendingIntent] and [ShortcutInfo] objects where applicable and sends the necessary data + * back via [getSplitLaunchData]. Note: there should be only one "initial" field and one "second" + * field set, with the rest remaining null. (Exception: [Intent] and [UserHandle] are always passed + * in together as a set, and are converted to a single [PendingIntent] or * [ShortcutInfo]+[PendingIntent] before launch.) * * [SplitLaunchType] indicates the type of tasks/apps/intents being launched given the provided * state */ -class SplitSelectDataHolder( - var context: Context? -) { +class SplitSelectDataHolder(var context: Context?) { val TAG = SplitSelectDataHolder::class.simpleName /** - * Order of the constant indicates the order of which task/app was selected. - * Ex. SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut + * Order of the constant indicates the order of which task/app was selected. Ex. + * SPLIT_TASK_SHORTCUT means primary split app identified by task, secondary is shortcut * SPLIT_SHORTCUT_TASK means primary split app is determined by shortcut, secondary is task */ companion object { - @IntDef(SPLIT_TASK_TASK, SPLIT_TASK_PENDINGINTENT, SPLIT_TASK_SHORTCUT, - SPLIT_PENDINGINTENT_TASK, SPLIT_PENDINGINTENT_PENDINGINTENT, SPLIT_SHORTCUT_TASK, - SPLIT_SINGLE_TASK_FULLSCREEN, SPLIT_SINGLE_INTENT_FULLSCREEN, - SPLIT_SINGLE_SHORTCUT_FULLSCREEN) + @IntDef( + SPLIT_TASK_TASK, + SPLIT_TASK_PENDINGINTENT, + SPLIT_TASK_SHORTCUT, + SPLIT_PENDINGINTENT_TASK, + SPLIT_PENDINGINTENT_PENDINGINTENT, + SPLIT_SHORTCUT_TASK, + SPLIT_SINGLE_TASK_FULLSCREEN, + SPLIT_SINGLE_INTENT_FULLSCREEN, + SPLIT_SINGLE_SHORTCUT_FULLSCREEN + ) @Retention(AnnotationRetention.SOURCE) annotation class SplitLaunchType @@ -84,8 +88,7 @@ class SplitSelectDataHolder( const val SPLIT_SINGLE_SHORTCUT_FULLSCREEN = 8 } - @StagePosition - private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED + @StagePosition private var initialStagePosition: Int = STAGE_POSITION_UNDEFINED private var itemInfo: ItemInfo? = null private var secondItemInfo: ItemInfo? = null private var splitEvent: EventEnum? = null @@ -108,12 +111,16 @@ class SplitSelectDataHolder( /** * @param alreadyRunningTask if set to [android.app.ActivityTaskManager.INVALID_TASK_ID] - * then @param intent will be used to launch the initial task + * then @param intent will be used to launch the initial task * @param intent will be ignored if @param alreadyRunningTask is set */ - fun setInitialTaskSelect(intent: Intent?, @StagePosition stagePosition: Int, - itemInfo: ItemInfo?, splitEvent: EventEnum?, - alreadyRunningTask: Int) { + fun setInitialTaskSelect( + intent: Intent?, + @StagePosition stagePosition: Int, + itemInfo: ItemInfo?, + splitEvent: EventEnum?, + alreadyRunningTask: Int + ) { if (alreadyRunningTask != INVALID_TASK_ID) { initialTaskId = alreadyRunningTask } else { @@ -127,15 +134,21 @@ class SplitSelectDataHolder( * To be called after first task selected from using a split shortcut from the fullscreen * running app. */ - fun setInitialTaskSelect(info: RunningTaskInfo, - @StagePosition stagePosition: Int, itemInfo: ItemInfo?, - splitEvent: EventEnum?) { + fun setInitialTaskSelect( + info: RunningTaskInfo, + @StagePosition stagePosition: Int, + itemInfo: ItemInfo?, + splitEvent: EventEnum? + ) { initialTaskId = info.taskId setInitialData(stagePosition, splitEvent, itemInfo) } - private fun setInitialData(@StagePosition stagePosition: Int, - event: EventEnum?, item: ItemInfo?) { + private fun setInitialData( + @StagePosition stagePosition: Int, + event: EventEnum?, + item: ItemInfo? + ) { itemInfo = item initialStagePosition = stagePosition splitEvent = event @@ -143,6 +156,7 @@ class SplitSelectDataHolder( /** * To be called as soon as user selects the second task (even if animations aren't complete) + * * @param taskId The second task that will be launched. */ fun setSecondTask(taskId: Int, itemInfo: ItemInfo) { @@ -152,6 +166,7 @@ class SplitSelectDataHolder( /** * To be called as soon as user selects the second app (even if animations aren't complete) + * * @param intent The second intent that will be launched. * @param user The user of that intent. */ @@ -162,8 +177,9 @@ class SplitSelectDataHolder( } /** - * To be called as soon as user selects the second app (even if animations aren't complete) - * Sets [secondUser] from that of the pendingIntent + * To be called as soon as user selects the second app (even if animations aren't complete) Sets + * [secondUser] from that of the pendingIntent + * * @param pendingIntent The second PendingIntent that will be launched. */ fun setSecondTask(pendingIntent: PendingIntent, itemInfo: ItemInfo) { @@ -173,9 +189,9 @@ class SplitSelectDataHolder( } /** - * Similar to [setSecondTask] except this is to be called for widgets which can pass through - * an extra intent from their RemoteResponse. - * See [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first + * Similar to [setSecondTask] except this is to be called for widgets which can pass through an + * extra intent from their RemoteResponse. See + * [android.widget.RemoteViews.RemoteResponse.getLaunchOptions].first */ fun setSecondWidget(pendingIntent: PendingIntent, widgetIntent: Intent?, itemInfo: ItemInfo) { setSecondTask(pendingIntent, itemInfo) @@ -184,8 +200,7 @@ class SplitSelectDataHolder( private fun getShortcutInfo(intent: Intent?, user: UserHandle?): ShortcutInfo? { val intentPackage = intent?.getPackage() ?: return null - val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) - ?: return null + val shortcutId = intent.getStringExtra(ShortcutKey.EXTRA_SHORTCUT_ID) ?: return null try { val context: Context = if (user != null) { @@ -200,9 +215,7 @@ class SplitSelectDataHolder( return null } - /** - * Converts intents to pendingIntents, associating the [user] with the intent if provided - */ + /** Converts intents to pendingIntents, associating the [user] with the intent if provided */ private fun getPendingIntent(intent: Intent?, user: UserHandle?): PendingIntent? { if (intent != initialIntent && intent != secondIntent) { throw IllegalStateException("Invalid intent to convert to PendingIntent") @@ -211,12 +224,21 @@ class SplitSelectDataHolder( return if (intent == null) { null } else if (user != null) { - PendingIntent.getActivityAsUser(context, 0, intent, - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, - null /* options */, user) + PendingIntent.getActivityAsUser( + context, + 0, + intent, + PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, + null /* options */, + user + ) } else { - PendingIntent.getActivity(context, 0, intent, - PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT) + PendingIntent.getActivity( + context, + 0, + intent, + PendingIntent.FLAG_MUTABLE or PendingIntent.FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT + ) } } @@ -224,7 +246,7 @@ class SplitSelectDataHolder( * @return [SplitLaunchData] with the necessary fields populated as determined by * [SplitLaunchData.splitLaunchType]. This is to be used for launching splitscreen */ - fun getSplitLaunchData() : SplitLaunchData { + fun getSplitLaunchData(): SplitLaunchData { // Convert all intents to shortcut infos to see if determine if we launch shortcut or intent convertIntentsToFinalTypes() val splitLaunchType = getSplitLaunchType() @@ -241,7 +263,7 @@ class SplitSelectDataHolder( * [SplitLaunchData.splitLaunchType]. This is to be used for launching an initially selected * split task in fullscreen */ - fun getFullscreenLaunchData() : SplitLaunchData { + fun getFullscreenLaunchData(): SplitLaunchData { // Convert all intents to shortcut infos to determine if we launch shortcut or intent convertIntentsToFinalTypes() val splitLaunchType = getFullscreenLaunchType() @@ -249,21 +271,22 @@ class SplitSelectDataHolder( return generateSplitLaunchData(splitLaunchType) } - private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int) : SplitLaunchData { + private fun generateSplitLaunchData(@SplitLaunchType splitLaunchType: Int): SplitLaunchData { return SplitLaunchData( - splitLaunchType, - initialTaskId, - secondTaskId, - initialPendingIntent, - secondPendingIntent, - widgetSecondIntent, - initialUser?.identifier ?: -1, - secondUser?.identifier ?: -1, - initialShortcut, - secondShortcut, - itemInfo, - splitEvent, - initialStagePosition) + splitLaunchType, + initialTaskId, + secondTaskId, + initialPendingIntent, + secondPendingIntent, + widgetSecondIntent, + initialUser?.identifier ?: -1, + secondUser?.identifier ?: -1, + initialShortcut, + secondShortcut, + itemInfo, + splitEvent, + initialStagePosition + ) } /** @@ -273,8 +296,7 @@ class SplitSelectDataHolder( * Note that both [initialIntent] and [secondIntent] will be nullified on method return * * One caveat is that if [secondPendingIntent] is set, we will use that and *not* attempt to - * convert [secondIntent]. - * This also leaves [widgetSecondIntent] untouched. + * convert [secondIntent]. This also leaves [widgetSecondIntent] untouched. */ private fun convertIntentsToFinalTypes() { initialShortcut = getShortcutInfo(initialIntent, initialUser) @@ -297,8 +319,8 @@ class SplitSelectDataHolder( } /** - * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents - * Intents need to be converted in [convertIntentsToFinalTypes] prior to calling this method + * Only valid data fields at this point should be tasks, shortcuts, or pendingIntents Intents + * need to be converted in [convertIntentsToFinalTypes] prior to calling this method */ @VisibleForTesting @SplitLaunchType @@ -354,41 +376,40 @@ class SplitSelectDataHolder( } data class SplitLaunchData( - @SplitLaunchType - val splitLaunchType: Int, - var initialTaskId: Int = INVALID_TASK_ID, - var secondTaskId: Int = INVALID_TASK_ID, - var initialPendingIntent: PendingIntent? = null, - var secondPendingIntent: PendingIntent? = null, - var widgetSecondIntent: Intent? = null, - var initialUserId: Int = -1, - var secondUserId: Int = -1, - var initialShortcut: ShortcutInfo? = null, - var secondShortcut: ShortcutInfo? = null, - var itemInfo: ItemInfo? = null, - var splitEvent: EventEnum? = null, - val initialStagePosition: Int = STAGE_POSITION_UNDEFINED + @SplitLaunchType val splitLaunchType: Int, + var initialTaskId: Int = INVALID_TASK_ID, + var secondTaskId: Int = INVALID_TASK_ID, + var initialPendingIntent: PendingIntent? = null, + var secondPendingIntent: PendingIntent? = null, + var widgetSecondIntent: Intent? = null, + var initialUserId: Int = -1, + var secondUserId: Int = -1, + var initialShortcut: ShortcutInfo? = null, + var secondShortcut: ShortcutInfo? = null, + var itemInfo: ItemInfo? = null, + var splitEvent: EventEnum? = null, + val initialStagePosition: Int = STAGE_POSITION_UNDEFINED ) /** - * @return `true` if first task has been selected and waiting for the second task to be - * chosen + * @return `true` if first task has been selected and waiting for the second task to be chosen */ fun isSplitSelectActive(): Boolean { return isInitialTaskIntentSet() && !isSecondTaskIntentSet() } /** - * @return `true` if the first and second task have been chosen and split is waiting to - * be launched + * @return `true` if the first and second task have been chosen and split is waiting to be + * launched */ fun isBothSplitAppsConfirmed(): Boolean { return isInitialTaskIntentSet() && isSecondTaskIntentSet() } private fun isInitialTaskIntentSet(): Boolean { - return initialTaskId != INVALID_TASK_ID || initialIntent != null || - initialPendingIntent != null + return initialTaskId != INVALID_TASK_ID || + initialIntent != null || + initialPendingIntent != null } fun getInitialTaskId(): Int { @@ -416,8 +437,9 @@ class SplitSelectDataHolder( } private fun isSecondTaskIntentSet(): Boolean { - return secondTaskId != INVALID_TASK_ID || secondIntent != null - || secondPendingIntent != null + return secondTaskId != INVALID_TASK_ID || + secondIntent != null || + secondPendingIntent != null } fun resetState() { @@ -437,7 +459,7 @@ class SplitSelectDataHolder( } fun dump(prefix: String, writer: PrintWriter) { - writer.println("$prefix ${javaClass.simpleName}") + writer.println("$prefix SplitSelectDataHolder") writer.println("$prefix\tinitialStagePosition= $initialStagePosition") writer.println("$prefix\tinitialTaskId= $initialTaskId") writer.println("$prefix\tsecondTaskId= $secondTaskId") diff --git a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java index f823affef9..99f10a75db 100644 --- a/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java +++ b/quickstep/src/com/android/quickstep/util/SwipePipToHomeAnimator.java @@ -46,7 +46,7 @@ import com.android.wm.shell.pip.PipContentOverlay; * when swiping up (in gesture navigation mode). */ public class SwipePipToHomeAnimator extends RectFSpringAnim { - private static final String TAG = SwipePipToHomeAnimator.class.getSimpleName(); + private static final String TAG = "SwipePipToHomeAnimator"; private static final float END_PROGRESS = 1.0f; diff --git a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java index 21c9e09b10..69137cc1b6 100644 --- a/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java +++ b/quickstep/src/com/android/quickstep/util/TaskKeyByLastActiveTimeCache.java @@ -37,7 +37,7 @@ import java.util.function.Predicate; * @param Type of object stored in the cache */ public class TaskKeyByLastActiveTimeCache implements TaskKeyCache { - private static final String TAG = TaskKeyByLastActiveTimeCache.class.getSimpleName(); + private static final String TAG = "TaskKeyByLastActiveTimeCache"; private final AtomicInteger mMaxSize; private final Map> mMap; // To sort task id by last active time diff --git a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java index 5968901787..74cf2ac441 100644 --- a/quickstep/src/com/android/quickstep/views/DesktopTaskView.java +++ b/quickstep/src/com/android/quickstep/views/DesktopTaskView.java @@ -65,7 +65,7 @@ import java.util.function.Consumer; // TODO(b/249371338): TaskView needs to be refactored to have better support for N tasks. public class DesktopTaskView extends TaskView { - private static final String TAG = DesktopTaskView.class.getSimpleName(); + private static final String TAG = "DesktopTaskView"; private static final boolean DEBUG = false; diff --git a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java index f92b9ddb55..4df9414832 100644 --- a/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java +++ b/quickstep/src/com/android/quickstep/views/DigitalWellBeingToast.java @@ -79,7 +79,7 @@ public final class DigitalWellBeingToast { static final Intent OPEN_APP_USAGE_SETTINGS_TEMPLATE = new Intent(ACTION_APP_USAGE_SETTINGS); static final int MINUTE_MS = 60000; - private static final String TAG = DigitalWellBeingToast.class.getSimpleName(); + private static final String TAG = "DigitalWellBeingToast"; private final RecentsViewContainer mContainer; private final TaskView mTaskView; diff --git a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java index c26fc0c342..f8b814fcf4 100644 --- a/quickstep/src/com/android/quickstep/views/GroupedTaskView.java +++ b/quickstep/src/com/android/quickstep/views/GroupedTaskView.java @@ -63,7 +63,7 @@ import java.util.function.Consumer; */ public class GroupedTaskView extends TaskView { - private static final String TAG = GroupedTaskView.class.getSimpleName(); + private static final String TAG = "GroupedTaskView"; // TODO(b/336612373): Support new TTV for GroupedTaskView private TaskThumbnailViewDeprecated mSnapshotView2; private TaskViewIcon mIconView2; diff --git a/quickstep/src/com/android/quickstep/views/TaskView.java b/quickstep/src/com/android/quickstep/views/TaskView.java index 4046a89f5f..62712db13c 100644 --- a/quickstep/src/com/android/quickstep/views/TaskView.java +++ b/quickstep/src/com/android/quickstep/views/TaskView.java @@ -135,7 +135,7 @@ import java.util.stream.Stream; */ public class TaskView extends FrameLayout implements Reusable { - private static final String TAG = TaskView.class.getSimpleName(); + private static final String TAG = "TaskView"; public static final int FLAG_UPDATE_ICON = 1; public static final int FLAG_UPDATE_THUMBNAIL = FLAG_UPDATE_ICON << 1; public static final int FLAG_UPDATE_CORNER_RADIUS = FLAG_UPDATE_THUMBNAIL << 1; diff --git a/src/com/android/launcher3/DevicePaddings.java b/src/com/android/launcher3/DevicePaddings.java index 08fb47b2cf..8494d11937 100644 --- a/src/com/android/launcher3/DevicePaddings.java +++ b/src/com/android/launcher3/DevicePaddings.java @@ -47,7 +47,7 @@ public class DevicePaddings { private static final String WORKSPACE_BOTTOM_PADDING = "workspaceBottomPadding"; private static final String HOTSEAT_BOTTOM_PADDING = "hotseatBottomPadding"; - private static final String TAG = DevicePaddings.class.getSimpleName(); + private static final String TAG = "DevicePaddings"; private static final boolean DEBUG = false; ArrayList mDevicePaddings = new ArrayList<>(); diff --git a/src/com/android/launcher3/PagedView.java b/src/com/android/launcher3/PagedView.java index cc9f08eadc..365fbd3919 100644 --- a/src/com/android/launcher3/PagedView.java +++ b/src/com/android/launcher3/PagedView.java @@ -788,7 +788,7 @@ public abstract class PagedView extends ViewGrou if (mScroller.isFinished() && pageScrollChanged) { // TODO(b/246283207): Remove logging once root cause of flake detected. if (Utilities.isRunningInTestHarness() && !(this instanceof Workspace)) { - Log.d("b/246283207", this.getClass().getSimpleName() + "#onLayout() -> " + Log.d("b/246283207", TAG + "#onLayout() -> " + "if(mScroller.isFinished() && pageScrollChanged) -> getNextPage(): " + getNextPage() + ", getScrollForPage(getNextPage()): " + getScrollForPage(getNextPage())); diff --git a/src/com/android/launcher3/model/data/ItemInfo.java b/src/com/android/launcher3/model/data/ItemInfo.java index 72e85c7cb7..b82d0a0985 100644 --- a/src/com/android/launcher3/model/data/ItemInfo.java +++ b/src/com/android/launcher3/model/data/ItemInfo.java @@ -73,6 +73,7 @@ import java.util.Optional; * Represents an item in the launcher. */ public class ItemInfo { + private static final String TAG = "ItemInfo"; public static final boolean DEBUG = false; public static final int NO_ID = -1; @@ -285,7 +286,7 @@ public class ItemInfo { @Override @NonNull public final String toString() { - return getClass().getSimpleName() + "(" + dumpProperties() + ")"; + return TAG + "(" + dumpProperties() + ")"; } @NonNull diff --git a/src/com/android/launcher3/pm/PackageInstallInfo.java b/src/com/android/launcher3/pm/PackageInstallInfo.java index 1797c1fc81..23d3b61f82 100644 --- a/src/com/android/launcher3/pm/PackageInstallInfo.java +++ b/src/com/android/launcher3/pm/PackageInstallInfo.java @@ -22,6 +22,7 @@ import android.os.UserHandle; import androidx.annotation.NonNull; public final class PackageInstallInfo { + private static final String TAG = "PackageInstallInfo"; public static final int STATUS_INSTALLED = 0; public static final int STATUS_INSTALLING = 1; @@ -61,7 +62,7 @@ public final class PackageInstallInfo { @Override public String toString() { - return getClass().getSimpleName() + "(" + dumpProperties() + ")"; + return TAG + "(" + dumpProperties() + ")"; } private String dumpProperties() { diff --git a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt index 7502a43ff9..2c3035f3ac 100644 --- a/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt +++ b/src/com/android/launcher3/responsive/HotseatSpecsProvider.kt @@ -135,7 +135,7 @@ data class HotseatSpec( hotseatQsbSpace.fixedSize + edgePadding.fixedSize <= maxAvailableSize private fun logError(message: String) { - Log.e(LOG_TAG, "${this::class.simpleName}#isValid - $message - $this") + Log.e(LOG_TAG, "$LOG_TAG #isValid - $message - $this") } companion object { diff --git a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt index a4b25e529a..ef9b7dfc6f 100644 --- a/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt +++ b/src/com/android/launcher3/responsive/ResponsiveCellSpecsProvider.kt @@ -31,7 +31,7 @@ class ResponsiveCellSpecsProvider(groupOfSpecs: List check(group.widthSpecs.isEmpty() && group.heightSpecs.isNotEmpty()) { - "${this::class.simpleName} is invalid, only heightSpecs are allowed - " + + "$LOG_TAG is invalid, only heightSpecs are allowed - " + "width list size = ${group.widthSpecs.size}; " + "height list size = ${group.heightSpecs.size}." } @@ -65,6 +65,7 @@ class ResponsiveCellSpecsProvider(groupOfSpecs: List check(group.widthSpecs.isNotEmpty() && group.heightSpecs.isNotEmpty()) { - "${this::class.simpleName} is incomplete - " + + "$LOG_TAG is incomplete - " + "width list size = ${group.widthSpecs.size}; " + "height list size = ${group.heightSpecs.size}." } @@ -124,6 +124,7 @@ class ResponsiveSpecsProvider( } companion object { + private const val LOG_TAG = "ResponsiveSpecsProvider" @JvmStatic fun create( resourceHelper: ResourceHelper, diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index 0ed6ea05c4..d925629822 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -84,7 +84,7 @@ import java.util.function.Consumer; */ public class ItemClickHandler { - private static final String TAG = ItemClickHandler.class.getSimpleName(); + private static final String TAG = "ItemClickHandler"; /** * Instance used for click handling on items diff --git a/src/com/android/launcher3/views/ArrowTipView.java b/src/com/android/launcher3/views/ArrowTipView.java index 2f0da03418..bb4f04008b 100644 --- a/src/com/android/launcher3/views/ArrowTipView.java +++ b/src/com/android/launcher3/views/ArrowTipView.java @@ -54,7 +54,7 @@ import com.android.launcher3.graphics.TriangleShape; */ public class ArrowTipView extends AbstractFloatingView { - private static final String TAG = ArrowTipView.class.getSimpleName(); + private static final String TAG = "ArrowTipView"; private static final long AUTO_CLOSE_TIMEOUT_MILLIS = 10 * 1000; private static final long SHOW_DELAY_MS = 200; private static final long SHOW_DURATION_MS = 300; diff --git a/src/com/android/launcher3/views/FloatingIconView.java b/src/com/android/launcher3/views/FloatingIconView.java index 0d07f639a1..1d5a9dcb97 100644 --- a/src/com/android/launcher3/views/FloatingIconView.java +++ b/src/com/android/launcher3/views/FloatingIconView.java @@ -68,7 +68,7 @@ import java.util.function.Supplier; public class FloatingIconView extends FrameLayout implements Animator.AnimatorListener, OnGlobalLayoutListener, FloatingView { - private static final String TAG = FloatingIconView.class.getSimpleName(); + private static final String TAG = "FloatingIconView"; // Manages loading the icon on a worker thread private static @Nullable IconLoadResult sIconLoadResult; From f3224cf8472e4a4e24c780bfc038bc15ffc06384 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Wed, 8 May 2024 14:05:03 -0700 Subject: [PATCH 04/12] Update expanded view drop target size based on value from shell When a bubble drag starts, shell sends the current expanded view size over as part of BubbleBarData. Update the size stored in BubblePinController based on latest value. Update drop target visual to match the spec. It should have 24dp insets compared to expanded view and 28dp corner radius. Bug: 330585402 Test: drag bubble in landscape, check that drop target for expanded view matches with what is shown when expanded view is dragged Test: drag bubble in portrait, check that the drop target for expanded view, matches with what is shown when expanded view is dragged Flag: ACONFIG com.android.wm.shell.enable_bubble_bar DEVELOPMENT Change-Id: Ic11c4c5c675107543ba08f24a4138cda422d24c1 --- .../bg_bubble_expanded_view_drop_target.xml | 19 +++++++++++-------- .../bubble_expanded_view_drop_target.xml | 4 ++-- quickstep/res/values/dimens.xml | 6 ++++-- .../taskbar/bubbles/BubbleBarController.java | 7 +++++++ .../taskbar/bubbles/BubblePinController.kt | 16 +++++++++++++++- 5 files changed, 39 insertions(+), 13 deletions(-) diff --git a/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml index 98aab67987..d722dd7f94 100644 --- a/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml +++ b/quickstep/res/drawable/bg_bubble_expanded_view_drop_target.xml @@ -13,12 +13,15 @@ ~ See the License for the specific language governing permissions and ~ limitations under the License. --> - - - - - + android:inset="@dimen/bubble_expanded_view_drop_target_padding"> + + + + + + diff --git a/quickstep/res/layout/bubble_expanded_view_drop_target.xml b/quickstep/res/layout/bubble_expanded_view_drop_target.xml index 15ec49a6b0..3bd5d31dd5 100644 --- a/quickstep/res/layout/bubble_expanded_view_drop_target.xml +++ b/quickstep/res/layout/bubble_expanded_view_drop_target.xml @@ -16,8 +16,8 @@ \ No newline at end of file diff --git a/quickstep/res/values/dimens.xml b/quickstep/res/values/dimens.xml index c5f25ad87e..aea460247e 100644 --- a/quickstep/res/values/dimens.xml +++ b/quickstep/res/values/dimens.xml @@ -456,8 +456,10 @@ 36dp - 16dp - 412dp + 412dp + 600dp + 28dp + 24dp 16dp diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java index 8c83508ad9..90e0108b40 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubbleBarController.java @@ -150,6 +150,7 @@ public class BubbleBarController extends IBubblesListener.Stub { private BubbleBarViewController mBubbleBarViewController; private BubbleStashController mBubbleStashController; private BubbleStashedHandleViewController mBubbleStashedHandleViewController; + private BubblePinController mBubblePinController; // Keep track of bubble bar bounds sent to shell to avoid sending duplicate updates private final Rect mLastSentBubbleBarBounds = new Rect(); @@ -169,6 +170,7 @@ public class BubbleBarController extends IBubblesListener.Stub { BubbleBarLocation bubbleBarLocation; List removedBubbles; List bubbleKeysInOrder; + Point expandedViewDropTargetSize; // These need to be loaded in the background BubbleBarBubble addedBubble; @@ -186,6 +188,7 @@ public class BubbleBarController extends IBubblesListener.Stub { bubbleBarLocation = update.bubbleBarLocation; removedBubbles = update.removedBubbles; bubbleKeysInOrder = update.bubbleKeysInOrder; + expandedViewDropTargetSize = update.expandedViewDropTargetSize; } } @@ -216,6 +219,7 @@ public class BubbleBarController extends IBubblesListener.Stub { mBubbleBarViewController = bubbleControllers.bubbleBarViewController; mBubbleStashController = bubbleControllers.bubbleStashController; mBubbleStashedHandleViewController = bubbleControllers.bubbleStashedHandleViewController; + mBubblePinController = bubbleControllers.bubblePinController; bubbleControllers.runAfterInit(() -> { mBubbleBarViewController.setHiddenForBubbles( @@ -419,6 +423,9 @@ public class BubbleBarController extends IBubblesListener.Stub { updateBubbleBarLocationInternal(update.bubbleBarLocation); } } + if (update.expandedViewDropTargetSize != null) { + mBubblePinController.setDropTargetSize(update.expandedViewDropTargetSize); + } } /** Tells WMShell to show the currently selected bubble. */ diff --git a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt index fef7fa1dd5..a77e685d00 100644 --- a/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt +++ b/quickstep/src/com/android/launcher3/taskbar/bubbles/BubblePinController.kt @@ -37,12 +37,17 @@ class BubblePinController( screenSizeProvider: () -> Point ) : BaseBubblePinController(screenSizeProvider) { + var dropTargetSize: Point? = null + private lateinit var bubbleBarViewController: BubbleBarViewController private lateinit var bubbleStashController: BubbleStashController private var exclRectWidth: Float = 0f private var exclRectHeight: Float = 0f private var dropTargetView: View? = null + // Fallback width and height in case shell has not sent the size over + private var dropTargetDefaultWidth: Int = 0 + private var dropTargetDefaultHeight: Int = 0 private var dropTargetMargin: Int = 0 fun init(bubbleControllers: BubbleControllers) { @@ -50,6 +55,14 @@ class BubblePinController( bubbleStashController = bubbleControllers.bubbleStashController exclRectWidth = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_width) exclRectHeight = context.resources.getDimension(R.dimen.bubblebar_dismiss_zone_height) + dropTargetDefaultWidth = + context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_drop_target_default_width + ) + dropTargetDefaultHeight = + context.resources.getDimensionPixelSize( + R.dimen.bubble_expanded_view_drop_target_default_height + ) dropTargetMargin = context.resources.getDimensionPixelSize(R.dimen.bubble_expanded_view_drop_target_margin) } @@ -75,7 +88,6 @@ class BubblePinController( return LayoutInflater.from(context) .inflate(R.layout.bubble_expanded_view_drop_target, container, false) .also { view -> - // TODO(b/330585402): dynamic height for the drop target based on actual height dropTargetView = view container.addView(view) } @@ -88,6 +100,8 @@ class BubblePinController( val bubbleBarBounds = bubbleBarViewController.bubbleBarBounds dropTargetView?.updateLayoutParams { gravity = BOTTOM or (if (onLeft) LEFT else RIGHT) + width = dropTargetSize?.x ?: dropTargetDefaultWidth + height = dropTargetSize?.y ?: dropTargetDefaultHeight bottomMargin = -bubbleStashController.bubbleBarTranslationY.toInt() + bubbleBarBounds.height() + From 5a4836b64f3d342fd6d801cebf9a272204bf4b68 Mon Sep 17 00:00:00 2001 From: Ats Jenk Date: Wed, 8 May 2024 14:24:01 -0700 Subject: [PATCH 05/12] Get display size from DisplayController instance DeviceProfile is not updated after rotation. Which led to drag to reposition using landscape display size in portrait. Bug: 330585402 Test: have device in landscape, drag bubbles and the bar itself left/right, observe that the drop target is shown when passing half the screen rotate device to portrait, start dragging again, observe that drop target is shown on the other side when passing half the screen Flag: ACONFIG com.android.wm.shell.enable_bubble_bar DEVELOPMENT Change-Id: I5c0e2e4ab47a669b6e178b45ab132989029f5913 --- .../com/android/launcher3/taskbar/TaskbarActivityContext.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java index b24be541a9..6538f77139 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarActivityContext.java @@ -260,9 +260,9 @@ public class TaskbarActivityContext extends BaseTaskbarContext { new BubbleDragController(this), new BubbleDismissController(this, mDragLayer), new BubbleBarPinController(this, mDragLayer, - () -> getDeviceProfile().getDisplayInfo().currentSize), + () -> DisplayController.INSTANCE.get(this).getInfo().currentSize), new BubblePinController(this, mDragLayer, - () -> getDeviceProfile().getDisplayInfo().currentSize) + () -> DisplayController.INSTANCE.get(this).getInfo().currentSize) )); } From 897791a9e7e8cf42e11f939637f87ac2c0cc7d39 Mon Sep 17 00:00:00 2001 From: Holly Sun Date: Mon, 29 Apr 2024 20:05:12 -0700 Subject: [PATCH 06/12] [PS] Add TAPL test for tile injection. Bug: 330892261 Test: tapl Flag: aconfig com.google.android.apps.nexuslauncher.enable_inject_private_space_tile nextfood Change-Id: I4cfaefa26a81a1026d62d4206d90881f323bffd3 --- .../launcher3/tapl/SearchResultFromQsb.java | 25 +++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java index 8d3a631744..4be46ab621 100644 --- a/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java +++ b/tests/tapl/com/android/launcher3/tapl/SearchResultFromQsb.java @@ -17,6 +17,7 @@ package com.android.launcher3.tapl; import static com.android.launcher3.testing.shared.TestProtocol.NORMAL_STATE_ORDINAL; +import android.text.TextUtils; import android.widget.TextView; import androidx.test.uiautomator.By; @@ -117,4 +118,28 @@ public class SearchResultFromQsb implements SearchInputSource { public SearchResultFromQsb getSearchResultForInput() { return this; } + + /** Verify a tile is present by checking its title and subtitle. */ + public void verifyTileIsPresent(String title, String subtitle) { + ArrayList searchResults = + new ArrayList<>(mLauncher.waitForObjectsInContainer( + mLauncher.waitForSystemLauncherObject(SEARCH_CONTAINER_RES_ID), + By.clazz(TextView.class))); + boolean foundTitle = false; + boolean foundSubtitle = false; + for (UiObject2 uiObject: searchResults) { + String currentString = uiObject.getText(); + if (TextUtils.equals(currentString, title)) { + foundTitle = true; + } else if (TextUtils.equals(currentString, subtitle)) { + foundSubtitle = true; + } + } + if (!foundTitle) { + mLauncher.fail("Tile not found for title: " + title); + } + if (!foundSubtitle) { + mLauncher.fail("Tile not found for subtitle: " + subtitle); + } + } } From 13025d7aca299dd85319bc101bf63f620c32c81c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Micha=C5=82=20Brzezi=C5=84ski?= Date: Thu, 9 May 2024 14:37:18 +0000 Subject: [PATCH 07/12] Rename gesture_blocking_activities to back_gesture_blocking_activities This is to make it more clear that this is only for the back gesture. Bug: 309928033 Flag: None, just renaming resource Test: just renaming resource Change-Id: Id48fada3bc3b6bc91b80337def3bddcdd40dde3c --- quickstep/res/values/config.xml | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/quickstep/res/values/config.xml b/quickstep/res/values/config.xml index b3502db6ed..fd122103e1 100644 --- a/quickstep/res/values/config.xml +++ b/quickstep/res/values/config.xml @@ -17,8 +17,7 @@ - - + com.android.launcher3/com.android.quickstep.interaction.GestureSandboxActivity From 94e8ad07312722c6133878632a8016c33f1235e7 Mon Sep 17 00:00:00 2001 From: Winson Chung Date: Wed, 8 May 2024 21:14:57 +0000 Subject: [PATCH 08/12] Add multi-instance state to item infos - Add legacy resource for supported multi-instance apps that matches the current SystemUI resource of the same name, and will be removed as apps migrate to the V manifest property to declare multi-instance support - Load the multi-instance state from PackageManager when the db is first loaded or when packages are updated - The multi-instance check is then used to determine if an app pair can be saved (ie. whether the action can be shown) Bug: 323112914 Test: atest NexusLauncherTests Change-Id: I565b4bee4ab5f7040910306b1fd60a4fc3bf9a1c --- .../model/QuickstepModelDelegate.java | 10 +- .../quickstep/TaskShortcutFactory.java | 17 +- .../quickstep/util/AppPairsController.java | 169 ++++++++++-------- .../quickstep/views/OverviewActionsView.java | 9 +- .../android/quickstep/views/RecentsView.java | 10 +- res/values/config.xml | 7 + .../android/launcher3/LauncherAppState.java | 3 +- src/com/android/launcher3/LauncherModel.java | 9 +- src/com/android/launcher3/Utilities.java | 4 + .../android/launcher3/model/AllAppsList.java | 3 +- .../android/launcher3/model/LoaderCursor.java | 6 +- .../android/launcher3/model/LoaderTask.java | 5 +- .../launcher3/model/ModelDelegate.java | 11 +- .../launcher3/model/PackageUpdatedTask.java | 13 +- .../launcher3/model/WorkspaceItemProcessor.kt | 3 +- .../android/launcher3/model/data/AppInfo.java | 10 +- .../model/data/ItemInfoWithIcon.java | 30 ++++ .../launcher3/provider/LauncherDbUtils.java | 5 +- .../launcher3/util/PackageManagerHelper.java | 64 ++++++- tests/AndroidManifest-common.xml | 4 + .../launcher3/model/LoaderCursorTest.java | 4 +- .../util/PackageManagerHelperTest.java | 3 + 22 files changed, 277 insertions(+), 122 deletions(-) diff --git a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java index 65a49bd7c9..8b5ed7cc4b 100644 --- a/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java +++ b/quickstep/src/com/android/launcher3/model/QuickstepModelDelegate.java @@ -73,6 +73,7 @@ import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.ApiWrapper; import com.android.launcher3.util.Executors; import com.android.launcher3.util.IntSparseArrayMap; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.PersistedItemArray; import com.android.quickstep.logging.SettingsChangeLogger; import com.android.quickstep.logging.StatsLogCompatManager; @@ -150,7 +151,8 @@ public class QuickstepModelDelegate extends ModelDelegate { // TODO: Implement caching and preloading WorkspaceItemFactory factory = - new WorkspaceItemFactory(mApp, ums, pinnedShortcuts, numColumns, state.containerId); + new WorkspaceItemFactory(mApp, ums, mPmHelper, pinnedShortcuts, numColumns, + state.containerId); FixedContainerItems fci = new FixedContainerItems(state.containerId, state.storage.read(mApp.getContext(), factory, ums.allUsers::get)); if (FeatureFlags.CHANGE_MODEL_DELEGATE_LOADING_ORDER.get()) { @@ -530,6 +532,7 @@ public class QuickstepModelDelegate extends ModelDelegate { private final LauncherAppState mAppState; private final UserManagerState mUMS; + private final PackageManagerHelper mPmHelper; private final Map mPinnedShortcuts; private final int mMaxCount; private final int mContainer; @@ -537,9 +540,11 @@ public class QuickstepModelDelegate extends ModelDelegate { private int mReadCount = 0; protected WorkspaceItemFactory(LauncherAppState appState, UserManagerState ums, - Map pinnedShortcuts, int maxCount, int container) { + PackageManagerHelper pmHelper, Map pinnedShortcuts, + int maxCount, int container) { mAppState = appState; mUMS = ums; + mPmHelper = pmHelper; mPinnedShortcuts = pinnedShortcuts; mMaxCount = maxCount; mContainer = container; @@ -563,6 +568,7 @@ public class QuickstepModelDelegate extends ModelDelegate { lai, UserCache.INSTANCE.get(mAppState.getContext()).getUserInfo(user), ApiWrapper.INSTANCE.get(mAppState.getContext()), + mPmHelper, mUMS.isUserQuiet(user)); info.container = mContainer; mAppState.getIconCache().getTitleAndIcon(info, lai, false); diff --git a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java index f052a9d580..a53d91fd7d 100644 --- a/quickstep/src/com/android/quickstep/TaskShortcutFactory.java +++ b/quickstep/src/com/android/quickstep/TaskShortcutFactory.java @@ -335,24 +335,15 @@ public interface TaskShortcutFactory { recentsView.isTaskInExpectedScrollPosition(recentsView.indexOfChild(taskView)); boolean shouldShowActionsButtonInstead = isLargeTileFocusedTask && isInExpectedScrollPosition; - boolean hasUnpinnableApp = taskView.getTaskContainers().stream() - .anyMatch(att -> att != null && att.getItemInfo() != null - && ((att.getItemInfo().runtimeStatusFlags - & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0)); // No "save app pair" menu item if: - // - app pairs feature is not enabled // - we are in 3p launcher - // - the task in question is a single task - // - at least one app in app pair is unpinnable // - the Overview Actions Button should be visible - // - the task is not a GroupedTaskView - if (!FeatureFlags.enableAppPairs() - || !recentsView.supportsAppPairs() - || !taskView.containsMultipleTasks() - || hasUnpinnableApp + // - the task view is not a valid save-able split pair + if (!recentsView.supportsAppPairs() || shouldShowActionsButtonInstead - || !(taskView instanceof GroupedTaskView)) { + || !recentsView.getSplitSelectController().getAppPairsController() + .canSaveAppPair(taskView)) { return null; } diff --git a/quickstep/src/com/android/quickstep/util/AppPairsController.java b/quickstep/src/com/android/quickstep/util/AppPairsController.java index 770a4525cf..e4e2eb2769 100644 --- a/quickstep/src/com/android/quickstep/util/AppPairsController.java +++ b/quickstep/src/com/android/quickstep/util/AppPairsController.java @@ -22,6 +22,7 @@ import static android.app.ActivityTaskManager.INVALID_TASK_ID; import static com.android.internal.jank.Cuj.CUJ_LAUNCHER_LAUNCH_APP_PAIR_FROM_TASKBAR; import static com.android.launcher3.logging.StatsLogManager.LauncherEvent.LAUNCHER_APP_PAIR_LAUNCH; import static com.android.launcher3.model.data.AppInfo.PACKAGE_KEY_COMPARATOR; +import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_SUPPORTS_MULTI_INSTANCE; import static com.android.launcher3.util.Executors.MAIN_EXECUTOR; import static com.android.launcher3.util.Executors.MODEL_EXECUTOR; import static com.android.launcher3.util.SplitConfigurationOptions.STAGE_POSITION_BOTTOM_OR_RIGHT; @@ -32,34 +33,38 @@ import static com.android.wm.shell.common.split.SplitScreenConstants.isPersisten import android.content.Context; import android.content.Intent; -import android.content.pm.ActivityInfo; import android.content.pm.LauncherApps; -import android.content.pm.PackageManager; import android.util.Log; import android.util.Pair; +import androidx.annotation.NonNull; import androidx.annotation.Nullable; import androidx.annotation.VisibleForTesting; import com.android.internal.jank.Cuj; import com.android.launcher3.LauncherAppState; import com.android.launcher3.LauncherSettings; +import com.android.launcher3.R; import com.android.launcher3.accessibility.LauncherAccessibilityDelegate; import com.android.launcher3.allapps.AllAppsStore; import com.android.launcher3.apppairs.AppPairIcon; +import com.android.launcher3.config.FeatureFlags; import com.android.launcher3.icons.IconCache; import com.android.launcher3.logging.InstanceId; import com.android.launcher3.logging.StatsLogManager; import com.android.launcher3.model.data.AppInfo; import com.android.launcher3.model.data.AppPairInfo; import com.android.launcher3.model.data.ItemInfo; +import com.android.launcher3.model.data.ItemInfoWithIcon; import com.android.launcher3.model.data.WorkspaceItemInfo; import com.android.launcher3.taskbar.TaskbarActivityContext; import com.android.launcher3.uioverrides.QuickstepLauncher; import com.android.launcher3.util.ComponentKey; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.SplitConfigurationOptions.StagePosition; import com.android.launcher3.views.ActivityContext; import com.android.quickstep.SystemUiProxy; +import com.android.quickstep.TaskUtils; import com.android.quickstep.TopTaskTracker; import com.android.quickstep.views.GroupedTaskView; import com.android.quickstep.views.TaskView; @@ -100,6 +105,55 @@ public class AppPairsController { mContext = null; } + /** + * Returns whether the specified GroupedTaskView can be saved as an app pair. + */ + public boolean canSaveAppPair(TaskView taskView) { + if (mContext == null) { + // Can ignore as the activity is already destroyed + return false; + } + + // Disallow saving app pairs if: + // - app pairs feature is not enabled + // - the task in question is a single task + // - at least one app in app pair is unpinnable + // - the task is not a GroupedTaskView + // - both tasks in the GroupedTaskView are from the same app and the app does not + // support multi-instance + boolean hasUnpinnableApp = taskView.getTaskContainers().stream() + .anyMatch(att -> att != null && att.getItemInfo() != null + && ((att.getItemInfo().runtimeStatusFlags + & ItemInfoWithIcon.FLAG_NOT_PINNABLE) != 0)); + if (!FeatureFlags.enableAppPairs() + || !taskView.containsMultipleTasks() + || hasUnpinnableApp + || !(taskView instanceof GroupedTaskView)) { + return false; + } + + GroupedTaskView gtv = (GroupedTaskView) taskView; + List containers = gtv.getTaskContainers(); + ComponentKey taskKey1 = TaskUtils.getLaunchComponentKeyForTask( + containers.get(0).getTask().key); + ComponentKey taskKey2 = TaskUtils.getLaunchComponentKeyForTask( + containers.get(1).getTask().key); + AppInfo app1 = resolveAppInfoByComponent(taskKey1); + AppInfo app2 = resolveAppInfoByComponent(taskKey2); + + if (app1 == null || app2 == null) { + // Disallow saving app pairs for apps that don't have a front-door in Launcher + return false; + } + + if (PackageManagerHelper.isSameAppForMultiInstance(app1, app2)) { + if (!app1.supportsMultiInstance() || !app2.supportsMultiInstance()) { + return false; + } + } + return true; + } + /** * Creates a new app pair ItemInfo and adds it to the workspace. *
@@ -119,31 +173,23 @@ public class AppPairsController { List containers = gtv.getTaskContainers(); WorkspaceItemInfo recentsInfo1 = containers.get(0).getItemInfo(); WorkspaceItemInfo recentsInfo2 = containers.get(1).getItemInfo(); - WorkspaceItemInfo app1 = lookupLaunchableItem(recentsInfo1.getComponentKey()); - WorkspaceItemInfo app2 = lookupLaunchableItem(recentsInfo2.getComponentKey()); + WorkspaceItemInfo app1 = resolveAppPairWorkspaceInfo(recentsInfo1); + WorkspaceItemInfo app2 = resolveAppPairWorkspaceInfo(recentsInfo2); - // If app lookup fails, use the WorkspaceItemInfo that we have, but try to override default - // intent with one from PackageManager. - if (app1 == null) { - Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo1.title - + " failed. Falling back to the WorkspaceItemInfo from Recents."); - app1 = convertRecentsItemToAppItem(recentsInfo1); + if (app1 == null || app2 == null) { + // This shouldn't happen if canSaveAppPair() is called above, but log an error and do + // not create the app pair if the workspace items can't be resolved + Log.w(TAG, "Failed to save app pair due to invalid apps (" + + "app1=" + recentsInfo1.getComponentKey().componentName + + " app2=" + recentsInfo2.getComponentKey().componentName + ")"); + return; } - if (app2 == null) { - Log.w(TAG, "Creating an app pair, but app lookup for " + recentsInfo2.title - + " failed. Falling back to the WorkspaceItemInfo from Recents."); - app2 = convertRecentsItemToAppItem(recentsInfo2); - } - - // WorkspaceItemProcessor won't process these new ItemInfos until the next launcher restart, - // so update some flags now. - updateWorkspaceItemFlags(app1); - updateWorkspaceItemFlags(app2); @PersistentSnapPosition int snapPosition = gtv.getSnapPosition(); if (!isPersistentSnapPosition(snapPosition)) { - // if we received an illegal snap position, log an error and do not create the app pair. - Log.wtf(TAG, "tried to save an app pair with illegal snapPosition " + snapPosition); + // If we received an illegal snap position, log an error and do not create the app pair + Log.wtf(TAG, "Tried to save an app pair with illegal snapPosition " + + snapPosition); return; } @@ -228,68 +274,39 @@ public class AppPairsController { ); } + /** + * Returns an AppInfo associated with the app for the given ComponentKey, or null if no such + * package exists in the AllAppsStore. + */ + @Nullable + private AppInfo resolveAppInfoByComponent(@NonNull ComponentKey key) { + AllAppsStore appsStore = ActivityContext.lookupContext(mContext) + .getAppsView().getAppsStore(); + + // First look up the app info in order of: + // - The exact activity for the recent task + // - The first(?) loaded activity from the package + AppInfo appInfo = appsStore.getApp(key); + if (appInfo == null) { + appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR); + } + return appInfo; + } + /** * Creates a new launchable WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION by looking the * ComponentKey up in the AllAppsStore. If no app is found, attempts a lookup by package * instead. If that lookup fails, returns null. */ @Nullable - private WorkspaceItemInfo lookupLaunchableItem(@Nullable ComponentKey key) { - if (key == null) { + private WorkspaceItemInfo resolveAppPairWorkspaceInfo( + @NonNull WorkspaceItemInfo recentTaskInfo) { + // ComponentKey should never be null (see TaskView#getItemInfo) + AppInfo appInfo = resolveAppInfoByComponent(recentTaskInfo.getComponentKey()); + if (appInfo == null) { return null; } - - AllAppsStore appsStore = ActivityContext.lookupContext(mContext) - .getAppsView().getAppsStore(); - - // Lookup by ComponentKey - AppInfo appInfo = appsStore.getApp(key); - if (appInfo == null) { - // Lookup by package - appInfo = appsStore.getApp(key, PACKAGE_KEY_COMPARATOR); - } - - return appInfo != null ? appInfo.makeWorkspaceItem(mContext) : null; - } - - /** - * Updates flags for newly created WorkspaceItemInfos. - */ - private void updateWorkspaceItemFlags(WorkspaceItemInfo wii) { - PackageManager pm = mContext.getPackageManager(); - ActivityInfo ai = null; - try { - ai = pm.getActivityInfo(wii.getTargetComponent(), 0); - } catch (PackageManager.NameNotFoundException e) { - Log.w(TAG, "PackageManager lookup failed."); - } - - if (ai != null) { - wii.setNonResizeable(ai.resizeMode == ActivityInfo.RESIZE_MODE_UNRESIZEABLE); - } - } - - /** - * Converts a WorkspaceItemInfo of itemType=ITEM_TYPE_TASK (from a Recents task) to a new - * WorkspaceItemInfo of itemType=ITEM_TYPE_APPLICATION. - */ - private WorkspaceItemInfo convertRecentsItemToAppItem(WorkspaceItemInfo recentsItem) { - if (recentsItem.itemType != LauncherSettings.Favorites.ITEM_TYPE_TASK) { - Log.w(TAG, "Expected ItemInfo of type ITEM_TYPE_TASK, but received " - + recentsItem.itemType); - } - - WorkspaceItemInfo launchableItem = recentsItem.clone(); - PackageManager p = mContext.getPackageManager(); - Intent launchIntent = p.getLaunchIntentForPackage(recentsItem.getTargetPackage()); - Log.w(TAG, "Initial intent from Recents: " + launchableItem.intent + "\n" - + "Intent from PackageManager: " + launchIntent); - if (launchIntent != null) { - // If lookup from PackageManager fails, just use the existing intent - launchableItem.intent = launchIntent; - } - launchableItem.itemType = LauncherSettings.Favorites.ITEM_TYPE_APPLICATION; - return launchableItem; + return appInfo.makeWorkspaceItem(mContext); } /** diff --git a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java index 8a917d68bf..ba60141aab 100644 --- a/quickstep/src/com/android/quickstep/views/OverviewActionsView.java +++ b/quickstep/src/com/android/quickstep/views/OverviewActionsView.java @@ -38,6 +38,7 @@ import com.android.launcher3.util.DisplayController; import com.android.launcher3.util.MultiValueAlpha; import com.android.launcher3.util.NavigationMode; import com.android.quickstep.TaskOverlayFactory.OverlayUICallbacks; +import com.android.quickstep.util.AppPairsController; import com.android.quickstep.util.LayoutUtils; import java.lang.annotation.Retention; @@ -139,6 +140,7 @@ public class OverviewActionsView extends FrameLayo protected DeviceProfile mDp; private final Rect mTaskSize = new Rect(); private boolean mIsGroupedTask = false; + private boolean mCanSaveAppPair = false; public OverviewActionsView(Context context) { this(context, null); @@ -245,9 +247,12 @@ public class OverviewActionsView extends FrameLayo * Updates a batch of flags to hide and show actions buttons when a grouped task (split screen) * is focused. * @param isGroupedTask True if the focused task is a grouped task. + * @param canSaveAppPair True if the focused task is a grouped task and can be saved as an app + * pair. */ - public void updateForGroupedTask(boolean isGroupedTask) { + public void updateForGroupedTask(boolean isGroupedTask, boolean canSaveAppPair) { mIsGroupedTask = isGroupedTask; + mCanSaveAppPair = canSaveAppPair; updateActionButtonsVisibility(); } @@ -264,7 +269,7 @@ public class OverviewActionsView extends FrameLayo private void updateActionButtonsVisibility() { assert mDp != null; boolean showSingleTaskActions = !mIsGroupedTask; - boolean showGroupActions = mIsGroupedTask && mDp.isTablet; + boolean showGroupActions = mIsGroupedTask && mDp.isTablet && mCanSaveAppPair; getActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showSingleTaskActions ? 1 : 0); getGroupActionsAlphas().get(INDEX_GROUPED_ALPHA).setValue(showGroupActions ? 1 : 0); } diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index b5ce7f7075..9c99dfc698 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4011,7 +4011,9 @@ public abstract class RecentsView com.android.settings
+ + + + diff --git a/src/com/android/launcher3/LauncherAppState.java b/src/com/android/launcher3/LauncherAppState.java index 869b9956c1..a4ae1c8050 100644 --- a/src/com/android/launcher3/LauncherAppState.java +++ b/src/com/android/launcher3/LauncherAppState.java @@ -52,6 +52,7 @@ import com.android.launcher3.pm.InstallSessionTracker; import com.android.launcher3.pm.UserCache; import com.android.launcher3.util.LockedUserState; import com.android.launcher3.util.MainThreadInitializedObject; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.Preconditions; import com.android.launcher3.util.RunnableList; import com.android.launcher3.util.SafeCloseable; @@ -181,7 +182,7 @@ public class LauncherAppState implements SafeCloseable { mIconCache = new IconCache(mContext, mInvariantDeviceProfile, iconCacheFileName, mIconProvider); mModel = new LauncherModel(context, this, mIconCache, new AppFilter(mContext), - iconCacheFileName != null); + PackageManagerHelper.INSTANCE.get(context), iconCacheFileName != null); mOnTerminateCallback.add(mIconCache::close); mOnTerminateCallback.add(mModel::destroy); } diff --git a/src/com/android/launcher3/LauncherModel.java b/src/com/android/launcher3/LauncherModel.java index be98589467..e3da38937d 100644 --- a/src/com/android/launcher3/LauncherModel.java +++ b/src/com/android/launcher3/LauncherModel.java @@ -98,6 +98,8 @@ public class LauncherModel implements InstallSessionTracker.Callback { @NonNull private final LauncherAppState mApp; @NonNull + private final PackageManagerHelper mPmHelper; + @NonNull private final ModelDbController mModelDbController; @NonNull private final Object mLock = new Object(); @@ -152,12 +154,13 @@ public class LauncherModel implements InstallSessionTracker.Callback { LauncherModel(@NonNull final Context context, @NonNull final LauncherAppState app, @NonNull final IconCache iconCache, @NonNull final AppFilter appFilter, - final boolean isPrimaryInstance) { + @NonNull final PackageManagerHelper pmHelper, final boolean isPrimaryInstance) { mApp = app; + mPmHelper = pmHelper; mModelDbController = new ModelDbController(context); mBgAllAppsList = new AllAppsList(iconCache, appFilter); - mModelDelegate = ModelDelegate.newInstance(context, app, mBgAllAppsList, mBgDataModel, - isPrimaryInstance); + mModelDelegate = ModelDelegate.newInstance(context, app, mPmHelper, mBgAllAppsList, + mBgDataModel, isPrimaryInstance); } @NonNull diff --git a/src/com/android/launcher3/Utilities.java b/src/com/android/launcher3/Utilities.java index b9a62e25b2..98bba08942 100644 --- a/src/com/android/launcher3/Utilities.java +++ b/src/com/android/launcher3/Utilities.java @@ -132,6 +132,10 @@ public final class Utilities { @ChecksSdkIntAtLeast(api = VERSION_CODES.UPSIDE_DOWN_CAKE, codename = "U") public static final boolean ATLEAST_U = Build.VERSION.SDK_INT >= VERSION_CODES.UPSIDE_DOWN_CAKE; + @ChecksSdkIntAtLeast(api = VERSION_CODES.VANILLA_ICE_CREAM, codename = "V") + public static final boolean ATLEAST_V = Build.VERSION.SDK_INT + >= VERSION_CODES.VANILLA_ICE_CREAM; + /** * Set on a motion event dispatched from the nav bar. See {@link MotionEvent#setEdgeFlags(int)}. */ diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 39c1243bd1..bcd6ad2453 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -301,6 +301,7 @@ public class AllAppsList { Context context, String packageName, UserHandle user) { final ApiWrapper apiWrapper = ApiWrapper.INSTANCE.get(context); final UserCache userCache = UserCache.getInstance(context); + final PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context); final List matches = context.getSystemService(LauncherApps.class) .getActivityList(packageName, user); if (matches.size() > 0) { @@ -330,7 +331,7 @@ public class AllAppsList { applicationInfo.sectionName = mIndex.computeSectionName(applicationInfo.title); applicationInfo.intent = launchIntent; AppInfo.updateRuntimeFlagsForActivityTarget(applicationInfo, info, - userCache.getUserInfo(user), apiWrapper); + userCache.getUserInfo(user), apiWrapper, pmHelper); mDataChanged = true; } } diff --git a/src/com/android/launcher3/model/LoaderCursor.java b/src/com/android/launcher3/model/LoaderCursor.java index 0875974a21..84130c796f 100644 --- a/src/com/android/launcher3/model/LoaderCursor.java +++ b/src/com/android/launcher3/model/LoaderCursor.java @@ -57,6 +57,7 @@ import com.android.launcher3.util.ContentWriter; import com.android.launcher3.util.GridOccupancy; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSparseArrayMap; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.UserIconInfo; import java.net.URISyntaxException; @@ -73,6 +74,7 @@ public class LoaderCursor extends CursorWrapper { private final LauncherAppState mApp; private final Context mContext; + private final PackageManagerHelper mPmHelper; private final IconCache mIconCache; private final InvariantDeviceProfile mIDP; private final @Nullable LauncherRestoreEventLogger mRestoreEventLogger; @@ -114,6 +116,7 @@ public class LoaderCursor extends CursorWrapper { public int restoreFlag; public LoaderCursor(Cursor cursor, LauncherAppState app, UserManagerState userManagerState, + PackageManagerHelper pmHelper, @Nullable LauncherRestoreEventLogger restoreEventLogger) { super(cursor); @@ -121,6 +124,7 @@ public class LoaderCursor extends CursorWrapper { allUsers = userManagerState.allUsers; mContext = app.getContext(); mIconCache = app.getIconCache(); + mPmHelper = pmHelper; mIDP = app.getInvariantDeviceProfile(); mRestoreEventLogger = restoreEventLogger; @@ -368,7 +372,7 @@ public class LoaderCursor extends CursorWrapper { if (mActivityInfo != null) { AppInfo.updateRuntimeFlagsForActivityTarget(info, mActivityInfo, userIconInfo, - ApiWrapper.INSTANCE.get(mContext)); + ApiWrapper.INSTANCE.get(mContext), mPmHelper); } // from the db diff --git a/src/com/android/launcher3/model/LoaderTask.java b/src/com/android/launcher3/model/LoaderTask.java index 876bed421f..0d40a2432e 100644 --- a/src/com/android/launcher3/model/LoaderTask.java +++ b/src/com/android/launcher3/model/LoaderTask.java @@ -435,7 +435,8 @@ public class LoaderTask implements Runnable { mShortcutKeyToPinnedShortcuts = new HashMap<>(); final LoaderCursor c = new LoaderCursor( dbController.query(TABLE_NAME, null, selection, null, null), - mApp, mUserManagerState, mIsRestoreFromBackup ? restoreEventLogger : null); + mApp, mUserManagerState, mPmHelper, + mIsRestoreFromBackup ? restoreEventLogger : null); final Bundle extras = c.getExtras(); mDbName = extras == null ? null : extras.getString(ModelDbController.EXTRA_DB_NAME); try { @@ -697,7 +698,7 @@ public class LoaderTask implements Runnable { for (int i = 0; i < apps.size(); i++) { LauncherActivityInfo app = apps.get(i); AppInfo appInfo = new AppInfo(app, mUserCache.getUserInfo(user), - ApiWrapper.INSTANCE.get(mApp.getContext()), quietMode); + ApiWrapper.INSTANCE.get(mApp.getContext()), mPmHelper, quietMode); if (Flags.enableSupportForArchiving() && app.getApplicationInfo().isArchived) { // For archived apps, include progress info in case there is a pending // install session post restart of device. diff --git a/src/com/android/launcher3/model/ModelDelegate.java b/src/com/android/launcher3/model/ModelDelegate.java index 8360b14fa4..2264d35df1 100644 --- a/src/com/android/launcher3/model/ModelDelegate.java +++ b/src/com/android/launcher3/model/ModelDelegate.java @@ -26,6 +26,7 @@ import androidx.annotation.WorkerThread; import com.android.launcher3.LauncherAppState; import com.android.launcher3.R; import com.android.launcher3.shortcuts.ShortcutKey; +import com.android.launcher3.util.PackageManagerHelper; import com.android.launcher3.util.ResourceBasedOverride; import java.io.FileDescriptor; @@ -41,15 +42,16 @@ public class ModelDelegate implements ResourceBasedOverride { * Creates and initializes a new instance of the delegate */ public static ModelDelegate newInstance( - Context context, LauncherAppState app, AllAppsList appsList, BgDataModel dataModel, - boolean isPrimaryInstance) { + Context context, LauncherAppState app, PackageManagerHelper pmHelper, + AllAppsList appsList, BgDataModel dataModel, boolean isPrimaryInstance) { ModelDelegate delegate = Overrides.getObject( ModelDelegate.class, context, R.string.model_delegate_class); - delegate.init(app, appsList, dataModel, isPrimaryInstance); + delegate.init(app, pmHelper, appsList, dataModel, isPrimaryInstance); return delegate; } protected final Context mContext; + protected PackageManagerHelper mPmHelper; protected LauncherAppState mApp; protected AllAppsList mAppsList; protected BgDataModel mDataModel; @@ -62,9 +64,10 @@ public class ModelDelegate implements ResourceBasedOverride { /** * Initializes the object with the given params. */ - private void init(LauncherAppState app, AllAppsList appsList, + private void init(LauncherAppState app, PackageManagerHelper pmHelper, AllAppsList appsList, BgDataModel dataModel, boolean isPrimaryInstance) { this.mApp = app; + this.mPmHelper = pmHelper; this.mAppsList = appsList; this.mDataModel = dataModel; this.mIsPrimaryInstance = isPrimaryInstance; diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 802faae136..6275ed0630 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -126,8 +126,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) { appsList.removePackage(packages[i], mUser); } - activitiesLists.put( - packages[i], appsList.addPackage(context, packages[i], mUser)); + activitiesLists.put(packages[i], + appsList.addPackage(context, packages[i], mUser)); } flagOp = FlagOp.NO_OP.removeFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); break; @@ -138,8 +138,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { for (int i = 0; i < N; i++) { if (DEBUG) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]); iconCache.updateIconsForPkg(packages[i], mUser); - activitiesLists.put( - packages[i], appsList.updatePackage(context, packages[i], mUser)); + activitiesLists.put(packages[i], + appsList.updatePackage(context, packages[i], mUser)); } } // Since package was just updated, the target must be available now. @@ -269,6 +269,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { if (isNewApkAvailable) { List activities = activitiesLists.get( packageName); + // TODO: See if we can migrate this to + // AppInfo#updateRuntimeFlagsForActivityTarget si.setProgressLevel( activities == null || activities.isEmpty() ? 100 @@ -399,7 +401,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { return false; } // Try to find the best match activity. - Intent intent = new PackageManagerHelper(context).getAppLaunchIntent(packageName, mUser); + Intent intent = PackageManagerHelper.INSTANCE.get(context) + .getAppLaunchIntent(packageName, mUser); if (intent != null) { si.intent = intent; si.status = WorkspaceItemInfo.DEFAULT; diff --git a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt index cea4380e5e..90e47d66cc 100644 --- a/src/com/android/launcher3/model/WorkspaceItemProcessor.kt +++ b/src/com/android/launcher3/model/WorkspaceItemProcessor.kt @@ -336,7 +336,8 @@ class WorkspaceItemProcessor( info, activityInfo, userCache.getUserInfo(c.user), - ApiWrapper.INSTANCE[app.context] + ApiWrapper.INSTANCE[app.context], + pmHelper ) } if ( diff --git a/src/com/android/launcher3/model/data/AppInfo.java b/src/com/android/launcher3/model/data/AppInfo.java index 18aa6e75f7..a4281f8677 100644 --- a/src/com/android/launcher3/model/data/AppInfo.java +++ b/src/com/android/launcher3/model/data/AppInfo.java @@ -90,12 +90,12 @@ public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory { */ public AppInfo(Context context, LauncherActivityInfo info, UserHandle user) { this(info, UserCache.INSTANCE.get(context).getUserInfo(user), - ApiWrapper.INSTANCE.get(context), + ApiWrapper.INSTANCE.get(context), PackageManagerHelper.INSTANCE.get(context), context.getSystemService(UserManager.class).isQuietModeEnabled(user)); } public AppInfo(LauncherActivityInfo info, UserIconInfo userIconInfo, - ApiWrapper apiWrapper, boolean quietModeEnabled) { + ApiWrapper apiWrapper, PackageManagerHelper pmHelper, boolean quietModeEnabled) { this.componentName = info.getComponentName(); this.container = CONTAINER_ALL_APPS; this.user = userIconInfo.user; @@ -105,7 +105,7 @@ public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory { runtimeStatusFlags |= FLAG_DISABLED_QUIET_USER; } uid = info.getApplicationInfo().uid; - updateRuntimeFlagsForActivityTarget(this, info, userIconInfo, apiWrapper); + updateRuntimeFlagsForActivityTarget(this, info, userIconInfo, apiWrapper, pmHelper); } public AppInfo(AppInfo info) { @@ -184,7 +184,7 @@ public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory { */ public static boolean updateRuntimeFlagsForActivityTarget( ItemInfoWithIcon info, LauncherActivityInfo lai, UserIconInfo userIconInfo, - ApiWrapper apiWrapper) { + ApiWrapper apiWrapper, PackageManagerHelper pmHelper) { final int oldProgressLevel = info.getProgressLevel(); final int oldRuntimeStatusFlags = info.runtimeStatusFlags; ApplicationInfo appInfo = lai.getApplicationInfo(); @@ -216,6 +216,8 @@ public class AppInfo extends ItemInfoWithIcon implements WorkspaceItemFactory { PackageManagerHelper.getLoadingProgress(lai), PackageInstallInfo.STATUS_INSTALLED_DOWNLOADING); info.setNonResizeable(apiWrapper.isNonResizeableActivity(lai)); + info.setSupportsMultiInstance( + pmHelper.supportsMultiInstance(lai.getComponentName())); return (oldProgressLevel != info.getProgressLevel()) || (oldRuntimeStatusFlags != info.runtimeStatusFlags); } diff --git a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java index d4c25cba8c..6ac44ffc93 100644 --- a/src/com/android/launcher3/model/data/ItemInfoWithIcon.java +++ b/src/com/android/launcher3/model/data/ItemInfoWithIcon.java @@ -126,6 +126,11 @@ public abstract class ItemInfoWithIcon extends ItemInfo { */ public static final int FLAG_NOT_RESIZEABLE = 1 << 15; + /** + * Flag indicating whether the package related to the item & user supports multiple instances. + */ + public static final int FLAG_SUPPORTS_MULTI_INSTANCE = 1 << 16; + /** * Status associated with the system state of the underlying item. This is calculated every * time a new info is created and not persisted on the disk. @@ -251,6 +256,24 @@ public abstract class ItemInfoWithIcon extends ItemInfo { } } + /** + * Sets whether this app info supports multi-instance. + */ + protected void setSupportsMultiInstance(boolean supportsMultiInstance) { + if (supportsMultiInstance) { + runtimeStatusFlags |= FLAG_SUPPORTS_MULTI_INSTANCE; + } else { + runtimeStatusFlags &= ~FLAG_SUPPORTS_MULTI_INSTANCE; + } + } + + /** + * Returns whether this app info supports multi-instance. + */ + public boolean supportsMultiInstance() { + return (runtimeStatusFlags & FLAG_SUPPORTS_MULTI_INSTANCE) != 0; + } + /** * Sets whether this app info is non-resizeable. */ @@ -301,4 +324,11 @@ public abstract class ItemInfoWithIcon extends ItemInfo { drawable.setIsDisabled(isDisabled()); return drawable; } + + @Override + protected String dumpProperties() { + return super.dumpProperties() + + " supportsMultiInstance=" + supportsMultiInstance() + + " nonResizeable=" + isNonResizeable(); + } } diff --git a/src/com/android/launcher3/provider/LauncherDbUtils.java b/src/com/android/launcher3/provider/LauncherDbUtils.java index b992a92ee4..3ae643e5b5 100644 --- a/src/com/android/launcher3/provider/LauncherDbUtils.java +++ b/src/com/android/launcher3/provider/LauncherDbUtils.java @@ -44,6 +44,7 @@ import com.android.launcher3.pm.UserCache; import com.android.launcher3.shortcuts.ShortcutKey; import com.android.launcher3.util.IntArray; import com.android.launcher3.util.IntSet; +import com.android.launcher3.util.PackageManagerHelper; /** * A set of utility methods for Launcher DB used for DB updates and migration. @@ -107,9 +108,11 @@ public class LauncherDbUtils { Cursor c = db.query( Favorites.TABLE_NAME, null, "itemType = 1", null, null, null, null); UserManagerState ums = new UserManagerState(); + PackageManagerHelper pmHelper = PackageManagerHelper.INSTANCE.get(context); ums.init(UserCache.INSTANCE.get(context), context.getSystemService(UserManager.class)); - LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, null); + LoaderCursor lc = new LoaderCursor(c, LauncherAppState.getInstance(context), ums, pmHelper, + null); IntSet deletedShortcuts = new IntSet(); while (lc.moveToNext()) { diff --git a/src/com/android/launcher3/util/PackageManagerHelper.java b/src/com/android/launcher3/util/PackageManagerHelper.java index 3684f569c3..f7c4df4527 100644 --- a/src/com/android/launcher3/util/PackageManagerHelper.java +++ b/src/com/android/launcher3/util/PackageManagerHelper.java @@ -17,6 +17,7 @@ package com.android.launcher3.util; import static com.android.launcher3.model.data.ItemInfoWithIcon.FLAG_INSTALL_SESSION_ACTIVE; +import static android.view.WindowManager.PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI; import android.content.ActivityNotFoundException; import android.content.ComponentName; @@ -73,10 +74,14 @@ public class PackageManagerHelper implements SafeCloseable{ @NonNull private final LauncherApps mLauncherApps; + private final String[] mLegacyMultiInstanceSupportedApps; + public PackageManagerHelper(@NonNull final Context context) { mContext = context; mPm = context.getPackageManager(); mLauncherApps = Objects.requireNonNull(context.getSystemService(LauncherApps.class)); + mLegacyMultiInstanceSupportedApps = mContext.getResources().getStringArray( + R.array.config_appsSupportMultiInstancesSplit); } @Override @@ -159,11 +164,23 @@ public class PackageManagerHelper implements SafeCloseable{ } } + /** + * Returns the preferred launch activity intent for a given package. + */ @Nullable public Intent getAppLaunchIntent(@Nullable final String pkg, @NonNull final UserHandle user) { + LauncherActivityInfo info = getAppLaunchInfo(pkg, user); + return info != null ? AppInfo.makeLaunchIntent(info) : null; + } + + /** + * Returns the preferred launch activity for a given package. + */ + @Nullable + public LauncherActivityInfo getAppLaunchInfo(@Nullable final String pkg, + @NonNull final UserHandle user) { List activities = mLauncherApps.getActivityList(pkg, user); - return activities.isEmpty() ? null : - AppInfo.makeLaunchIntent(activities.get(0)); + return activities.isEmpty() ? null : activities.get(0); } /** @@ -285,4 +302,47 @@ public class PackageManagerHelper implements SafeCloseable{ return (info.flags & ApplicationInfo.FLAG_INSTALLED) != 0 || ( Flags.enableSupportForArchiving() && info.isArchived); } + + /** + * Returns whether the given component or its application has the multi-instance property set. + */ + public boolean supportsMultiInstance(@NonNull ComponentName component) { + // Check the legacy hardcoded allowlist first + for (String pkg : mLegacyMultiInstanceSupportedApps) { + if (pkg.equals(component.getPackageName())) { + return true; + } + } + + // Check app multi-instance properties after V + if (!Utilities.ATLEAST_V) { + return false; + } + + try { + // Check if the component has the multi-instance property + return mPm.getProperty(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI, component) + .getBoolean(); + } catch (PackageManager.NameNotFoundException e1) { + try { + // Check if the application has the multi-instance property + return mPm.getProperty(PROPERTY_SUPPORTS_MULTI_INSTANCE_SYSTEM_UI, + component.getPackageName()) + .getBoolean(); + } catch (PackageManager.NameNotFoundException e2) { + // Fall through + } + } + return false; + } + + /** + * Returns whether two apps should be considered the same for multi-instance purposes, which + * requires additional checks to ensure they can be started as multiple instances. + */ + public static boolean isSameAppForMultiInstance(@NonNull ItemInfo app1, + @NonNull ItemInfo app2) { + return app1.getTargetPackage().equals(app2.getTargetPackage()) + && app1.user.equals(app2.user); + } } diff --git a/tests/AndroidManifest-common.xml b/tests/AndroidManifest-common.xml index a9b75eaf41..8c5195e096 100644 --- a/tests/AndroidManifest-common.xml +++ b/tests/AndroidManifest-common.xml @@ -412,5 +412,9 @@ android:name="androidx.startup.InitializationProvider" android:authorities="${applicationId}.androidx-startup" tools:node="remove" /> + + diff --git a/tests/src/com/android/launcher3/model/LoaderCursorTest.java b/tests/src/com/android/launcher3/model/LoaderCursorTest.java index 56ac960c21..b4945d7129 100644 --- a/tests/src/com/android/launcher3/model/LoaderCursorTest.java +++ b/tests/src/com/android/launcher3/model/LoaderCursorTest.java @@ -79,6 +79,7 @@ public class LoaderCursorTest { private LauncherModelHelper mModelHelper; private LauncherAppState mApp; + private PackageManagerHelper mPmHelper; private MatrixCursor mCursor; private InvariantDeviceProfile mIDP; @@ -92,6 +93,7 @@ public class LoaderCursorTest { mContext = mModelHelper.sandboxContext; mIDP = InvariantDeviceProfile.INSTANCE.get(mContext); mApp = LauncherAppState.getInstance(mContext); + mPmHelper = PackageManagerHelper.INSTANCE.get(mContext); mCursor = new MatrixCursor(new String[] { ICON, TITLE, _ID, CONTAINER, ITEM_TYPE, @@ -101,7 +103,7 @@ public class LoaderCursorTest { }); UserManagerState ums = new UserManagerState(); - mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, null); + mLoaderCursor = new LoaderCursor(mCursor, mApp, ums, mPmHelper, null); ums.allUsers.put(0, Process.myUserHandle()); } diff --git a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java index d1da5f4f2d..b5e797ed39 100644 --- a/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java +++ b/tests/src/com/android/launcher3/util/PackageManagerHelperTest.java @@ -34,6 +34,7 @@ import android.platform.test.flag.junit.DeviceFlagsValueProvider; import androidx.test.ext.junit.runners.AndroidJUnit4; import androidx.test.filters.SmallTest; +import androidx.test.platform.app.InstrumentationRegistry; import org.junit.Before; import org.junit.Rule; @@ -63,6 +64,8 @@ public final class PackageManagerHelperTest { mContext = mock(Context.class); mLauncherApps = mock(LauncherApps.class); when(mContext.getSystemService(eq(LauncherApps.class))).thenReturn(mLauncherApps); + when(mContext.getResources()).thenReturn( + InstrumentationRegistry.getInstrumentation().getTargetContext().getResources()); mPackageManagerHelper = new PackageManagerHelper(mContext); } From cf10603ed3953cffed97198eb0455e986fb6361c Mon Sep 17 00:00:00 2001 From: fbaron Date: Thu, 9 May 2024 14:23:33 -0700 Subject: [PATCH 09/12] Fix bug where hotseat disappears Fix: 336096469 Bug: 339700174 Flag: NONE Test: n/a Change-Id: Ie567c08445d7743281f501c782a8fd51a75ad9bc --- .../hybridhotseat/HotseatPredictionController.java | 12 ++++++++++++ .../launcher3/uioverrides/QuickstepLauncher.java | 6 ++++++ 2 files changed, 18 insertions(+) diff --git a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java index 1c5a75dd1c..ae8848ff1f 100644 --- a/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java +++ b/quickstep/src/com/android/launcher3/hybridhotseat/HotseatPredictionController.java @@ -29,6 +29,7 @@ import android.animation.Animator; import android.animation.AnimatorSet; import android.animation.ObjectAnimator; import android.content.ComponentName; +import android.util.Log; import android.view.HapticFeedbackConstants; import android.view.View; import android.view.ViewGroup; @@ -80,6 +81,7 @@ public class HotseatPredictionController implements DragController.DragListener, SystemShortcut.Factory, DeviceProfile.OnDeviceProfileChangeListener, DragSource, ViewGroup.OnHierarchyChangeListener { + private static final String TAG = "HotseatPredictionController"; private static final int FLAG_UPDATE_PAUSED = 1 << 0; private static final int FLAG_DRAG_IN_PROGRESS = 1 << 1; private static final int FLAG_FILL_IN_PROGRESS = 1 << 2; @@ -291,6 +293,16 @@ public class HotseatPredictionController implements DragController.DragListener, } } + /** + * Ensures that if the flag FLAG_UPDATE_PAUSED is active we set it to false. + */ + public void verifyUIUpdateNotPaused() { + if ((mPauseFlags & FLAG_UPDATE_PAUSED) != 0) { + setPauseUIUpdate(false); + Log.e(TAG, "FLAG_UPDATE_PAUSED should not be set to true (see b/339700174)"); + } + } + /** * Sets or updates the predicted items */ diff --git a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java index 4184ab27cc..b1bb198dff 100644 --- a/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java +++ b/quickstep/src/com/android/launcher3/uioverrides/QuickstepLauncher.java @@ -397,6 +397,12 @@ public class QuickstepLauncher extends Launcher implements RecentsViewContainer return result; } + @Override + public void startBinding() { + super.startBinding(); + mHotseatPredictionController.verifyUIUpdateNotPaused(); + } + @Override protected void onActivityFlagsChanged(int changeBits) { if ((changeBits & ACTIVITY_STATE_STARTED) != 0) { From 2b73f89b14a30e55111c56573315f06f954fd9d4 Mon Sep 17 00:00:00 2001 From: Willie Koomson Date: Fri, 10 May 2024 00:08:18 +0000 Subject: [PATCH 10/12] Fix NPE in WidgetsTwoPaneSheet Check if mSelectedHeader is null. Bug: 27214675 Test: build Flag: ACONFIG com.android.launcher3.enable_widget_tap_to_add NEXTFOOD Change-Id: I640ac0b46846b94655414788177fcc1fa52fcee8 --- .../launcher3/widget/picker/WidgetsTwoPaneSheet.java | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java index b7b9f6e61d..308526c2ad 100644 --- a/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java +++ b/src/com/android/launcher3/widget/picker/WidgetsTwoPaneSheet.java @@ -36,6 +36,7 @@ import android.widget.LinearLayout; import android.widget.ScrollView; import androidx.annotation.NonNull; +import androidx.annotation.Nullable; import androidx.annotation.Px; import com.android.launcher3.DeviceProfile; @@ -78,6 +79,7 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { private boolean mOldIsSwipeToDismissInProgress; private int mActivePage = -1; + @Nullable private PackageUserKey mSelectedHeader; public WidgetsTwoPaneSheet(Context context, AttributeSet attrs, int defStyleAttr) { @@ -230,7 +232,8 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { if (mSuggestedWidgetsContainer == null && mRecommendedWidgetsCount > 0) { setupSuggestedWidgets(LayoutInflater.from(getContext())); mSuggestedWidgetsHeader.callOnClick(); - } else if (mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) { + } else if (mSelectedHeader != null + && mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey)) { // Reselect widget if we are reloading recommendations while it is currently showing. selectWidgetCell(mWidgetRecommendationsContainer, getLastSelectedWidgetItem()); } @@ -280,8 +283,8 @@ public class WidgetsTwoPaneSheet extends WidgetsFullSheet { mRightPaneScrollView.setScrollY(0); mRightPane.setAccessibilityPaneTitle(suggestionsRightPaneTitle); mSuggestedWidgetsPackageUserKey = PackageUserKey.fromPackageItemInfo(packageItemInfo); - final boolean isChangingHeaders = - !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey); + final boolean isChangingHeaders = mSelectedHeader == null + || !mSelectedHeader.equals(mSuggestedWidgetsPackageUserKey); if (isChangingHeaders) { // If switching from another header, unselect any WidgetCells. This is necessary // because we do not clear/recycle the WidgetCells in the recommendations container From 380014f131b2ee8688ed5018f6f152ba20ceca62 Mon Sep 17 00:00:00 2001 From: hyunyoungs Date: Thu, 9 May 2024 23:40:45 -0700 Subject: [PATCH 11/12] Run test in postsubmit for openPrivateSpaceSettings_triggerCorrectintent Bug:339109319 Test: not needed as disabling test in presubmit Flag: NA Change-Id: Idf106f30d9f4de949385545566345913dc551920 --- .../com/android/launcher3/allapps/PrivateProfileManagerTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java index 4021b175bc..8934574321 100644 --- a/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java +++ b/tests/src/com/android/launcher3/allapps/PrivateProfileManagerTest.java @@ -204,6 +204,7 @@ public class PrivateProfileManagerTest { } @Test + @TestStabilityRule.Stability(flavors = LOCAL | PLATFORM_POSTSUBMIT) // b/339109319 public void openPrivateSpaceSettings_triggersCorrectIntent() { Intent expectedIntent = ApiWrapper.INSTANCE.get(mContext).getPrivateSpaceSettingsIntent(); ArgumentCaptor acIntent = ArgumentCaptor.forClass(Intent.class); From 5fa4f02c70f8b404c0f291e66e108a7f6d21d014 Mon Sep 17 00:00:00 2001 From: Charlie Anderson Date: Wed, 1 May 2024 15:25:46 -0400 Subject: [PATCH 12/12] add more logging around package updates and widget click handling in Launcher Bug: 336976070 Test: locally verified Flag: N/A Change-Id: I8a1204fb6d96eccbc20b0ddd3c1e6fb1ae75fc6c --- .../android/launcher3/model/AllAppsList.java | 16 ++++- .../launcher3/model/PackageUpdatedTask.java | 65 +++++++++++++++---- .../launcher3/touch/ItemClickHandler.java | 24 +++++++ .../launcher3/widget/WidgetManagerHelper.java | 5 ++ 4 files changed, 96 insertions(+), 14 deletions(-) diff --git a/src/com/android/launcher3/model/AllAppsList.java b/src/com/android/launcher3/model/AllAppsList.java index 39c1243bd1..9234b67e7b 100644 --- a/src/com/android/launcher3/model/AllAppsList.java +++ b/src/com/android/launcher3/model/AllAppsList.java @@ -60,7 +60,7 @@ public class AllAppsList { private static final String TAG = "AllAppsList"; private static final Consumer NO_OP_CONSUMER = a -> { }; - + private static final boolean DEBUG = true; public static final int DEFAULT_APPLICATIONS_NUMBER = 42; @@ -220,6 +220,11 @@ public class AllAppsList { updatedAppInfos.add(appInfo); } else if (installInfo.state == PackageInstallInfo.STATUS_FAILED && !appInfo.isAppStartable()) { + if (DEBUG) { + Log.w(TAG, "updatePromiseInstallInfo: removing app due to install" + + " failure and appInfo not startable." + + " package=" + appInfo.getTargetPackage()); + } removeApp(i); } } @@ -311,7 +316,10 @@ public class AllAppsList { if (user.equals(applicationInfo.user) && packageName.equals(applicationInfo.componentName.getPackageName())) { if (!findActivity(matches, applicationInfo.componentName)) { - Log.w(TAG, "Changing shortcut target due to app component name change."); + if (DEBUG) { + Log.w(TAG, "Changing shortcut target due to app component name change." + + " package=" + packageName); + } removeApp(i); } } @@ -336,6 +344,10 @@ public class AllAppsList { } } else { // Remove all data for this package. + if (DEBUG) { + Log.w(TAG, "updatePromiseInstallInfo: no Activities matched updated package," + + " removing all apps from package=" + packageName); + } for (int i = data.size() - 1; i >= 0; i--) { final AppInfo applicationInfo = data.get(i); if (user.equals(applicationInfo.user) diff --git a/src/com/android/launcher3/model/PackageUpdatedTask.java b/src/com/android/launcher3/model/PackageUpdatedTask.java index 802faae136..414fa41151 100644 --- a/src/com/android/launcher3/model/PackageUpdatedTask.java +++ b/src/com/android/launcher3/model/PackageUpdatedTask.java @@ -74,8 +74,8 @@ import java.util.stream.Collectors; public class PackageUpdatedTask implements ModelUpdateTask { // TODO(b/290090023): Set to false after root causing is done. - private static final boolean DEBUG = true; private static final String TAG = "PackageUpdatedTask"; + private static final boolean DEBUG = true; public static final int OP_NONE = 0; public static final int OP_ADD = 1; @@ -117,13 +117,19 @@ public class PackageUpdatedTask implements ModelUpdateTask { : ItemInfoMatcher.ofPackages(packageSet, mUser); final HashSet removedComponents = new HashSet<>(); final HashMap> activitiesLists = new HashMap<>(); - + if (DEBUG) { + Log.d(TAG, "Package updated: mOp=" + getOpString() + + " packages=" + Arrays.toString(packages)); + } switch (mOp) { case OP_ADD: { for (int i = 0; i < N; i++) { - if (DEBUG) Log.d(TAG, "mAllAppsList.addPackage " + packages[i]); iconCache.updateIconsForPkg(packages[i], mUser); if (FeatureFlags.PROMISE_APPS_IN_ALL_APPS.get()) { + if (DEBUG) { + Log.d(TAG, "OP_ADD: PROMISE_APPS_IN_ALL_APPS enabled:" + + " removing promise icon apps from package=" + packages[i]); + } appsList.removePackage(packages[i], mUser); } activitiesLists.put( @@ -133,10 +139,14 @@ public class PackageUpdatedTask implements ModelUpdateTask { break; } case OP_UPDATE: - try (SafeCloseable t = - appsList.trackRemoves(a -> removedComponents.add(a.componentName))) { + try (SafeCloseable t = appsList.trackRemoves(a -> { + Log.d(TAG, "OP_UPDATE - AllAppsList.trackRemoves callback:" + + " removed component=" + a.componentName + + " id=" + a.id + + " Look for earlier AllAppsList logs to find more information."); + removedComponents.add(a.componentName); + })) { for (int i = 0; i < N; i++) { - if (DEBUG) Log.d(TAG, "mAllAppsList.updatePackage " + packages[i]); iconCache.updateIconsForPkg(packages[i], mUser); activitiesLists.put( packages[i], appsList.updatePackage(context, packages[i], mUser)); @@ -147,14 +157,15 @@ public class PackageUpdatedTask implements ModelUpdateTask { break; case OP_REMOVE: { for (int i = 0; i < N; i++) { - FileLog.d(TAG, "Removing app icon: " + packages[i]); iconCache.removeIconsForPkg(packages[i], mUser); } // Fall through } case OP_UNAVAILABLE: for (int i = 0; i < N; i++) { - if (DEBUG) Log.d(TAG, "mAllAppsList.removePackage " + packages[i]); + if (DEBUG) { + Log.d(TAG, getOpString() + ": removing package=" + packages[i]); + } appsList.removePackage(packages[i], mUser); } flagOp = FlagOp.NO_OP.addFlag(WorkspaceItemInfo.FLAG_DISABLED_NOT_AVAILABLE); @@ -163,7 +174,6 @@ public class PackageUpdatedTask implements ModelUpdateTask { case OP_UNSUSPEND: flagOp = FlagOp.NO_OP.setFlag( WorkspaceItemInfo.FLAG_DISABLED_SUSPENDED, mOp == OP_SUSPEND); - if (DEBUG) Log.d(TAG, "mAllAppsList.(un)suspend " + N); appsList.updateDisabledFlags(matcher, flagOp); break; case OP_USER_AVAILABILITY_CHANGE: { @@ -249,12 +259,21 @@ public class PackageUpdatedTask implements ModelUpdateTask { infoUpdated = true; } else if (si.hasPromiseIconUi()) { removedShortcuts.add(si.id); + if (DEBUG) { + Log.d(TAG, "Removing restored shortcut promise icon" + + " that no longer points to valid component." + + " id=" + si.id + + ", package=" + si.getTargetPackage()); + } return; } } else if (!isTargetValid) { removedShortcuts.add(si.id); - FileLog.e(TAG, "Restored shortcut no longer valid " - + si.getIntent()); + FileLog.e(TAG, "Removing shortcut that no longer points to" + + " valid component." + + " id=" + si.id + + " package=" + si.getTargetPackage() + + " status=" + si.status); return; } else { si.status = WorkspaceItemInfo.DEFAULT; @@ -334,7 +353,8 @@ public class PackageUpdatedTask implements ModelUpdateTask { if (!removedShortcuts.isEmpty()) { taskController.deleteAndBindComponentsRemoved( ItemInfoMatcher.ofItemIds(removedShortcuts), - "removed because the target component is invalid"); + "removing shortcuts with invalid target components." + + " ids=" + removedShortcuts); } if (!widgets.isEmpty()) { @@ -346,6 +366,9 @@ public class PackageUpdatedTask implements ModelUpdateTask { if (mOp == OP_REMOVE) { // Mark all packages in the broadcast to be removed Collections.addAll(removedPackages, packages); + if (DEBUG) { + Log.d(TAG, "OP_REMOVE: removing packages=" + Arrays.toString(packages)); + } // No need to update the removedComponents as // removedPackages is a super-set of removedComponents @@ -354,6 +377,10 @@ public class PackageUpdatedTask implements ModelUpdateTask { final LauncherApps launcherApps = context.getSystemService(LauncherApps.class); for (int i=0; i "NONE"; + case OP_ADD -> "ADD"; + case OP_UPDATE -> "UPDATE"; + case OP_REMOVE -> "REMOVE"; + case OP_UNAVAILABLE -> "UNAVAILABLE"; + case OP_SUSPEND -> "SUSPEND"; + case OP_UNSUSPEND -> "UNSUSPEND"; + case OP_USER_AVAILABILITY_CHANGE -> "USER_AVAILABILITY_CHANGE"; + default -> "UNKNOWN"; + }; + } } diff --git a/src/com/android/launcher3/touch/ItemClickHandler.java b/src/com/android/launcher3/touch/ItemClickHandler.java index d925629822..f46dcd328c 100644 --- a/src/com/android/launcher3/touch/ItemClickHandler.java +++ b/src/com/android/launcher3/touch/ItemClickHandler.java @@ -85,6 +85,7 @@ import java.util.function.Consumer; public class ItemClickHandler { private static final String TAG = "ItemClickHandler"; + private static final boolean DEBUG = true; /** * Instance used for click handling on items @@ -110,7 +111,19 @@ public class ItemClickHandler { startAppShortcutOrInfoActivity(v, (AppInfo) tag, launcher); } else if (tag instanceof LauncherAppWidgetInfo) { if (v instanceof PendingAppWidgetHostView) { + if (DEBUG) { + String targetPackage = ((LauncherAppWidgetInfo) tag).getTargetPackage(); + Log.d(TAG, "onClick: PendingAppWidgetHostView clicked for" + + " package=" + targetPackage); + } onClickPendingWidget((PendingAppWidgetHostView) v, launcher); + } else { + if (DEBUG) { + String targetPackage = ((LauncherAppWidgetInfo) tag).getTargetPackage(); + Log.d(TAG, "onClick: LauncherAppWidgetInfo clicked," + + " but not instance of PendingAppWidgetHostView. Returning." + + " package=" + targetPackage); + } } } else if (tag instanceof ItemClickProxy) { ((ItemClickProxy) tag).onItemClicked(v); @@ -120,6 +133,10 @@ public class ItemClickHandler { launcher.getString(R.string.long_accessible_way_to_add_shortcut)); Snackbar.show(launcher, msg, null); } else if (tag instanceof PendingAddWidgetInfo) { + if (DEBUG) { + String targetPackage = ((PendingAddWidgetInfo) tag).getTargetPackage(); + Log.d(TAG, "onClick: PendingAddWidgetInfo clicked for package=" + targetPackage); + } CharSequence msg = Utilities.wrapForTts( launcher.getText(R.string.long_press_widget_to_add), launcher.getString(R.string.long_accessible_way_to_add)); @@ -199,6 +216,9 @@ public class ItemClickHandler { LauncherAppWidgetProviderInfo appWidgetInfo = new WidgetManagerHelper(launcher) .findProvider(info.providerName, info.user); if (appWidgetInfo == null) { + Log.e(TAG, "onClickPendingWidget: Pending widget ready for click setup," + + " but LauncherAppWidgetProviderInfo was null. Returning." + + " component=" + info.getTargetComponent()); return; } WidgetAddFlowHandler addFlowHandler = new WidgetAddFlowHandler(appWidgetInfo); @@ -206,6 +226,10 @@ public class ItemClickHandler { if (info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_NOT_VALID)) { if (!info.hasRestoreFlag(LauncherAppWidgetInfo.FLAG_ID_ALLOCATED)) { // This should not happen, as we make sure that an Id is allocated during bind. + Log.e(TAG, "onClickPendingWidget: Pending widget ready for click setup," + + " and LauncherAppWidgetProviderInfo was found. However," + + " no appWidgetId was allocated. Returning." + + " component=" + info.getTargetComponent()); return; } addFlowHandler.startBindFlow(launcher, info.appWidgetId, info, diff --git a/src/com/android/launcher3/widget/WidgetManagerHelper.java b/src/com/android/launcher3/widget/WidgetManagerHelper.java index d293d15f38..9132b4f18c 100644 --- a/src/com/android/launcher3/widget/WidgetManagerHelper.java +++ b/src/com/android/launcher3/widget/WidgetManagerHelper.java @@ -26,6 +26,7 @@ import android.content.Context; import android.os.Build; import android.os.Bundle; import android.os.UserHandle; +import android.util.Log; import android.widget.RemoteViews; import androidx.annotation.NonNull; @@ -104,6 +105,8 @@ public class WidgetManagerHelper { // If exception is thrown because of device is locked, it means a race condition occurs // that the user got locked again while launcher is processing the event. In this case // we should return empty list. + Log.e(TAG, "getAllProviders: Error getting installed providers for" + + " package=" + packageUser.mPackageName, e); return Collections.emptyList(); } } @@ -133,6 +136,8 @@ public class WidgetManagerHelper { return LauncherAppWidgetProviderInfo.fromProviderInfo(mContext, info); } } + Log.w(TAG, "findProvider: No App Widget Provider found for component=" + provider + + " user=" + user); return null; }