diff --git a/core/api/current.txt b/core/api/current.txt index abd770d7edf66..7e6ab7c2d7ddc 100644 --- a/core/api/current.txt +++ b/core/api/current.txt @@ -12881,18 +12881,18 @@ package android.content.pm { } public class ShortcutManager { - method public boolean addDynamicShortcuts(@NonNull java.util.List); - method public android.content.Intent createShortcutResultIntent(@NonNull android.content.pm.ShortcutInfo); + method @WorkerThread public boolean addDynamicShortcuts(@NonNull java.util.List); + method @WorkerThread public android.content.Intent createShortcutResultIntent(@NonNull android.content.pm.ShortcutInfo); method public void disableShortcuts(@NonNull java.util.List); method public void disableShortcuts(@NonNull java.util.List, CharSequence); method public void enableShortcuts(@NonNull java.util.List); - method @NonNull public java.util.List getDynamicShortcuts(); + method @NonNull @WorkerThread public java.util.List getDynamicShortcuts(); method public int getIconMaxHeight(); method public int getIconMaxWidth(); - method @NonNull public java.util.List getManifestShortcuts(); + method @NonNull @WorkerThread public java.util.List getManifestShortcuts(); method public int getMaxShortcutCountPerActivity(); - method @NonNull public java.util.List getPinnedShortcuts(); - method @NonNull public java.util.List getShortcuts(int); + method @NonNull @WorkerThread public java.util.List getPinnedShortcuts(); + method @NonNull @WorkerThread public java.util.List getShortcuts(int); method public boolean isRateLimitingActive(); method public boolean isRequestPinShortcutSupported(); method public void pushDynamicShortcut(@NonNull android.content.pm.ShortcutInfo); @@ -12900,10 +12900,10 @@ package android.content.pm { method public void removeDynamicShortcuts(@NonNull java.util.List); method public void removeLongLivedShortcuts(@NonNull java.util.List); method public void reportShortcutUsed(String); - method public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender); - method public boolean setDynamicShortcuts(@NonNull java.util.List); + method @WorkerThread public boolean requestPinShortcut(@NonNull android.content.pm.ShortcutInfo, @Nullable android.content.IntentSender); + method @WorkerThread public boolean setDynamicShortcuts(@NonNull java.util.List); method public void updateShortcutVisibility(@NonNull String, @Nullable byte[], boolean); - method public boolean updateShortcuts(@NonNull java.util.List); + method @WorkerThread public boolean updateShortcuts(@NonNull java.util.List); field public static final int FLAG_MATCH_CACHED = 8; // 0x8 field public static final int FLAG_MATCH_DYNAMIC = 2; // 0x2 field public static final int FLAG_MATCH_MANIFEST = 1; // 0x1 diff --git a/core/api/system-current.txt b/core/api/system-current.txt index 6f36b06c9c645..3a238e29dd232 100644 --- a/core/api/system-current.txt +++ b/core/api/system-current.txt @@ -2703,7 +2703,7 @@ package android.content.pm { } public class ShortcutManager { - method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS) public java.util.List getShareTargets(@NonNull android.content.IntentFilter); + method @NonNull @RequiresPermission(android.Manifest.permission.MANAGE_APP_PREDICTIONS) @WorkerThread public java.util.List getShareTargets(@NonNull android.content.IntentFilter); method public boolean hasShareTargets(@NonNull String); } diff --git a/core/java/android/content/pm/IShortcutService.aidl b/core/java/android/content/pm/IShortcutService.aidl index b34574811bcaf..c91334a5470fc 100644 --- a/core/java/android/content/pm/IShortcutService.aidl +++ b/core/java/android/content/pm/IShortcutService.aidl @@ -21,32 +21,34 @@ import android.content.IntentSender; import android.content.pm.ParceledListSlice; import android.content.pm.ShortcutInfo; -/** - * {@hide} - */ +import com.android.internal.infra.AndroidFuture; + +/** {@hide} */ interface IShortcutService { - boolean setDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList, - int userId); + oneway void setDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList, + int userId, in AndroidFuture callback); - boolean addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList, - int userId); + oneway void addDynamicShortcuts(String packageName, in ParceledListSlice shortcutInfoList, + int userId, in AndroidFuture callback); - void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId); + oneway void removeDynamicShortcuts(String packageName, in List shortcutIds, int userId); - void removeAllDynamicShortcuts(String packageName, int userId); + oneway void removeAllDynamicShortcuts(String packageName, int userId); - boolean updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId); + oneway void updateShortcuts(String packageName, in ParceledListSlice shortcuts, int userId, + in AndroidFuture callback); - boolean requestPinShortcut(String packageName, in ShortcutInfo shortcut, - in IntentSender resultIntent, int userId); + oneway void requestPinShortcut(String packageName, in ShortcutInfo shortcut, + in IntentSender resultIntent, int userId, in AndroidFuture callback); - Intent createShortcutResultIntent(String packageName, in ShortcutInfo shortcut, int userId); + oneway void createShortcutResultIntent(String packageName, in ShortcutInfo shortcut, + int userId, in AndroidFuture callback); - void disableShortcuts(String packageName, in List shortcutIds, CharSequence disabledMessage, - int disabledMessageResId, int userId); + oneway void disableShortcuts(String packageName, in List shortcutIds, + CharSequence disabledMessage, int disabledMessageResId, int userId); - void enableShortcuts(String packageName, in List shortcutIds, int userId); + oneway void enableShortcuts(String packageName, in List shortcutIds, int userId); int getMaxShortcutCountPerActivity(String packageName, int userId); @@ -56,29 +58,31 @@ interface IShortcutService { int getIconMaxDimensions(String packageName, int userId); - void reportShortcutUsed(String packageName, String shortcutId, int userId); + oneway void reportShortcutUsed(String packageName, String shortcutId, int userId); - void resetThrottling(); // system only API for developer opsions + oneway void resetThrottling(); // system only API for developer opsions - void onApplicationActive(String packageName, int userId); // system only API for sysUI + oneway void onApplicationActive(String packageName, int userId); // system only API for sysUI byte[] getBackupPayload(int user); - void applyRestore(in byte[] payload, int user); + oneway void applyRestore(in byte[] payload, int user); boolean isRequestPinItemSupported(int user, int requestType); // System API used by framework's ShareSheet (ChooserActivity) - ParceledListSlice getShareTargets(String packageName, in IntentFilter filter, int userId); + oneway void getShareTargets(String packageName, in IntentFilter filter, int userId, + in AndroidFuture callback); boolean hasShareTargets(String packageName, String packageToCheck, int userId); - void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId); + oneway void removeLongLivedShortcuts(String packageName, in List shortcutIds, int userId); - ParceledListSlice getShortcuts(String packageName, int matchFlags, int userId); + oneway void getShortcuts(String packageName, int matchFlags, int userId, + in AndroidFuture> callback); - void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId); + oneway void pushDynamicShortcut(String packageName, in ShortcutInfo shortcut, int userId); - void updateShortcutVisibility(String callingPkg, String packageName, in byte[] certificate, - in boolean visible, int userId); -} \ No newline at end of file + oneway void updateShortcutVisibility(String callingPkg, String packageName, + in byte[] certificate, in boolean visible, int userId); +} diff --git a/core/java/android/content/pm/ShortcutManager.java b/core/java/android/content/pm/ShortcutManager.java index d3bac79aa2b98..f584ff33fa50d 100644 --- a/core/java/android/content/pm/ShortcutManager.java +++ b/core/java/android/content/pm/ShortcutManager.java @@ -24,6 +24,7 @@ import android.annotation.SystemApi; import android.annotation.SystemService; import android.annotation.TestApi; import android.annotation.UserIdInt; +import android.annotation.WorkerThread; import android.app.Notification; import android.app.usage.UsageStatsManager; import android.compat.annotation.UnsupportedAppUsage; @@ -42,10 +43,12 @@ import android.os.ServiceManager; import android.os.UserHandle; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.infra.AndroidFuture; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.util.List; +import java.util.concurrent.ExecutionException; /** *

ShortcutManager executes operations on an app's set of shortcuts, which @@ -140,13 +143,16 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread public boolean setDynamicShortcuts(@NonNull List shortcutInfoList) { + final AndroidFuture future = new AndroidFuture<>(); try { - return mService.setDynamicShortcuts(mContext.getPackageName(), - new ParceledListSlice(shortcutInfoList), injectMyUserId()); + mService.setDynamicShortcuts(mContext.getPackageName(), + new ParceledListSlice(shortcutInfoList), injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future); } /** @@ -158,14 +164,17 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread @NonNull public List getDynamicShortcuts() { + final AndroidFuture> future = new AndroidFuture<>(); try { - return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_DYNAMIC, - injectMyUserId()).getList(); + mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_DYNAMIC, injectMyUserId(), + future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future).getList(); } /** @@ -177,14 +186,17 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread @NonNull public List getManifestShortcuts() { + final AndroidFuture> future = new AndroidFuture<>(); try { - return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_MANIFEST, - injectMyUserId()).getList(); + mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_MANIFEST, injectMyUserId(), + future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future).getList(); } /** @@ -205,14 +217,16 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread @NonNull public List getShortcuts(@ShortcutMatchFlags int matchFlags) { + final AndroidFuture> future = new AndroidFuture<>(); try { - return mService.getShortcuts(mContext.getPackageName(), matchFlags, injectMyUserId()) - .getList(); + mService.getShortcuts(mContext.getPackageName(), matchFlags, injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future).getList(); } /** @@ -228,13 +242,16 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread public boolean addDynamicShortcuts(@NonNull List shortcutInfoList) { + final AndroidFuture future = new AndroidFuture<>(); try { - return mService.addDynamicShortcuts(mContext.getPackageName(), - new ParceledListSlice(shortcutInfoList), injectMyUserId()); + mService.addDynamicShortcuts(mContext.getPackageName(), + new ParceledListSlice(shortcutInfoList), injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future); } /** @@ -287,14 +304,17 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread @NonNull public List getPinnedShortcuts() { + final AndroidFuture> future = new AndroidFuture<>(); try { - return mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_PINNED, - injectMyUserId()).getList(); + mService.getShortcuts(mContext.getPackageName(), FLAG_MATCH_PINNED, injectMyUserId(), + future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future).getList(); } /** @@ -309,13 +329,16 @@ public class ShortcutManager { * * @throws IllegalStateException when the user is locked. */ + @WorkerThread public boolean updateShortcuts(@NonNull List shortcutInfoList) { + final AndroidFuture future = new AndroidFuture<>(); try { - return mService.updateShortcuts(mContext.getPackageName(), - new ParceledListSlice(shortcutInfoList), injectMyUserId()); + mService.updateShortcuts(mContext.getPackageName(), + new ParceledListSlice(shortcutInfoList), injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future); } /** @@ -584,14 +607,17 @@ public class ShortcutManager { * @throws IllegalStateException The caller doesn't have a foreground activity or a foreground * service, or the device is locked. */ + @WorkerThread public boolean requestPinShortcut(@NonNull ShortcutInfo shortcut, @Nullable IntentSender resultIntent) { + final AndroidFuture future = new AndroidFuture<>(); try { - return mService.requestPinShortcut(mContext.getPackageName(), shortcut, - resultIntent, injectMyUserId()); + mService.requestPinShortcut(mContext.getPackageName(), shortcut, + resultIntent, injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future); } /** @@ -611,13 +637,16 @@ public class ShortcutManager { * * @throws IllegalArgumentException if a shortcut with the same ID exists and is disabled. */ + @WorkerThread public Intent createShortcutResultIntent(@NonNull ShortcutInfo shortcut) { + final AndroidFuture future = new AndroidFuture<>(); try { - return mService.createShortcutResultIntent(mContext.getPackageName(), shortcut, - injectMyUserId()); + mService.createShortcutResultIntent(mContext.getPackageName(), shortcut, + injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future); } /** @@ -650,16 +679,18 @@ public class ShortcutManager { * @return List of {@link ShareShortcutInfo}s that match the given IntentFilter. * @hide */ + @WorkerThread @NonNull @SystemApi @RequiresPermission(Manifest.permission.MANAGE_APP_PREDICTIONS) public List getShareTargets(@NonNull IntentFilter filter) { + final AndroidFuture future = new AndroidFuture<>(); try { - return mService.getShareTargets(mContext.getPackageName(), filter, - injectMyUserId()).getList(); + mService.getShareTargets(mContext.getPackageName(), filter, injectMyUserId(), future); } catch (RemoteException e) { - throw e.rethrowFromSystemServer(); + future.completeExceptionally(e); } + return getFutureOrThrow(future).getList(); } /** @@ -788,4 +819,21 @@ public class ShortcutManager { throw e.rethrowFromSystemServer(); } } + + private static T getFutureOrThrow(@NonNull AndroidFuture future) { + try { + return future.get(); + } catch (Throwable e) { + if (e instanceof ExecutionException) { + e = e.getCause(); + } + if (e instanceof RuntimeException) { + throw (RuntimeException) e; + } + if (e instanceof Error) { + throw (Error) e; + } + throw new RuntimeException(e); + } + } } diff --git a/services/core/java/com/android/server/pm/ShortcutService.java b/services/core/java/com/android/server/pm/ShortcutService.java index a377f1c723757..d1cf55de72548 100644 --- a/services/core/java/com/android/server/pm/ShortcutService.java +++ b/services/core/java/com/android/server/pm/ShortcutService.java @@ -103,6 +103,7 @@ import android.view.IWindowManager; import com.android.internal.annotations.GuardedBy; import com.android.internal.annotations.VisibleForTesting; +import com.android.internal.infra.AndroidFuture; import com.android.internal.logging.MetricsLogger; import com.android.internal.os.BackgroundThread; import com.android.internal.util.CollectionUtils; @@ -142,6 +143,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.List; import java.util.Objects; +import java.util.concurrent.ExecutionException; import java.util.concurrent.atomic.AtomicBoolean; import java.util.function.Consumer; import java.util.function.Predicate; @@ -1885,8 +1887,8 @@ public class ShortcutService extends IShortcutService.Stub { // === APIs === @Override - public boolean setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, - @UserIdInt int userId) { + public void setDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, + @UserIdInt int userId, @NonNull AndroidFuture callback) { verifyCaller(packageName, userId); final List newShortcuts = (List) shortcutInfoList.getList(); @@ -1913,7 +1915,7 @@ public class ShortcutService extends IShortcutService.Stub { // Throttling. if (!ps.tryApiCall(unlimited)) { - return false; + callback.complete(false); } // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). @@ -1949,12 +1951,12 @@ public class ShortcutService extends IShortcutService.Stub { verifyStates(); - return true; + callback.complete(true); } @Override - public boolean updateShortcuts(String packageName, ParceledListSlice shortcutInfoList, - @UserIdInt int userId) { + public void updateShortcuts(String packageName, ParceledListSlice shortcutInfoList, + @UserIdInt int userId, AndroidFuture callback) { verifyCaller(packageName, userId); final List newShortcuts = (List) shortcutInfoList.getList(); @@ -1981,7 +1983,8 @@ public class ShortcutService extends IShortcutService.Stub { // Throttling. if (!ps.tryApiCall(unlimited)) { - return false; + callback.complete(false); + return; } // Initialize the implicit ranks for ShortcutPackage.adjustRanks(). @@ -2046,12 +2049,12 @@ public class ShortcutService extends IShortcutService.Stub { verifyStates(); - return true; + callback.complete(true); } @Override - public boolean addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, - @UserIdInt int userId) { + public void addDynamicShortcuts(String packageName, ParceledListSlice shortcutInfoList, + @UserIdInt int userId, AndroidFuture callback) { verifyCaller(packageName, userId); final List newShortcuts = (List) shortcutInfoList.getList(); @@ -2081,7 +2084,8 @@ public class ShortcutService extends IShortcutService.Stub { // Throttling. if (!ps.tryApiCall(unlimited)) { - return false; + callback.complete(false); + return; } for (int i = 0; i < size; i++) { final ShortcutInfo newShortcut = newShortcuts.get(i); @@ -2109,7 +2113,7 @@ public class ShortcutService extends IShortcutService.Stub { verifyStates(); - return true; + callback.complete(true); } @Override @@ -2174,15 +2178,17 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public boolean requestPinShortcut(String packageName, ShortcutInfo shortcut, - IntentSender resultIntent, int userId) { + public void requestPinShortcut(String packageName, ShortcutInfo shortcut, + IntentSender resultIntent, int userId, AndroidFuture callback) { Objects.requireNonNull(shortcut); + Objects.requireNonNull(callback); Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); - return requestPinItem(packageName, userId, shortcut, null, null, resultIntent); + callback.complete(requestPinItem(packageName, userId, shortcut, null, null, resultIntent)); } @Override - public Intent createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId) + public void createShortcutResultIntent(String packageName, ShortcutInfo shortcut, int userId, + AndroidFuture callback) throws RemoteException { Objects.requireNonNull(shortcut); Preconditions.checkArgument(shortcut.isEnabled(), "Shortcut must be enabled"); @@ -2198,7 +2204,7 @@ public class ShortcutService extends IShortcutService.Stub { } verifyStates(); - return ret; + callback.complete(ret); } /** @@ -2455,8 +2461,9 @@ public class ShortcutService extends IShortcutService.Stub { } @Override - public ParceledListSlice getShortcuts(String packageName, - @ShortcutManager.ShortcutMatchFlags int matchFlags, @UserIdInt int userId) { + public void getShortcuts(String packageName, + @ShortcutManager.ShortcutMatchFlags int matchFlags, @UserIdInt int userId, + AndroidFuture> callback) { verifyCaller(packageName, userId); synchronized (mLock) { @@ -2472,16 +2479,16 @@ public class ShortcutService extends IShortcutService.Stub { | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); - return getShortcutsWithQueryLocked( + callback.complete(getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, (ShortcutInfo si) -> - si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0); + si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0)); } } @Override - public ParceledListSlice getShareTargets(String packageName, - IntentFilter filter, @UserIdInt int userId) { + public void getShareTargets(String packageName, IntentFilter filter, @UserIdInt int userId, + AndroidFuture callback) { Preconditions.checkStringNotEmpty(packageName, "packageName"); Objects.requireNonNull(filter, "intentFilter"); @@ -2497,7 +2504,7 @@ public class ShortcutService extends IShortcutService.Stub { final ShortcutUser user = getUserShortcutsLocked(userId); user.forAllPackages(p -> shortcutInfoList.addAll(p.getMatchingShareTargets(filter))); - return new ParceledListSlice<>(shortcutInfoList); + callback.complete(new ParceledListSlice<>(shortcutInfoList)); } } @@ -3081,8 +3088,14 @@ public class ShortcutService extends IShortcutService.Stub { @Override public List getShareTargets( @NonNull String callingPackage, @NonNull IntentFilter intentFilter, int userId) { - return ShortcutService.this.getShareTargets( - callingPackage, intentFilter, userId).getList(); + final AndroidFuture future = new AndroidFuture<>(); + ShortcutService.this.getShareTargets( + callingPackage, intentFilter, userId, future); + try { + return future.get().getList(); + } catch (InterruptedException | ExecutionException e) { + throw new RuntimeException(e); + } } @Override