Loading core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2918,6 +2918,7 @@ package android.content.pm { } public static class LauncherApps.ShortcutQuery { field public static final int FLAG_GET_PERSISTED_DATA = 4096; // 0x1000 field @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public static final int FLAG_GET_PERSONS_DATA = 2048; // 0x800 } core/java/android/content/pm/ILauncherApps.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.ParcelFileDescriptor; import com.android.internal.infra.AndroidFuture; import java.util.List; /** Loading Loading @@ -73,6 +75,8 @@ interface ILauncherApps { ParceledListSlice getShortcuts(String callingPackage, in ShortcutQueryWrapper query, in UserHandle user); void getShortcutsAsync(String callingPackage, in ShortcutQueryWrapper query, in UserHandle user, in AndroidFuture<List<ShortcutInfo>> cb); void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, in UserHandle user); boolean startShortcut(String callingPackage, String packageName, String featureId, String id, Loading core/java/android/content/pm/LauncherApps.java +35 −2 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileNotFoundException; Loading @@ -84,6 +85,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; /** Loading Loading @@ -439,6 +441,17 @@ public class LauncherApps { */ public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2; /** * Includes shortcuts from persistence layer in the search result. * * <p>The caller should make the query on a worker thread since accessing persistence layer * is considered asynchronous. * * @hide */ @SystemApi public static final int FLAG_GET_PERSISTED_DATA = 1 << 12; /** * Populate the persons field in the result. See {@link ShortcutInfo#getPersons()}. * Loading @@ -459,6 +472,7 @@ public class LauncherApps { FLAG_MATCH_PINNED_BY_ANY_LAUNCHER, FLAG_GET_KEY_FIELDS_ONLY, FLAG_GET_PERSONS_DATA, FLAG_GET_PERSISTED_DATA }) @Retention(RetentionPolicy.SOURCE) public @interface QueryFlags {} Loading Loading @@ -1137,6 +1151,9 @@ public class LauncherApps { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { if ((query.mQueryFlags & ShortcutQuery.FLAG_GET_PERSISTED_DATA) != 0) { return getShortcutsBlocked(query, user); } // Note this is the only case we need to update the disabled message for shortcuts // that weren't restored. // The restore problem messages are only shown by the user, and publishers will never Loading @@ -1151,6 +1168,22 @@ public class LauncherApps { } } private List<ShortcutInfo> getShortcutsBlocked(@NonNull ShortcutQuery query, @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>(); future.thenApply(this::maybeUpdateDisabledMessage); try { mService.getShortcutsAsync(mContext.getPackageName(), new ShortcutQueryWrapper(query), user, future); return future.get(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } /** * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests. */ Loading core/java/android/content/pm/ShortcutServiceInternal.java +38 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ import android.content.pm.LauncherApps.ShortcutQuery; import android.os.Bundle; import android.os.ParcelFileDescriptor; import com.android.internal.infra.AndroidFuture; import java.util.List; /** Loading @@ -50,6 +52,19 @@ public abstract class ShortcutServiceInternal { @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid); /** * Retrieves shortcuts asynchronously. Query will go through persistence layer (thus making the * call async) if querying by shortcutIds in a specific package; otherwise it's effectively the * same as calling {@link #getShortcuts}. */ public abstract void getShortcutsAsync(int launcherUserId, @NonNull String callingPackage, long changedSince, @Nullable String packageName, @Nullable List<String> shortcutIds, @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid, AndroidFuture<List<ShortcutInfo>> cb); public abstract boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String id, int userId); Loading @@ -63,6 +78,14 @@ public abstract class ShortcutServiceInternal { @NonNull String packageName, @NonNull String shortcutId, int userId, int callingPid, int callingUid); /** * Retrieves the intents from a specified shortcut asynchronously. */ public abstract void createShortcutIntentsAsync( int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, int callingPid, int callingUid, @NonNull AndroidFuture<Intent[]> cb); public abstract void addListener(@NonNull ShortcutChangeListener listener); public abstract void addShortcutChangeCallback( Loading @@ -82,6 +105,13 @@ public abstract class ShortcutServiceInternal { @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); /** * Retrieves a file descriptor from the icon in a specified shortcut asynchronously. */ public abstract void getShortcutIconFdAsync(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, @NonNull AndroidFuture<ParcelFileDescriptor> cb); public abstract boolean hasShortcutHostPermission(int launcherUserId, @NonNull String callingPackage, int callingPid, int callingUid); Loading Loading @@ -117,6 +147,14 @@ public abstract class ShortcutServiceInternal { public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); /** * Retrieves the icon Uri of the shortcut asynchronously, and grants Uri read permission to the * caller. */ public abstract void getShortcutIconUriAsync(int launcherUserId, @NonNull String launcherPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, @NonNull AndroidFuture<String> cb); public abstract boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, @NonNull IntentFilter filter); Loading services/core/java/com/android/server/pm/LauncherAppsService.java +72 −10 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; Loading @@ -103,6 +104,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; /** * Service that manages requests and callbacks for launchers that support Loading Loading @@ -728,9 +730,16 @@ public class LauncherAppsService extends SystemService { return null; } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( getCallingUserId(), callingPackage, packageName, shortcutId, user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid()); final AndroidFuture<Intent[]> ret = new AndroidFuture<>(); Intent[] intents; mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage, packageName, shortcutId, user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid(), ret); try { intents = ret.get(); } catch (InterruptedException | ExecutionException e) { return null; } if (intents == null || intents.length == 0) { return null; } Loading Loading @@ -900,6 +909,40 @@ public class LauncherAppsService extends SystemService { injectBinderCallingPid(), injectBinderCallingUid())); } @Override public void getShortcutsAsync(@NonNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser, @NonNull final AndroidFuture<List<ShortcutInfo>> cb) { ensureShortcutPermission(callingPackage); if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { cb.complete(Collections.EMPTY_LIST); return; } final long changedSince = query.getChangedSince(); final String packageName = query.getPackage(); final List<String> shortcutIds = query.getShortcutIds(); final List<LocusId> locusIds = query.getLocusIds(); final ComponentName componentName = query.getActivity(); final int flags = query.getQueryFlags(); if (shortcutIds != null && packageName == null) { throw new IllegalArgumentException( "To query by shortcut ID, package name must also be set"); } if (locusIds != null && packageName == null) { throw new IllegalArgumentException( "To query by locus ID, package name must also be set"); } if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) { ensureStrictAccessShortcutsPermission(callingPackage); } mShortcutServiceInternal.getShortcutsAsync(getCallingUserId(), callingPackage, changedSince, packageName, shortcutIds, locusIds, componentName, flags, targetUser.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid(), cb); } @Override public void registerShortcutChangeCallback(@NonNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, Loading Loading @@ -991,8 +1034,14 @@ public class LauncherAppsService extends SystemService { return null; } return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), callingPackage, packageName, id, targetUserId); final AndroidFuture<ParcelFileDescriptor> ret = new AndroidFuture<>(); mShortcutServiceInternal.getShortcutIconFdAsync(getCallingUserId(), callingPackage, packageName, id, targetUserId, ret); try { return ret.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } @Override Loading @@ -1003,8 +1052,14 @@ public class LauncherAppsService extends SystemService { return null; } return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage, packageName, shortcutId, userId); final AndroidFuture<String> ret = new AndroidFuture<>(); mShortcutServiceInternal.getShortcutIconUriAsync(getCallingUserId(), callingPackage, packageName, shortcutId, userId, ret); try { return ret.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } @Override Loading Loading @@ -1037,9 +1092,16 @@ public class LauncherAppsService extends SystemService { ensureShortcutPermission(callerUid, callerPid, callingPackage); } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( callingUserId, callingPackage, packageName, shortcutId, targetUserId, callerPid, callerUid); final AndroidFuture<Intent[]> ret = new AndroidFuture<>(); Intent[] intents; mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, injectBinderCallingPid(), injectBinderCallingUid(), ret); try { intents = ret.get(); } catch (InterruptedException | ExecutionException e) { return false; } if (intents == null || intents.length == 0) { return false; } Loading Loading
core/api/system-current.txt +1 −0 Original line number Diff line number Diff line Loading @@ -2918,6 +2918,7 @@ package android.content.pm { } public static class LauncherApps.ShortcutQuery { field public static final int FLAG_GET_PERSISTED_DATA = 4096; // 0x1000 field @RequiresPermission(android.Manifest.permission.ACCESS_SHORTCUTS) public static final int FLAG_GET_PERSONS_DATA = 2048; // 0x800 }
core/java/android/content/pm/ILauncherApps.aidl +4 −0 Original line number Diff line number Diff line Loading @@ -38,6 +38,8 @@ import android.os.Bundle; import android.os.UserHandle; import android.os.ParcelFileDescriptor; import com.android.internal.infra.AndroidFuture; import java.util.List; /** Loading Loading @@ -73,6 +75,8 @@ interface ILauncherApps { ParceledListSlice getShortcuts(String callingPackage, in ShortcutQueryWrapper query, in UserHandle user); void getShortcutsAsync(String callingPackage, in ShortcutQueryWrapper query, in UserHandle user, in AndroidFuture<List<ShortcutInfo>> cb); void pinShortcuts(String callingPackage, String packageName, in List<String> shortcutIds, in UserHandle user); boolean startShortcut(String callingPackage, String packageName, String featureId, String id, Loading
core/java/android/content/pm/LauncherApps.java +35 −2 Original line number Diff line number Diff line Loading @@ -69,6 +69,7 @@ import android.util.Log; import android.util.Pair; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.infra.AndroidFuture; import com.android.internal.util.function.pooled.PooledLambda; import java.io.FileNotFoundException; Loading @@ -84,6 +85,7 @@ import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.Objects; import java.util.concurrent.ExecutionException; import java.util.concurrent.Executor; /** Loading Loading @@ -439,6 +441,17 @@ public class LauncherApps { */ public static final int FLAG_GET_KEY_FIELDS_ONLY = 1 << 2; /** * Includes shortcuts from persistence layer in the search result. * * <p>The caller should make the query on a worker thread since accessing persistence layer * is considered asynchronous. * * @hide */ @SystemApi public static final int FLAG_GET_PERSISTED_DATA = 1 << 12; /** * Populate the persons field in the result. See {@link ShortcutInfo#getPersons()}. * Loading @@ -459,6 +472,7 @@ public class LauncherApps { FLAG_MATCH_PINNED_BY_ANY_LAUNCHER, FLAG_GET_KEY_FIELDS_ONLY, FLAG_GET_PERSONS_DATA, FLAG_GET_PERSISTED_DATA }) @Retention(RetentionPolicy.SOURCE) public @interface QueryFlags {} Loading Loading @@ -1137,6 +1151,9 @@ public class LauncherApps { @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); try { if ((query.mQueryFlags & ShortcutQuery.FLAG_GET_PERSISTED_DATA) != 0) { return getShortcutsBlocked(query, user); } // Note this is the only case we need to update the disabled message for shortcuts // that weren't restored. // The restore problem messages are only shown by the user, and publishers will never Loading @@ -1151,6 +1168,22 @@ public class LauncherApps { } } private List<ShortcutInfo> getShortcutsBlocked(@NonNull ShortcutQuery query, @NonNull UserHandle user) { logErrorForInvalidProfileAccess(user); final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>(); future.thenApply(this::maybeUpdateDisabledMessage); try { mService.getShortcutsAsync(mContext.getPackageName(), new ShortcutQueryWrapper(query), user, future); return future.get(); } catch (RemoteException e) { throw e.rethrowFromSystemServer(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } /** * @hide // No longer used. Use getShortcuts() instead. Kept for unit tests. */ Loading
core/java/android/content/pm/ShortcutServiceInternal.java +38 −0 Original line number Diff line number Diff line Loading @@ -29,6 +29,8 @@ import android.content.pm.LauncherApps.ShortcutQuery; import android.os.Bundle; import android.os.ParcelFileDescriptor; import com.android.internal.infra.AndroidFuture; import java.util.List; /** Loading @@ -50,6 +52,19 @@ public abstract class ShortcutServiceInternal { @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid); /** * Retrieves shortcuts asynchronously. Query will go through persistence layer (thus making the * call async) if querying by shortcutIds in a specific package; otherwise it's effectively the * same as calling {@link #getShortcuts}. */ public abstract void getShortcutsAsync(int launcherUserId, @NonNull String callingPackage, long changedSince, @Nullable String packageName, @Nullable List<String> shortcutIds, @Nullable List<LocusId> locusIds, @Nullable ComponentName componentName, @ShortcutQuery.QueryFlags int flags, int userId, int callingPid, int callingUid, AndroidFuture<List<ShortcutInfo>> cb); public abstract boolean isPinnedByCaller(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String id, int userId); Loading @@ -63,6 +78,14 @@ public abstract class ShortcutServiceInternal { @NonNull String packageName, @NonNull String shortcutId, int userId, int callingPid, int callingUid); /** * Retrieves the intents from a specified shortcut asynchronously. */ public abstract void createShortcutIntentsAsync( int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, int callingPid, int callingUid, @NonNull AndroidFuture<Intent[]> cb); public abstract void addListener(@NonNull ShortcutChangeListener listener); public abstract void addShortcutChangeCallback( Loading @@ -82,6 +105,13 @@ public abstract class ShortcutServiceInternal { @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); /** * Retrieves a file descriptor from the icon in a specified shortcut asynchronously. */ public abstract void getShortcutIconFdAsync(int launcherUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, @NonNull AndroidFuture<ParcelFileDescriptor> cb); public abstract boolean hasShortcutHostPermission(int launcherUserId, @NonNull String callingPackage, int callingPid, int callingUid); Loading Loading @@ -117,6 +147,14 @@ public abstract class ShortcutServiceInternal { public abstract String getShortcutIconUri(int launcherUserId, @NonNull String launcherPackage, @NonNull String packageName, @NonNull String shortcutId, int userId); /** * Retrieves the icon Uri of the shortcut asynchronously, and grants Uri read permission to the * caller. */ public abstract void getShortcutIconUriAsync(int launcherUserId, @NonNull String launcherPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, @NonNull AndroidFuture<String> cb); public abstract boolean isSharingShortcut(int callingUserId, @NonNull String callingPackage, @NonNull String packageName, @NonNull String shortcutId, int userId, @NonNull IntentFilter filter); Loading
services/core/java/com/android/server/pm/LauncherAppsService.java +72 −10 Original line number Diff line number Diff line Loading @@ -88,6 +88,7 @@ import android.util.Slog; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; import com.android.internal.content.PackageMonitor; import com.android.internal.infra.AndroidFuture; import com.android.internal.os.BackgroundThread; import com.android.internal.util.ArrayUtils; import com.android.internal.util.CollectionUtils; Loading @@ -103,6 +104,7 @@ import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; import java.util.concurrent.ExecutionException; /** * Service that manages requests and callbacks for launchers that support Loading Loading @@ -728,9 +730,16 @@ public class LauncherAppsService extends SystemService { return null; } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( getCallingUserId(), callingPackage, packageName, shortcutId, user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid()); final AndroidFuture<Intent[]> ret = new AndroidFuture<>(); Intent[] intents; mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage, packageName, shortcutId, user.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid(), ret); try { intents = ret.get(); } catch (InterruptedException | ExecutionException e) { return null; } if (intents == null || intents.length == 0) { return null; } Loading Loading @@ -900,6 +909,40 @@ public class LauncherAppsService extends SystemService { injectBinderCallingPid(), injectBinderCallingUid())); } @Override public void getShortcutsAsync(@NonNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, @NonNull final UserHandle targetUser, @NonNull final AndroidFuture<List<ShortcutInfo>> cb) { ensureShortcutPermission(callingPackage); if (!canAccessProfile(targetUser.getIdentifier(), "Cannot get shortcuts")) { cb.complete(Collections.EMPTY_LIST); return; } final long changedSince = query.getChangedSince(); final String packageName = query.getPackage(); final List<String> shortcutIds = query.getShortcutIds(); final List<LocusId> locusIds = query.getLocusIds(); final ComponentName componentName = query.getActivity(); final int flags = query.getQueryFlags(); if (shortcutIds != null && packageName == null) { throw new IllegalArgumentException( "To query by shortcut ID, package name must also be set"); } if (locusIds != null && packageName == null) { throw new IllegalArgumentException( "To query by locus ID, package name must also be set"); } if ((query.getQueryFlags() & ShortcutQuery.FLAG_GET_PERSONS_DATA) != 0) { ensureStrictAccessShortcutsPermission(callingPackage); } mShortcutServiceInternal.getShortcutsAsync(getCallingUserId(), callingPackage, changedSince, packageName, shortcutIds, locusIds, componentName, flags, targetUser.getIdentifier(), injectBinderCallingPid(), injectBinderCallingUid(), cb); } @Override public void registerShortcutChangeCallback(@NonNull final String callingPackage, @NonNull final ShortcutQueryWrapper query, Loading Loading @@ -991,8 +1034,14 @@ public class LauncherAppsService extends SystemService { return null; } return mShortcutServiceInternal.getShortcutIconFd(getCallingUserId(), callingPackage, packageName, id, targetUserId); final AndroidFuture<ParcelFileDescriptor> ret = new AndroidFuture<>(); mShortcutServiceInternal.getShortcutIconFdAsync(getCallingUserId(), callingPackage, packageName, id, targetUserId, ret); try { return ret.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } @Override Loading @@ -1003,8 +1052,14 @@ public class LauncherAppsService extends SystemService { return null; } return mShortcutServiceInternal.getShortcutIconUri(getCallingUserId(), callingPackage, packageName, shortcutId, userId); final AndroidFuture<String> ret = new AndroidFuture<>(); mShortcutServiceInternal.getShortcutIconUriAsync(getCallingUserId(), callingPackage, packageName, shortcutId, userId, ret); try { return ret.get(); } catch (InterruptedException | ExecutionException e) { throw new RuntimeException(e); } } @Override Loading Loading @@ -1037,9 +1092,16 @@ public class LauncherAppsService extends SystemService { ensureShortcutPermission(callerUid, callerPid, callingPackage); } final Intent[] intents = mShortcutServiceInternal.createShortcutIntents( callingUserId, callingPackage, packageName, shortcutId, targetUserId, callerPid, callerUid); final AndroidFuture<Intent[]> ret = new AndroidFuture<>(); Intent[] intents; mShortcutServiceInternal.createShortcutIntentsAsync(getCallingUserId(), callingPackage, packageName, shortcutId, targetUserId, injectBinderCallingPid(), injectBinderCallingUid(), ret); try { intents = ret.get(); } catch (InterruptedException | ExecutionException e) { return false; } if (intents == null || intents.length == 0) { return false; } Loading