diff options
| author | 2021-12-07 20:50:14 -0800 | |
|---|---|---|
| committer | 2021-12-09 13:09:54 -0800 | |
| commit | 95cd24e26ee08bd46315a39e5c2c98d8cbf5dca1 (patch) | |
| tree | 9a9d6597e14674eec6e5819d2c49629f6d7df838 | |
| parent | 7dbd479b368f0e981dce37d3efa009562cc87738 (diff) | |
Add support for launching a shortcut in WindowContainerTransaction
Some shell actions require the ability to launch a shortcut either
in a transaction and/or with other window operations (eg. Bubbles
and Split-screen).
This required changes to LauncherAppsService to support forwarding
the caller information internally from systemserver.
Bug: 209073176
Test: existing LauncherAppsService tests still pass
Change-Id: I11893abca24cab0b899c3385af0ca46932bcc9e3
4 files changed, 139 insertions, 17 deletions
diff --git a/core/java/android/window/WindowContainerTransaction.java b/core/java/android/window/WindowContainerTransaction.java index 5e7579767b67..4745220e6e56 100644 --- a/core/java/android/window/WindowContainerTransaction.java +++ b/core/java/android/window/WindowContainerTransaction.java @@ -23,6 +23,7 @@ import android.app.PendingIntent; import android.app.WindowConfiguration; import android.content.Intent; import android.content.pm.ActivityInfo; +import android.content.pm.ShortcutInfo; import android.content.res.Configuration; import android.graphics.Rect; import android.os.Bundle; @@ -435,6 +436,21 @@ public final class WindowContainerTransaction implements Parcelable { } /** + * Starts activity(s) from a shortcut. + * @param callingPackage The package launching the shortcut. + * @param shortcutInfo Information about the shortcut to start + * @param options bundle containing ActivityOptions for the task's top activity. + * @hide + */ + @NonNull + public WindowContainerTransaction startShortcut(@NonNull String callingPackage, + @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) { + mHierarchyOps.add(HierarchyOp.createForStartShortcut( + callingPackage, shortcutInfo, options)); + return this; + } + + /** * Creates a new TaskFragment with the given options. * @param taskFragmentOptions the options used to create the TaskFragment. */ @@ -957,11 +973,16 @@ public final class WindowContainerTransaction implements Parcelable { public static final int HIERARCHY_OP_TYPE_REPARENT_CHILDREN = 11; public static final int HIERARCHY_OP_TYPE_PENDING_INTENT = 12; public static final int HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS = 13; + public static final int HIERARCHY_OP_TYPE_START_SHORTCUT = 14; // The following key(s) are for use with mLaunchOptions: // When launching a task (eg. from recents), this is the taskId to be launched. public static final String LAUNCH_KEY_TASK_ID = "android:transaction.hop.taskId"; + // When starting from a shortcut, this contains the calling package. + public static final String LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE = + "android:transaction.hop.shortcut_calling_package"; + private final int mType; // Container we are performing the operation on. @@ -999,6 +1020,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private PendingIntent mPendingIntent; + @Nullable + private ShortcutInfo mShortcutInfo; + public static HierarchyOp createForReparent( @NonNull IBinder container, @Nullable IBinder reparent, boolean toTop) { return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_REPARENT) @@ -1058,6 +1082,17 @@ public final class WindowContainerTransaction implements Parcelable { .build(); } + /** Create a hierarchy op for starting a shortcut. */ + public static HierarchyOp createForStartShortcut(@NonNull String callingPackage, + @NonNull ShortcutInfo shortcutInfo, @Nullable Bundle options) { + final Bundle fullOptions = options == null ? new Bundle() : options; + fullOptions.putString(LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE, callingPackage); + return new HierarchyOp.Builder(HIERARCHY_OP_TYPE_START_SHORTCUT) + .setShortcutInfo(shortcutInfo) + .setLaunchOptions(fullOptions) + .build(); + } + /** Create a hierarchy op for setting launch adjacent flag root. */ public static HierarchyOp createForSetLaunchAdjacentFlagRoot(IBinder container, boolean clearRoot) { @@ -1085,6 +1120,7 @@ public final class WindowContainerTransaction implements Parcelable { mActivityIntent = copy.mActivityIntent; mTaskFragmentCreationOptions = copy.mTaskFragmentCreationOptions; mPendingIntent = copy.mPendingIntent; + mShortcutInfo = copy.mShortcutInfo; } protected HierarchyOp(Parcel in) { @@ -1100,6 +1136,7 @@ public final class WindowContainerTransaction implements Parcelable { mActivityIntent = in.readTypedObject(Intent.CREATOR); mTaskFragmentCreationOptions = in.readTypedObject(TaskFragmentCreationParams.CREATOR); mPendingIntent = in.readTypedObject(PendingIntent.CREATOR); + mShortcutInfo = in.readTypedObject(ShortcutInfo.CREATOR); } public int getType() { @@ -1170,6 +1207,11 @@ public final class WindowContainerTransaction implements Parcelable { return mPendingIntent; } + @Nullable + public ShortcutInfo getShortcutInfo() { + return mShortcutInfo; + } + @Override public String toString() { switch (mType) { @@ -1212,6 +1254,9 @@ public final class WindowContainerTransaction implements Parcelable { case HIERARCHY_OP_TYPE_SET_ADJACENT_TASK_FRAGMENTS: return "{SetAdjacentTaskFragments: container=" + mContainer + " adjacentContainer=" + mReparent + "}"; + case HIERARCHY_OP_TYPE_START_SHORTCUT: + return "{StartShortcut: options=" + mLaunchOptions + " info=" + mShortcutInfo + + "}"; default: return "{mType=" + mType + " container=" + mContainer + " reparent=" + mReparent + " mToTop=" + mToTop @@ -1234,6 +1279,7 @@ public final class WindowContainerTransaction implements Parcelable { dest.writeTypedObject(mActivityIntent, flags); dest.writeTypedObject(mTaskFragmentCreationOptions, flags); dest.writeTypedObject(mPendingIntent, flags); + dest.writeTypedObject(mShortcutInfo, flags); } @Override @@ -1287,6 +1333,9 @@ public final class WindowContainerTransaction implements Parcelable { @Nullable private PendingIntent mPendingIntent; + @Nullable + private ShortcutInfo mShortcutInfo; + Builder(int type) { mType = type; } @@ -1347,6 +1396,11 @@ public final class WindowContainerTransaction implements Parcelable { return this; } + Builder setShortcutInfo(@Nullable ShortcutInfo shortcutInfo) { + mShortcutInfo = shortcutInfo; + return this; + } + HierarchyOp build() { final HierarchyOp hierarchyOp = new HierarchyOp(mType); hierarchyOp.mContainer = mContainer; @@ -1364,6 +1418,7 @@ public final class WindowContainerTransaction implements Parcelable { hierarchyOp.mActivityIntent = mActivityIntent; hierarchyOp.mPendingIntent = mPendingIntent; hierarchyOp.mTaskFragmentCreationOptions = mTaskFragmentCreationOptions; + hierarchyOp.mShortcutInfo = mShortcutInfo; return hierarchyOp; } diff --git a/services/core/java/com/android/server/pm/LauncherAppsService.java b/services/core/java/com/android/server/pm/LauncherAppsService.java index 9c11cd4811b4..6e6773feb5f8 100644 --- a/services/core/java/com/android/server/pm/LauncherAppsService.java +++ b/services/core/java/com/android/server/pm/LauncherAppsService.java @@ -121,6 +121,7 @@ public class LauncherAppsService extends SystemService { public void onStart() { publishBinderService(Context.LAUNCHER_APPS_SERVICE, mLauncherAppsImpl); mLauncherAppsImpl.registerLoadingProgressForIncrementalApps(); + LocalServices.addService(LauncherAppsServiceInternal.class, mLauncherAppsImpl.mInternal); } static class BroadcastCookie { @@ -137,6 +138,17 @@ public class LauncherAppsService extends SystemService { } } + /** + * Local system service interface. + * @hide Only for use within system server + */ + public abstract static class LauncherAppsServiceInternal { + /** Same as startShortcut except supports forwarding of caller uid/pid. */ + public abstract boolean startShortcut(int callerUid, int callerPid, String callingPackage, + String packageName, String featureId, String shortcutId, Rect sourceBounds, + Bundle startActivityOptions, int targetUserId); + } + @VisibleForTesting static class LauncherAppsImpl extends ILauncherApps.Stub { private static final boolean DEBUG = false; @@ -168,6 +180,8 @@ public class LauncherAppsService extends SystemService { private PackageInstallerService mPackageInstallerService; + final LauncherAppsServiceInternal mInternal; + public LauncherAppsImpl(Context context) { mContext = context; mIPM = AppGlobals.getPackageManager(); @@ -189,6 +203,7 @@ public class LauncherAppsService extends SystemService { mShortcutServiceInternal.addShortcutChangeCallback(mShortcutChangeHandler); mCallbackHandler = BackgroundThread.getHandler(); mDpm = (DevicePolicyManager) mContext.getSystemService(Context.DEVICE_POLICY_SERVICE); + mInternal = new LocalService(); } @VisibleForTesting @@ -359,11 +374,15 @@ public class LauncherAppsService extends SystemService { * group. */ private boolean canAccessProfile(int targetUserId, String message) { - final int callingUserId = injectCallingUserId(); + return canAccessProfile(injectBinderCallingUid(), injectCallingUserId(), + injectBinderCallingPid(), targetUserId, message); + } + + private boolean canAccessProfile(int callingUid, int callingUserId, int callingPid, + int targetUserId, String message) { if (targetUserId == callingUserId) return true; - if (injectHasInteractAcrossUsersFullPermission(injectBinderCallingPid(), - injectBinderCallingUid())) { + if (injectHasInteractAcrossUsersFullPermission(callingPid, callingUid)) { return true; } @@ -379,25 +398,29 @@ public class LauncherAppsService extends SystemService { injectRestoreCallingIdentity(ident); } - return mUserManagerInternal.isProfileAccessible(injectCallingUserId(), targetUserId, + return mUserManagerInternal.isProfileAccessible(callingUserId, targetUserId, message, true); } + private void verifyCallingPackage(String callingPackage) { + verifyCallingPackage(callingPackage, injectBinderCallingUid()); + } + @VisibleForTesting // We override it in unit tests - void verifyCallingPackage(String callingPackage) { + void verifyCallingPackage(String callingPackage, int callerUid) { int packageUid = -1; try { packageUid = mIPM.getPackageUid(callingPackage, PackageManager.MATCH_DIRECT_BOOT_AWARE | PackageManager.MATCH_DIRECT_BOOT_UNAWARE | PackageManager.MATCH_UNINSTALLED_PACKAGES, - UserHandle.getUserId(getCallingUid())); + UserHandle.getUserId(callerUid)); } catch (RemoteException ignore) { } if (packageUid < 0) { Log.e(TAG, "Package not found: " + callingPackage); } - if (packageUid != injectBinderCallingUid()) { + if (packageUid != callerUid) { throw new SecurityException("Calling package name mismatch"); } } @@ -797,9 +820,15 @@ public class LauncherAppsService extends SystemService { } private void ensureShortcutPermission(@NonNull String callingPackage) { - verifyCallingPackage(callingPackage); - if (!mShortcutServiceInternal.hasShortcutHostPermission(getCallingUserId(), - callingPackage, injectBinderCallingPid(), injectBinderCallingUid())) { + ensureShortcutPermission(injectBinderCallingUid(), injectBinderCallingPid(), + callingPackage); + } + + private void ensureShortcutPermission(int callerUid, int callerPid, + @NonNull String callingPackage) { + verifyCallingPackage(callingPackage, callerUid); + if (!mShortcutServiceInternal.hasShortcutHostPermission(UserHandle.getUserId(callerUid), + callingPackage, callerPid, callerUid)) { throw new SecurityException("Caller can't access shortcut information"); } } @@ -989,20 +1018,28 @@ public class LauncherAppsService extends SystemService { public boolean startShortcut(String callingPackage, String packageName, String featureId, String shortcutId, Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { - verifyCallingPackage(callingPackage); + return startShortcutInner(injectBinderCallingUid(), injectBinderCallingPid(), + injectCallingUserId(), callingPackage, packageName, featureId, shortcutId, + sourceBounds, startActivityOptions, targetUserId); + } + + private boolean startShortcutInner(int callerUid, int callerPid, int callingUserId, + String callingPackage, String packageName, String featureId, String shortcutId, + Rect sourceBounds, Bundle startActivityOptions, int targetUserId) { + verifyCallingPackage(callingPackage, callerUid); if (!canAccessProfile(targetUserId, "Cannot start activity")) { return false; } // Even without the permission, pinned shortcuts are always launchable. - if (!mShortcutServiceInternal.isPinnedByCaller(getCallingUserId(), + if (!mShortcutServiceInternal.isPinnedByCaller(callingUserId, callingPackage, packageName, shortcutId, targetUserId)) { - ensureShortcutPermission(callingPackage); + ensureShortcutPermission(callerUid, callerPid, callingPackage); } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( - getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, - injectBinderCallingPid(), injectBinderCallingUid()); + callingUserId, callingPackage, packageName, shortcutId, targetUserId, + callerPid, callerUid); if (intents == null || intents.length == 0) { return false; } @@ -1023,7 +1060,7 @@ public class LauncherAppsService extends SystemService { // Replace theme for splash screen final String splashScreenThemeResName = - mShortcutServiceInternal.getShortcutStartingThemeResName(getCallingUserId(), + mShortcutServiceInternal.getShortcutStartingThemeResName(callingUserId, callingPackage, packageName, shortcutId, targetUserId); if (splashScreenThemeResName != null && !splashScreenThemeResName.isEmpty()) { if (startActivityOptions == null) { @@ -1809,5 +1846,16 @@ public class LauncherAppsService extends SystemService { } } } + + final class LocalService extends LauncherAppsServiceInternal { + @Override + public boolean startShortcut(int callerUid, int callerPid, String callingPackage, + String packageName, String featureId, String shortcutId, Rect sourceBounds, + Bundle startActivityOptions, int targetUserId) { + return LauncherAppsImpl.this.startShortcutInner(callerUid, callerPid, + UserHandle.getUserId(callerUid), callingPackage, packageName, featureId, + shortcutId, sourceBounds, startActivityOptions, targetUserId); + } + } } } diff --git a/services/core/java/com/android/server/wm/WindowOrganizerController.java b/services/core/java/com/android/server/wm/WindowOrganizerController.java index 525d84be8680..79dcbcb23870 100644 --- a/services/core/java/com/android/server/wm/WindowOrganizerController.java +++ b/services/core/java/com/android/server/wm/WindowOrganizerController.java @@ -33,6 +33,7 @@ import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ADJACENT_FLAG_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_SET_LAUNCH_ROOT; import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_ACTIVITY_IN_TASK_FRAGMENT; +import static android.window.WindowContainerTransaction.HierarchyOp.HIERARCHY_OP_TYPE_START_SHORTCUT; import static com.android.internal.protolog.ProtoLogGroup.WM_DEBUG_WINDOW_ORGANIZER; import static com.android.server.wm.ActivityTaskManagerService.LAYOUT_REASON_CONFIG_CHANGED; @@ -79,6 +80,8 @@ import com.android.internal.protolog.common.ProtoLog; import com.android.internal.util.ArrayUtils; import com.android.internal.util.function.pooled.PooledConsumer; import com.android.internal.util.function.pooled.PooledLambda; +import com.android.server.LocalServices; +import com.android.server.pm.LauncherAppsService.LauncherAppsServiceInternal; import java.util.ArrayList; import java.util.HashMap; @@ -785,6 +788,22 @@ class WindowOrganizerController extends IWindowOrganizerController.Stub null /* requiredPermission */, options); break; } + case HIERARCHY_OP_TYPE_START_SHORTCUT: { + final Bundle launchOpts = hop.getLaunchOptions(); + final String callingPackage = launchOpts.getString( + WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE); + launchOpts.remove( + WindowContainerTransaction.HierarchyOp.LAUNCH_KEY_SHORTCUT_CALLING_PACKAGE); + + final LauncherAppsServiceInternal launcherApps = LocalServices.getService( + LauncherAppsServiceInternal.class); + + launcherApps.startShortcut(caller.mUid, caller.mPid, callingPackage, + hop.getShortcutInfo().getPackage(), null /* default featureId */, + hop.getShortcutInfo().getId(), null /* sourceBounds */, launchOpts, + hop.getShortcutInfo().getUserId()); + break; + } case HIERARCHY_OP_TYPE_REPARENT_CHILDREN: { final WindowContainer oldParent = WindowContainer.fromBinder(hop.getContainer()); final WindowContainer newParent = hop.getNewParent() != null diff --git a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java index 3722ba4ec468..58c9db76c282 100644 --- a/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +++ b/services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java @@ -579,7 +579,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } @Override - public void verifyCallingPackage(String callingPackage) { + public void verifyCallingPackage(String callingPackage, int callerUid) { // SKIP } |