summaryrefslogtreecommitdiff
path: root/apex
diff options
context:
space:
mode:
author Tyler Saunders <tylersaunders@google.com> 2024-09-20 11:52:44 +0100
committer Tyler Saunders <tylersaunders@google.com> 2024-10-24 13:43:06 +0100
commit8885490578b0a91dba973c9f5b36ffef761a7e32 (patch)
tree94c17f6b3f2f1ade8cc2d7a2605f2b145f9e2b72 /apex
parentea4bf3dc76e434c78a9641db779e5d5535e0f189 (diff)
Add CloudMediaProviderContract.Capabilities APIs and MEDIA_CATEGORY_TYPE_USER_ALBUMS.
Introduce the getCapabilities API in CloudMediaProvider to allow the system to determine which optional APIs are available for a provider. By default, the CloudMediaProvider will return the base implementation set of features and newly added features will be optional off-by-default forcing new implementations to declare their support for a capability by overriding getCapabilities and explicitly enabling support. Introduce MEDIA_CATEGORY_TYPE_USER_ALBUMS for allowing CloudMediaProvider to provide albums as a MediaCategory rather than via onQueryAlbums. This API will be unhidden at a future date. Bug: b/316356081 Test: atest MediaProviderTests:CloudMediaProviderTest Flag: com.android.providers.media.flags.enable_cloud_media_provider_capabilities Change-Id: I2af93a72e7e03b64018b381bdb41b2fc00f3ecd1
Diffstat (limited to 'apex')
-rw-r--r--apex/framework/api/current.txt16
-rw-r--r--apex/framework/java/android/provider/CloudMediaProvider.java37
-rw-r--r--apex/framework/java/android/provider/CloudMediaProviderContract.java262
-rw-r--r--apex/framework/java/android/provider/CmpApiVerifier.java45
4 files changed, 356 insertions, 4 deletions
diff --git a/apex/framework/api/current.txt b/apex/framework/api/current.txt
index 0290f7c16..c0dc1e3f9 100644
--- a/apex/framework/api/current.txt
+++ b/apex/framework/api/current.txt
@@ -10,6 +10,7 @@ package android.provider {
method @NonNull public final String getType(@NonNull android.net.Uri);
method @NonNull public final android.net.Uri insert(@NonNull android.net.Uri, @NonNull android.content.ContentValues);
method @Nullable public android.provider.CloudMediaProvider.CloudMediaSurfaceController onCreateCloudMediaSurfaceController(@NonNull android.os.Bundle, @NonNull android.provider.CloudMediaProvider.CloudMediaSurfaceStateChangedCallback);
+ method @FlaggedApi("com.android.providers.media.flags.enable_cloud_media_provider_capabilities") @NonNull public android.provider.CloudMediaProviderContract.Capabilities onGetCapabilities();
method @NonNull public abstract android.os.Bundle onGetMediaCollectionInfo(@NonNull android.os.Bundle);
method @NonNull public abstract android.os.ParcelFileDescriptor onOpenMedia(@NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
method @NonNull public abstract android.content.res.AssetFileDescriptor onOpenPreview(@NonNull String, @NonNull android.graphics.Point, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@@ -87,6 +88,21 @@ package android.provider {
field public static final String MEDIA_COVER_ID = "album_media_cover_id";
}
+ @FlaggedApi("com.android.providers.media.flags.enable_cloud_media_provider_capabilities") public static final class CloudMediaProviderContract.Capabilities implements android.os.Parcelable {
+ method public int describeContents();
+ method @FlaggedApi("com.android.providers.media.flags.cloud_media_provider_search") public boolean isMediaCollectionsEnabled();
+ method @FlaggedApi("com.android.providers.media.flags.cloud_media_provider_search") public boolean isSearchEnabled();
+ method public void writeToParcel(@NonNull android.os.Parcel, int);
+ field @NonNull public static final android.os.Parcelable.Creator<android.provider.CloudMediaProviderContract.Capabilities> CREATOR;
+ }
+
+ @FlaggedApi("com.android.providers.media.flags.enable_cloud_media_provider_capabilities") public static final class CloudMediaProviderContract.Capabilities.Builder {
+ ctor public CloudMediaProviderContract.Capabilities.Builder();
+ method @NonNull public android.provider.CloudMediaProviderContract.Capabilities build();
+ method @FlaggedApi("com.android.providers.media.flags.cloud_media_provider_search") @NonNull public android.provider.CloudMediaProviderContract.Capabilities.Builder setMediaCollectionsEnabled(boolean);
+ method @FlaggedApi("com.android.providers.media.flags.cloud_media_provider_search") @NonNull public android.provider.CloudMediaProviderContract.Capabilities.Builder setSearchEnabled(boolean);
+ }
+
@FlaggedApi("com.android.providers.media.flags.cloud_media_provider_search") public static final class CloudMediaProviderContract.MediaCategoryColumns {
field public static final String DISPLAY_NAME = "display_name";
field public static final String ID = "id";
diff --git a/apex/framework/java/android/provider/CloudMediaProvider.java b/apex/framework/java/android/provider/CloudMediaProvider.java
index f9f8aace4..1d13426ad 100644
--- a/apex/framework/java/android/provider/CloudMediaProvider.java
+++ b/apex/framework/java/android/provider/CloudMediaProvider.java
@@ -22,6 +22,7 @@ import static android.provider.CloudMediaProviderContract.EXTRA_ERROR_MESSAGE;
import static android.provider.CloudMediaProviderContract.EXTRA_FILE_DESCRIPTOR;
import static android.provider.CloudMediaProviderContract.EXTRA_LOOPING_PLAYBACK_ENABLED;
import static android.provider.CloudMediaProviderContract.EXTRA_MEDIASTORE_THUMB;
+import static android.provider.CloudMediaProviderContract.EXTRA_PROVIDER_CAPABILITIES;
import static android.provider.CloudMediaProviderContract.EXTRA_SURFACE_CONTROLLER;
import static android.provider.CloudMediaProviderContract.EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED;
import static android.provider.CloudMediaProviderContract.EXTRA_SURFACE_STATE_CALLBACK;
@@ -32,6 +33,7 @@ import static android.provider.CloudMediaProviderContract.KEY_PREFIX_TEXT;
import static android.provider.CloudMediaProviderContract.KEY_SEARCH_TEXT;
import static android.provider.CloudMediaProviderContract.METHOD_CREATE_SURFACE_CONTROLLER;
import static android.provider.CloudMediaProviderContract.METHOD_GET_ASYNC_CONTENT_PROVIDER;
+import static android.provider.CloudMediaProviderContract.METHOD_GET_CAPABILITIES;
import static android.provider.CloudMediaProviderContract.METHOD_GET_MEDIA_COLLECTION_INFO;
import static android.provider.CloudMediaProviderContract.URI_PATH_ALBUM;
import static android.provider.CloudMediaProviderContract.URI_PATH_DELETED_MEDIA;
@@ -184,6 +186,27 @@ public abstract class CloudMediaProvider extends ContentProvider {
}
/**
+ * Returns the {@link CloudMediaProviderContract.Capabilities} of this
+ * CloudMediaProvider.
+ *
+ * This object is used to determine which APIs can be safely invoked during
+ * runtime.
+ *
+ * If not overridden the default capabilities are used.
+ *
+ * IMPORTANT: This method is performance critical and should avoid long running
+ * or expensive operations.
+ *
+ * @see CloudMediaProviderContract.Capabilities
+ *
+ */
+ @NonNull
+ @FlaggedApi(Flags.FLAG_ENABLE_CLOUD_MEDIA_PROVIDER_CAPABILITIES)
+ public CloudMediaProviderContract.Capabilities onGetCapabilities() {
+ return new CloudMediaProviderContract.Capabilities.Builder().build();
+ }
+
+ /**
* Returns metadata about the media collection itself.
* <p>
* This is useful for the OS to determine if its cache of media items in the collection is
@@ -694,7 +717,7 @@ public abstract class CloudMediaProvider extends ContentProvider {
}
private Bundle callUnchecked(@NonNull String method, @Nullable String arg,
- @Nullable Bundle extras)
+ @Nullable Bundle extras)
throws FileNotFoundException {
if (extras == null) {
extras = new Bundle();
@@ -704,12 +727,22 @@ public abstract class CloudMediaProvider extends ContentProvider {
long startTime = System.currentTimeMillis();
result = onGetMediaCollectionInfo(extras);
CmpApiVerifier.verifyApiResult(new CmpApiResult(
- CmpApiVerifier.CloudMediaProviderApis.OnGetMediaCollectionInfo, result),
+ CmpApiVerifier.CloudMediaProviderApis.OnGetMediaCollectionInfo, result),
System.currentTimeMillis() - startTime, mAuthority);
} else if (METHOD_CREATE_SURFACE_CONTROLLER.equals(method)) {
result = onCreateCloudMediaSurfaceController(extras);
} else if (METHOD_GET_ASYNC_CONTENT_PROVIDER.equals(method)) {
result = onGetAsyncContentProvider();
+ } else if (Flags.enableCloudMediaProviderCapabilities()
+ && METHOD_GET_CAPABILITIES.equals(method)) {
+ long startTime = System.currentTimeMillis();
+
+ CloudMediaProviderContract.Capabilities capabilities = onGetCapabilities();
+ result.putParcelable(EXTRA_PROVIDER_CAPABILITIES, capabilities);
+
+ CmpApiVerifier.verifyApiResult(new CmpApiResult(
+ CmpApiVerifier.CloudMediaProviderApis.OnGetCapabilities, result),
+ System.currentTimeMillis() - startTime, mAuthority);
} else {
throw new UnsupportedOperationException("Method not supported " + method);
}
diff --git a/apex/framework/java/android/provider/CloudMediaProviderContract.java b/apex/framework/java/android/provider/CloudMediaProviderContract.java
index 4625503ca..0ac27a4fd 100644
--- a/apex/framework/java/android/provider/CloudMediaProviderContract.java
+++ b/apex/framework/java/android/provider/CloudMediaProviderContract.java
@@ -20,11 +20,14 @@ import static java.lang.annotation.RetentionPolicy.SOURCE;
import android.annotation.FlaggedApi;
import android.annotation.IntDef;
+import android.annotation.NonNull;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Intent;
import android.database.Cursor;
import android.os.Bundle;
+import android.os.Parcel;
+import android.os.Parcelable;
import com.android.providers.media.flags.Flags;
@@ -58,6 +61,235 @@ public final class CloudMediaProviderContract {
public static final String MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION =
"com.android.providers.media.permission.MANAGE_CLOUD_MEDIA_PROVIDERS";
+ /**
+ * Information about what capabilities a CloudMediaProvider can support. This
+ * will be used by the system to inform which APIs should be expected to return
+ * data. This object is returned from {@link CloudMediaProvider#onGetCapabilities}.
+ *
+ * This object enumerates which capabilities are provided by the
+ * CloudMediaProvider implementation that supplied this object.
+ *
+ * @see CloudMediaProvider#onGetCapabilities()
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_CLOUD_MEDIA_PROVIDER_CAPABILITIES)
+ public static final class Capabilities implements Parcelable {
+
+ private boolean mSearchEnabled;
+ private boolean mMediaCollectionsEnabled;
+ private boolean mAlbumsAsCategory;
+
+ Capabilities(@NonNull Builder builder) {
+ this.mSearchEnabled = builder.mSearchEnabled;
+ this.mMediaCollectionsEnabled = builder.mMediaCollectionsEnabled;
+ this.mAlbumsAsCategory = builder.mAlbumsAsCategoryEnabled;
+ }
+
+
+ /**
+ * If the CloudMediaProvider supports Search functionality.
+ *
+ * In order for search to be enabled the CloudMediaProvider needs to
+ * implement the following APIs:
+ *
+ * @see CloudMediaProvider#onSearchMedia
+ * @see CloudMediaProvider#onQuerySearchSuggestions
+ *
+ * This capability is disabled by default.
+ *
+ * @return true if search is enabled for this CloudMediaProvider.
+ */
+ @FlaggedApi(Flags.FLAG_CLOUD_MEDIA_PROVIDER_SEARCH)
+ public boolean isSearchEnabled() {
+ return mSearchEnabled;
+ }
+
+ /**
+ * If the CloudMediaProvider supports MediaCollections.
+ *
+ * In order for MediaCollections to be enabled the CloudMediaProvider needs to
+ * implement the following APIs:
+ *
+ * @see CloudMediaProvider#onQueryMediaCategories
+ * @see CloudMediaProvider#onQueryMediaSets
+ *
+ * This capability is disabled by default.
+ *
+ * @return true if media collections are enabled for this CloudMediaProvider.
+ */
+ @FlaggedApi(Flags.FLAG_CLOUD_MEDIA_PROVIDER_SEARCH)
+ public boolean isMediaCollectionsEnabled() {
+ return mMediaCollectionsEnabled;
+ }
+
+ /**
+ * If the CloudMediaProvider will return user albums as a grouped category.
+ *
+ * When this capability is enabled, {@link CloudMediaProvider#onQueryAlbums} will
+ * no longer be called to sync the users albums, and it is expected that a
+ * category with the type {@link #MEDIA_CATEGORY_TYPE_USER_ALBUMS} will be
+ * provided in the {@link CloudMediaProvider#onQueryMediaCategories} for
+ * providing the user's custom albums. If no such category is returned,
+ * then there will be no data for user custom albums.
+ *
+ * NOTE: This capability requires the
+ * {@link Capabilities#isMediaCollectionsEnabled} capability to also be enabled
+ * for the CloudMediaProvider. If it is not, this Capability has no effect and
+ * will be ignored.
+ *
+ * @see CloudMediaProvider#onQueryMediaCategories
+ * @see #MEDIA_CATEGORY_TYPE_USER_ALBUMS
+ *
+ * This capability is disabled by default.
+ *
+ * @return true if albums will be returned as a MediaCategory.
+ *
+ * @hide
+ */
+ public boolean isAlbumsAsCategoryEnabled() {
+ return mAlbumsAsCategory;
+ }
+
+ /**
+ * Implemented for {@link Parcelable}
+ */
+ @Override
+ public int describeContents() {
+ return 0;
+ }
+
+ /**
+ * Implemented for {@link Parcelable}
+ */
+ @Override
+ public void writeToParcel(@NonNull Parcel dest, int flags) {
+ dest.writeBoolean(mSearchEnabled);
+ dest.writeBoolean(mMediaCollectionsEnabled);
+ dest.writeBoolean(mAlbumsAsCategory);
+ }
+
+ /**
+ * Implemented for {@link Parcelable}
+ */
+ @NonNull
+ public static final Parcelable.Creator<Capabilities> CREATOR =
+ new Parcelable.Creator<Capabilities>() {
+
+ @NonNull
+ @Override
+ public Capabilities createFromParcel(Parcel source) {
+ boolean searchEnabled = source.readBoolean();
+ boolean mediaCollectionsEnabled = source.readBoolean();
+ boolean mAlbumsAsCategoryEnabled = source.readBoolean();
+
+ Capabilities.Builder builder = new Capabilities.Builder();
+
+ if (Flags.cloudMediaProviderSearch()) {
+ builder
+ .setSearchEnabled(searchEnabled)
+ .setMediaCollectionsEnabled(mediaCollectionsEnabled)
+ .setAlbumsAsCategoryEnabled(mAlbumsAsCategoryEnabled);
+ }
+
+ return builder.build();
+ }
+
+ @NonNull
+ @Override
+ public Capabilities[] newArray(int size) {
+ return new Capabilities[size];
+ }
+ };
+
+ /**
+ * Builder for a {@link CloudMediaProviderContract.Capabilities} object.
+ *
+ * @see Capabilities
+ */
+ @FlaggedApi(Flags.FLAG_ENABLE_CLOUD_MEDIA_PROVIDER_CAPABILITIES)
+ public static final class Builder {
+
+ // Default values for each capability. These are used if not explicitly changed.
+ private boolean mSearchEnabled = false;
+ private boolean mMediaCollectionsEnabled = false;
+ private boolean mAlbumsAsCategoryEnabled = false;
+
+ public Builder() {
+ }
+
+
+ /**
+ * The SearchEnabled capability informs that search related APIs are supported
+ * and can be invoked on this provider.
+ *
+ * @see CloudMediaProvider#onSearchMedia
+ * @see CloudMediaProvider#onQuerySearchSuggestions
+ *
+ * @param enabled true if this capability is supported, the default value is false.
+ */
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CLOUD_MEDIA_PROVIDER_SEARCH)
+ public Builder setSearchEnabled(boolean enabled) {
+ mSearchEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * The MediaCollections capability informs that collection related APIs are
+ * supported and can be invoked on this provider.
+ *
+ * @see CloudMediaProvider#onQueryMediaCategories
+ * @see CloudMediaProvider#onQueryMediaSets
+ *
+ * @param enabled true if this capability is supported, the default value is false.
+ */
+ @NonNull
+ @FlaggedApi(Flags.FLAG_CLOUD_MEDIA_PROVIDER_SEARCH)
+ public Builder setMediaCollectionsEnabled(boolean enabled) {
+ mMediaCollectionsEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * If the CloudMediaProvider will return user albums as a grouped category.
+ *
+ * When this capability is enabled, {@link CloudMediaProvider#onQueryAlbums} will
+ * no longer be called to sync the users albums, and it is expected that a
+ * category with the type {@link #MEDIA_CATEGORY_TYPE_USER_ALBUMS} will be
+ * provided in the {@link CloudMediaProvider#onQueryMediaCategories} for
+ * providing the user's custom albums. If no such category is returned,
+ * then there will be no data for user custom albums.
+ *
+ * NOTE: This capability requires the
+ * {@link Capabilities#isMediaCollectionsEnabled} capability to also be enabled
+ * for the CloudMediaProvider. If it is not, this Capability has no effect and
+ * will be ignored.
+ *
+ * @see CloudMediaProvider#onQueryMediaCategories
+ * @see #MEDIA_CATEGORY_TYPE_USER_ALBUMS
+ *
+ * @param enabled true if this capability is supported, the default value is false.
+ *
+ * @hide
+ */
+ @NonNull
+ public Builder setAlbumsAsCategoryEnabled(boolean enabled) {
+ mAlbumsAsCategoryEnabled = enabled;
+ return this;
+ }
+
+ /**
+ * Create a new {@link CloudMediaProviderContract.Capabilities} object with the
+ * current builder's Capabilities.
+ */
+ @NonNull
+ public Capabilities build() {
+ return new Capabilities(this);
+ }
+
+ }
+
+ }
+
/** Constants related to a media item, including {@link Cursor} column names */
public static final class MediaColumns {
private MediaColumns() {}
@@ -710,6 +942,21 @@ public final class CloudMediaProviderContract {
"android:getAsyncContentProvider";
/**
+ * Constant used to execute {@link CloudMediaProvider#onGetCapabilities()} via
+ * {@link android.content.ContentProvider#call}.
+ *
+ */
+ static final String METHOD_GET_CAPABILITIES = "android:getCapabilities";
+
+ /**
+ * Constant used to get/set {@link Capabilities} in {@link Bundle}.
+ *
+ */
+ static final String EXTRA_PROVIDER_CAPABILITIES =
+ "android.provider.extra.PROVIDER_CAPABILITIES";
+
+
+ /**
* Constant used to get/set {@link IAsyncContentProvider} in {@link Bundle}.
*
* {@hide}
@@ -985,7 +1232,9 @@ public final class CloudMediaProviderContract {
/**
* The type of the media category.
* This must contain one of the values from the supported media category types.
- * Currently supported types are: {@link #MEDIA_CATEGORY_TYPE_PEOPLE_AND_PETS}
+ * Currently supported types are:
+ * {@link #MEDIA_CATEGORY_TYPE_PEOPLE_AND_PETS}
+ * {@link #MEDIA_CATEGORY_TYPE_USER_ALBUMS}
*
* Type: INTEGER
*/
@@ -1061,13 +1310,22 @@ public final class CloudMediaProviderContract {
public static final int MEDIA_CATEGORY_TYPE_PEOPLE_AND_PETS = 1;
/**
+ * Represents media category related to a user's custom albums.
+ * @see MediaCategoryColumns#MEDIA_CATEGORY_TYPE
+ * Type: INTEGER
+ *
+ * @hide
+ */
+ public static final int MEDIA_CATEGORY_TYPE_USER_ALBUMS = 2;
+
+ /**
* Defines the types of media categories available and supported in photo picker.
* All MediaCategories returned must be of any type from the fields available in this class.
*
* @see MediaCategoryColumns#MEDIA_CATEGORY_TYPE
* @hide
*/
- @IntDef(value = {MEDIA_CATEGORY_TYPE_PEOPLE_AND_PETS})
+ @IntDef(value = {MEDIA_CATEGORY_TYPE_PEOPLE_AND_PETS, MEDIA_CATEGORY_TYPE_USER_ALBUMS})
@Retention(SOURCE)
public @interface MediaCategoryTypes {}
diff --git a/apex/framework/java/android/provider/CmpApiVerifier.java b/apex/framework/java/android/provider/CmpApiVerifier.java
index 4977d45be..fab82a651 100644
--- a/apex/framework/java/android/provider/CmpApiVerifier.java
+++ b/apex/framework/java/android/provider/CmpApiVerifier.java
@@ -80,6 +80,10 @@ final class CmpApiVerifier {
CMP_API_TO_THRESHOLD_MAP.get(result.getApi()), errors);
switch (result.getApi()) {
+ case CloudMediaProviderApis.OnGetCapabilities: {
+ verifyOnGetCapabilities(result.getBundle(), verificationResult, errors);
+ break;
+ }
case CloudMediaProviderApis.OnGetMediaCollectionInfo: {
verifyOnGetMediaCollectionInfo(result.getBundle(), verificationResult,
errors);
@@ -144,6 +148,44 @@ final class CmpApiVerifier {
}
/**
+ * Verifies the {@link CloudMediaProvider#onGetCapabilities()} API.
+ *
+ * Verifies the Capabilities object returned is non-null.
+ */
+ static void verifyOnGetCapabilities(
+ Bundle outputBundle, List<String> verificationResult, List<String> errors) {
+
+ // Only Verify if the flag for capabilities is on.
+ if (Flags.enableCloudMediaProviderCapabilities()) {
+
+ if (outputBundle != null
+ && outputBundle.containsKey(
+ CloudMediaProviderContract.EXTRA_PROVIDER_CAPABILITIES)) {
+
+ verificationResult.add("Capabilities is present.");
+
+ CloudMediaProviderContract.Capabilities capabilities = outputBundle
+ .getParcelable(CloudMediaProviderContract.EXTRA_PROVIDER_CAPABILITIES);
+
+ // Verify CMP search capabilities if the search flag is on.
+ if (Flags.cloudMediaProviderSearch()) {
+ if (capabilities.isAlbumsAsCategoryEnabled()
+ && !capabilities.isMediaCollectionsEnabled()) {
+ errors.add(createIsNotValidLog("Declared capabilities are invalid. "
+ + "AlbumsAsCategory capability can only be enabled when "
+ + "MediaCollections is enabled."));
+ } else {
+ verificationResult.add("Declared Capabilities are valid.");
+ }
+
+ }
+ } else {
+ errors.add(createIsNullLog("Capabilities were not returned by OnGetCapabilities"));
+ }
+ }
+ }
+
+ /**
* Verifies OnGetMediaCollectionInfo API by performing and logging the following checks:
*
* <ul>
@@ -520,6 +562,7 @@ final class CmpApiVerifier {
}
@StringDef({
+ CloudMediaProviderApis.OnGetCapabilities,
CloudMediaProviderApis.OnGetMediaCollectionInfo,
CloudMediaProviderApis.OnQueryMedia,
CloudMediaProviderApis.OnQueryDeletedMedia,
@@ -534,6 +577,7 @@ final class CmpApiVerifier {
})
@Retention(RetentionPolicy.SOURCE)
@interface CloudMediaProviderApis {
+ String OnGetCapabilities = "OnGetCapabilities";
String OnGetMediaCollectionInfo = "onGetMediaCollectionInfo";
String OnQueryMedia = "onQueryMedia";
String OnQueryDeletedMedia = "onQueryDeletedMedia";
@@ -548,6 +592,7 @@ final class CmpApiVerifier {
}
private static final Map<String, Long> CMP_API_TO_THRESHOLD_MAP = new HashMap<>(Map.ofEntries(
+ Map.entry(CloudMediaProviderApis.OnGetCapabilities, 200L),
Map.entry(CloudMediaProviderApis.OnGetMediaCollectionInfo, 200L),
Map.entry(CloudMediaProviderApis.OnQueryMedia, 500L),
Map.entry(CloudMediaProviderApis.OnQueryDeletedMedia, 500L),