Tạo nhà cung cấp nội dung nghe nhìn trên đám mây cho Android

Nhà cung cấp nội dung nghe nhìn trên đám mây cung cấp thêm nội dung nghe nhìn trên đám mây cho Android công cụ chọn ảnh. Người dùng có thể chọn ảnh hoặc video do nhà cung cấp nội dung nghe nhìn trên đám mây khi một ứng dụng dùng ACTION_PICK_IMAGES hoặc ACTION_GET_CONTENT để yêu cầu người dùng cung cấp tệp đa phương tiện. Nội dung nghe nhìn trên đám mây cũng có thể cung cấp thông tin về đĩa nhạc. Mọi người có thể duyệt xem thông tin này trong Công cụ chọn ảnh của Android.

Trước khi bắt đầu

Hãy cân nhắc các mục sau trước khi bắt đầu xây dựng nền tảng đám mây nhà cung cấp nội dung nghe nhìn của mình.

Điều kiện sử dụng

Android đang chạy một chương trình thí điểm để cho phép các ứng dụng do OEM chỉ định trở thành nền tảng đám mây nhà cung cấp nội dung đa phương tiện. Chỉ những ứng dụng do OEM chỉ định mới đủ điều kiện tham gia chương trình này để trở thành nhà cung cấp nội dung đa phương tiện trên đám mây cho Android tại thời điểm này. Một OEM có thể chỉ định tối đa 3 ứng dụng. Sau khi được phê duyệt, bạn có thể truy cập các ứng dụng này dưới dạng nhà cung cấp nội dung nghe nhìn trên đám mây trên bất kỳ thiết bị hỗ trợ GMS Android nào có hỗ trợ .

Android duy trì một danh sách phía máy chủ gồm tất cả các nhà cung cấp dịch vụ đám mây đủ điều kiện. Từng OEM (Nhà sản xuất thiết bị gốc) có thể chọn một nhà cung cấp dịch vụ đám mây mặc định bằng cách sử dụng một lớp phủ có thể định cấu hình. Được đề cử ứng dụng phải đáp ứng mọi yêu cầu kỹ thuật và vượt qua mọi bài kiểm tra chất lượng. Để tìm hiểu tìm hiểu thêm về quy trình của chương trình thí điểm nhà cung cấp nội dung đa phương tiện trên đám mây của OEM và hãy hoàn tất biểu mẫu yêu cầu.

Quyết định xem bạn có cần tạo một nhà cung cấp nội dung nghe nhìn trên đám mây

Nhà cung cấp nội dung nghe nhìn trên đám mây là những ứng dụng hoặc dịch vụ hoạt động như một người dùng nguồn chính để sao lưu và truy xuất ảnh cũng như video từ đám mây. Nếu ứng dụng của bạn có một thư viện nội dung hữu ích nhưng thư viện này thường không được dùng làm giải pháp lưu trữ ảnh, bạn nên cân nhắc việc tạo một trình cung cấp tài liệu thay thế.

Một nhà cung cấp dịch vụ đám mây đang hoạt động cho mỗi hồ sơ

Có thể có tối đa một nhà cung cấp nội dung nghe nhìn trên đám mây đang hoạt động tại một thời điểm cho mỗi Android hồ sơ. Người dùng có thể xoá hoặc thay đổi nhà cung cấp nội dung nghe nhìn trên đám mây mà họ đã chọn của bạn bất cứ lúc nào từ cài đặt công cụ chọn ảnh.

Theo mặc định, công cụ chọn ảnh của Android sẽ tìm cách chọn một nhà cung cấp dịch vụ đám mây tự động.

  • Nếu chỉ có một nhà cung cấp dịch vụ đám mây đủ điều kiện trên thiết bị, thì ứng dụng đó sẽ đã tự động được chọn làm nhà cung cấp hiện tại.
  • Nếu trên thiết bị có nhiều nhà cung cấp dịch vụ đám mây đủ điều kiện và một trong chúng khớp với ứng dụng mặc định mà OEM đã chọn, thì ứng dụng do OEM chọn sẽ được chọn.

  • Nếu trên thiết bị có nhiều nhà cung cấp dịch vụ đám mây đủ điều kiện và không có chúng khớp với chế độ mặc định mà OEM đã chọn, thì sẽ không có ứng dụng nào được chọn.

Xây dựng nhà cung cấp nội dung nghe nhìn trên đám mây

Sơ đồ dưới đây minh hoạ trình tự của các sự kiện cả trước và trong khi một phiên chọn ảnh giữa ứng dụng Android, công cụ chọn ảnh của Android, MediaProvider của thiết bị cục bộ và CloudMediaProvider.

Sơ đồ trình tự cho thấy quy trình từ công cụ chọn ảnh đến nhà cung cấp nội dung nghe nhìn trên đám mây
Hình 1: Sơ đồ trình tự sự kiện trong một phiên lựa chọn ảnh.
  1. Hệ thống sẽ khởi chạy nhà cung cấp dịch vụ đám mây mà người dùng ưu tiên và định kỳ đồng bộ hoá siêu dữ liệu đa phương tiện vào phần phụ trợ công cụ chọn ảnh của Android.
  2. Khi một ứng dụng Android chạy công cụ chọn ảnh, trước khi hiển thị một ảnh đã hợp nhất trên máy hoặc lưới mục trên đám mây cho người dùng, công cụ chọn ảnh sẽ thực hiện tính năng nhạy cảm với độ trễ đồng bộ hoá gia tăng với nhà cung cấp dịch vụ đám mây để đảm bảo kết quả luôn được cập nhật nhất có thể. Sau khi nhận được phản hồi hoặc khi đến thời hạn, Lưới công cụ chọn ảnh hiện hiển thị tất cả ảnh có thể truy cập, kết hợp những ảnh đã lưu được đồng bộ hoá từ đám mây trên thiết bị của bạn.
  3. Trong khi người dùng cuộn, công cụ chọn ảnh sẽ tìm nạp hình thu nhỏ đa phương tiện từ trên đám mây để hiển thị trong giao diện người dùng.
  4. Khi người dùng hoàn tất phiên và kết quả bao gồm một nội dung nghe nhìn trên đám mây công cụ chọn ảnh yêu cầu mã mô tả tệp cho nội dung, tạo ra một URI và cấp quyền truy cập vào tệp cho ứng dụng gọi.
  5. Ứng dụng này hiện có thể mở URI và có quyền truy cập chỉ đọc vào nội dung nghe nhìn . Theo mặc định, siêu dữ liệu nhạy cảm sẽ bị loại bỏ. Công cụ chọn ảnh tận dụng hệ thống tệp FUSE để điều phối trao đổi dữ liệu giữa Ứng dụng Android và nhà cung cấp nội dung nghe nhìn trên đám mây.

Các vấn đề thường gặp

Sau đây là một số điểm quan trọng bạn cần lưu ý khi cân nhắc triển khai:

Tránh các tệp trùng lặp

Vì công cụ chọn ảnh của Android không có cách nào để kiểm tra trạng thái của phương tiện trên đám mây, CloudMediaProvider cần cung cấp MEDIA_STORE_URI trong con trỏ hàng của bất kỳ tệp nào tồn tại cả trên đám mây và trên thiết bị cục bộ hoặc người dùng sẽ thấy các tệp trùng lặp trong công cụ chọn ảnh.

Tối ưu hoá kích thước hình ảnh để xem trước

Tệp mà onOpenPreview trả về chưa phải là tệp đầy đủ hình ảnh có độ phân giải và tuân thủ Size được yêu cầu. Hình ảnh quá lớn sẽ phải mất thời gian tải trong giao diện người dùng và hình ảnh quá nhỏ có thể bị tạo pixel hoặc bị mờ dựa trên kích thước màn hình của thiết bị.

Xử lý đúng hướng

Nếu hình thu nhỏ được trả về trong onOpenPreview không chứa dữ liệu EXIF, chúng phải được trả về theo đúng hướng để tránh hình thu nhỏ bị xoay không chính xác trong lưới xem trước.

Ngăn chặn truy cập trái phép

Hãy kiểm tra MANAGE_CLOUD_MEDIA_PROVIDERS_PERMISSION trước khi trả dữ liệu về phương thức gọi qua ContentProvider. Điều này sẽ ngăn các ứng dụng trái phép truy cập vào dữ liệu đám mây.

Lớp CloudMediaProvider

Bắt nguồn từ android.content.ContentProvider, CloudMediaProvider bao gồm các phương thức như các phương thức được minh hoạ trong ví dụ sau:

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

Lớp CloudMediaProviderContract

Ngoài lớp triển khai CloudMediaProvider chính, lớp Công cụ chọn ảnh của Android kết hợp một lớp CloudMediaProviderContract. Lớp này trình bày khả năng tương tác giữa công cụ chọn ảnh và đám mây nhà cung cấp nội dung đa phương tiện, bao gồm các khía cạnh như MediaCollectionInfo cho hoạt động đồng bộ hoá, Cursor cột dự kiến và Bundle cột bổ sung.

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

Hệ điều hành sử dụng phương thức onGetMediaCollectionInfo() để đánh giá tính hợp lệ của các mục nội dung đa phương tiện trên đám mây được lưu vào bộ nhớ đệm và xác định những nội dung cần thiết đồng bộ hoá với nhà cung cấp nội dung đa phương tiện trên đám mây. Do có khả năng xảy ra thường xuyên lệnh gọi theo hệ điều hành, onGetMediaCollectionInfo() sẽ được xem là quan trọng đối với hiệu suất; bạn cần tránh các hoạt động diễn ra lâu dài hoặc có thể tác động tiêu cực đến hiệu suất. Bộ nhớ đệm của hệ điều hành các phản hồi trước đó từ phương thức này rồi so sánh với các phản hồi tiếp theo để xác định hành động thích hợp.

Kotlin

abstract fun onGetMediaCollectionInfo(extras: Bundle): Bundle

Java

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

Gói MediaCollectionInfo được trả về bao gồm các hằng số sau:

onQueryMedia

Phương thức onQueryMedia() được dùng để điền vào lưới ảnh chính công cụ chọn ảnh trong nhiều chế độ xem. Các cuộc gọi này có thể nhạy cảm về độ trễ và có thể được gọi trong quá trình đồng bộ hoá chủ động ở chế độ nền hoặc trong công cụ chọn ảnh khi cần trạng thái đồng bộ hóa đầy đủ hoặc tăng dần. Công cụ chọn ảnh giao diện người dùng sẽ không đợi phản hồi hiển thị kết quả vô thời hạn, và có thể hết thời gian chờ các yêu cầu này cho mục đích giao diện người dùng. Con trỏ được trả về sẽ vẫn cố được xử lý vào cơ sở dữ liệu của công cụ chọn ảnh trong tương lai phiên hoạt động.

Phương thức này trả về một Cursor đại diện cho tất cả mục nội dung đa phương tiện trong nội dung đa phương tiện bộ sưu tập được lọc tuỳ ý theo các phần bổ sung đã cho và sắp xếp ngược lại trình tự thời gian của MediaColumns#DATE_TAKEN_MILLIS (các mục gần đây nhất ).

Gói CloudMediaProviderContract được trả về bao gồm những thông tin sau hằng số:

Nhà cung cấp nội dung nghe nhìn trên đám mây phải đặt CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID thuộc giá trị trả về Bundle Nếu không thiết lập thì đây là lỗi và vô hiệu hoá Cursor được trả về. Nếu nhà cung cấp nội dung đa phương tiện trên đám mây đã xử lý bất kỳ bộ lọc nào trong các ứng dụng bổ sung được cung cấp, thì nhà cung cấp này phải thêm khoá cho ContentResolver#EXTRA_HONORED_ARGS như một phần của dữ liệu được trả về Cursor#setExtras

onQueryXoáMedia

Phương thức onQueryDeletedMedia() được dùng để đảm bảo các mục đã xoá trong Cloud đã bị xoá đúng cách khỏi giao diện người dùng công cụ chọn ảnh. Do độ nhạy có thể có với độ trễ, các lệnh gọi này có thể được thực hiện như một phần của:

  • Đồng bộ hoá chủ động ở chế độ nền
  • Phiên sử dụng công cụ chọn ảnh (khi cần trạng thái đồng bộ hoá đầy đủ hoặc tăng dần)

Giao diện người dùng của công cụ chọn ảnh ưu tiên trải nghiệm thích ứng và sẽ không đợi phản hồi vô thời hạn. Để đảm bảo tương tác suôn sẻ, có thể hết thời gian chờ. Mọi Cursor đã trả lại vẫn sẽ cố gắng được xử lý vào cơ sở dữ liệu của công cụ chọn ảnh cho các phiên trong tương lai.

Phương thức này trả về một Cursor đại diện cho tất cả mục nội dung đa phương tiện đã xoá trong toàn bộ bộ sưu tập đa phương tiện trong phiên bản trình cung cấp hiện tại được trả về bởi onGetMediaCollectionInfo() Bạn có thể tuỳ ý lọc các mục này theo phần bổ sung. Nhà cung cấp nội dung nghe nhìn trên đám mây phải đặt CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID thuộc giá trị trả về Cursor#setExtras Nếu không thiết lập thì đây là lỗi và khiến Cursor mất hiệu lực. Nếu nhà cung cấp đã xử lý bất kỳ bộ lọc nào trong các ứng dụng bổ sung được cung cấp thì phải thêm khoá vào ContentResolver#EXTRA_HONORED_ARGS.

onQueryAlbums

Phương thức onQueryAlbums() được dùng để tìm nạp danh sách album trên đám mây đều có trong nhà cung cấp dịch vụ đám mây và siêu dữ liệu liên quan. Xem CloudMediaProviderContract.AlbumColumns để biết thêm thông tin.

Phương thức này trả về một Cursor đại diện cho tất cả các mục trong album trong nội dung nghe nhìn bộ sưu tập được lọc tuỳ ý theo các phần bổ sung đã cho và sắp xếp ngược lại thứ tự thời gian của AlbumColumns#DATE_TAKEN_MILLIS , các mục gần đây nhất đầu tiên. Nhà cung cấp nội dung nghe nhìn trên đám mây phải đặt CloudMediaProviderContract#EXTRA_MEDIA_COLLECTION_ID thuộc giá trị trả về Cursor Nếu không thiết lập thì đây là lỗi và vô hiệu hoá Cursor được trả về. Nếu nhà cung cấp đã xử lý bất kỳ bộ lọc nào trong các ứng dụng bổ sung được cung cấp thì phải thêm khoá vào ContentResolver#EXTRA_HONORED_ARGS như một phần của Cursor được trả về.

onOpenMedia

Phương thức onOpenMedia() sẽ trả về nội dung nghe nhìn có kích thước đầy đủ được xác định theo mediaId được cung cấp. Nếu phương thức này chặn trong khi tải nội dung xuống bạn nên kiểm tra định kỳ CancellationSignal được cung cấp để huỷ yêu cầu bị bỏ qua.

onOpenPreview

Phương thức onOpenPreview() sẽ trả về hình thu nhỏ của size cho mục của mediaId đã cung cấp. Hình thu nhỏ phải ở CloudMediaProviderContract.MediaColumns#MIME_TYPE ban đầu và dự kiến sẽ có độ phân giải thấp hơn nhiều so với mục do onOpenMedia trả về. Nếu phương thức này bị chặn trong khi tải nội dung xuống thiết bị, bạn nên định kỳ hãy kiểm tra CancellationSignal đã cung cấp để huỷ các yêu cầu bị bỏ qua.

onCreateCloudMediaSurfaceController

Phương thức onCreateCloudMediaSurfaceController() sẽ trả về một giá trị CloudMediaSurfaceController dùng để hiển thị bản xem trước của các mục nội dung đa phương tiện, hoặc null nếu tính năng kết xuất bản xem trước không được hỗ trợ.

CloudMediaSurfaceController quản lý quá trình hiển thị bản xem trước của các mục nội dung đa phương tiện trên các bản sao nhất định của Surface. Các phương thức của lớp này được dành để không đồng bộ và không được chặn bằng cách thực hiện bất kỳ thao tác lớn nào. Một Thực thể CloudMediaSurfaceController chịu trách nhiệm kết xuất nhiều các mục nội dung nghe nhìn liên kết với nhiều nền tảng.

CloudMediaSurfaceController hỗ trợ danh sách sau phương thức gọi lại trong vòng đời: