From 0c5262b9e1985a8c9b8a39f95e36144e0d65dcf8 Mon Sep 17 00:00:00 2001 From: Jeremy Sim Date: Mon, 3 Apr 2023 21:20:55 -0700 Subject: [PATCH] Fix bug with split screen not recognizing user differences This patch fixes a bug where split screen did not fully support launching intents with different users. The bug arose because SplitSelectStateController only had one place to store user information about the staged intent, mUser, but this disregarded the fact that the secondary app could also be passed in as an intent, and could belong to a different user from that of the initial app and the existing context. We need to support this case now since we now allow second-app selection from Taskbar. Fixed by splitting the field into mInitialUser and mSecondUser, which will be tightly bound with mInitialTaskIntent and mSecondTaskIntent to make sure that Intents are always launched with the correct UserHandle. Change-Id: I1ec49c75d562e4309a41d98010f0eff113c81e9d Fixes: 275410160 Test: Manual Merged-In: Ic904672769be8fd116180d457b36eb567c5ee304 --- .../taskbar/TaskbarUIController.java | 6 +- .../util/SplitSelectStateController.java | 94 +++++++++++-------- .../util/SplitToWorkspaceController.java | 6 +- .../android/quickstep/views/RecentsView.java | 6 +- .../com/android/quickstep/views/TaskView.java | 3 +- 5 files changed, 70 insertions(+), 45 deletions(-) diff --git a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java index b9242b234a..1435cb0996 100644 --- a/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java +++ b/quickstep/src/com/android/launcher3/taskbar/TaskbarUIController.java @@ -244,7 +244,8 @@ public class TaskbarUIController { taskAttributes.getIconView().getDrawable(), taskAttributes.getThumbnailView(), taskAttributes.getThumbnailView().getThumbnail(), - null /* intent */); + null /* intent */, + null /* user */); return; } } @@ -256,7 +257,8 @@ public class TaskbarUIController { new BitmapDrawable(info.bitmap.icon), startingView, null /* thumbnail */, - intent); + intent, + info.user); } ); } diff --git a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java index c537ef88d7..11e1fbd391 100644 --- a/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java +++ b/quickstep/src/com/android/quickstep/util/SplitSelectStateController.java @@ -89,11 +89,17 @@ public class SplitSelectStateController { private final StateManager mStateManager; @Nullable private DepthController mDepthController; - private @StagePosition int mStagePosition; + private @StagePosition int mInitialStagePosition; private ItemInfo mItemInfo; + /** {@link #mInitialTaskIntent} and {@link #mInitialUser} (the user of the Intent) are set + * together when split is initiated from an Intent. */ private Intent mInitialTaskIntent; + private UserHandle mInitialUser; private int mInitialTaskId = INVALID_TASK_ID; + /** {@link #mSecondTaskIntent} and {@link #mSecondUser} (the user of the Intent) are set + * together when split is confirmed with an Intent. */ private Intent mSecondTaskIntent; + private UserHandle mSecondUser; private int mSecondTaskId = INVALID_TASK_ID; private boolean mRecentsAnimationRunning; /** If {@code true}, animates the existing task view split placeholder view */ @@ -103,8 +109,6 @@ public class SplitSelectStateController { * split pair task view without wanting to animate current task dismissal overall */ private boolean mDismissingFromSplitPair; - @Nullable - private UserHandle mUser; /** If not null, this is the TaskView we want to launch from */ @Nullable private GroupedTaskView mLaunchingTaskView; @@ -138,7 +142,7 @@ public class SplitSelectStateController { mInitialTaskId = alreadyRunningTask; } else { mInitialTaskIntent = intent; - mUser = itemInfo.user; + mInitialUser = itemInfo.user; } setInitialData(stagePosition, splitEvent, itemInfo); @@ -158,7 +162,7 @@ public class SplitSelectStateController { private void setInitialData(@StagePosition int stagePosition, StatsLogManager.EventEnum splitEvent, ItemInfo itemInfo) { mItemInfo = itemInfo; - mStagePosition = stagePosition; + mInitialStagePosition = stagePosition; mSplitEvent = splitEvent; } @@ -215,7 +219,7 @@ public class SplitSelectStateController { Pair instanceIds = LogUtils.getShellShareableInstanceId(); launchTasks(mInitialTaskId, mInitialTaskIntent, mSecondTaskId, mSecondTaskIntent, - mStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO, + mInitialStagePosition, callback, false /* freezeTaskList */, DEFAULT_SPLIT_RATIO, instanceIds.first); mStatsLogManager.logger() @@ -232,8 +236,14 @@ public class SplitSelectStateController { mSecondTaskId = task.key.id; } - public void setSecondTask(Intent intent) { + /** + * 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. + */ + public void setSecondTask(Intent intent, UserHandle user) { mSecondTaskIntent = intent; + mSecondUser = user; } /** @@ -291,16 +301,17 @@ public class SplitSelectStateController { null /* options2 */, stagePosition, splitRatio, remoteTransition, shellInstanceId); } else if (intent2 == null) { - launchIntentOrShortcut(intent1, options1, taskId2, stagePosition, splitRatio, - remoteTransition, shellInstanceId); + launchIntentOrShortcut(intent1, mInitialUser, options1, taskId2, stagePosition, + splitRatio, remoteTransition, shellInstanceId); } else if (intent1 == null) { - launchIntentOrShortcut(intent2, options1, taskId1, + launchIntentOrShortcut(intent2, mSecondUser, options1, taskId1, getOppositeStagePosition(stagePosition), splitRatio, remoteTransition, shellInstanceId); } else { - mSystemUiProxy.startIntents(getPendingIntent(intent1), options1.toBundle(), - getPendingIntent(intent2), null /* options2 */, stagePosition, - splitRatio, remoteTransition, shellInstanceId); + mSystemUiProxy.startIntents(getPendingIntent(intent1, mInitialUser), + options1.toBundle(), getPendingIntent(intent2, mSecondUser), + null /* options2 */, stagePosition, splitRatio, remoteTransition, + shellInstanceId); } } else { final RemoteSplitLaunchAnimationRunner animationRunner = @@ -314,61 +325,64 @@ public class SplitSelectStateController { taskId2, null /* options2 */, stagePosition, splitRatio, adapter, shellInstanceId); } else if (intent2 == null) { - launchIntentOrShortcutLegacy(intent1, options1, taskId2, stagePosition, splitRatio, - adapter, shellInstanceId); + launchIntentOrShortcutLegacy(intent1, mInitialUser, options1, taskId2, + stagePosition, splitRatio, adapter, shellInstanceId); } else if (intent1 == null) { - launchIntentOrShortcutLegacy(intent2, options1, taskId1, + launchIntentOrShortcutLegacy(intent2, mSecondUser, options1, taskId1, getOppositeStagePosition(stagePosition), splitRatio, adapter, shellInstanceId); } else { mSystemUiProxy.startIntentsWithLegacyTransition( - getPendingIntent(intent1), getShortcutInfo(intent1), options1.toBundle(), - getPendingIntent(intent2), getShortcutInfo(intent2), null /* options2 */, - stagePosition, splitRatio, adapter, shellInstanceId); + getPendingIntent(intent1, mInitialUser), + getShortcutInfo(intent1, mInitialUser), options1.toBundle(), + getPendingIntent(intent2, mSecondUser), + getShortcutInfo(intent2, mSecondUser), null /* options2 */, stagePosition, + splitRatio, adapter, shellInstanceId); } } } - private void launchIntentOrShortcut(Intent intent, ActivityOptions options1, int taskId, - @StagePosition int stagePosition, float splitRatio, RemoteTransition remoteTransition, - @Nullable InstanceId shellInstanceId) { - final ShortcutInfo shortcutInfo = getShortcutInfo(intent); + private void launchIntentOrShortcut(Intent intent, UserHandle user, ActivityOptions options1, + int taskId, @StagePosition int stagePosition, float splitRatio, + RemoteTransition remoteTransition, @Nullable InstanceId shellInstanceId) { + final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user); if (shortcutInfo != null) { mSystemUiProxy.startShortcutAndTask(shortcutInfo, options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio, remoteTransition, shellInstanceId); } else { - mSystemUiProxy.startIntentAndTask(getPendingIntent(intent), options1.toBundle(), taskId, - null /* options2 */, stagePosition, splitRatio, remoteTransition, - shellInstanceId); + mSystemUiProxy.startIntentAndTask(getPendingIntent(intent, user), + options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio, + remoteTransition, shellInstanceId); } } - private void launchIntentOrShortcutLegacy(Intent intent, ActivityOptions options1, int taskId, - @StagePosition int stagePosition, float splitRatio, RemoteAnimationAdapter adapter, + private void launchIntentOrShortcutLegacy(Intent intent, UserHandle user, + ActivityOptions options1, int taskId, @StagePosition int stagePosition, + float splitRatio, RemoteAnimationAdapter adapter, @Nullable InstanceId shellInstanceId) { - final ShortcutInfo shortcutInfo = getShortcutInfo(intent); + final ShortcutInfo shortcutInfo = getShortcutInfo(intent, user); if (shortcutInfo != null) { mSystemUiProxy.startShortcutAndTaskWithLegacyTransition(shortcutInfo, options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio, adapter, shellInstanceId); } else { - mSystemUiProxy.startIntentAndTaskWithLegacyTransition(getPendingIntent(intent), - options1.toBundle(), taskId, null /* options2 */, stagePosition, splitRatio, - adapter, shellInstanceId); + mSystemUiProxy.startIntentAndTaskWithLegacyTransition( + getPendingIntent(intent, user), options1.toBundle(), taskId, + null /* options2 */, stagePosition, splitRatio, adapter, shellInstanceId); } } - private PendingIntent getPendingIntent(Intent intent) { - return intent == null ? null : (mUser != null + private PendingIntent getPendingIntent(Intent intent, UserHandle user) { + return intent == null ? null : (user != null ? PendingIntent.getActivityAsUser(mContext, 0, intent, - FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, null /* options */, mUser) + FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT, null /* options */, user) : PendingIntent.getActivity(mContext, 0, intent, FLAG_MUTABLE | FLAG_ALLOW_UNSAFE_IMPLICIT_INTENT)); } public @StagePosition int getActiveSplitStagePosition() { - return mStagePosition; + return mInitialStagePosition; } public StatsLogManager.EventEnum getSplitEvent() { @@ -380,7 +394,7 @@ public class SplitSelectStateController { } @Nullable - private ShortcutInfo getShortcutInfo(Intent intent) { + private ShortcutInfo getShortcutInfo(Intent intent, UserHandle user) { if (intent == null || intent.getPackage() == null) { return null; } @@ -392,7 +406,7 @@ public class SplitSelectStateController { try { final Context context = mContext.createPackageContextAsUser( - intent.getPackage(), 0 /* flags */, mUser); + intent.getPackage(), 0 /* flags */, user); return new ShortcutInfo.Builder(context, shortcutId).build(); } catch (PackageManager.NameNotFoundException e) { Log.w(TAG, "Failed to create a ShortcutInfo for " + intent.getPackage()); @@ -522,7 +536,9 @@ public class SplitSelectStateController { mInitialTaskIntent = null; mSecondTaskId = INVALID_TASK_ID; mSecondTaskIntent = null; - mStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; + mInitialUser = null; + mSecondUser = null; + mInitialStagePosition = SplitConfigurationOptions.STAGE_POSITION_UNDEFINED; mRecentsAnimationRunning = false; mLaunchingTaskView = null; mItemInfo = null; diff --git a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java index e5c74dc2e3..dd10c2da5d 100644 --- a/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java +++ b/quickstep/src/com/android/quickstep/util/SplitToWorkspaceController.java @@ -24,6 +24,7 @@ import android.animation.AnimatorListenerAdapter; import android.content.Intent; import android.graphics.Rect; import android.graphics.RectF; +import android.os.UserHandle; import android.view.View; import com.android.launcher3.DeviceProfile; @@ -66,21 +67,24 @@ public class SplitToWorkspaceController { } Object tag = view.getTag(); Intent intent; + UserHandle user; BitmapInfo bitmapInfo; if (tag instanceof WorkspaceItemInfo) { final WorkspaceItemInfo workspaceItemInfo = (WorkspaceItemInfo) tag; intent = workspaceItemInfo.intent; + user = workspaceItemInfo.user; bitmapInfo = workspaceItemInfo.bitmap; } else if (tag instanceof com.android.launcher3.model.data.AppInfo) { final com.android.launcher3.model.data.AppInfo appInfo = (com.android.launcher3.model.data.AppInfo) tag; intent = appInfo.intent; + user = appInfo.user; bitmapInfo = appInfo.bitmap; } else { return false; } - mController.setSecondTask(intent); + mController.setSecondTask(intent, user); boolean isTablet = mLauncher.getDeviceProfile().isTablet; SplitAnimationTimings timings = AnimUtils.getDeviceSplitToConfirmTimings(isTablet); diff --git a/quickstep/src/com/android/quickstep/views/RecentsView.java b/quickstep/src/com/android/quickstep/views/RecentsView.java index 7989bb0b65..cf6ee2d2e5 100644 --- a/quickstep/src/com/android/quickstep/views/RecentsView.java +++ b/quickstep/src/com/android/quickstep/views/RecentsView.java @@ -4589,11 +4589,13 @@ public abstract class RecentsView