Merge "AppSearch as persistent layer for shortcut"
This commit is contained in:
committed by
Android (Google) Code Review
commit
2a5851b2e5
File diff suppressed because it is too large
Load Diff
@@ -467,7 +467,7 @@ class ShortcutRequestPinProcessor {
|
||||
launcher.attemptToRestoreIfNeededAndSave();
|
||||
if (launcher.hasPinned(original)) {
|
||||
if (DEBUG) {
|
||||
Slog.d(TAG, "Shortcut " + original + " already pinned."); // This too.
|
||||
Slog.d(TAG, "Shortcut " + original + " already pinned."); // This too.
|
||||
}
|
||||
return true;
|
||||
}
|
||||
@@ -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.
|
||||
|
||||
@@ -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++) {
|
||||
@@ -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);
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
@@ -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));
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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,
|
||||
@@ -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);
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -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));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ class ShortcutUser {
|
||||
final ShortcutPackage removed = mPackages.remove(packageName);
|
||||
|
||||
if (removed != null) {
|
||||
removed.removeShortcuts();
|
||||
removed.removeAllShortcutsAsync();
|
||||
}
|
||||
mService.cleanupBitmapsForPackage(mUserId, packageName);
|
||||
|
||||
@@ -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();
|
||||
@@ -714,6 +714,7 @@ class ShortcutUser {
|
||||
.setSubtype(totalSharingShortcutCount));
|
||||
}
|
||||
|
||||
@NonNull
|
||||
AndroidFuture<AppSearchSession> getAppSearch(
|
||||
@NonNull final AppSearchManager.SearchContext searchContext) {
|
||||
final AndroidFuture<AppSearchSession> future = new AndroidFuture<>();
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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.
|
||||
@@ -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 {
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
@@ -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);
|
||||
@@ -1314,9 +1044,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
shutdownServices();
|
||||
|
||||
mMockAppSearchManager.removeShortcuts();
|
||||
mMockAppSearchManager = null;
|
||||
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
@@ -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
|
||||
@@ -2425,8 +2164,6 @@ public abstract class BaseShortcutManagerTest extends InstrumentationTestCase {
|
||||
|
||||
deleteAllSavedFiles();
|
||||
|
||||
mMockAppSearchManager.removeShortcuts();
|
||||
|
||||
initService();
|
||||
mService.applyRestore(payload, USER_0);
|
||||
|
||||
|
||||
@@ -18,9 +18,20 @@ package com.android.server.pm;
|
||||
import static com.android.server.pm.shortcutmanagertest.ShortcutManagerTestUtils.list;
|
||||
|
||||
import android.app.PendingIntent;
|
||||
import android.content.pm.ShortcutInfo;
|
||||
import android.os.RemoteException;
|
||||
import android.os.SystemClock;
|
||||
import android.os.UserHandle;
|
||||
|
||||
import com.android.internal.infra.AndroidFuture;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.function.Function;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
/**
|
||||
* Tests for {@link android.app.appsearch.AppSearchManager} and relevant APIs in ShortcutManager.
|
||||
*
|
||||
@@ -28,6 +39,21 @@ import android.os.UserHandle;
|
||||
*/
|
||||
public class ShortcutManagerTest12 extends BaseShortcutManagerTest {
|
||||
|
||||
@Override
|
||||
protected void setUp() throws Exception {
|
||||
super.setUp();
|
||||
mService.updateConfigurationLocked(
|
||||
ShortcutService.ConfigConstants.KEY_MAX_SHORTCUTS + "=5,"
|
||||
+ ShortcutService.ConfigConstants.KEY_SAVE_DELAY_MILLIS + "=1");
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tearDown() throws Exception {
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mService.getPackageShortcutForTest(CALLING_PACKAGE_1, USER_0).removeAllShortcutsAsync();
|
||||
super.tearDown();
|
||||
}
|
||||
|
||||
public void testGetShortcutIntents_ReturnsMutablePendingIntents() throws RemoteException {
|
||||
setDefaultLauncher(USER_0, LAUNCHER_1);
|
||||
|
||||
@@ -41,4 +67,201 @@ public class ShortcutManagerTest12 extends BaseShortcutManagerTest {
|
||||
assertNotNull(intent);
|
||||
});
|
||||
}
|
||||
|
||||
public void testSetDynamicShortcuts_PersistsShortcutsToDisk() throws RemoteException {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
// Verifies setDynamicShortcuts persists shortcuts into AppSearch
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3")
|
||||
));
|
||||
List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(3, shortcuts.size());
|
||||
Set<String> shortcutIds =
|
||||
shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s1"));
|
||||
assertTrue(shortcutIds.contains("s2"));
|
||||
assertTrue(shortcutIds.contains("s3"));
|
||||
|
||||
// Verifies removeAllDynamicShortcuts removes shortcuts from persistence layer
|
||||
mManager.removeAllDynamicShortcuts();
|
||||
shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertTrue(shortcuts.isEmpty());
|
||||
}
|
||||
|
||||
public void testAddDynamicShortcuts_PersistsShortcutsToDisk() {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3")
|
||||
));
|
||||
// Verifies addDynamicShortcuts persists shortcuts into AppSearch
|
||||
mManager.addDynamicShortcuts(list(makeShortcut("s4"), makeShortcut("s5")));
|
||||
final List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(5, shortcuts.size());
|
||||
final Set<String> shortcutIds =
|
||||
shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s1"));
|
||||
assertTrue(shortcutIds.contains("s2"));
|
||||
assertTrue(shortcutIds.contains("s3"));
|
||||
assertTrue(shortcutIds.contains("s4"));
|
||||
assertTrue(shortcutIds.contains("s5"));
|
||||
}
|
||||
|
||||
public void testPushDynamicShortcuts_PersistsShortcutsToDisk() {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3"),
|
||||
makeShortcut("s4"),
|
||||
makeShortcut("s5")
|
||||
));
|
||||
List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(5, shortcuts.size());
|
||||
Set<String> shortcutIds =
|
||||
shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s1"));
|
||||
assertTrue(shortcutIds.contains("s2"));
|
||||
assertTrue(shortcutIds.contains("s3"));
|
||||
assertTrue(shortcutIds.contains("s4"));
|
||||
assertTrue(shortcutIds.contains("s5"));
|
||||
// Verifies pushDynamicShortcuts further persists shortcuts into AppSearch without
|
||||
// removing previous shortcuts when max number of shortcuts is reached.
|
||||
mManager.pushDynamicShortcut(makeShortcut("s6"));
|
||||
shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(6, shortcuts.size());
|
||||
shortcutIds = shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s1"));
|
||||
assertTrue(shortcutIds.contains("s2"));
|
||||
assertTrue(shortcutIds.contains("s3"));
|
||||
assertTrue(shortcutIds.contains("s4"));
|
||||
assertTrue(shortcutIds.contains("s5"));
|
||||
assertTrue(shortcutIds.contains("s6"));
|
||||
}
|
||||
|
||||
public void testRemoveDynamicShortcuts_RemovesShortcutsFromDisk() {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3"),
|
||||
makeShortcut("s4"),
|
||||
makeShortcut("s5")
|
||||
));
|
||||
|
||||
// Verifies removeDynamicShortcuts removes shortcuts from persistence layer
|
||||
mManager.removeDynamicShortcuts(list("s1"));
|
||||
final List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(4, shortcuts.size());
|
||||
final Set<String> shortcutIds =
|
||||
shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s2"));
|
||||
assertTrue(shortcutIds.contains("s3"));
|
||||
assertTrue(shortcutIds.contains("s4"));
|
||||
assertTrue(shortcutIds.contains("s5"));
|
||||
}
|
||||
|
||||
public void testRemoveLongLivedShortcuts_RemovesShortcutsFromDisk() {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3"),
|
||||
makeShortcut("s4"),
|
||||
makeShortcut("s5")
|
||||
));
|
||||
mManager.removeDynamicShortcuts(list("s2"));
|
||||
final List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(4, shortcuts.size());
|
||||
final Set<String> shortcutIds =
|
||||
shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s1"));
|
||||
assertTrue(shortcutIds.contains("s3"));
|
||||
assertTrue(shortcutIds.contains("s4"));
|
||||
assertTrue(shortcutIds.contains("s5"));
|
||||
}
|
||||
|
||||
public void testDisableShortcuts_RemovesShortcutsFromDisk() {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3"),
|
||||
makeShortcut("s4"),
|
||||
makeShortcut("s5")
|
||||
));
|
||||
// Verifies disableShortcuts removes shortcuts from persistence layer
|
||||
mManager.disableShortcuts(list("s3"));
|
||||
final List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(4, shortcuts.size());
|
||||
final Set<String> shortcutIds =
|
||||
shortcuts.stream().map(ShortcutInfo::getId).collect(Collectors.toSet());
|
||||
assertTrue(shortcutIds.contains("s1"));
|
||||
assertTrue(shortcutIds.contains("s2"));
|
||||
assertTrue(shortcutIds.contains("s4"));
|
||||
assertTrue(shortcutIds.contains("s5"));
|
||||
}
|
||||
|
||||
public void testUpdateShortcuts_UpdateShortcutsOnDisk() {
|
||||
if (!mService.isAppSearchEnabled()) {
|
||||
return;
|
||||
}
|
||||
setCaller(CALLING_PACKAGE_1, USER_0);
|
||||
mManager.setDynamicShortcuts(list(
|
||||
makeShortcut("s1"),
|
||||
makeShortcut("s2"),
|
||||
makeShortcut("s3"),
|
||||
makeShortcut("s4"),
|
||||
makeShortcut("s5")
|
||||
));
|
||||
// Verifies disableShortcuts removes shortcuts from persistence layer
|
||||
mManager.updateShortcuts(list(makeShortcutWithShortLabel("s3", "custom")));
|
||||
final List<ShortcutInfo> shortcuts = getAllPersistedShortcuts();
|
||||
assertNotNull(shortcuts);
|
||||
assertEquals(5, shortcuts.size());
|
||||
final Map<String, ShortcutInfo> map = shortcuts.stream()
|
||||
.collect(Collectors.toMap(ShortcutInfo::getId, Function.identity()));
|
||||
assertTrue(map.containsKey("s3"));
|
||||
assertEquals("custom", map.get("s3").getShortLabel());
|
||||
}
|
||||
|
||||
private List<ShortcutInfo> getAllPersistedShortcuts() {
|
||||
try {
|
||||
SystemClock.sleep(500);
|
||||
final AndroidFuture<List<ShortcutInfo>> future = new AndroidFuture<>();
|
||||
getPersistedShortcut(future);
|
||||
return future.get(10, TimeUnit.SECONDS);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user