summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/com/android/providers/media/ConfigStore.java39
-rw-r--r--src/com/android/providers/media/MediaProvider.java31
-rw-r--r--src/com/android/providers/media/photopicker/sync/MediaSetsResetWorker.java138
-rw-r--r--src/com/android/providers/media/photopicker/sync/MediaSetsSyncWorker.java1
-rw-r--r--src/com/android/providers/media/photopicker/sync/PickerSyncManager.java80
-rw-r--r--src/com/android/providers/media/photopicker/sync/SyncTrackerRegistry.java13
-rw-r--r--src/com/android/providers/media/photopicker/v2/PickerDataLayerV2.java10
-rw-r--r--src/com/android/providers/media/photopicker/v2/sqlite/MediaInMediaSetsDatabaseUtil.java30
-rw-r--r--src/com/android/providers/media/photopicker/v2/sqlite/MediaSetsDatabaseUtil.java50
9 files changed, 326 insertions, 66 deletions
diff --git a/src/com/android/providers/media/ConfigStore.java b/src/com/android/providers/media/ConfigStore.java
index a16e956e3..b2ae87e98 100644
--- a/src/com/android/providers/media/ConfigStore.java
+++ b/src/com/android/providers/media/ConfigStore.java
@@ -22,6 +22,7 @@ import static android.provider.DeviceConfig.NAMESPACE_STORAGE_NATIVE_BOOT;
import static java.util.Objects.requireNonNull;
import android.content.res.Resources;
+import android.content.res.Resources.NotFoundException;
import android.os.Binder;
import android.os.Build;
import android.os.SystemProperties;
@@ -399,18 +400,24 @@ public interface ConfigStore {
@Nullable
@Override
public String getDefaultCloudProviderPackage() {
- String pkg = mResources.getString(R.string.config_default_cloud_media_provider_package);
- if (pkg == null && Build.VERSION.SDK_INT <= TIRAMISU) {
- // We are on Android T or below and do not have
- // config_default_cloud_media_provider_package: let's see if we have now deprecated
- // config_default_cloud_provider_authority.
- final String authority =
- mResources.getString(R.string.config_default_cloud_provider_authority);
- if (authority != null) {
- pkg = maybeExtractPackageNameFromCloudProviderAuthority(authority);
+ try {
+ String pkg =
+ mResources.getString(R.string.config_default_cloud_media_provider_package);
+ if (pkg == null && Build.VERSION.SDK_INT <= TIRAMISU) {
+ // We are on Android T or below and do not have
+ // config_default_cloud_media_provider_package: let's see if we have now
+ // deprecated
+ // config_default_cloud_provider_authority.
+ final String authority =
+ mResources.getString(R.string.config_default_cloud_provider_authority);
+ if (authority != null) {
+ pkg = maybeExtractPackageNameFromCloudProviderAuthority(authority);
+ }
}
+ return pkg;
+ } catch (NotFoundException e) {
+ return null;
}
- return pkg;
}
@NonNull
@@ -533,12 +540,16 @@ public interface ConfigStore {
@Override
public Optional<String> getDefaultOemMetadataServicePackage() {
- String pkg = mResources.getString(R.string.config_default_oem_metadata_service_package);
- if (pkg == null || pkg.isEmpty()) {
+ try {
+ String pkg =
+ mResources.getString(R.string.config_default_oem_metadata_service_package);
+ if (pkg == null || pkg.isEmpty()) {
+ return Optional.empty();
+ }
+ return Optional.of(pkg);
+ } catch (NotFoundException e) {
return Optional.empty();
}
-
- return Optional.of(pkg);
}
@Override
diff --git a/src/com/android/providers/media/MediaProvider.java b/src/com/android/providers/media/MediaProvider.java
index 4fc5f21e4..0beb07b8d 100644
--- a/src/com/android/providers/media/MediaProvider.java
+++ b/src/com/android/providers/media/MediaProvider.java
@@ -553,6 +553,14 @@ public class MediaProvider extends ContentProvider {
@EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
static final long LOCKDOWN_MEDIASTORE_VERSION = 343977174L;
+ /**
+ * Number of uris sent to bulk write/delete/trash/favorite requests restricted at 2000.
+ * Attempting to send more than 2000 uris will result in an IllegalArgumentException.
+ */
+ @ChangeId
+ @EnabledSince(targetSdkVersion = Build.VERSION_CODES.BAKLAVA)
+ static final long LIMIT_CREATE_REQUEST_URIS = 203408344L;
+
@GuardedBy("mPendingOpenInfo")
private final Map<Integer, PendingOpenInfo> mPendingOpenInfo = new ArrayMap<>();
@@ -1337,13 +1345,19 @@ public class MediaProvider extends ContentProvider {
}
final SharedPreferences prefs = PreferenceManager.getDefaultSharedPreferences(getContext());
- // Get case insensitive exclusion list.
- List<String> exclusionList =
- Flags.enableExclusionListForDefaultFolders()
- ? getFoldersToSkipInDefaultCreation().stream().map(
- String::toLowerCase).collect(Collectors.toList())
- : List.of();
if (prefs.getInt(key, 0) == 0) {
+ // Get case insensitive exclusion list.
+ List<String> exclusionList =
+ Flags.enableExclusionListForDefaultFolders()
+ ? getFoldersToSkipInDefaultCreation().stream().map(
+ String::toLowerCase).collect(Collectors.toList())
+ : List.of();
+ if (exclusionList.size() > getDefaultFolderNames().length) {
+ Log.e(TAG, "Exclusion list has " + exclusionList.size()
+ + " items which exceeds the size of default folders list which has size "
+ + getDefaultFolderNames().length);
+ exclusionList = List.of();
+ }
for (String folderName : getDefaultFolderNames()) {
final File folder = new File(volume.getPath(), folderName);
if (folder.exists()) {
@@ -8176,6 +8190,11 @@ public class MediaProvider extends ContentProvider {
final ClipData clipData = extras.getParcelable(MediaStore.EXTRA_CLIP_DATA);
final List<Uri> uris = collectUris(clipData);
+ if (getCallingPackageTargetSdkVersion() > Build.VERSION_CODES.VANILLA_ICE_CREAM
+ && CompatChanges.isChangeEnabled(LIMIT_CREATE_REQUEST_URIS) && uris.size() > 2000) {
+ throw new IllegalArgumentException("URI list restricted to 2000 per request");
+ }
+
for (Uri uri : uris) {
final int match = matchUri(uri, false);
switch (match) {
diff --git a/src/com/android/providers/media/photopicker/sync/MediaSetsResetWorker.java b/src/com/android/providers/media/photopicker/sync/MediaSetsResetWorker.java
new file mode 100644
index 000000000..5991ae049
--- /dev/null
+++ b/src/com/android/providers/media/photopicker/sync/MediaSetsResetWorker.java
@@ -0,0 +1,138 @@
+/*
+ * Copyright (C) 2024 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.providers.media.photopicker.sync;
+
+import static com.android.providers.media.photopicker.sync.PickerSyncManager.SYNC_WORKER_INPUT_SYNC_SOURCE;
+import static com.android.providers.media.photopicker.sync.SyncTrackerRegistry.markMediaSetsSyncAsComplete;
+
+import android.content.Context;
+import android.database.sqlite.SQLiteDatabase;
+import android.util.Log;
+
+import androidx.annotation.NonNull;
+import androidx.work.ListenableWorker;
+import androidx.work.Worker;
+import androidx.work.WorkerParameters;
+
+import com.android.providers.media.photopicker.PickerSyncController;
+import com.android.providers.media.photopicker.util.exceptions.RequestObsoleteException;
+import com.android.providers.media.photopicker.v2.sqlite.MediaInMediaSetsDatabaseUtil;
+import com.android.providers.media.photopicker.v2.sqlite.MediaSetsDatabaseUtil;
+
+/**
+ * This worker is responsible for cleaning up the cached media sets or media sets content based
+ * on the type input reset parameter received
+ */
+public class MediaSetsResetWorker extends Worker {
+ private static final String TAG = "MediaSetsResetWorker";
+
+ public MediaSetsResetWorker(
+ @NonNull Context context, @NonNull WorkerParameters workerParameters) {
+ super(context, workerParameters);
+ }
+
+ @Override
+ public ListenableWorker.Result doWork() {
+
+ final int syncSource = getInputData().getInt(SYNC_WORKER_INPUT_SYNC_SOURCE,
+ /* defaultValue */ -1);
+
+ // Do not allow endless re-runs of this worker, if this isn't the original run,
+ // just fail and wait until the next scheduled run.
+ if (getRunAttemptCount() > 0) {
+ Log.w(TAG, "Worker retry was detected, ending this run in failure.");
+ return ListenableWorker.Result.failure();
+ }
+
+ boolean isMediaSetsTableDeleted = clearMediaSetsCache(syncSource);
+ boolean isMediaInMediaSetsTabledDeleted = clearMediaSetsContentCache();
+
+ // Both the tables were cleared. Mark the worker's run as success
+ if (isMediaSetsTableDeleted && isMediaInMediaSetsTabledDeleted) {
+ return ListenableWorker.Result.success();
+ }
+
+ return ListenableWorker.Result.failure();
+ }
+
+ private boolean clearMediaSetsCache(int syncSource) {
+ SQLiteDatabase database = getDatabase();
+
+ try {
+ checkIfWorkerHasStopped();
+
+ database.beginTransaction();
+
+ MediaSetsDatabaseUtil.clearMediaSetsCache(database);
+
+ if (database.inTransaction()) {
+ database.setTransactionSuccessful();
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not clear media sets cache", e);
+ return false;
+ } finally {
+ // Ensure that the transaction ends and the DB lock is released.
+ if (database.inTransaction()) {
+ database.endTransaction();
+ }
+ markMediaSetsSyncAsComplete(syncSource, getId());
+ }
+ }
+
+ private boolean clearMediaSetsContentCache() {
+
+ SQLiteDatabase database = getDatabase();
+
+ try {
+ checkIfWorkerHasStopped();
+
+ database.beginTransaction();
+
+ MediaInMediaSetsDatabaseUtil.clearMediaInMediaSetsCache(database);
+
+ if (database.inTransaction()) {
+ database.setTransactionSuccessful();
+ return true;
+ } else {
+ return false;
+ }
+ } catch (Exception e) {
+ Log.e(TAG, "Could not clear media sets content cache", e);
+ return false;
+ } finally {
+ // Ensure that the transaction ends and the DB lock is released.
+ if (database.inTransaction()) {
+ database.endTransaction();
+ }
+ }
+ }
+
+ private void checkIfWorkerHasStopped() throws RequestObsoleteException {
+ if (isStopped()) {
+ throw new RequestObsoleteException("CategoriesResetWorker has stopped.");
+ }
+ }
+
+ @NonNull
+ private SQLiteDatabase getDatabase() {
+ return PickerSyncController.getInstanceOrThrow().getDbFacade().getDatabase();
+ }
+}
diff --git a/src/com/android/providers/media/photopicker/sync/MediaSetsSyncWorker.java b/src/com/android/providers/media/photopicker/sync/MediaSetsSyncWorker.java
index c0126ef2f..8e151141a 100644
--- a/src/com/android/providers/media/photopicker/sync/MediaSetsSyncWorker.java
+++ b/src/com/android/providers/media/photopicker/sync/MediaSetsSyncWorker.java
@@ -71,6 +71,7 @@ public class MediaSetsSyncWorker extends Worker {
@NonNull
@Override
public ListenableWorker.Result doWork() {
+
final int syncSource = getInputData().getInt(SYNC_WORKER_INPUT_SYNC_SOURCE,
/* defaultValue */ INVALID_SYNC_SOURCE);
final String categoryId = getInputData().getString(SYNC_WORKER_INPUT_CATEGORY_ID);
diff --git a/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java b/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java
index 6d879a306..7be806a6c 100644
--- a/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java
+++ b/src/com/android/providers/media/photopicker/sync/PickerSyncManager.java
@@ -17,6 +17,7 @@
package com.android.providers.media.photopicker.sync;
import static com.android.providers.media.photopicker.sync.SyncTrackerRegistry.markAlbumMediaSyncAsComplete;
+import static com.android.providers.media.photopicker.sync.SyncTrackerRegistry.markAllMediaInMediaSetsSyncAsComplete;
import static com.android.providers.media.photopicker.sync.SyncTrackerRegistry.markAllSearchResultsSyncAsComplete;
import static com.android.providers.media.photopicker.sync.SyncTrackerRegistry.markMediaInMediaSetSyncAsComplete;
import static com.android.providers.media.photopicker.sync.SyncTrackerRegistry.markMediaSetsSyncAsComplete;
@@ -620,7 +621,10 @@ public class PickerSyncManager {
}
/**
- * Creates OneTimeWork request for syncing media sets with the given provider
+ * Creates OneTimeWork request for syncing media sets with the given provider.
+ * The existing media sets cache and the media sets content cache is cleared before a new media
+ * sets sync is triggered to ensure accuracy of the media sets metadata stored in the database.
+ * The reset cache and sync requests are chained to ensure correctness of the entire operation.
* @param requestParams The MediaSetsSyncRequestsParams object containing all input parameters
* for creating a sync request
* @param syncSource Indicates whether the sync is required with the local provider or
@@ -628,18 +632,35 @@ public class PickerSyncManager {
*/
public void syncMediaSetsForProvider(
MediaSetsSyncRequestParams requestParams, @SyncSource int syncSource) {
- final Map<String, Object> inputMap = new HashMap<>();
- inputMap.put(SYNC_WORKER_INPUT_AUTHORITY, requestParams.getAuthority());
- inputMap.put(SYNC_WORKER_INPUT_SYNC_SOURCE, syncSource);
- inputMap.put(SYNC_WORKER_INPUT_CATEGORY_ID, requestParams.getCategoryId());
+ // Create media sets sync request
+ final Map<String, Object> syncRequestInputMap = new HashMap<>();
+ syncRequestInputMap.put(SYNC_WORKER_INPUT_AUTHORITY, requestParams.getAuthority());
+ syncRequestInputMap.put(SYNC_WORKER_INPUT_SYNC_SOURCE, syncSource);
+ syncRequestInputMap.put(SYNC_WORKER_INPUT_CATEGORY_ID, requestParams.getCategoryId());
if (requestParams.getMimeTypes() != null) {
- inputMap.put(EXTRA_MIME_TYPES, requestParams.getMimeTypes().toArray(new String[0]));
+ syncRequestInputMap.put(EXTRA_MIME_TYPES, requestParams.getMimeTypes().toArray(
+ new String[0]
+ ));
}
- final Data inputData = new Data(inputMap);
+ final Data syncRequestInputData = new Data(syncRequestInputMap);
final OneTimeWorkRequest syncRequest =
- buildOneTimeWorkerRequest(MediaSetsSyncWorker.class, inputData);
+ buildOneTimeWorkerRequest(MediaSetsSyncWorker.class, syncRequestInputData);
+
+ // Create media sets reset request. MediaSets sync are non-resumable.
+ // It's fine to delete the entire cache before a new set is triggered.
+ // The media sets content cache is also completely cleared before we start syncing
+ // any particular media set for its content.
+ // These tables are cleared once per picker session before the media sets sync for this
+ // session is triggered. This ensures that the data read from the cache in every session
+ // is always in sync with the cloud provider.
+ final Data resetRequestInputData = new Data(Map.of(
+ SYNC_WORKER_INPUT_SYNC_SOURCE, syncSource
+ ));
+ final OneTimeWorkRequest resetRequest =
+ buildOneTimeWorkerRequest(MediaSetsResetWorker.class, resetRequestInputData);
- // track the new request
+ // Track the new requests
+ trackNewMediaSetsSyncRequest(syncSource, resetRequest.getId());
trackNewMediaSetsSyncRequest(syncSource, syncRequest.getId());
final String workName = syncSource == SYNC_LOCAL_ONLY
@@ -647,15 +668,18 @@ public class PickerSyncManager {
: IMMEDIATE_CLOUD_MEDIA_SETS_SYNC_WORK_NAME;
// Enqueue local or cloud sync request
try {
- final Operation enqueueOperation = mWorkManager.enqueueUniqueWork(
- workName,
- ExistingWorkPolicy.APPEND_OR_REPLACE,
- syncRequest);
+ final Operation enqueueOperation = mWorkManager
+ .beginUniqueWork(
+ workName,
+ ExistingWorkPolicy.APPEND_OR_REPLACE,
+ resetRequest)
+ .then(syncRequest).enqueue();
// Check that the request has been successfully enqueued.
enqueueOperation.getResult().get();
} catch (Exception e) {
Log.e(TAG, "Could not enqueue expedited media sets sync request", e);
+ markMediaSetsSyncAsComplete(syncSource, resetRequest.getId());
markMediaSetsSyncAsComplete(syncSource, syncRequest.getId());
}
}
@@ -668,7 +692,9 @@ public class PickerSyncManager {
* the cloud provider.
*/
public void syncMediaInMediaSetForProvider(
- MediaInMediaSetSyncRequestParams requestParams, @SyncSource int syncSource) {
+ MediaInMediaSetSyncRequestParams requestParams,
+ @SyncSource int syncSource) {
+
final Data inputData =
new Data(
Map.of(
@@ -679,6 +705,8 @@ public class PickerSyncManager {
final OneTimeWorkRequest syncRequest =
buildOneTimeWorkerRequest(MediaInMediaSetsSyncWorker.class, inputData);
+ markAllMediaInMediaSetsSyncAsComplete(syncSource);
+
// track the new request
trackNewMediaInMediaSetSyncRequest(syncSource, syncRequest.getId());
@@ -688,10 +716,10 @@ public class PickerSyncManager {
// Enqueue local or cloud sync request
try {
final Operation enqueueOperation = mWorkManager.enqueueUniqueWork(
- workName,
- ExistingWorkPolicy.APPEND_OR_REPLACE,
- syncRequest
- );
+ workName,
+ ExistingWorkPolicy.REPLACE,
+ syncRequest
+ );
// Check that the request has been successfully enqueued.
enqueueOperation.getResult().get();
@@ -703,11 +731,17 @@ public class PickerSyncManager {
@NonNull
private OneTimeWorkRequest buildOneTimeWorkerRequest(
- @NonNull Class<? extends Worker> workerClass, @NonNull Data inputData) {
- return new OneTimeWorkRequest.Builder(workerClass)
- .setInputData(inputData)
- .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
- .build();
+ @NonNull Class<? extends Worker> workerClass, Data inputData) {
+ if (inputData != null) {
+ return new OneTimeWorkRequest.Builder(workerClass)
+ .setInputData(inputData)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .build();
+ } else {
+ return new OneTimeWorkRequest.Builder(workerClass)
+ .setExpedited(OutOfQuotaPolicy.RUN_AS_NON_EXPEDITED_WORK_REQUEST)
+ .build();
+ }
}
@NonNull
diff --git a/src/com/android/providers/media/photopicker/sync/SyncTrackerRegistry.java b/src/com/android/providers/media/photopicker/sync/SyncTrackerRegistry.java
index 3c2898b96..82acd40fe 100644
--- a/src/com/android/providers/media/photopicker/sync/SyncTrackerRegistry.java
+++ b/src/com/android/providers/media/photopicker/sync/SyncTrackerRegistry.java
@@ -390,4 +390,17 @@ public class SyncTrackerRegistry {
getCloudMediaInMediaSetTracker().markSyncCompleted(syncRequestId);
}
}
+
+ /**
+ * Mark all media in media sets sync pending futures as complete
+ */
+ public static void markAllMediaInMediaSetsSyncAsComplete(
+ @PickerSyncManager.SyncSource int syncSource) {
+ if (syncSource == SYNC_LOCAL_ONLY || syncSource == SYNC_LOCAL_AND_CLOUD) {
+ getLocalMediaInMediaSetTracker().markAllSyncsCompleted();
+ }
+ if (syncSource == SYNC_CLOUD_ONLY || syncSource == SYNC_LOCAL_AND_CLOUD) {
+ getCloudMediaInMediaSetTracker().markAllSyncsCompleted();
+ }
+ }
}
diff --git a/src/com/android/providers/media/photopicker/v2/PickerDataLayerV2.java b/src/com/android/providers/media/photopicker/v2/PickerDataLayerV2.java
index b8b78d94e..b39bc5472 100644
--- a/src/com/android/providers/media/photopicker/v2/PickerDataLayerV2.java
+++ b/src/com/android/providers/media/photopicker/v2/PickerDataLayerV2.java
@@ -1452,7 +1452,8 @@ public class PickerDataLayerV2 {
new MediaInMediaSetSyncRequestParams(extras);
final Set<String> providers = new HashSet<>(
Objects.requireNonNull(extras.getStringArrayList("providers")));
- scheduleMediaInMediaSetSync(requestParams, appContext, workManager, providers);
+ scheduleMediaInMediaSetSync(
+ requestParams, appContext, workManager, providers);
}
/**
@@ -1466,6 +1467,7 @@ public class PickerDataLayerV2 {
private static void scheduleMediaInMediaSetSync(
@NonNull MediaInMediaSetSyncRequestParams requestParams, @NonNull Context context,
@NonNull WorkManager workManager, @NonNull Set<String> providers) {
+
PickerSyncController syncController = PickerSyncController.getInstanceOrThrow();
PickerSyncManager syncManager = new PickerSyncManager(workManager, context);
int syncSource = Objects.equals(requestParams.getAuthority(),
@@ -1474,10 +1476,12 @@ public class PickerDataLayerV2 {
// Sync MediaSet content only if the media sets can actually be queried
if (syncSource == SYNC_LOCAL_ONLY && syncController.shouldQueryLocalMediaSets(providers)) {
- syncManager.syncMediaInMediaSetForProvider(requestParams, SYNC_LOCAL_ONLY);
+ syncManager.syncMediaInMediaSetForProvider(
+ requestParams, SYNC_LOCAL_ONLY);
} else if (syncController.shouldQueryCloudMediaSets(
providers, requestParams.getAuthority())) {
- syncManager.syncMediaInMediaSetForProvider(requestParams, SYNC_CLOUD_ONLY);
+ syncManager.syncMediaInMediaSetForProvider(
+ requestParams, SYNC_CLOUD_ONLY);
} else {
Log.e(TAG, "Unidentified provider authority: " + requestParams.getAuthority()
+ " skipping MediaSet content sync.");
diff --git a/src/com/android/providers/media/photopicker/v2/sqlite/MediaInMediaSetsDatabaseUtil.java b/src/com/android/providers/media/photopicker/v2/sqlite/MediaInMediaSetsDatabaseUtil.java
index 6f93998c9..0c43445fe 100644
--- a/src/com/android/providers/media/photopicker/v2/sqlite/MediaInMediaSetsDatabaseUtil.java
+++ b/src/com/android/providers/media/photopicker/v2/sqlite/MediaInMediaSetsDatabaseUtil.java
@@ -22,6 +22,8 @@ import static android.database.sqlite.SQLiteDatabase.CONFLICT_REPLACE;
import static com.android.providers.media.photopicker.v2.sqlite.PickerMediaDatabaseUtil.addNextPageKey;
import static com.android.providers.media.photopicker.v2.sqlite.PickerMediaDatabaseUtil.addPrevPageKey;
+import static java.util.Objects.requireNonNull;
+
import android.content.ContentUris;
import android.content.ContentValues;
import android.database.Cursor;
@@ -40,7 +42,6 @@ import com.android.providers.media.photopicker.PickerSyncController;
import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
-import java.util.Objects;
/**
* Utility class for insertion or querying the media items in various media sets
@@ -63,8 +64,8 @@ public class MediaInMediaSetsDatabaseUtil {
@Nullable List<ContentValues> mediaListToInsert,
@NonNull String authority) {
- Objects.requireNonNull(database);
- Objects.requireNonNull(authority);
+ requireNonNull(database);
+ requireNonNull(authority);
final boolean isLocal = PickerSyncController.getInstanceOrThrow()
.getLocalProvider()
@@ -298,8 +299,8 @@ public class MediaInMediaSetsDatabaseUtil {
*/
public static List<ContentValues> getMediaContentValuesFromCursor(
@NonNull Cursor mediaCursor, @NonNull Long mediaSetPickerId, boolean isLocal) {
- Objects.requireNonNull(mediaSetPickerId);
- Objects.requireNonNull(mediaCursor);
+ requireNonNull(mediaSetPickerId);
+ requireNonNull(mediaCursor);
List<ContentValues> contentValuesList = new ArrayList<>(mediaCursor.getCount());
if (mediaCursor.moveToFirst()) {
@@ -337,4 +338,23 @@ public class MediaInMediaSetsDatabaseUtil {
}
return contentValuesList;
}
+
+ /**
+ * Deletes all the rows from the MediaInMediaSets table
+ */
+ public static void clearMediaInMediaSetsCache(@NonNull SQLiteDatabase database) {
+
+ requireNonNull(database);
+
+ try {
+ int deletedRows = database.delete(
+ PickerSQLConstants.Table.MEDIA_IN_MEDIA_SETS.name(),
+ /*whereClause*/ null,
+ /*whereArgs*/ null);
+
+ Log.d(TAG, "Deleted " + deletedRows + " rows from the media in media sets table");
+ } catch (Exception e) {
+ Log.d(TAG, "Couldn't clear the media in media sets table due to " + e);
+ }
+ }
}
diff --git a/src/com/android/providers/media/photopicker/v2/sqlite/MediaSetsDatabaseUtil.java b/src/com/android/providers/media/photopicker/v2/sqlite/MediaSetsDatabaseUtil.java
index ee312fbed..f71b9d4ac 100644
--- a/src/com/android/providers/media/photopicker/v2/sqlite/MediaSetsDatabaseUtil.java
+++ b/src/com/android/providers/media/photopicker/v2/sqlite/MediaSetsDatabaseUtil.java
@@ -18,6 +18,8 @@ package com.android.providers.media.photopicker.v2.sqlite;
import static android.database.sqlite.SQLiteDatabase.CONFLICT_IGNORE;
+import static java.util.Objects.requireNonNull;
+
import android.content.ContentValues;
import android.database.Cursor;
import android.database.SQLException;
@@ -35,7 +37,6 @@ import java.util.ArrayList;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
-import java.util.Objects;
/**
* Utility class which holds functionality for inserting and querying media set data
@@ -61,10 +62,10 @@ public class MediaSetsDatabaseUtil {
@NonNull String categoryId, @NonNull String authority,
@Nullable List<String> mimeTypes) {
- Objects.requireNonNull(database);
- Objects.requireNonNull(mediaSetMetadataCursor);
- Objects.requireNonNull(categoryId);
- Objects.requireNonNull(authority);
+ requireNonNull(database);
+ requireNonNull(mediaSetMetadataCursor);
+ requireNonNull(categoryId);
+ requireNonNull(authority);
String mimeTypesAsString = getMimeTypesAsString(mimeTypes);
List<ContentValues> insertValues = getMediaSetContentValues(
@@ -126,8 +127,8 @@ public class MediaSetsDatabaseUtil {
public static Pair<String, String[]> getMediaSetIdAndMimeType(
@NonNull SQLiteDatabase database,
@NonNull Long mediaSetPickerId) {
- Objects.requireNonNull(database);
- Objects.requireNonNull(mediaSetPickerId);
+ requireNonNull(database);
+ requireNonNull(mediaSetPickerId);
SelectSQLiteQueryBuilder queryBuilder = new SelectSQLiteQueryBuilder(database)
.setTables(PickerSQLConstants.Table.MEDIA_SETS.name())
@@ -168,8 +169,8 @@ public class MediaSetsDatabaseUtil {
*/
public static Cursor getMediaSetsForCategory(
@NonNull SQLiteDatabase database, @NonNull MediaSetsSyncRequestParams requestParams) {
- Objects.requireNonNull(database);
- Objects.requireNonNull(requestParams);
+ requireNonNull(database);
+ requireNonNull(requestParams);
final String categoryId = requestParams.getCategoryId();
final String authority = requestParams.getAuthority();
final List<String> mimeTypes;
@@ -178,8 +179,8 @@ public class MediaSetsDatabaseUtil {
} else {
mimeTypes = null;
}
- Objects.requireNonNull(categoryId);
- Objects.requireNonNull(authority);
+ requireNonNull(categoryId);
+ requireNonNull(authority);
final List<String> projection = List.of(
PickerSQLConstants.MediaSetsTableColumns.PICKER_ID.getColumnName(),
@@ -223,8 +224,8 @@ public class MediaSetsDatabaseUtil {
*/
public static String getMediaResumeKey(
@NonNull SQLiteDatabase database, @NonNull Long mediaPickerId) {
- Objects.requireNonNull(database);
- Objects.requireNonNull(mediaPickerId);
+ requireNonNull(database);
+ requireNonNull(mediaPickerId);
final List<String> projection = List.of(
PickerSQLConstants.MediaSetsTableColumns.MEDIA_IN_MEDIA_SET_SYNC_RESUME_KEY
@@ -261,8 +262,8 @@ public class MediaSetsDatabaseUtil {
*/
public static void updateMediaInMediaSetSyncResumeKey(@NonNull SQLiteDatabase database,
@NonNull Long mediaSetPickerId, @Nullable String resumeKey) {
- Objects.requireNonNull(database);
- Objects.requireNonNull(mediaSetPickerId);
+ requireNonNull(database);
+ requireNonNull(mediaSetPickerId);
String table = PickerSQLConstants.Table.MEDIA_SETS.name();
@@ -285,6 +286,25 @@ public class MediaSetsDatabaseUtil {
);
}
+ /**
+ * Deletes all the rows from the MediaSets table
+ */
+ public static void clearMediaSetsCache(@NonNull SQLiteDatabase database) {
+
+ requireNonNull(database);
+
+ try {
+ int deletedRows = database.delete(
+ PickerSQLConstants.Table.MEDIA_SETS.name(),
+ /*whereClause*/ null,
+ /*whereClauseArgs*/ null);
+
+ Log.d(TAG, "Deleted " + deletedRows + " rows from the media sets table.");
+ } catch (Exception exception) {
+ Log.e(TAG, "couldn't clear the media sets table due to " + exception);
+ }
+ }
+
private static List<ContentValues> getMediaSetContentValues(
Cursor mediaSetCursor, String categoryId, String authority, String mimeTypes) {