summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
author Evan Rosky <erosky@google.com> 2021-12-07 20:50:14 -0800
committer Evan Rosky <erosky@google.com> 2021-12-09 13:09:54 -0800
commit95cd24e26ee08bd46315a39e5c2c98d8cbf5dca1 (patch)
tree9a9d6597e14674eec6e5819d2c49629f6d7df838
parent7dbd479b368f0e981dce37d3efa009562cc87738 (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
-rw-r--r--core/java/android/window/WindowContainerTransaction.java55
-rw-r--r--services/core/java/com/android/server/pm/LauncherAppsService.java80
-rw-r--r--services/core/java/com/android/server/wm/WindowOrganizerController.java19
-rw-r--r--services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java2
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
}