Loading services/core/java/com/android/server/pm/ShortcutPackage.java +252 −462 File changed.Preview size limit exceeded, changes collapsed. Show changes services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java +3 −2 Original line number Diff line number Diff line Loading @@ -517,7 +517,8 @@ class ShortcutRequestPinProcessor { if (DEBUG) { Slog.d(TAG, "Removing " + shortcutId + " as dynamic"); } ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false); ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false, /*wasPushedOut=*/ false); } ps.adjustRanks(); // Shouldn't be needed, but just in case. Loading services/core/java/com/android/server/pm/ShortcutService.java +20 −41 Original line number Diff line number Diff line Loading @@ -1965,13 +1965,12 @@ public class ShortcutService extends IShortcutService.Stub { ArrayList<ShortcutInfo> cachedOrPinned = new ArrayList<>(); ps.findAll(cachedOrPinned, AppSearchShortcutInfo.QUERY_IS_VISIBLE_CACHED_OR_PINNED, (ShortcutInfo si) -> si.isVisibleToPublisher() && si.isDynamic() && (si.isCached() || si.isPinned()), ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); // First, remove all un-pinned and non-cached; dynamic shortcuts removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); removedShortcuts = ps.deleteAllDynamicShortcuts(); // Then, add/update all. We need to make sure to take over "pinned" flag. for (int i = 0; i < size; i++) { Loading Loading @@ -2381,7 +2380,8 @@ public class ShortcutService extends IShortcutService.Stub { if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { continue; } ShortcutInfo removed = ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true); ShortcutInfo removed = ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true, /*wasPushedOut*/ false); if (removed == null) { if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); Loading Loading @@ -2412,11 +2412,10 @@ public class ShortcutService extends IShortcutService.Stub { userId); // Dynamic shortcuts that are either cached or pinned will not get deleted. ps.findAll(changedShortcuts, AppSearchShortcutInfo.QUERY_IS_VISIBLE_CACHED_OR_PINNED, (ShortcutInfo si) -> si.isVisibleToPublisher() && si.isDynamic() && (si.isCached() || si.isPinned()), ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); removedShortcuts = ps.deleteAllDynamicShortcuts(); changedShortcuts = prepareChangedShortcuts( changedShortcuts, null, removedShortcuts, ps); } Loading Loading @@ -2475,10 +2474,8 @@ public class ShortcutService extends IShortcutService.Stub { | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); final String query = AppSearchShortcutInfo.QUERY_IS_VISIBLE_TO_PUBLISHER + " " + createQuery(matchDynamic, matchPinned, matchManifest, matchCached); return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, query, packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, (ShortcutInfo si) -> si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0); Loading Loading @@ -2542,13 +2539,12 @@ public class ShortcutService extends IShortcutService.Stub { @GuardedBy("mLock") private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName, @UserIdInt int userId, int cloneFlags, @NonNull final String query, @NonNull Predicate<ShortcutInfo> filter) { @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> filter) { final ArrayList<ShortcutInfo> ret = new ArrayList<>(); final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); ps.findAll(ret, query, filter, cloneFlags); ps.findAll(ret, filter, cloneFlags); return new ParceledListSlice<>(setReturnedByServer(ret)); } Loading Loading @@ -2955,27 +2951,14 @@ public class ShortcutService extends IShortcutService.Stub { ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0); queryFlags |= (getPinnedByAnyLauncher ? ShortcutQuery.FLAG_MATCH_PINNED : 0); final boolean matchPinnedOnly = ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0) && ((queryFlags & ShortcutQuery.FLAG_MATCH_CACHED) == 0) && ((queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) == 0) && ((queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) == 0); final Predicate<ShortcutInfo> filter = getFilterFromQuery(ids, locusIds, changedSince, componentName, queryFlags, getPinnedByAnyLauncher); if (matchPinnedOnly) { p.findAllPinned(ret, filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); } else if (ids != null && !ids.isEmpty()) { if (ids != null && !ids.isEmpty()) { p.findAllByIds(ret, ids, filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); } else { final boolean matchDynamic = (queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0; final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0; final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0; final boolean matchCached = (queryFlags & ShortcutQuery.FLAG_MATCH_CACHED) != 0; p.findAll(ret, createQuery(matchDynamic, matchPinned, matchManifest, matchCached), filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); p.findAll(ret, filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); } } Loading Loading @@ -3090,8 +3073,7 @@ public class ShortcutService extends IShortcutService.Stub { if (sp != null) { // List the shortcuts that are pinned only, these will get removed. removedShortcuts = new ArrayList<>(); sp.findAll(removedShortcuts, AppSearchShortcutInfo.QUERY_IS_VISIBLE_PINNED_ONLY, (ShortcutInfo si) -> si.isVisibleToPublisher() sp.findAll(removedShortcuts, (ShortcutInfo si) -> si.isVisibleToPublisher() && si.isPinned() && !si.isCached() && !si.isDynamic() && !si.isDeclaredInManifest(), ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO, Loading Loading @@ -3183,8 +3165,7 @@ public class ShortcutService extends IShortcutService.Stub { if (doCache) { if (si.isLongLived()) { sp.mutateShortcut(si.getId(), si, shortcut -> shortcut.addFlags(cacheFlags)); si.addFlags(cacheFlags); if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); } Loading @@ -3195,21 +3176,20 @@ public class ShortcutService extends IShortcutService.Stub { } } else { ShortcutInfo removed = null; sp.mutateShortcut(si.getId(), si, shortcut -> shortcut.clearFlags(cacheFlags)); si.clearFlags(cacheFlags); if (!si.isDynamic() && !si.isCached()) { removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true); } if (removed != null) { if (removedShortcuts == null) { removedShortcuts = new ArrayList<>(1); } removedShortcuts.add(removed); } else { if (removed == null) { if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); } changedShortcuts.add(si); } else { if (removedShortcuts == null) { removedShortcuts = new ArrayList<>(1); } removedShortcuts.add(removed); } } } Loading Loading @@ -5084,8 +5064,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId); if (pkg == null) return; pkg.mutateShortcut(shortcutId, null, cb); cb.accept(pkg.findShortcutById(shortcutId)); } } Loading services/core/java/com/android/server/pm/ShortcutUser.java +3 −2 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ class ShortcutUser { final ShortcutPackage removed = mPackages.remove(packageName); if (removed != null) { removed.removeShortcuts(); removed.removeAllShortcutsAsync(); } mService.cleanupBitmapsForPackage(mUserId, packageName); Loading Loading @@ -577,7 +577,7 @@ class ShortcutUser { Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored." + " Existing non-manifeset shortcuts will be overwritten."); } sp.restoreParsedShortcuts(); sp.removeAllShortcutsAsync(); addPackage(sp); restoredPackages[0]++; restoredShortcuts[0] += sp.getShortcutCount(); Loading Loading @@ -714,6 +714,7 @@ class ShortcutUser { .setSubtype(totalSharingShortcutCount)); } @NonNull AndroidFuture<AppSearchSession> getAppSearch( @NonNull final AppSearchManager.SearchContext searchContext) { final AndroidFuture<AppSearchSession> future = new AndroidFuture<>(); Loading services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +13 −276 Original line number Diff line number Diff line Loading @@ -46,18 +46,6 @@ import android.app.IUidObserver; import android.app.PendingIntent; import android.app.Person; import android.app.admin.DevicePolicyManager; import android.app.appsearch.AppSearchBatchResult; import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchResult; import android.app.appsearch.GenericDocument; import android.app.appsearch.PackageIdentifier; import android.app.appsearch.SearchResultPage; import android.app.appsearch.SetSchemaResponse; import android.app.appsearch.aidl.AppSearchBatchResultParcel; import android.app.appsearch.aidl.AppSearchResultParcel; import android.app.appsearch.aidl.IAppSearchBatchResultCallback; import android.app.appsearch.aidl.IAppSearchManager; import android.app.appsearch.aidl.IAppSearchResultCallback; import android.app.role.OnRoleHoldersChangedListener; import android.app.usage.UsageStatsManagerInternal; import android.content.ActivityNotFoundException; Loading Loading @@ -92,9 +80,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; Loading @@ -106,6 +92,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import com.android.internal.infra.AndroidFuture; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; Loading Loading @@ -168,7 +155,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { case Context.DEVICE_POLICY_SERVICE: return mMockDevicePolicyManager; case Context.APP_SEARCH_SERVICE: return new AppSearchManager(this, mMockAppSearchManager); case Context.ROLE_SERVICE: // RoleManager is final and cannot be mocked, so we only override the inject // accessor methods in ShortcutService. Loading Loading @@ -647,260 +633,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } } protected class MockAppSearchManager implements IAppSearchManager { protected Map<String, List<PackageIdentifier>> mSchemasVisibleToPackages = new ArrayMap<>(1); private Map<String, Map<String, GenericDocument>> mDocumentMap = new ArrayMap<>(1); private String getKey(UserHandle userHandle, String databaseName) { return userHandle.getIdentifier() + "@" + databaseName; } @Override public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles, List<String> schemasNotDisplayedBySystem, Map<String, List<Bundle>> schemasVisibleToPackagesBundles, boolean forceOverride, int version, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { for (Map.Entry<String, List<Bundle>> entry : schemasVisibleToPackagesBundles.entrySet()) { final String key = entry.getKey(); final List<PackageIdentifier> packageIdentifiers; if (!mSchemasVisibleToPackages.containsKey(key)) { packageIdentifiers = new ArrayList<>(entry.getValue().size()); mSchemasVisibleToPackages.put(key, packageIdentifiers); } else { packageIdentifiers = mSchemasVisibleToPackages.get(key); } for (int i = 0; i < entry.getValue().size(); i++) { packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i))); } } final SetSchemaResponse response = new SetSchemaResponse.Builder().build(); callback.onResult( new AppSearchResultParcel( AppSearchResult.newSuccessfulResult(response.getBundle()))); } @Override public void getSchema(String packageName, String databaseName, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void getNamespaces(String packageName, String databaseName, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void putDocuments(String packageName, String databaseName, List<Bundle> documentBundles, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchBatchResultCallback callback) throws RemoteException { final List<GenericDocument> docs = new ArrayList<>(documentBundles.size()); for (Bundle bundle : documentBundles) { docs.add(new GenericDocument(bundle)); } final AppSearchBatchResult.Builder<String, Void> builder = new AppSearchBatchResult.Builder<>(); final String key = getKey(userHandle, databaseName); Map<String, GenericDocument> docMap = mDocumentMap.get(key); for (GenericDocument doc : docs) { builder.setSuccess(doc.getId(), null); if (docMap == null) { docMap = new ArrayMap<>(1); mDocumentMap.put(key, docMap); } docMap.put(doc.getId(), doc); } callback.onResult(new AppSearchBatchResultParcel<>(builder.build())); } @Override public void getDocuments(String packageName, String databaseName, String namespace, List<String> ids, Map<String, List<String>> typePropertyPaths, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchBatchResultCallback callback) throws RemoteException { final AppSearchBatchResult.Builder<String, Bundle> builder = new AppSearchBatchResult.Builder<>(); final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { for (String id : ids) { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, key + " not found when getting: " + id); } } else { final Map<String, GenericDocument> docs = mDocumentMap.get(key); for (String id : ids) { if (docs.containsKey(id)) { builder.setSuccess(id, docs.get(id).getBundle()); } else { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, "shortcut not found: " + id); } } } callback.onResult(new AppSearchBatchResultParcel<>(builder.build())); } @Override public void query(String packageName, String databaseName, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { final Bundle page = new Bundle(); page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1); page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>()); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page))); return; } final List<GenericDocument> documents = new ArrayList<>(mDocumentMap.get(key).values()); final Bundle page = new Bundle(); page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 0); final ArrayList<Bundle> resultBundles = new ArrayList<>(); for (GenericDocument document : documents) { final Bundle resultBundle = new Bundle(); resultBundle.putBundle("document", document.getBundle()); resultBundle.putString("packageName", packageName); resultBundle.putString("databaseName", databaseName); resultBundle.putParcelableArrayList("matches", new ArrayList<>()); resultBundles.add(resultBundle); } page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page))); } @Override public void globalQuery(String packageName, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void getNextPage(String packageName, long nextPageToken, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { final Bundle page = new Bundle(); page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1); page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>()); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page))); } @Override public void invalidateNextPageToken(String packageName, long nextPageToken, UserHandle userHandle) throws RemoteException { } @Override public void writeQueryResultsToFile(String packageName, String databaseName, ParcelFileDescriptor fileDescriptor, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void putDocumentsFromFile(String packageName, String databaseName, ParcelFileDescriptor fileDescriptor, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void reportUsage(String packageName, String databaseName, String namespace, String documentId, long usageTimestampMillis, boolean systemUsage, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void removeByDocumentId(String packageName, String databaseName, String namespace, List<String> ids, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchBatchResultCallback callback) throws RemoteException { final AppSearchBatchResult.Builder<String, Void> builder = new AppSearchBatchResult.Builder<>(); final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { for (String id : ids) { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, "package " + key + " not found when removing " + id); } } else { final Map<String, GenericDocument> docs = mDocumentMap.get(key); for (String id : ids) { if (docs.containsKey(id)) { docs.remove(id); builder.setSuccess(id, null); } else { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, "shortcut not found when removing " + id); } } } callback.onResult(new AppSearchBatchResultParcel<>(builder.build())); } @Override public void removeByQuery(String packageName, String databaseName, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null))); return; } mDocumentMap.get(key).clear(); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null))); } @Override public void getStorageInfo(String packageName, String databaseName, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void persistToDisk(String packageName, UserHandle userHandle, long binderCallStartTimeMillis) throws RemoteException { } @Override public void initialize(String packageName, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public IBinder asBinder() { return null; } private void removeShortcuts() { mDocumentMap.clear(); } private void ignore(IAppSearchResultCallback callback) throws RemoteException { callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null))); } } public static class ShortcutActivity extends Activity { } Loading Loading @@ -952,7 +684,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected PackageManagerInternal mMockPackageManagerInternal; protected UserManager mMockUserManager; protected DevicePolicyManager mMockDevicePolicyManager; protected MockAppSearchManager mMockAppSearchManager; protected UserManagerInternal mMockUserManagerInternal; protected UsageStatsManagerInternal mMockUsageStatsManagerInternal; protected ActivityManagerInternal mMockActivityManagerInternal; Loading Loading @@ -1102,7 +833,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mMockPackageManagerInternal = mock(PackageManagerInternal.class); mMockUserManager = mock(UserManager.class); mMockDevicePolicyManager = mock(DevicePolicyManager.class); mMockAppSearchManager = new MockAppSearchManager(); mMockUserManagerInternal = mock(UserManagerInternal.class); mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class); mMockActivityManagerInternal = mock(ActivityManagerInternal.class); Loading Loading @@ -1314,9 +1044,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { shutdownServices(); mMockAppSearchManager.removeShortcuts(); mMockAppSearchManager = null; super.tearDown(); } Loading Loading @@ -2235,6 +1962,18 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return p == null ? null : p.getAllShareTargetsForTest(); } protected void resetPersistedShortcuts() { final ShortcutPackage p = mService.getPackageShortcutForTest( getCallingPackage(), getCallingUserId()); p.removeAllShortcutsAsync(); } protected void getPersistedShortcut(AndroidFuture<List<ShortcutInfo>> cb) { final ShortcutPackage p = mService.getPackageShortcutForTest( getCallingPackage(), getCallingUserId()); p.getTopShortcutsFromPersistence(cb); } /** * @return the number of shortcuts stored internally for the caller that can be used as a share * target in the ShareSheet. Such shortcuts have a matching category with at least one of the Loading Loading @@ -2425,8 +2164,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { deleteAllSavedFiles(); mMockAppSearchManager.removeShortcuts(); initService(); mService.applyRestore(payload, USER_0); Loading Loading
services/core/java/com/android/server/pm/ShortcutPackage.java +252 −462 File changed.Preview size limit exceeded, changes collapsed. Show changes
services/core/java/com/android/server/pm/ShortcutRequestPinProcessor.java +3 −2 Original line number Diff line number Diff line Loading @@ -517,7 +517,8 @@ class ShortcutRequestPinProcessor { if (DEBUG) { Slog.d(TAG, "Removing " + shortcutId + " as dynamic"); } ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false); ps.deleteDynamicWithId(shortcutId, /*ignoreInvisible=*/ false, /*wasPushedOut=*/ false); } ps.adjustRanks(); // Shouldn't be needed, but just in case. Loading
services/core/java/com/android/server/pm/ShortcutService.java +20 −41 Original line number Diff line number Diff line Loading @@ -1965,13 +1965,12 @@ public class ShortcutService extends IShortcutService.Stub { ArrayList<ShortcutInfo> cachedOrPinned = new ArrayList<>(); ps.findAll(cachedOrPinned, AppSearchShortcutInfo.QUERY_IS_VISIBLE_CACHED_OR_PINNED, (ShortcutInfo si) -> si.isVisibleToPublisher() && si.isDynamic() && (si.isCached() || si.isPinned()), ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); // First, remove all un-pinned and non-cached; dynamic shortcuts removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); removedShortcuts = ps.deleteAllDynamicShortcuts(); // Then, add/update all. We need to make sure to take over "pinned" flag. for (int i = 0; i < size; i++) { Loading Loading @@ -2381,7 +2380,8 @@ public class ShortcutService extends IShortcutService.Stub { if (!ps.isShortcutExistsAndVisibleToPublisher(id)) { continue; } ShortcutInfo removed = ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true); ShortcutInfo removed = ps.deleteDynamicWithId(id, /*ignoreInvisible=*/ true, /*wasPushedOut*/ false); if (removed == null) { if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); Loading Loading @@ -2412,11 +2412,10 @@ public class ShortcutService extends IShortcutService.Stub { userId); // Dynamic shortcuts that are either cached or pinned will not get deleted. ps.findAll(changedShortcuts, AppSearchShortcutInfo.QUERY_IS_VISIBLE_CACHED_OR_PINNED, (ShortcutInfo si) -> si.isVisibleToPublisher() && si.isDynamic() && (si.isCached() || si.isPinned()), ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO); removedShortcuts = ps.deleteAllDynamicShortcuts(/*ignoreInvisible=*/ true); removedShortcuts = ps.deleteAllDynamicShortcuts(); changedShortcuts = prepareChangedShortcuts( changedShortcuts, null, removedShortcuts, ps); } Loading Loading @@ -2475,10 +2474,8 @@ public class ShortcutService extends IShortcutService.Stub { | (matchPinned ? ShortcutInfo.FLAG_PINNED : 0) | (matchManifest ? ShortcutInfo.FLAG_MANIFEST : 0) | (matchCached ? ShortcutInfo.FLAG_CACHED_ALL : 0); final String query = AppSearchShortcutInfo.QUERY_IS_VISIBLE_TO_PUBLISHER + " " + createQuery(matchDynamic, matchPinned, matchManifest, matchCached); return getShortcutsWithQueryLocked( packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, query, packageName, userId, ShortcutInfo.CLONE_REMOVE_FOR_CREATOR, (ShortcutInfo si) -> si.isVisibleToPublisher() && (si.getFlags() & shortcutFlags) != 0); Loading Loading @@ -2542,13 +2539,12 @@ public class ShortcutService extends IShortcutService.Stub { @GuardedBy("mLock") private ParceledListSlice<ShortcutInfo> getShortcutsWithQueryLocked(@NonNull String packageName, @UserIdInt int userId, int cloneFlags, @NonNull final String query, @NonNull Predicate<ShortcutInfo> filter) { @UserIdInt int userId, int cloneFlags, @NonNull Predicate<ShortcutInfo> filter) { final ArrayList<ShortcutInfo> ret = new ArrayList<>(); final ShortcutPackage ps = getPackageShortcutsForPublisherLocked(packageName, userId); ps.findAll(ret, query, filter, cloneFlags); ps.findAll(ret, filter, cloneFlags); return new ParceledListSlice<>(setReturnedByServer(ret)); } Loading Loading @@ -2955,27 +2951,14 @@ public class ShortcutService extends IShortcutService.Stub { ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED_BY_ANY_LAUNCHER) != 0); queryFlags |= (getPinnedByAnyLauncher ? ShortcutQuery.FLAG_MATCH_PINNED : 0); final boolean matchPinnedOnly = ((queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0) && ((queryFlags & ShortcutQuery.FLAG_MATCH_CACHED) == 0) && ((queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) == 0) && ((queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) == 0); final Predicate<ShortcutInfo> filter = getFilterFromQuery(ids, locusIds, changedSince, componentName, queryFlags, getPinnedByAnyLauncher); if (matchPinnedOnly) { p.findAllPinned(ret, filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); } else if (ids != null && !ids.isEmpty()) { if (ids != null && !ids.isEmpty()) { p.findAllByIds(ret, ids, filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); } else { final boolean matchDynamic = (queryFlags & ShortcutQuery.FLAG_MATCH_DYNAMIC) != 0; final boolean matchPinned = (queryFlags & ShortcutQuery.FLAG_MATCH_PINNED) != 0; final boolean matchManifest = (queryFlags & ShortcutQuery.FLAG_MATCH_MANIFEST) != 0; final boolean matchCached = (queryFlags & ShortcutQuery.FLAG_MATCH_CACHED) != 0; p.findAll(ret, createQuery(matchDynamic, matchPinned, matchManifest, matchCached), filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); p.findAll(ret, filter, cloneFlag, callingPackage, launcherUserId, getPinnedByAnyLauncher); } } Loading Loading @@ -3090,8 +3073,7 @@ public class ShortcutService extends IShortcutService.Stub { if (sp != null) { // List the shortcuts that are pinned only, these will get removed. removedShortcuts = new ArrayList<>(); sp.findAll(removedShortcuts, AppSearchShortcutInfo.QUERY_IS_VISIBLE_PINNED_ONLY, (ShortcutInfo si) -> si.isVisibleToPublisher() sp.findAll(removedShortcuts, (ShortcutInfo si) -> si.isVisibleToPublisher() && si.isPinned() && !si.isCached() && !si.isDynamic() && !si.isDeclaredInManifest(), ShortcutInfo.CLONE_REMOVE_NON_KEY_INFO, Loading Loading @@ -3183,8 +3165,7 @@ public class ShortcutService extends IShortcutService.Stub { if (doCache) { if (si.isLongLived()) { sp.mutateShortcut(si.getId(), si, shortcut -> shortcut.addFlags(cacheFlags)); si.addFlags(cacheFlags); if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); } Loading @@ -3195,21 +3176,20 @@ public class ShortcutService extends IShortcutService.Stub { } } else { ShortcutInfo removed = null; sp.mutateShortcut(si.getId(), si, shortcut -> shortcut.clearFlags(cacheFlags)); si.clearFlags(cacheFlags); if (!si.isDynamic() && !si.isCached()) { removed = sp.deleteLongLivedWithId(id, /*ignoreInvisible=*/ true); } if (removed != null) { if (removedShortcuts == null) { removedShortcuts = new ArrayList<>(1); } removedShortcuts.add(removed); } else { if (removed == null) { if (changedShortcuts == null) { changedShortcuts = new ArrayList<>(1); } changedShortcuts.add(si); } else { if (removedShortcuts == null) { removedShortcuts = new ArrayList<>(1); } removedShortcuts.add(removed); } } } Loading Loading @@ -5084,8 +5064,7 @@ public class ShortcutService extends IShortcutService.Stub { synchronized (mLock) { final ShortcutPackage pkg = getPackageShortcutForTest(packageName, userId); if (pkg == null) return; pkg.mutateShortcut(shortcutId, null, cb); cb.accept(pkg.findShortcutById(shortcutId)); } } Loading
services/core/java/com/android/server/pm/ShortcutUser.java +3 −2 Original line number Diff line number Diff line Loading @@ -186,7 +186,7 @@ class ShortcutUser { final ShortcutPackage removed = mPackages.remove(packageName); if (removed != null) { removed.removeShortcuts(); removed.removeAllShortcutsAsync(); } mService.cleanupBitmapsForPackage(mUserId, packageName); Loading Loading @@ -577,7 +577,7 @@ class ShortcutUser { Log.w(TAG, "Shortcuts for package " + sp.getPackageName() + " are being restored." + " Existing non-manifeset shortcuts will be overwritten."); } sp.restoreParsedShortcuts(); sp.removeAllShortcutsAsync(); addPackage(sp); restoredPackages[0]++; restoredShortcuts[0] += sp.getShortcutCount(); Loading Loading @@ -714,6 +714,7 @@ class ShortcutUser { .setSubtype(totalSharingShortcutCount)); } @NonNull AndroidFuture<AppSearchSession> getAppSearch( @NonNull final AppSearchManager.SearchContext searchContext) { final AndroidFuture<AppSearchSession> future = new AndroidFuture<>(); Loading
services/tests/servicestests/src/com/android/server/pm/BaseShortcutManagerTest.java +13 −276 Original line number Diff line number Diff line Loading @@ -46,18 +46,6 @@ import android.app.IUidObserver; import android.app.PendingIntent; import android.app.Person; import android.app.admin.DevicePolicyManager; import android.app.appsearch.AppSearchBatchResult; import android.app.appsearch.AppSearchManager; import android.app.appsearch.AppSearchResult; import android.app.appsearch.GenericDocument; import android.app.appsearch.PackageIdentifier; import android.app.appsearch.SearchResultPage; import android.app.appsearch.SetSchemaResponse; import android.app.appsearch.aidl.AppSearchBatchResultParcel; import android.app.appsearch.aidl.AppSearchResultParcel; import android.app.appsearch.aidl.IAppSearchBatchResultCallback; import android.app.appsearch.aidl.IAppSearchManager; import android.app.appsearch.aidl.IAppSearchResultCallback; import android.app.role.OnRoleHoldersChangedListener; import android.app.usage.UsageStatsManagerInternal; import android.content.ActivityNotFoundException; Loading Loading @@ -92,9 +80,7 @@ import android.net.Uri; import android.os.Bundle; import android.os.FileUtils; import android.os.Handler; import android.os.IBinder; import android.os.Looper; import android.os.ParcelFileDescriptor; import android.os.PersistableBundle; import android.os.Process; import android.os.RemoteException; Loading @@ -106,6 +92,7 @@ import android.util.ArrayMap; import android.util.Log; import android.util.Pair; import com.android.internal.infra.AndroidFuture; import com.android.server.LocalServices; import com.android.server.SystemService; import com.android.server.pm.LauncherAppsService.LauncherAppsImpl; Loading Loading @@ -168,7 +155,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { case Context.DEVICE_POLICY_SERVICE: return mMockDevicePolicyManager; case Context.APP_SEARCH_SERVICE: return new AppSearchManager(this, mMockAppSearchManager); case Context.ROLE_SERVICE: // RoleManager is final and cannot be mocked, so we only override the inject // accessor methods in ShortcutService. Loading Loading @@ -647,260 +633,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { } } protected class MockAppSearchManager implements IAppSearchManager { protected Map<String, List<PackageIdentifier>> mSchemasVisibleToPackages = new ArrayMap<>(1); private Map<String, Map<String, GenericDocument>> mDocumentMap = new ArrayMap<>(1); private String getKey(UserHandle userHandle, String databaseName) { return userHandle.getIdentifier() + "@" + databaseName; } @Override public void setSchema(String packageName, String databaseName, List<Bundle> schemaBundles, List<String> schemasNotDisplayedBySystem, Map<String, List<Bundle>> schemasVisibleToPackagesBundles, boolean forceOverride, int version, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { for (Map.Entry<String, List<Bundle>> entry : schemasVisibleToPackagesBundles.entrySet()) { final String key = entry.getKey(); final List<PackageIdentifier> packageIdentifiers; if (!mSchemasVisibleToPackages.containsKey(key)) { packageIdentifiers = new ArrayList<>(entry.getValue().size()); mSchemasVisibleToPackages.put(key, packageIdentifiers); } else { packageIdentifiers = mSchemasVisibleToPackages.get(key); } for (int i = 0; i < entry.getValue().size(); i++) { packageIdentifiers.add(new PackageIdentifier(entry.getValue().get(i))); } } final SetSchemaResponse response = new SetSchemaResponse.Builder().build(); callback.onResult( new AppSearchResultParcel( AppSearchResult.newSuccessfulResult(response.getBundle()))); } @Override public void getSchema(String packageName, String databaseName, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void getNamespaces(String packageName, String databaseName, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void putDocuments(String packageName, String databaseName, List<Bundle> documentBundles, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchBatchResultCallback callback) throws RemoteException { final List<GenericDocument> docs = new ArrayList<>(documentBundles.size()); for (Bundle bundle : documentBundles) { docs.add(new GenericDocument(bundle)); } final AppSearchBatchResult.Builder<String, Void> builder = new AppSearchBatchResult.Builder<>(); final String key = getKey(userHandle, databaseName); Map<String, GenericDocument> docMap = mDocumentMap.get(key); for (GenericDocument doc : docs) { builder.setSuccess(doc.getId(), null); if (docMap == null) { docMap = new ArrayMap<>(1); mDocumentMap.put(key, docMap); } docMap.put(doc.getId(), doc); } callback.onResult(new AppSearchBatchResultParcel<>(builder.build())); } @Override public void getDocuments(String packageName, String databaseName, String namespace, List<String> ids, Map<String, List<String>> typePropertyPaths, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchBatchResultCallback callback) throws RemoteException { final AppSearchBatchResult.Builder<String, Bundle> builder = new AppSearchBatchResult.Builder<>(); final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { for (String id : ids) { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, key + " not found when getting: " + id); } } else { final Map<String, GenericDocument> docs = mDocumentMap.get(key); for (String id : ids) { if (docs.containsKey(id)) { builder.setSuccess(id, docs.get(id).getBundle()); } else { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, "shortcut not found: " + id); } } } callback.onResult(new AppSearchBatchResultParcel<>(builder.build())); } @Override public void query(String packageName, String databaseName, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { final Bundle page = new Bundle(); page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1); page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>()); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page))); return; } final List<GenericDocument> documents = new ArrayList<>(mDocumentMap.get(key).values()); final Bundle page = new Bundle(); page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 0); final ArrayList<Bundle> resultBundles = new ArrayList<>(); for (GenericDocument document : documents) { final Bundle resultBundle = new Bundle(); resultBundle.putBundle("document", document.getBundle()); resultBundle.putString("packageName", packageName); resultBundle.putString("databaseName", databaseName); resultBundle.putParcelableArrayList("matches", new ArrayList<>()); resultBundles.add(resultBundle); } page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, resultBundles); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page))); } @Override public void globalQuery(String packageName, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void getNextPage(String packageName, long nextPageToken, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { final Bundle page = new Bundle(); page.putLong(SearchResultPage.NEXT_PAGE_TOKEN_FIELD, 1); page.putParcelableArrayList(SearchResultPage.RESULTS_FIELD, new ArrayList<>()); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(page))); } @Override public void invalidateNextPageToken(String packageName, long nextPageToken, UserHandle userHandle) throws RemoteException { } @Override public void writeQueryResultsToFile(String packageName, String databaseName, ParcelFileDescriptor fileDescriptor, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void putDocumentsFromFile(String packageName, String databaseName, ParcelFileDescriptor fileDescriptor, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void reportUsage(String packageName, String databaseName, String namespace, String documentId, long usageTimestampMillis, boolean systemUsage, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void removeByDocumentId(String packageName, String databaseName, String namespace, List<String> ids, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchBatchResultCallback callback) throws RemoteException { final AppSearchBatchResult.Builder<String, Void> builder = new AppSearchBatchResult.Builder<>(); final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { for (String id : ids) { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, "package " + key + " not found when removing " + id); } } else { final Map<String, GenericDocument> docs = mDocumentMap.get(key); for (String id : ids) { if (docs.containsKey(id)) { docs.remove(id); builder.setSuccess(id, null); } else { builder.setFailure(id, AppSearchResult.RESULT_NOT_FOUND, "shortcut not found when removing " + id); } } } callback.onResult(new AppSearchBatchResultParcel<>(builder.build())); } @Override public void removeByQuery(String packageName, String databaseName, String queryExpression, Bundle searchSpecBundle, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { final String key = getKey(userHandle, databaseName); if (!mDocumentMap.containsKey(key)) { callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null))); return; } mDocumentMap.get(key).clear(); callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null))); } @Override public void getStorageInfo(String packageName, String databaseName, UserHandle userHandle, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public void persistToDisk(String packageName, UserHandle userHandle, long binderCallStartTimeMillis) throws RemoteException { } @Override public void initialize(String packageName, UserHandle userHandle, long binderCallStartTimeMillis, IAppSearchResultCallback callback) throws RemoteException { ignore(callback); } @Override public IBinder asBinder() { return null; } private void removeShortcuts() { mDocumentMap.clear(); } private void ignore(IAppSearchResultCallback callback) throws RemoteException { callback.onResult( new AppSearchResultParcel<>(AppSearchResult.newSuccessfulResult(null))); } } public static class ShortcutActivity extends Activity { } Loading Loading @@ -952,7 +684,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { protected PackageManagerInternal mMockPackageManagerInternal; protected UserManager mMockUserManager; protected DevicePolicyManager mMockDevicePolicyManager; protected MockAppSearchManager mMockAppSearchManager; protected UserManagerInternal mMockUserManagerInternal; protected UsageStatsManagerInternal mMockUsageStatsManagerInternal; protected ActivityManagerInternal mMockActivityManagerInternal; Loading Loading @@ -1102,7 +833,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { mMockPackageManagerInternal = mock(PackageManagerInternal.class); mMockUserManager = mock(UserManager.class); mMockDevicePolicyManager = mock(DevicePolicyManager.class); mMockAppSearchManager = new MockAppSearchManager(); mMockUserManagerInternal = mock(UserManagerInternal.class); mMockUsageStatsManagerInternal = mock(UsageStatsManagerInternal.class); mMockActivityManagerInternal = mock(ActivityManagerInternal.class); Loading Loading @@ -1314,9 +1044,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { shutdownServices(); mMockAppSearchManager.removeShortcuts(); mMockAppSearchManager = null; super.tearDown(); } Loading Loading @@ -2235,6 +1962,18 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { return p == null ? null : p.getAllShareTargetsForTest(); } protected void resetPersistedShortcuts() { final ShortcutPackage p = mService.getPackageShortcutForTest( getCallingPackage(), getCallingUserId()); p.removeAllShortcutsAsync(); } protected void getPersistedShortcut(AndroidFuture<List<ShortcutInfo>> cb) { final ShortcutPackage p = mService.getPackageShortcutForTest( getCallingPackage(), getCallingUserId()); p.getTopShortcutsFromPersistence(cb); } /** * @return the number of shortcuts stored internally for the caller that can be used as a share * target in the ShareSheet. Such shortcuts have a matching category with at least one of the Loading Loading @@ -2425,8 +2164,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase { deleteAllSavedFiles(); mMockAppSearchManager.removeShortcuts(); initService(); mService.applyRestore(payload, USER_0); Loading