Un fournisseur de services multimédias cloud fournit du contenu multimédia cloud supplémentaire sur Android
sélecteur de photos. Les utilisateurs peuvent sélectionner les photos ou vidéos fournies par le
fournisseur de services multimédias cloud lorsqu'une application utilise ACTION_PICK_IMAGES
ou
ACTION_GET_CONTENT
pour demander des fichiers multimédias à l'utilisateur. Un contenu multimédia cloud
fournisseur peut également fournir des informations sur les albums, que vous pouvez parcourir dans
Sélecteur de photos Android.
Avant de commencer
Tenez compte des éléments suivants avant de commencer à créer votre infrastructure fournisseur de services multimédias.
Éligibilité
Android exécute un programme pilote pour permettre la migration vers le cloud des applications nommées par les OEM fournisseurs de services multimédias. Seules les applications désignées par les OEM peuvent participer à ce programme pour devenir, à l'heure actuelle, un fournisseur de services multimédias cloud pour Android. Chaque L'OEM peut désigner jusqu'à trois applications. Une fois approuvées, ces applications deviennent accessibles des fournisseurs de services multimédias cloud sur tous les appareils GMS Android sur lesquels ils installés.
Android tient à jour une liste côté serveur de tous les fournisseurs de services cloud éligibles. Chaque OEM Possibilité de choisir un fournisseur de services cloud par défaut à l'aide d'une superposition configurable Nomination les applications doivent répondre à toutes les exigences techniques et réussir tous les tests de qualité. Pour apprendre en savoir plus sur le processus du programme pilote OEM pour les fournisseurs de médias cloud exigences, remplissez le formulaire de demande.
Déterminer si vous devez créer un fournisseur de services multimédias cloud
Les fournisseurs de services multimédias cloud sont conçus pour être des applications ou des services principale pour sauvegarder et récupérer des photos et des vidéos dans le cloud. Si votre application possède une bibliothèque de contenus utiles, mais qu'elle n'est généralement pas utilisée solution de stockage de photos, envisagez de créer un fournisseur de documents à la place.
Un seul fournisseur cloud actif par profil
Il ne peut y avoir qu'un seul fournisseur de services multimédias cloud actif à la fois pour chaque Android profil. Les utilisateurs peuvent supprimer ou modifier le fournisseur multimédia cloud sélectionné l'application à tout moment dans les paramètres du sélecteur de photos.
Par défaut, le sélecteur de photos Android tente de choisir un fournisseur de services cloud. automatiquement.
- S'il n'y a qu'un seul fournisseur de services cloud éligible sur l'appareil, cette application automatiquement sélectionné comme fournisseur actuel.
Si plusieurs fournisseurs de services cloud éligibles sont installés sur l'appareil et que l'un de correspondent à la valeur par défaut choisie par l'OEM, l'application choisie par l'OEM sera sélectionnée.
S'il y a plus d'un fournisseur de services cloud éligible sur l'appareil et qu'aucun de correspondent aux paramètres par défaut choisis par l'OEM, aucune application ne sera sélectionnée.
Créer votre fournisseur de services multimédias cloud
Le schéma suivant illustre la séquence des événements avant et pendant
une session de sélection de photos entre l'application Android, le sélecteur de photos Android,
le MediaProvider
de l'appareil local et un CloudMediaProvider
.
- Le système initialise le fournisseur de services cloud préféré de l'utilisateur synchronise les métadonnées multimédias avec le backend du sélecteur de photos Android.
- Lorsqu'une application Android lance le sélecteur de photos, avant d'afficher une image locale fusionnée ou une grille d'éléments cloud à l'utilisateur, le sélecteur de photos effectue une synchronisation incrémentielle avec le fournisseur de services cloud pour s'assurer que les résultats sont aussi à jour que possible. Après réception d'une réponse ou lorsque le délai est atteint, le La grille du sélecteur de photos affiche désormais toutes les photos accessibles en combinant celles stockées localement sur votre appareil avec celles synchronisées à partir du cloud.
- Pendant que l'utilisateur fait défiler la page, le sélecteur de photos extrait les vignettes multimédias d'un fournisseur de services multimédias cloud pour l'afficher dans l'UI.
- Lorsque l'utilisateur termine la session et que les résultats incluent un média cloud le sélecteur de photos demande des descripteurs de fichier pour le contenu, puis génère URI, et accorde à l'application appelante l'accès au fichier.
- L'application peut désormais ouvrir l'URI et dispose d'un accès en lecture seule aux contenus multimédias contenus. Par défaut, les métadonnées sensibles sont masquées. Sélecteur de photos utilise le système de fichiers FUSE pour coordonner l'échange de données entre l'application Android et le fournisseur de services multimédias cloud.
Problèmes courants
Voici quelques points importants à prendre en compte implémentation:
Éviter les fichiers en double
Comme le sélecteur de photos Android n'a aucun moyen d'inspecter l'état multimédia dans le cloud,
CloudMediaProvider
doit fournir MEDIA_STORE_URI
dans le curseur
ligne d'un fichier existant à la fois dans le cloud et sur l'appareil local, ou la
l'utilisateur verra les fichiers en double dans le sélecteur de photos.
Optimiser les tailles d'image pour l'affichage des aperçus
Il est très important que le fichier renvoyé par onOpenPreview
ne soit pas
résolution d'image et respecte le Size
demandé. Image trop grande
entraîne des temps de chargement dans l'interface utilisateur, et une image trop petite risque d'être pixélisée ou
floue en fonction de la taille
de l'écran de l'appareil.
Gérer la bonne orientation
Si les vignettes renvoyées dans onOpenPreview
ne contiennent pas leurs données EXIF, elles
doivent être renvoyés dans le bon sens pour éviter la rotation des vignettes ;
incorrectement dans la grille d'aperçu.
Empêcher les accès non autorisés
Vérifiez l'MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION
avant de renvoyer les données à
l'appelant à partir de ContentProvider. Vous empêcherez ainsi les applications non autorisées
l'accès aux données cloud.
La classe CloudMediaProvider
Issu de android.content.ContentProvider
, le CloudMediaProvider
inclut des méthodes semblables à celles présentées dans l'exemple suivant:
Kotlin
abstract class CloudMediaProvider : ContentProvider() {
@NonNull
abstract override fun onGetMediaCollectionInfo(@NonNull bundle: Bundle): Bundle
@NonNull
override fun onQueryAlbums(@NonNull bundle: Bundle): Cursor = TODO("Implement onQueryAlbums")
@NonNull
abstract override fun onQueryDeletedMedia(@NonNull bundle: Bundle): Cursor
@NonNull
abstract override fun onQueryMedia(@NonNull bundle: Bundle): Cursor
@NonNull
abstract override fun onOpenMedia(
@NonNull string: String,
@Nullable bundle: Bundle?,
@Nullable cancellationSignal: CancellationSignal?
): ParcelFileDescriptor
@NonNull
abstract override fun onOpenPreview(
@NonNull string: String,
@NonNull point: Point,
@Nullable bundle: Bundle?,
@Nullable cancellationSignal: CancellationSignal?
): AssetFileDescriptor
@Nullable
override fun onCreateCloudMediaSurfaceController(
@NonNull bundle: Bundle,
@NonNull callback: CloudMediaSurfaceStateChangedCallback
): CloudMediaSurfaceController? = null
}
Java
public abstract class CloudMediaProvider extends android.content.ContentProvider {
@NonNull
public abstract android.os.Bundle onGetMediaCollectionInfo(@NonNull android.os.Bundle);
@NonNull
public android.database.Cursor onQueryAlbums(@NonNull android.os.Bundle);
@NonNull
public abstract android.database.Cursor onQueryDeletedMedia(@NonNull android.os.Bundle);
@NonNull
public abstract android.database.Cursor onQueryMedia(@NonNull android.os.Bundle);
@NonNull
public abstract android.os.ParcelFileDescriptor onOpenMedia(@NonNull String, @Nullable android.os.Bundle, @Nullable android.os.CancellationSignal) throws java.io.FileNotFoundException;
@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;
@Nullable
public android.provider.CloudMediaProvider.CloudMediaSurfaceController onCreateCloudMediaSurfaceController(@NonNull android.os.Bundle, @NonNull android.provider.CloudMediaProvider.CloudMediaSurfaceStateChangedCallback);
}
Classe CloudMediaProviderContract
En plus de la classe d'implémentation principale CloudMediaProvider
,
Le sélecteur de photos Android intègre une classe CloudMediaProviderContract
.
Ce cours décrit l'interopérabilité entre le sélecteur de photos et le cloud.
fournisseur de services multimédias, englobant des aspects tels que MediaCollectionInfo
pour
opérations de synchronisation, colonnes Cursor
prévues et extras Bundle
.
Kotlin
object CloudMediaProviderContract {
const val EXTRA_ALBUM_ID = "android.provider.extra.ALBUM_ID"
const val EXTRA_LOOPING_PLAYBACK_ENABLED = "android.provider.extra.LOOPING_PLAYBACK_ENABLED"
const val EXTRA_MEDIA_COLLECTION_ID = "android.provider.extra.MEDIA_COLLECTION_ID"
const val EXTRA_PAGE_SIZE = "android.provider.extra.PAGE_SIZE"
const val EXTRA_PAGE_TOKEN = "android.provider.extra.PAGE_TOKEN"
const val EXTRA_PREVIEW_THUMBNAIL = "android.provider.extra.PREVIEW_THUMBNAIL"
const val EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED = "android.provider.extra.SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED"
const val EXTRA_SYNC_GENERATION = "android.provider.extra.SYNC_GENERATION"
const val MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION = "com.android.providers.media.permission.MANAGE_CLOUD_MEDIA_PROVIDERS"
const val PROVIDER_INTERFACE = "android.content.action.CLOUD_MEDIA_PROVIDER"
object MediaColumns {
const val DATE_TAKEN_MILLIS = "date_taken_millis"
const val DURATION_MILLIS = "duration_millis"
const val HEIGHT = "height"
const val ID = "id"
const val IS_FAVORITE = "is_favorite"
const val MEDIA_STORE_URI = "media_store_uri"
const val MIME_TYPE = "mime_type"
const val ORIENTATION = "orientation"
const val SIZE_BYTES = "size_bytes"
const val STANDARD_MIME_TYPE_EXTENSION = "standard_mime_type_extension"
const val STANDARD_MIME_TYPE_EXTENSION_ANIMATED_WEBP = 3 // 0x3
const val STANDARD_MIME_TYPE_EXTENSION_GIF = 1 // 0x1
const val STANDARD_MIME_TYPE_EXTENSION_MOTION_PHOTO = 2 // 0x2
const val STANDARD_MIME_TYPE_EXTENSION_NONE = 0 // 0x0
const val SYNC_GENERATION = "sync_generation"
const val WIDTH = "width"
}
object AlbumColumns {
const val DATE_TAKEN_MILLIS = "date_taken_millis"
const val DISPLAY_NAME = "display_name"
const val ID = "id"
const val MEDIA_COUNT = "album_media_count"
const val MEDIA_COVER_ID = "album_media_cover_id"
}
object MediaCollectionInfo {
const val ACCOUNT_CONFIGURATION_INTENT = "account_configuration_intent"
const val ACCOUNT_NAME = "account_name"
const val LAST_MEDIA_SYNC_GENERATION = "last_media_sync_generation"
const val MEDIA_COLLECTION_ID = "media_collection_id"
}
}
Java
public final class CloudMediaProviderContract {
public static final String EXTRA_ALBUM_ID = "android.provider.extra.ALBUM_ID";
public static final String EXTRA_LOOPING_PLAYBACK_ENABLED = "android.provider.extra.LOOPING_PLAYBACK_ENABLED";
public static final String EXTRA_MEDIA_COLLECTION_ID = "android.provider.extra.MEDIA_COLLECTION_ID";
public static final String EXTRA_PAGE_SIZE = "android.provider.extra.PAGE_SIZE";
public static final String EXTRA_PAGE_TOKEN = "android.provider.extra.PAGE_TOKEN";
public static final String EXTRA_PREVIEW_THUMBNAIL = "android.provider.extra.PREVIEW_THUMBNAIL";
public static final String EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED = "android.provider.extra.SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED";
public static final String EXTRA_SYNC_GENERATION = "android.provider.extra.SYNC_GENERATION";
public static final String MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION = "com.android.providers.media.permission.MANAGE_CLOUD_MEDIA_PROVIDERS";
public static final String PROVIDER_INTERFACE = "android.content.action.CLOUD_MEDIA_PROVIDER";
}
// Columns available for every media item
public static final class CloudMediaProviderContract.MediaColumns {
public static final String DATE_TAKEN_MILLIS = "date_taken_millis";
public static final String DURATION_MILLIS = "duration_millis";
public static final String HEIGHT = "height";
public static final String ID = "id";
public static final String IS_FAVORITE = "is_favorite";
public static final String MEDIA_STORE_URI = "media_store_uri";
public static final String MIME_TYPE = "mime_type";
public static final String ORIENTATION = "orientation";
public static final String SIZE_BYTES = "size_bytes";
public static final String STANDARD_MIME_TYPE_EXTENSION = "standard_mime_type_extension";
public static final int STANDARD_MIME_TYPE_EXTENSION_ANIMATED_WEBP = 3; // 0x3
public static final int STANDARD_MIME_TYPE_EXTENSION_GIF = 1; // 0x1
public static final int STANDARD_MIME_TYPE_EXTENSION_MOTION_PHOTO = 2; // 0x2
public static final int STANDARD_MIME_TYPE_EXTENSION_NONE = 0; // 0x0
public static final String SYNC_GENERATION = "sync_generation";
public static final String WIDTH = "width";
}
// Columns available for every album item
public static final class CloudMediaProviderContract.AlbumColumns {
public static final String DATE_TAKEN_MILLIS = "date_taken_millis";
public static final String DISPLAY_NAME = "display_name";
public static final String ID = "id";
public static final String MEDIA_COUNT = "album_media_count";
public static final String MEDIA_COVER_ID = "album_media_cover_id";
}
// Media Collection metadata that is cached by the OS to compare sync states.
public static final class CloudMediaProviderContract.MediaCollectionInfo {
public static final String ACCOUNT_CONFIGURATION_INTENT = "account_configuration_intent";
public static final String ACCOUNT_NAME = "account_name";
public static final String LAST_MEDIA_SYNC_GENERATION = "last_media_sync_generation";
public static final String MEDIA_COLLECTION_ID = "media_collection_id";
}
onGetMediaCollectionInfo
La méthode onGetMediaCollectionInfo()
est utilisée par le système d'exploitation pour
d'évaluer la validité de ses éléments multimédias cloud mis en cache et de déterminer
la synchronisation avec le fournisseur
de services multimédias cloud. En raison de la possibilité
par le système d'exploitation, onGetMediaCollectionInfo()
est considéré comme
les performances essentielles ; il est essentiel d'éviter les opérations de longue durée
qui pourraient avoir un impact
négatif sur les performances. Le système d'exploitation met en cache
réponses précédentes de cette méthode et les compare aux réponses suivantes
pour déterminer les mesures à prendre.
Kotlin
abstract fun onGetMediaCollectionInfo(extras: Bundle): Bundle
Java
@NonNull
public abstract Bundle onGetMediaCollectionInfo(@NonNull Bundle extras);
Le bundle MediaCollectionInfo
renvoyé comprend les constantes suivantes:
onQueryMedia
La méthode onQueryMedia()
permet de remplir la grille de photos principale dans
sélecteur de photos dans
différentes vues. Ces appels peuvent être sensibles à la latence.
peut être appelé lors d'une synchronisation proactive en arrière-plan ou lors du sélecteur de photos
lorsqu'un état de synchronisation complet ou incrémentiel est requis. Sélecteur de photos
l'interface utilisateur n'attend pas indéfiniment une réponse pour afficher les résultats et
pourrait expirer ces demandes
pour des raisons d’interface utilisateur. Curseur renvoyé
tentera tout de même d'être traité dans la base de données du sélecteur de photos
sessions.
Cette méthode renvoie un Cursor
représentant tous les éléments multimédias de ce type de contenu.
collection facultative filtrée par les extras fournis et triée dans l'ordre inverse
ordre chronologique de MediaColumns#DATE_TAKEN_MILLIS
(éléments les plus récents)
d'abord).
Le bundle CloudMediaProviderContract
renvoyé comprend les éléments suivants :
constantes:
EXTRA_ALBUM_ID
EXTRA_LOOPING_PLAYBACK_ENABLED
EXTRA_MEDIA_COLLECTION_ID
EXTRA_PAGE_SIZE
EXTRA_PAGE_TOKEN
EXTRA_PREVIEW_THUMBNAIL
EXTRA_SURFACE_CONTROLLER_AUDIO_MUTE_ENABLED
EXTRA_SYNC_GENERATION
MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION
PROVIDER_INTERFACE
Le fournisseur de services multimédias cloud doit définir
CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID
dans l'élément renvoyé
Bundle
Si vous ne définissez pas ce paramètre, cela entraînera une erreur et invalidera le Cursor
renvoyé. Si
que le fournisseur de services multimédias cloud a géré tous les filtres dans les extras fournis, il doit ajouter
la clé de ContentResolver#EXTRA_HONORED_ARGS
dans l'objet renvoyé
Cursor#setExtras
onQueryDeleteMedia
La méthode onQueryDeletedMedia()
permet de s'assurer que les éléments supprimés dans le
compte cloud sont correctement supprimés de l'interface utilisateur du sélecteur de photos. Motif :
leur sensibilité potentielle à la latence, ces appels peuvent être initiés pour:
- Synchronisation proactive en arrière-plan
- Sessions avec sélecteur de photos (quand une synchronisation complète ou incrémentielle est requise)
L'interface utilisateur du sélecteur de photos donne la priorité à une expérience utilisateur réactive et
n'attendra pas indéfiniment une réponse. Pour maintenir
des interactions fluides,
les délais avant expiration peuvent se produire. Tout Cursor
renvoyé tentera quand même d'être traité
dans la base de données du sélecteur de photos pour les sessions futures.
Cette méthode renvoie un Cursor
représentant tous les éléments multimédias supprimés dans
la collection complète de médias dans la version actuelle du fournisseur, telle que renvoyée par
onGetMediaCollectionInfo()
Vous pouvez éventuellement filtrer ces éléments par "extras".
Le fournisseur de services multimédias cloud doit définir
CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID
dans l'élément renvoyé
Cursor#setExtras
Si vous ne définissez pas ce paramètre, il s'agit d'une erreur et invalide le Cursor
. Si
le fournisseur a géré tous les filtres dans les extras fournis, il doit ajouter la clé à
le ContentResolver#EXTRA_HONORED_ARGS
.
onQueryAlbums
La méthode onQueryAlbums()
permet d'extraire une liste des albums Cloud qui
disponibles auprès du fournisseur de services cloud, ainsi que les métadonnées associées. Voir
CloudMediaProviderContract.AlbumColumns
pour en savoir plus.
Cette méthode renvoie un Cursor
représentant tous les éléments de l'album dans le contenu multimédia.
collection facultative filtrée par les extras fournis et triée dans l'ordre inverse
ordre chronologique de AlbumColumns#DATE_TAKEN_MILLIS
, éléments les plus récents
en premier. Le fournisseur de services multimédias cloud doit définir
CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID
dans l'élément renvoyé
Cursor
Si vous ne définissez pas ce paramètre, cela entraînera une erreur et invalidera le Cursor
renvoyé. Si
le fournisseur a géré tous les filtres dans les extras fournis, il doit ajouter la clé à
ContentResolver#EXTRA_HONORED_ARGS
dans l'élément Cursor
renvoyé.
OnOpenMedia
La méthode onOpenMedia()
doit renvoyer le support en taille réelle identifié par
le mediaId
fourni. Si cette méthode se bloque lors du téléchargement de contenu
l'appareil, vérifiez régulièrement le CancellationSignal
fourni pour annuler
les demandes abandonnées.
onOpenPreview
La méthode onOpenPreview()
doit renvoyer une vignette de la
size
pour l'élément de l'élément mediaId fourni. La miniature doit se trouver
CloudMediaProviderContract.MediaColumns#MIME_TYPE
d'origine et devrait
avoir une résolution beaucoup plus faible que celle de l'élément renvoyé par onOpenMedia
. Si cette méthode
est bloqué pendant le téléchargement de contenu sur l'appareil, veillez à vérifier régulièrement
Vérifiez le CancellationSignal
fourni pour annuler les requêtes abandonnées.
onCreateCloudMediaSurfaceController
La méthode onCreateCloudMediaSurfaceController()
doit renvoyer une
CloudMediaSurfaceController
utilisé pour afficher l'aperçu des éléments multimédias ; ou
null
si l'aperçu n'est pas disponible.
CloudMediaSurfaceController
gère l'affichage de l'aperçu des éléments multimédias
sur des instances données de Surface
. Les méthodes de cette classe sont censées être
asynchrone et ne doit pas être bloqué en effectuant une opération lourde. Une seule
L'instance CloudMediaSurfaceController
est chargée d'afficher plusieurs
éléments multimédias associés à plusieurs surfaces.
Le CloudMediaSurfaceController
est compatible avec la liste suivante de
Rappels de cycle de vie:
onConfigChange
onDestroy
onMediaPause
onMediaPlay
onMediaSeekTo
onPlayerCreate
onPlayerRelease
onSurfaceChanged
onSurfaceCreated
onSurfaceDestroyed