Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9f77e432 authored by Evan Rosky's avatar Evan Rosky Committed by Android (Google) Code Review
Browse files

Merge "Add support for launching a shortcut in WindowContainerTransaction"

parents ae84a4a4 95cd24e2
Loading
Loading
Loading
Loading
+55 −0
Original line number Diff line number Diff line
@@ -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;
@@ -434,6 +435,21 @@ public final class WindowContainerTransaction implements Parcelable {
        return this;
    }

    /**
     * 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;
            }
+64 −16
Original line number Diff line number Diff line
@@ -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);
            }
        }
    }
}
+19 −0
Original line number Diff line number Diff line
@@ -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
+1 −1
Original line number Diff line number Diff line
@@ -579,7 +579,7 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
        }

        @Override
        public void verifyCallingPackage(String callingPackage) {
        public void verifyCallingPackage(String callingPackage, int callerUid) {
            // SKIP
        }