إنشاء مقدّم وسائط في السحابة الإلكترونية لنظام التشغيل Android

يوفّر مزوّد الوسائط السحابية محتوًى إضافيًا من الوسائط السحابية إلى أجهزة Android أداة اختيار الصور يمكن للمستخدمين اختيار الصور أو الفيديوهات التي يوفّرها مقدّم خدمات الوسائط السحابية عندما يستخدم أحد التطبيقات ACTION_PICK_IMAGES أو ACTION_GET_CONTENT لطلب ملفات الوسائط من المستخدم. وسائط سحابية أيضًا تقديم معلومات حول الألبومات، التي يمكن تصفحها في "أداة اختيار الصور" من Android

قبل البدء

يُرجى مراعاة العناصر التالية قبل البدء في إنشاء السحابة الإلكترونية الوسائط المختلفة.

الأهلية

تشغيل Android لبرنامج تجريبي يتيح تحويل التطبيقات المرشّحة من قِبل المصنّعين الأصليين إلى السحابة الإلكترونية وسائط متعددة. التطبيقات التي يرشّحها المصنّعون الأصليون للأجهزة فقط مؤهَّلة للمشاركة في هذا البرنامج لتصبح مقدّم وسائط سحابة إلكترونية في Android في الوقت الحالي. على كل يمكن للمصنّع الأصلي للجهاز ترشيح ما يصل إلى 3 تطبيقات. بعد الموافقة على هذه التطبيقات، يصبح من الممكن الوصول إليها لمزودي الوسائط السحابية على أي جهاز GMS يعمل بنظام Android مثبت.

يحتفظ Android بقائمة من جانب الخادم بجميع مقدمي خدمات السحابة الإلكترونية المؤهلين. كل مصنّع أصلي للجهاز اختيار مقدّم خدمات سحابة إلكترونية تلقائي باستخدام تراكب قابل للضبط. مرشّح أن تستوفي التطبيقات جميع المتطلبات الفنية وتجتاز جميع اختبارات الجودة. للتعلّم المزيد حول عملية البرنامج التجريبي لمقدم خدمات السحابة الإلكترونية للمصنّع الأصلي للجهاز المتطلبات، يُرجى إكمال نموذج الاستعلام.

تحديد ما إذا كنت بحاجة إلى إنشاء موفِّر وسائط على السحابة الإلكترونية

يهدف مقدّمو خدمات الوسائط في السحابة الإلكترونية إلى أن يكونوا تطبيقات أو خدمات تعمل كجهات اتصال للمستخدمين. المصدر الأساسي للاحتفاظ بنسخة احتياطية من الصور والفيديوهات واستردادها من السحابة الإلكترونية. إذا كان تطبيقك يحتوي على مكتبة من المحتوى المفيد، ولكن لا يتم استخدامه عادةً حل لتخزين الصور، نقترح عليك إنشاء موفِّر للمستندات بدلاً من ذلك.

مقدّم خدمات سحابة إلكترونية نشط واحد لكل ملف شخصي

يمكن أن يتوفر مقدم خدمة وسائط سحابية واحد على الأكثر في كل مرة لكل نظام تشغيل Android بك. يمكن للمستخدمين إزالة مقدّم الوسائط السحابية المحدَّد أو تغييره. التطبيق في أي وقت من خلال إعدادات "أداة اختيار الصور".

ستحاول "أداة اختيار الصور" من Android تلقائيًا اختيار مقدّم خدمات السحابة الإلكترونية تلقائيًا.

  • فإذا كان هناك مقدّم خدمات سحابية مؤهّل واحد فقط على الجهاز، سيتم يتم تحديده تلقائيًا كمقدّم الخدمة الحالي.
  • إذا كان هناك أكثر من مقدّم خدمات سحابة إلكترونية مؤهّل على الجهاز تتطابق مع الإعدادات التلقائية التي اختارها المصنّع الأصلي للجهاز، سيتم بعد ذلك اختيار التطبيق الذي اختاره المصنّع الأصلي للجهاز.

  • إذا كان هناك أكثر من مقدّم خدمات سحابة إلكترونية مؤهل على الجهاز، ولم يتم تضمين أي من تتطابق مع الإعدادات التلقائية التي اختارها المصنّع الأصلي للجهاز، لن يتم اختيار أي تطبيق.

إنشاء مقدّم خدمات السحابة الإلكترونية

يوضِّح الرسم البياني التالي تسلسل الأحداث قبل وأثناء جلسة اختيار صورة بين تطبيق Android وأداة اختيار الصور على Android MediaProvider للجهاز المحلي وCloudMediaProvider.

مخطط تسلسلي يعرض مسار الانتقال من أداة اختيار الصور إلى مقدّم خدمات وسائط السحابة الإلكترونية
الشكل 1: مخطّط بياني لتسلسل الأحداث خلال جلسة اختيار صورة
  1. ويعمل النظام على إعداد مقدّم خدمات السحابة الإلكترونية المفضّل للمستخدم بشكل دوري يزامن البيانات الوصفية للوسائط مع الواجهة الخلفية "أداة اختيار الصور" على Android.
  2. عند تشغيل تطبيق Android لأداة اختيار الصور، قبل عرض صورة مدمجة أو شبكة العناصر في السحابة الإلكترونية للمستخدم، تعمل "أداة اختيار الصور" على إنشاء محتوى حساس لوقت الاستجابة مزامنة إضافية مع مقدّم خدمات السحابة الإلكترونية لضمان عرض أحدث النتائج قدر الإمكان. بعد تلقي رد، أو عند الوصول إلى الموعد النهائي، تعرض شبكة "أداة اختيار الصور" الآن جميع الصور التي يمكن الوصول إليها، مع دمج الصور المخزَّنة على جهازك باستخدام تلك التي تمت مزامنتها من السحابة الإلكترونية.
  3. أثناء تنقُّل المستخدم، تجلب "أداة اختيار الصور" الصور المصغّرة للوسائط من مقدّم خدمات الوسائط السحابية لعرضها في واجهة المستخدم.
  4. عندما يكمل المستخدم الجلسة وتتضمن النتائج وسائط سحابية عنصر، فسيطلب "أداة اختيار الصور" واصفات ملفات للمحتوى، ثم ينشئ معرف موارد منتظم (URI)، ويمنح إمكانية الوصول إلى الملف لتطبيق الاتصال.
  5. يمكن للتطبيق الآن فتح عنوان URI ولديه إذن بالقراءة فقط في الوسائط. المحتوى. يتم تلقائيًا إخفاء البيانات الوصفية الحسّاسة. أداة اختيار الصور نظام ملفات FUSE لتنسيق تبادل البيانات بين تطبيق Android ومزوّد الوسائط السحابية.

المشاكل الشائعة

فيما يلي بعض الاعتبارات المهمة التي يجب وضعها في الاعتبار عند التفكير في التنفيذ:

تجنُّب الملفات المكرّرة

وبما أنّ أداة اختيار الصور في Android لا تتوفّر بها أي طريقة لفحص حالة وسائط السحابة الإلكترونية، يجب أن يوفّر "CloudMediaProvider" القيمة "MEDIA_STORE_URI" في المؤشر أي ملف موجود في السحابة الإلكترونية وعلى الجهاز المحلي على حد سواء، ستظهر للمستخدم ملفات مكرَّرة في "أداة اختيار الصور".

تحسين أحجام الصور لعرض المعاينة

من المهم جدًا ألا يكون الملف المعروض من onOpenPreview كاملاً بدرجة الدقة وتتوافق مع Size المطلوبة. الصورة كبيرة جدًا أوقات التحميل في واجهة المستخدم، وقد يتم تقسيم الصورة الصغيرة جدًا أو غير واضحة بناءً على حجم شاشة الجهاز.

التعامل مع الاتجاه الصحيح

إذا كانت الصور المصغّرة التي تم عرضها في onOpenPreview لا تحتوي على بيانات EXIF، سيتم يجب إرجاعها في الاتجاه الصحيح لتجنّب تدوير الصور المصغَّرة بشكل غير صحيح في شبكة المعاينة.

منع الوصول غير المُصرح به

تحقق من MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION قبل عرض البيانات إلى المتصل من ContentProvider. سيؤدي هذا الإجراء إلى منع التطبيقات غير المصرّح بها والوصول إلى بيانات السحابة.

فئة CloudMediaProvider

مشتقة من android.content.ContentProvider، وCloudMediaProvider تتضمن الفئة طرقًا مثل تلك المعروضة في المثال التالي:

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);
}

فئة CloudMediaProvider استخدم

بالإضافة إلى فئة تنفيذ CloudMediaProvider الأساسية، تتضمن "أداة اختيار الصور" من Android صفًا CloudMediaProviderContract. توضّح هذه الفئة إمكانية التشغيل التفاعلي بين أداة اختيار الصور والسحابة الإلكترونية. ومقدّم خدمات الوسائط، ويشمل جوانب مثل MediaCollectionInfo وعمليات المزامنة المتوقعة Cursor عمود و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

يستخدم نظام التشغيل الطريقة onGetMediaCollectionInfo() من أجل لتقييم صلاحية عناصر الوسائط المخزّنة مؤقتًا على السحابة الإلكترونية وتحديد المزامنة مع مزوّد الوسائط السحابية. نظرًا لإمكانية تكرار من خلال نظام التشغيل، يتم اعتبار onGetMediaCollectionInfo() بالغ الأهمية من الضروري تجنب العمليات الطويلة المدى أو والتأثيرات التي قد تؤثر سلبًا على الأداء. يخزِّن نظام التشغيل ذاكرة التخزين المؤقت. الردود السابقة من هذه الطريقة وتقارنها بالردود اللاحقة لتحديد الإجراءات المناسبة.

Kotlin

abstract fun onGetMediaCollectionInfo(extras: Bundle): Bundle

Java

@NonNull
public abstract Bundle onGetMediaCollectionInfo(@NonNull Bundle extras);

تحتوي حزمة MediaCollectionInfo التي تم عرضها على الثوابت التالية:

onQueryMedia

تُستخدَم الطريقة onQueryMedia() لتعبئة شبكة الصور الرئيسية في "أداة اختيار الصور" في مجموعة متنوعة من طرق العرض. قد تكون هذه المكالمات حسّاسة لوقت الاستجابة، كجزء من مزامنة استباقية للخلفية أو أثناء "أداة اختيار الصور" الجلسات عندما تكون هناك حالة مزامنة كاملة أو تزايدية مطلوبة. أداة اختيار الصور واجهة المستخدم لن تنتظر إلى أجل غير مسمى استجابة لعرض النتائج، مهلة هذه الطلبات لأغراض واجهة المستخدم. مؤشر الماوس الذي تم إرجاعه ستحاول معالجتها في قاعدة بيانات أداة اختيار الصور في المستقبل الجلسات.

تؤدي هذه الطريقة إلى عرض علامة Cursor تمثّل جميع ملفات الوسائط في الوسائط. مجموعة تمت تصفيتها اختياريًا حسب العناصر الإضافية المتوفرة وفرزها عكسيًا ترتيب زمني لـ MediaColumns#DATE_TAKEN_MILLIS (أحدث العناصر أولاً).

تشمل حزمة CloudMediaProviderContract التي تم إرجاعها ما يلي: الثوابت:

على موفِّر الوسائط السحابية تحديد CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID كجزء من المبلغ الذي تم إرجاعه Bundle يؤدي عدم ضبط هذا الخيار إلى إلغاء صلاحية Cursor التي تم عرضها. في حال حذف أن يكون مزود الوسائط السحابية قد تعامل مع أي فلاتر في الميزات الإضافية المتوفرة، فيجب إضافة إلى ContentResolver#EXTRA_HONORED_ARGS كجزء من الدالة التي تم إرجاعها Cursor#setExtras

onQueryDeletedMedia

يتم استخدام الطريقة onQueryDeletedMedia() لضمان حذف العناصر في تمت إزالة حساب السحابة الإلكترونية بشكل صحيح من واجهة مستخدم "أداة اختيار الصور". بسبب الحساسية المحتملة لوقت الاستجابة، فقد يتم بدء هذه المكالمات كجزء من:

  • المزامنة الاستباقية في الخلفية
  • جلسات "أداة اختيار الصور" (عندما تكون هناك حالة مزامنة كاملة أو تزايدية)

تعطي واجهة المستخدم لأداة اختيار الصور الأولوية لتجربة المستخدم سريعة الاستجابة لن تنتظر إلى أجل غير مسمى تلقي رد. للحفاظ على التفاعلات السلسة، المهلات النهائية. ستتم معالجة أي رسائل Cursor تم إرجاعها. في قاعدة بيانات أداة اختيار الصور للجلسات المستقبلية.

تعرض هذه الطريقة علامة Cursor التي تمثّل جميع ملفات الوسائط المحذوفة في مجموعة الوسائط بأكملها ضمن إصدار الموفر الحالي وفقًا لما يعرضه onGetMediaCollectionInfo() يمكن فلترة هذه العناصر اختياريًا باستخدام العناصر الإضافية. على موفِّر الوسائط السحابية إعداد CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID كجزء من المبلغ الذي تم إرجاعه Cursor#setExtras يؤدي عدم ضبط هذا الإعداد إلى خطأ وإلى إلغاء صلاحية Cursor. في حال حذف كان المزود قد تعامل مع أي فلاتر في الإضافات المتوفرة، فيجب إضافة المفتاح إلى ContentResolver#EXTRA_HONORED_ARGS.

ألبوم onQueryAlbums

تُستخدَم الطريقة onQueryAlbums() لاسترجاع قائمة بألبومات السحابة الإلكترونية التي متاحة لدى مزود الخدمة السحابية والبيانات الوصفية المرتبطة بها. عرض يمكنك CloudMediaProviderContract.AlbumColumns للاطّلاع على تفاصيل إضافية.

تؤدي هذه الطريقة إلى عرض رمز Cursor الذي يمثّل كل عناصر الألبوم في الوسائط. مجموعة تمت تصفيتها اختياريًا حسب العناصر الإضافية المتوفرة وفرزها عكسيًا ترتيب زمني بقيمة AlbumColumns#DATE_TAKEN_MILLIS، أحدث العناصر أولاً. على موفِّر الوسائط السحابية إعداد CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID كجزء من المبلغ الذي تم إرجاعه Cursor يؤدي عدم ضبط هذا الخيار إلى إلغاء صلاحية Cursor التي تم عرضها. في حال حذف كان المزود قد تعامل مع أي فلاتر في الإضافات المتوفرة، فيجب إضافة المفتاح إلى ContentResolver#EXTRA_HONORED_ARGS كجزء من Cursor الذي تم إرجاعه.

onOpenMedia

يجب أن تعرض الطريقة onOpenMedia() الوسائط بالحجم الكامل التي تم تحديدها بواسطة mediaId المقدّمة. إذا كانت هذه الطريقة تمنع تنزيل المحتوى إلى جهاز، يجب فحص CancellationSignal المقدّم بشكل دوري لإلغائه. الطلبات المهملة.

onOpenPreview

من المفترض أن تعرض الطريقة onOpenPreview() صورة مصغّرة للصورة المقدَّمة. size لعنصر المعرّف MediaId المقدَّم. يجب أن تكون الصورة المصغّرة في قسم CloudMediaProviderContract.MediaColumns#MIME_TYPE الأصلية ومن المتوقع درجة دقة أقل بكثير من العنصر الذي يعرضه onOpenMedia. إذا كانت هذه الطريقة محظور أثناء تنزيل المحتوى على الجهاز، فيجب عليك بشكل دوري يمكنك التحقّق من CancellationSignal المقدَّم لإلغاء الطلبات التي تم تجاهلها.

onCreateCloudMediaSurfaceController

يجب أن تعرض الطريقة onCreateCloudMediaSurfaceController() CloudMediaSurfaceController المستخدَم لعرض معاينة عناصر الوسائط null إذا لم يكن عرض المعاينة متاحًا.

يدير CloudMediaSurfaceController عرض معاينة عناصر الوسائط على حالات معيّنة من Surface. من المفترض أن تكون طرق هذه الفئة غير متزامن، ويجب ألا يتم حظره من خلال إجراء أي عملية ثقيلة. أغنية واحدة مثيل CloudMediaSurfaceController مسؤول عن عرض العديد ملفات وسائط مرتبطة بمساحات عرض متعددة

تتوافق CloudMediaSurfaceController مع القائمة التالية من عمليات الاستدعاء في مراحل النشاط: