Bật tính năng Truyền cho ứng dụng Android

1. Tổng quan

Biểu trưng Google Cast

Lớp học lập trình này sẽ hướng dẫn bạn cách chỉnh sửa một ứng dụng video Android hiện có để truyền nội dung trên một thiết bị hỗ trợ Google Cast.

Google Cast là gì?

Google Cast cho phép người dùng truyền nội dung từ thiết bị di động sang TV. Sau đó, người dùng có thể sử dụng thiết bị di động làm điều khiển từ xa để phát nội dung đa phương tiện trên TV.

Google Cast SDK cho phép bạn mở rộng ứng dụng của mình để điều khiển TV hoặc hệ thống âm thanh. Cast SDK cho phép bạn thêm các thành phần giao diện người dùng cần thiết dựa trên Danh sách kiểm tra thiết kế Google Cast.

Danh sách kiểm tra thiết kế Google Cast được cung cấp để giúp trải nghiệm người dùng Cast đơn giản và có thể dự đoán được trên tất cả các nền tảng được hỗ trợ.

Chúng tôi sẽ xây dựng những gì?

Khi hoàn thành lớp học lập trình này, bạn sẽ có một ứng dụng video trên Android có thể truyền video tới thiết bị hỗ trợ Google Cast.

Kiến thức bạn sẽ học được

  • Cách thêm Google Cast SDK vào ứng dụng video mẫu.
  • Cách thêm nút Truyền để chọn thiết bị Google Cast.
  • Cách kết nối với thiết bị truyền và khởi chạy thiết bị nhận nội dung nghe nhìn.
  • Cách truyền video.
  • Cách thêm bộ điều khiển Cast Mini vào ứng dụng.
  • Cách hỗ trợ thông báo về nội dung nghe nhìn và chế độ điều khiển màn hình khoá.
  • Cách thêm tay điều khiển mở rộng.
  • Cách cung cấp lớp phủ giới thiệu.
  • Cách tuỳ chỉnh các tiện ích Truyền.
  • Cách tích hợp với Cast Connect

Bạn cần có

  • SDK Android mới nhất.
  • Android Studio phiên bản 3.2 trở lên
  • Một thiết bị di động chạy Android 4.1 trở lên Jelly Bean (API cấp 16).
  • Cáp dữ liệu USB để kết nối thiết bị di động với máy tính dùng để phát triển.
  • Thiết bị Google Cast như Chromecast hoặc Android TV được định cấu hình có quyền truy cập Internet.
  • TV hoặc màn hình có đầu vào HDMI.
  • Bạn cần phải có Chromecast có Google TV để kiểm thử việc tích hợp Cast Connect nhưng không bắt buộc phải cung cấp cho phần còn lại của Lớp học lập trình. Nếu bạn chưa có tài khoản này, hãy bỏ qua bước Thêm tính năng hỗ trợ Cast Connect ở cuối hướng dẫn này.

Trải nghiệm

  • Bạn cần có kiến thức về Kotlin và phát triển Android.
  • Bạn cũng cần có kiến thức trước về cách xem TV :)

Bạn sẽ sử dụng hướng dẫn này như thế nào?

Chỉ đọc qua Đọc và hoàn thành các bài tập

Bạn đánh giá trải nghiệm của mình trong quá trình tạo ứng dụng Android như thế nào?

Người mới bắt đầu Trung cấp Thành thạo

Bạn đánh giá thế nào về trải nghiệm của mình khi xem TV?

Người mới bắt đầu Trung cấp Thành thạo

2. Nhận mã mẫu

Bạn có thể tải tất cả mã mẫu xuống máy tính của mình...

rồi giải nén tệp zip đã tải xuống.

3. Chạy ứng dụng mẫu

biểu tượng một cặp la bàn

Trước tiên, hãy xem ứng dụng mẫu hoàn chỉnh trông như thế nào. Ứng dụng này là một trình phát video cơ bản. Người dùng có thể chọn một video trong danh sách rồi phát video đó trên thiết bị hoặc Truyền video đó tới thiết bị Google Cast.

Sau khi tải mã xuống, hướng dẫn sau đây sẽ mô tả cách mở và chạy ứng dụng mẫu đã hoàn chỉnh trong Android Studio:

Chọn Import Project (Nhập dự án) trên màn hình chào mừng hoặc lựa chọn trình đơn File > New > Import Project... (Tệp > Mới > Nhập dự án...).

Chọn thư mục biểu tượng thư mụcapp-done trong thư mục mã mẫu rồi nhấp vào OK.

Nhấp vào File > Nút "Sync Project with Gradle" (Đồng bộ hoá dự án với Gradle) trong Android Studio Sync Project with Gradle Files (Tệp > Đồng bộ hoá dự án với các tệp Gradle).

Bật tính năng gỡ lỗi qua USB trên thiết bị Android của bạn – trên Android 4.2 trở lên, màn hình Tuỳ chọn cho nhà phát triển sẽ bị ẩn theo mặc định. Để hiển thị số điện thoại, hãy chuyển đến phần Cài đặt > Giới thiệu về điện thoại rồi nhấn 7 lần vào Số bản dựng. Quay lại màn hình trước, chuyển đến Hệ thống > Nâng cao rồi nhấn vào Tuỳ chọn cho nhà phát triển ở gần dưới cùng, sau đó nhấn vào Gỡ lỗi qua USB để bật.

Cắm thiết bị Android rồi nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) trong Android Studio. Bạn sẽ thấy ứng dụng video có tên Truyền video xuất hiện sau vài giây.

Nhấp vào nút Truyền trong ứng dụng video và chọn thiết bị Google Cast của bạn.

Chọn một video và nhấp vào nút phát.

Video sẽ bắt đầu phát trên thiết bị Google Cast của bạn.

Bộ điều khiển mở rộng sẽ xuất hiện. Bạn có thể sử dụng nút phát/tạm dừng để điều khiển quá trình phát.

Quay lại danh sách video.

Một bộ điều khiển mini hiện đã hiển thị ở cuối màn hình. Hình minh hoạ một chiếc điện thoại Android đang chạy ứng dụng "Truyền video" với bộ điều khiển mini xuất hiện ở cuối màn hình

Nhấp vào nút tạm dừng trong bộ điều khiển thu nhỏ để tạm dừng video trên bộ thu. Nhấp vào nút phát trong bộ điều khiển thu nhỏ để tiếp tục phát lại video.

Nhấp vào nút trang chủ trên thiết bị di động. Kéo thông báo xuống và bạn sẽ thấy thông báo cho phiên Truyền.

Khoá điện thoại và khi mở khoá, bạn sẽ thấy thông báo trên màn hình khoá để điều khiển chế độ phát nội dung nghe nhìn hoặc dừng truyền.

Quay lại ứng dụng video rồi nhấp vào nút Truyền để dừng truyền trên thiết bị Google Cast.

Câu hỏi thường gặp

4. Chuẩn bị dự án khởi động

Hình minh hoạ chiếc điện thoại Android đang chạy ứng dụng "Truyền video"

Chúng tôi cần thêm tính năng hỗ trợ cho Google Cast vào ứng dụng ban đầu mà bạn tải xuống. Sau đây là một số thuật ngữ của Google Cast mà chúng ta sẽ sử dụng trong lớp học lập trình này:

  • một ứng dụng của người gửi chạy trên thiết bị di động hoặc máy tính xách tay,
  • một ứng dụng broadcast receiver chạy trên thiết bị Google Cast.

Giờ đây, bạn đã sẵn sàng xây dựng dựa trên dự án khởi đầu bằng Android Studio:

  1. Chọn thư mục biểu tượng thư mụcapp-start từ tệp tải xuống mã mẫu của bạn (Chọn Nhập dự án trên màn hình chào mừng hoặc tuỳ chọn trình đơn Tệp > Mới > Nhập dự án...).
  2. Nhấp vào nút Nút "Sync Project with Gradle" (Đồng bộ hoá dự án với Gradle) trong Android Studio Sync Project with Gradle Files (Đồng bộ hoá dự án với tệp Gradle).
  3. Nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng và khám phá giao diện người dùng.

Thiết kế ứng dụng

Ứng dụng này tìm nạp danh sách video qua một máy chủ web từ xa và cung cấp một danh sách để người dùng duyệt xem. Người dùng có thể chọn một video để xem chi tiết hoặc phát video trên thiết bị di động.

Ứng dụng này bao gồm hai hoạt động chính: VideoBrowserActivityLocalPlayerActivity. Để tích hợp chức năng Google Cast, các Hoạt động cần phải kế thừa từ AppCompatActivity hoặc thành phần mẹ FragmentActivity. Giới hạn này tồn tại vì chúng ta cần thêm MediaRouteButton (được cung cấp trong thư viện hỗ trợ MediaRouter) dưới dạng MediaRouteActionProvider và tính năng này chỉ hoạt động nếu hoạt động kế thừa từ các lớp nêu trên. Thư viện hỗ trợ MediaRouter phụ thuộc vào thư viện hỗ trợ AppCompat cung cấp các lớp cần thiết.

VideoBrowserActivity

Hoạt động này chứa một Fragment (VideoBrowserFragment). Danh sách này được một ArrayAdapter (VideoListAdapter) hỗ trợ. Danh sách video và siêu dữ liệu liên quan được lưu trữ trên máy chủ từ xa dưới dạng tệp JSON. AsyncTaskLoader (VideoItemLoader) tìm nạp JSON này rồi xử lý để tạo danh sách đối tượng MediaItem.

Đối tượng MediaItem tạo mô hình cho một video và siêu dữ liệu liên quan, chẳng hạn như tiêu đề, nội dung mô tả, URL của luồng, URL của hình ảnh hỗ trợ và Đoạn văn bản liên kết (dành cho phụ đề) (nếu có). Đối tượng MediaItem được truyền giữa các hoạt động, vì vậy MediaItem có các phương thức tiện ích để chuyển đổi đối tượng thành Bundle và ngược lại.

Khi tạo danh sách MediaItems, trình tải sẽ truyền danh sách đó đến VideoListAdapter, sau đó hiển thị danh sách MediaItems trong VideoBrowserFragment. Người dùng sẽ thấy một danh sách hình thu nhỏ video cùng với nội dung mô tả ngắn cho mỗi video. Khi bạn chọn một mục, MediaItem tương ứng sẽ được chuyển đổi thành Bundle và được truyền vào LocalPlayerActivity.

LocalPlayerActivity

Hoạt động này hiển thị siêu dữ liệu về một video cụ thể và cho phép người dùng phát video đó trên thiết bị di động.

Hoạt động này lưu trữ một VideoView, một số chế độ điều khiển nội dung nghe nhìn và một vùng văn bản để hiện nội dung mô tả của video đã chọn. Trình phát này bao phủ phần trên cùng của màn hình, chừa chỗ cho nội dung mô tả chi tiết về video bên dưới. Người dùng có thể phát/tạm dừng hoặc tìm cách phát lại trên thiết bị.

Phần phụ thuộc

Vì chúng ta đang sử dụng AppCompatActivity nên chúng ta cần có thư viện hỗ trợ AppCompat. Để quản lý danh sách video và nhận không đồng bộ hình ảnh cho danh sách, chúng ta đang sử dụng thư viện Volley.

Câu hỏi thường gặp

5. Thêm nút Truyền

Hình minh hoạ phần trên của điện thoại Android khi ứng dụng Truyền video đang chạy; nút Truyền xuất hiện ở góc trên bên phải màn hình

Ứng dụng hỗ trợ Cast hiển thị nút Truyền trong từng hoạt động của ứng dụng đó. Khi nhấp vào nút Truyền, bạn sẽ thấy danh sách các Thiết bị truyền mà người dùng có thể chọn. Nếu người dùng đang phát nội dung trên thiết bị gửi, thì thao tác chọn một Thiết bị truyền sẽ bắt đầu hoặc tiếp tục phát trên Thiết bị truyền đó. Bất cứ lúc nào trong phiên Truyền, người dùng có thể nhấp vào nút Truyền và dừng truyền ứng dụng của bạn tới Thiết bị truyền. Người dùng phải có khả năng kết nối hoặc ngắt kết nối khỏi Thiết bị truyền khi đang tham gia bất kỳ hoạt động nào của ứng dụng, như mô tả trong Danh sách kiểm tra thiết kế của Google Cast.

Phần phụ thuộc

Cập nhật tệp build.gradle của ứng dụng để thêm các phần phụ thuộc cần thiết của thư viện:

dependencies {
    implementation 'androidx.appcompat:appcompat:1.5.0'
    implementation 'androidx.mediarouter:mediarouter:1.3.1'
    implementation 'androidx.recyclerview:recyclerview:1.2.1'
    implementation 'com.google.android.gms:play-services-cast-framework:21.1.0'
    implementation 'com.android.volley:volley:1.2.1'
    implementation "androidx.core:core-ktx:1.8.0"
    implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
}

Đồng bộ hoá dự án để xác nhận các bản dựng dự án không gặp lỗi.

Khởi chạy

Khung Truyền có một đối tượng singleton toàn cầu là CastContext, đối tượng này sẽ điều phối tất cả các tương tác Truyền.

Bạn phải triển khai giao diện OptionsProvider để cung cấp CastOptions cần thiết để khởi chạy singleton CastContext. Tuỳ chọn quan trọng nhất là mã ứng dụng của bộ thu. Mã này được dùng để lọc kết quả khám phá thiết bị truyền và chạy ứng dụng nhận khi phiên Truyền bắt đầu.

Khi phát triển ứng dụng có hỗ trợ Cast, bạn phải đăng ký làm nhà phát triển Cast, sau đó lấy mã ứng dụng cho ứng dụng của mình. Đối với lớp học lập trình này, chúng ta sẽ sử dụng một mã ứng dụng mẫu.

Thêm tệp CastOptionsProvider.kt mới sau đây vào gói com.google.sample.cast.refplayer của dự án:

package com.google.sample.cast.refplayer

import android.content.Context
import com.google.android.gms.cast.framework.OptionsProvider
import com.google.android.gms.cast.framework.CastOptions
import com.google.android.gms.cast.framework.SessionProvider

class CastOptionsProvider : OptionsProvider {
    override fun getCastOptions(context: Context): CastOptions {
        return CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .build()
    }

    override fun getAdditionalSessionProviders(context: Context): List<SessionProvider>? {
        return null
    }
}

Bây giờ, hãy khai báo OptionsProvider trong thẻ "application" của tệp AndroidManifest.xml của ứng dụng:

<meta-data
    android:name="com.google.android.gms.cast.framework.OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.google.sample.cast.refplayer.CastOptionsProvider" />

Khởi chạy từng phần CastContext trong phương thức onCreate VideoBrowserActivity:

import com.google.android.gms.cast.framework.CastContext

private var mCastContext: CastContext? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.video_browser)
    setupActionBar()

    mCastContext = CastContext.getSharedInstance(this)
}

Thêm logic khởi động tương tự vào LocalPlayerActivity.

Nút truyền

Giờ đây, CastContext đã được khởi chạy, chúng ta cần thêm nút Truyền để cho phép người dùng chọn Thiết bị truyền. Nút Truyền được MediaRouteButton triển khai từ thư viện hỗ trợ MediaRouter. Giống như mọi biểu tượng hành động mà bạn có thể thêm vào hoạt động của mình (sử dụng ActionBar hoặc Toolbar), trước tiên, bạn cần thêm mục trong trình đơn tương ứng vào trình đơn của mình.

Chỉnh sửa tệp res/menu/browse.xml và thêm mục MediaRouteActionProvider trong trình đơn trước mục cài đặt:

<item
    android:id="@+id/media_route_menu_item"
    android:title="@string/media_route_menu_title"
    app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
    app:showAsAction="always"/>

Ghi đè phương thức onCreateOptionsMenu() của VideoBrowserActivity bằng cách sử dụng CastButtonFactory để kết nối MediaRouteButton với khung Truyền:

import com.google.android.gms.cast.framework.CastButtonFactory

private var mediaRouteMenuItem: MenuItem? = null

override fun onCreateOptionsMenu(menu: Menu): Boolean {
     super.onCreateOptionsMenu(menu)
     menuInflater.inflate(R.menu.browse, menu)
     mediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(getApplicationContext(), menu,
                R.id.media_route_menu_item)
     return true
}

Ghi đè onCreateOptionsMenu trong LocalPlayerActivity theo cách tương tự.

Nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động. Bạn sẽ thấy nút Truyền trong thanh thao tác của ứng dụng. Khi bạn nhấp vào nút đó, nút Truyền sẽ liệt kê các thiết bị Truyền trên mạng cục bộ của bạn. Tính năng khám phá thiết bị được CastContext quản lý tự động. Chọn Thiết bị truyền của bạn và ứng dụng nhận mẫu sẽ tải trên Thiết bị truyền. Bạn có thể di chuyển giữa hoạt động duyệt web và hoạt động của người chơi trên máy tính cũng như trạng thái của nút Truyền được đồng bộ hoá.

Chúng tôi chưa kết nối bất kỳ tính năng hỗ trợ nào cho tính năng phát nội dung nghe nhìn, vì vậy bạn chưa thể phát video trên Thiết bị truyền. Nhấp vào nút Truyền để ngắt kết nối.

6. Truyền nội dung video

Hình minh hoạ chiếc điện thoại Android đang chạy ứng dụng &quot;Truyền video&quot;

Chúng tôi sẽ mở rộng ứng dụng mẫu để phát video từ xa trên Thiết bị truyền. Để làm được việc đó, chúng ta cần theo dõi các sự kiện do Khung Truyền tạo ra.

Truyền nội dung đa phương tiện

Nhìn chung, nếu muốn phát nội dung nghe nhìn trên Thiết bị truyền, bạn cần làm những việc sau:

  1. Tạo đối tượng MediaInfo để tạo mô hình cho một mục nội dung đa phương tiện.
  2. Kết nối với Thiết bị truyền và chạy ứng dụng nhận.
  3. Tải đối tượng MediaInfo vào receiver (trình thu nhận) rồi phát nội dung đó.
  4. Theo dõi trạng thái nội dung nghe nhìn.
  5. Gửi lệnh phát đến thiết bị nhận dựa trên tương tác của người dùng.

Chúng ta đã thực hiện Bước 2 trong phần trước. Bước 3 rất dễ thực hiện bằng khung Truyền. Bước 1 giống như việc ánh xạ một đối tượng sang một đối tượng khác; MediaInfo là điều mà khung Truyền hiểu được và MediaItem là gói đóng gói của ứng dụng cho một mục nội dung đa phương tiện; chúng ta có thể dễ dàng liên kết MediaItem với MediaInfo.

Ứng dụng mẫu LocalPlayerActivity đã phân biệt giữa chế độ phát cục bộ và phát từ xa bằng cách sử dụng giá trị enum sau:

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

enum class PlaybackState {
    PLAYING, PAUSED, BUFFERING, IDLE
}

Trong lớp học lập trình này, điều quan trọng là bạn phải hiểu chính xác cách thức hoạt động của tất cả logic của trình phát mẫu. Bạn cần hiểu rằng trình phát nội dung đa phương tiện của ứng dụng sẽ phải được sửa đổi để nhận biết được hai vị trí phát theo cách tương tự nhau.

Hiện tại, trình phát cục bộ luôn ở trạng thái phát cục bộ vì chưa biết gì về trạng thái Truyền. Chúng ta cần cập nhật giao diện người dùng dựa trên quá trình chuyển đổi trạng thái diễn ra trong khung Truyền. Ví dụ: Nếu bắt đầu truyền, chúng ta cần dừng việc phát trên thiết bị và tắt một số chế độ điều khiển. Tương tự, nếu ngừng truyền khi đang thực hiện hoạt động này, chúng ta cần phải chuyển sang chế độ phát trên máy. Để xử lý việc đó, chúng ta cần theo dõi các sự kiện do khung Truyền tạo ra.

Quản lý phiên truyền

Đối với khung Truyền, phiên Truyền sẽ kết hợp các bước kết nối với thiết bị, khởi chạy (hoặc tham gia), kết nối với ứng dụng bộ thu và khởi chạy kênh điều khiển nội dung nghe nhìn nếu thích hợp. Kênh điều khiển nội dung nghe nhìn là cách Khung truyền gửi và nhận thông báo từ trình phát nội dung nghe nhìn của bộ thu.

Phiên Truyền sẽ tự động bắt đầu khi người dùng chọn một thiết bị từ nút Truyền và sẽ tự động dừng khi người dùng ngắt kết nối. Việc kết nối lại với phiên bộ thu do các vấn đề kết nối mạng cũng được SDK Truyền tự động xử lý.

Hãy thêm SessionManagerListener vào LocalPlayerActivity:

import com.google.android.gms.cast.framework.CastSession
import com.google.android.gms.cast.framework.SessionManagerListener
...

private var mSessionManagerListener: SessionManagerListener<CastSession>? = null
private var mCastSession: CastSession? = null
...

private fun setupCastListener() {
    mSessionManagerListener = object : SessionManagerListener<CastSession> {
        override fun onSessionEnded(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionResumed(session: CastSession, wasSuspended: Boolean) {
            onApplicationConnected(session)
        }

        override fun onSessionResumeFailed(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionStarted(session: CastSession, sessionId: String) {
            onApplicationConnected(session)
        }

        override fun onSessionStartFailed(session: CastSession, error: Int) {
            onApplicationDisconnected()
        }

        override fun onSessionStarting(session: CastSession) {}
        override fun onSessionEnding(session: CastSession) {}
        override fun onSessionResuming(session: CastSession, sessionId: String) {}
        override fun onSessionSuspended(session: CastSession, reason: Int) {}
        private fun onApplicationConnected(castSession: CastSession) {
            mCastSession = castSession
            if (null != mSelectedMedia) {
                if (mPlaybackState == PlaybackState.PLAYING) {
                    mVideoView!!.pause()
                    loadRemoteMedia(mSeekbar!!.progress, true)
                    return
                } else {
                    mPlaybackState = PlaybackState.IDLE
                    updatePlaybackLocation(PlaybackLocation.REMOTE)
                }
            }
            updatePlayButton(mPlaybackState)
            invalidateOptionsMenu()
        }

        private fun onApplicationDisconnected() {
            updatePlaybackLocation(PlaybackLocation.LOCAL)
            mPlaybackState = PlaybackState.IDLE
            mLocation = PlaybackLocation.LOCAL
            updatePlayButton(mPlaybackState)
            invalidateOptionsMenu()
       }
   }
}

Trong hoạt động của LocalPlayerActivity, chúng ta muốn được thông báo khi kết nối hoặc ngắt kết nối khỏi Thiết bị truyền để chúng ta có thể chuyển sang hoặc từ trình phát cục bộ. Xin lưu ý rằng khả năng kết nối có thể bị gián đoạn không chỉ do phiên bản ứng dụng đang chạy trên thiết bị di động của bạn, mà có thể bị gián đoạn bởi phiên bản khác của ứng dụng (hoặc ứng dụng khác) chạy trên thiết bị di động khác.

Bạn có thể truy cập vào phiên đang hoạt động bằng địa chỉ SessionManager.getCurrentSession(). Các phiên được tạo và tự động thu gọn theo tương tác của người dùng với hộp thoại Truyền.

Chúng ta cần đăng ký trình nghe phiên và khởi chạy một số biến mà chúng ta sẽ sử dụng trong hoạt động. Thay đổi phương thức LocalPlayerActivity onCreate thành:

import com.google.android.gms.cast.framework.CastContext
...

private var mCastContext: CastContext? = null
...

override fun onCreate(savedInstanceState: Bundle?) {
    ...
    mCastContext = CastContext.getSharedInstance(this)
    mCastSession = mCastContext!!.sessionManager.currentCastSession
    setupCastListener()
    ...
    loadViews()
    ...
    val bundle = intent.extras
    if (bundle != null) {
        ....
        if (shouldStartPlayback) {
              ....

        } else {
            if (mCastSession != null && mCastSession!!.isConnected()) {
                updatePlaybackLocation(PlaybackLocation.REMOTE)
            } else {
                updatePlaybackLocation(PlaybackLocation.LOCAL)
            }
            mPlaybackState = PlaybackState.IDLE
            updatePlayButton(mPlaybackState)
        }
    }
    ...
}

Đang tải nội dung nghe nhìn

Trong Cast SDK, RemoteMediaClient cung cấp một bộ API thuận tiện để quản lý việc phát nội dung đa phương tiện từ xa trên bộ thu. Đối với CastSession có hỗ trợ phát nội dung đa phương tiện, một thực thể của RemoteMediaClient sẽ được SDK tạo tự động. Bạn có thể truy cập lớp này bằng cách gọi phương thức getRemoteMediaClient() trên thực thể CastSession. Thêm các phương thức sau vào LocalPlayerActivity để tải video hiện được chọn trên receiver:

import com.google.android.gms.cast.framework.media.RemoteMediaClient
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaLoadOptions
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.common.images.WebImage
import com.google.android.gms.cast.MediaLoadRequestData

private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
    if (mCastSession == null) {
        return
    }
    val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
    remoteMediaClient.load( MediaLoadRequestData.Builder()
                .setMediaInfo(buildMediaInfo())
                .setAutoplay(autoPlay)
                .setCurrentTime(position.toLong()).build())
}

private fun buildMediaInfo(): MediaInfo? {
    val movieMetadata = MediaMetadata(MediaMetadata.MEDIA_TYPE_MOVIE)
    mSelectedMedia?.studio?.let { movieMetadata.putString(MediaMetadata.KEY_SUBTITLE, it) }
    mSelectedMedia?.title?.let { movieMetadata.putString(MediaMetadata.KEY_TITLE, it) }
    movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(0))))
    movieMetadata.addImage(WebImage(Uri.parse(mSelectedMedia!!.getImage(1))))
    return mSelectedMedia!!.url?.let {
        MediaInfo.Builder(it)
            .setStreamType(MediaInfo.STREAM_TYPE_BUFFERED)
            .setContentType("videos/mp4")
            .setMetadata(movieMetadata)
            .setStreamDuration((mSelectedMedia!!.duration * 1000).toLong())
            .build()
    }
}

Bây giờ, hãy cập nhật nhiều phương thức hiện có để sử dụng logic phiên Truyền nhằm hỗ trợ phát từ xa:

private fun play(position: Int) {
    startControllersTimer()
    when (mLocation) {
        PlaybackLocation.LOCAL -> {
            mVideoView!!.seekTo(position)
            mVideoView!!.start()
        }
        PlaybackLocation.REMOTE -> {
            mPlaybackState = PlaybackState.BUFFERING
            updatePlayButton(mPlaybackState)
            //seek to a new position within the current media item's new position 
            //which is in milliseconds from the beginning of the stream
            mCastSession!!.remoteMediaClient?.seek(position.toLong())
        }
        else -> {}
    }
    restartTrickplayTimer()
}
private fun togglePlayback() {
    ...
    PlaybackState.IDLE -> when (mLocation) {
        ...
        PlaybackLocation.REMOTE -> {
            if (mCastSession != null && mCastSession!!.isConnected) {
                loadRemoteMedia(mSeekbar!!.progress, true)
            }
        }
        else -> {}
    }
    ...
}
override fun onPause() {
    ...
    mCastContext!!.sessionManager.removeSessionManagerListener(
                mSessionManagerListener!!, CastSession::class.java)
}
override fun onResume() {
    Log.d(TAG, "onResume() was called")
    mCastContext!!.sessionManager.addSessionManagerListener(
            mSessionManagerListener!!, CastSession::class.java)
    if (mCastSession != null && mCastSession!!.isConnected) {
        updatePlaybackLocation(PlaybackLocation.REMOTE)
    } else {
        updatePlaybackLocation(PlaybackLocation.LOCAL)
    }
    super.onResume()
}

Đối với phương thức updatePlayButton, hãy thay đổi giá trị của biến isConnected:

private fun updatePlayButton(state: PlaybackState?) {
    ...
    val isConnected = (mCastSession != null
                && (mCastSession!!.isConnected || mCastSession!!.isConnecting))
    ...
}

Bây giờ, hãy nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động của bạn. Kết nối với Thiết bị truyền và bắt đầu phát video. Bạn sẽ thấy video đang phát trên bộ thu.

7. Bộ điều khiển mini

Danh sách kiểm tra thiết kế truyền yêu cầu tất cả các ứng dụng Truyền phải cung cấp một bộ điều khiển nhỏ xuất hiện khi người dùng rời khỏi trang nội dung hiện tại. Bộ điều khiển mini cung cấp quyền truy cập tức thì và lời nhắc hiển thị cho phiên Truyền hiện tại.

Hình minh hoạ phần dưới cùng của chiếc điện thoại Android, cho thấy trình phát thu nhỏ trong ứng dụng Cast Videos

SDK truyền cung cấp khung hiển thị tuỳ chỉnh, MiniControllerFragment, có thể được thêm vào tệp bố cục ứng dụng của các hoạt động mà bạn muốn hiển thị bộ điều khiển thu nhỏ.

Thêm phần định nghĩa mảnh dưới đây vào cuối cả res/layout/player_activity.xmlres/layout/video_browser.xml:

<fragment
    android:id="@+id/castMiniController"
    android:layout_width="fill_parent"
    android:layout_height="wrap_content"
    android:layout_alignParentBottom="true"
    android:visibility="gone"
    class="com.google.android.gms.cast.framework.media.widget.MiniControllerFragment"/>

Nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng và truyền một video. Khi quá trình phát bắt đầu trên bộ thu, bạn sẽ thấy bộ điều khiển thu nhỏ xuất hiện ở cuối mỗi hoạt động. Bạn có thể điều khiển tính năng phát từ xa bằng tay điều khiển mini. Nếu bạn chuyển giữa hoạt động duyệt web và hoạt động của người chơi trên máy, thì trạng thái tay điều khiển thu nhỏ sẽ luôn đồng bộ với trạng thái phát nội dung nghe nhìn của trình thu nhận.

8. Thông báo và màn hình khoá

Danh sách kiểm tra thiết kế Google Cast yêu cầu ứng dụng của người gửi triển khai các chức năng điều khiển nội dung nghe nhìn từ thông báomàn hình khoá.

Hình minh hoạ một chiếc điện thoại Android cho thấy các nút điều khiển nội dung nghe nhìn trong khu vực thông báo

Cast SDK cung cấp một MediaNotificationService để giúp ứng dụng của người gửi tạo các chế độ điều khiển nội dung nghe nhìn cho thông báo và màn hình khoá. Dịch vụ được tự động hợp nhất vào tệp kê khai của ứng dụng bằng gradle.

MediaNotificationService sẽ chạy ở chế độ nền khi người gửi đang truyền và sẽ hiển thị thông báo kèm theo hình thu nhỏ và siêu dữ liệu về nội dung truyền hiện tại, nút phát/tạm dừng và nút dừng.

Bạn có thể bật các chế độ điều khiển thông báo và màn hình khoá bằng CastOptions khi khởi tạo CastContext. Các chế độ điều khiển nội dung nghe nhìn cho thông báo và màn hình khoá được bật theo mặc định. Tính năng màn hình khoá sẽ bật khi bạn đã bật thông báo.

Chỉnh sửa CastOptionsProvider và thay đổi cách triển khai getCastOptions để phù hợp với mã này:

import com.google.android.gms.cast.framework.media.CastMediaOptions
import com.google.android.gms.cast.framework.media.NotificationOptions

override fun getCastOptions(context: Context): CastOptions {
   val notificationOptions = NotificationOptions.Builder()
            .setTargetActivityClassName(VideoBrowserActivity::class.java.name)
            .build()
    val mediaOptions = CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .build()
   return CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .setCastMediaOptions(mediaOptions)
                .build()
}

Nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động. Truyền video và chuyển khỏi ứng dụng mẫu. Sẽ có thông báo cho video hiện đang phát trên bộ thu. Khoá thiết bị di động của bạn và màn hình khoá giờ đây sẽ hiện các nút điều khiển chế độ phát nội dung nghe nhìn trên Thiết bị truyền.

Hình minh hoạ một chiếc điện thoại Android đang cho thấy các nút điều khiển nội dung nghe nhìn trên màn hình khoá

9. Lớp phủ giới thiệu

Danh sách kiểm tra thiết kế Google Cast yêu cầu ứng dụng dành cho người gửi ra mắt nút Truyền cho người dùng hiện tại để cho họ biết rằng ứng dụng của người gửi hiện hỗ trợ truyền và cũng giúp người dùng mới sử dụng Google Cast.

Hình minh hoạ cho thấy lớp phủ Giới thiệu xung quanh nút Truyền trên ứng dụng Truyền video của Android

SDK Truyền cung cấp một khung hiển thị tuỳ chỉnh, IntroductoryOverlay, có thể dùng để làm nổi bật nút Truyền khi nút này hiển thị lần đầu với người dùng. Thêm mã sau vào VideoBrowserActivity:

import com.google.android.gms.cast.framework.IntroductoryOverlay
import android.os.Looper

private var mIntroductoryOverlay: IntroductoryOverlay? = null

private fun showIntroductoryOverlay() {
    mIntroductoryOverlay?.remove()
    if (mediaRouteMenuItem?.isVisible == true) {
       Looper.myLooper().run {
           mIntroductoryOverlay = com.google.android.gms.cast.framework.IntroductoryOverlay.Builder(
                    this@VideoBrowserActivity, mediaRouteMenuItem!!)
                   .setTitleText("Introducing Cast")
                   .setSingleTime()
                   .setOnOverlayDismissedListener(
                           object : IntroductoryOverlay.OnOverlayDismissedListener {
                               override fun onOverlayDismissed() {
                                   mIntroductoryOverlay = null
                               }
                          })
                   .build()
          mIntroductoryOverlay!!.show()
        }
    }
}

Bây giờ, hãy thêm CastStateListener và gọi phương thức showIntroductoryOverlay khi có Thiết bị truyền bằng cách sửa đổi phương thức onCreate và ghi đè các phương thức onResumeonPause sao cho khớp với các phương thức sau:

import com.google.android.gms.cast.framework.CastState
import com.google.android.gms.cast.framework.CastStateListener

private var mCastStateListener: CastStateListener? = null

override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.video_browser)
    setupActionBar()
    mCastStateListener = object : CastStateListener {
            override fun onCastStateChanged(newState: Int) {
                if (newState != CastState.NO_DEVICES_AVAILABLE) {
                    showIntroductoryOverlay()
                }
            }
        }
    mCastContext = CastContext.getSharedInstance(this)
}

override fun onResume() {
    super.onResume()
    mCastContext?.addCastStateListener(mCastStateListener!!)
}

override fun onPause() {
    super.onPause()
    mCastContext?.removeCastStateListener(mCastStateListener!!)
}

Xoá dữ liệu ứng dụng hoặc gỡ bỏ ứng dụng khỏi thiết bị. Sau đó, nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động và bạn sẽ thấy lớp phủ giới thiệu (xoá dữ liệu ứng dụng nếu lớp phủ không hiển thị).

10. Mở rộng bộ điều khiển

Danh sách kiểm tra thiết kế Google Cast yêu cầu ứng dụng người gửi cung cấp bộ điều khiển mở rộng cho nội dung nghe nhìn đang truyền. Tay điều khiển mở rộng là phiên bản toàn màn hình của tay điều khiển mini.

Hình minh hoạ một video đang phát trên điện thoại Android với bộ điều khiển mở rộng ở trên

Cast SDK cung cấp một tiện ích cho bộ điều khiển mở rộng có tên là ExpandedControllerActivity. Đây là một lớp trừu tượng mà bạn phải đưa vào lớp con để thêm nút Truyền.

Trước tiên, hãy tạo một tệp tài nguyên trình đơn mới có tên là expanded_controller.xml cho bộ điều khiển mở rộng để cung cấp nút Truyền:

<?xml version="1.0" encoding="utf-8"?>

<menu xmlns:android="http://schemas.android.com/apk/res/android"
      xmlns:app="http://schemas.android.com/apk/res-auto">

    <item
            android:id="@+id/media_route_menu_item"
            android:title="@string/media_route_menu_title"
            app:actionProviderClass="androidx.mediarouter.app.MediaRouteActionProvider"
            app:showAsAction="always"/>

</menu>

Tạo một gói expandedcontrols mới trong gói com.google.sample.cast.refplayer. Tiếp theo, hãy tạo một tệp mới có tên là ExpandedControlsActivity.kt trong gói com.google.sample.cast.refplayer.expandedcontrols.

package com.google.sample.cast.refplayer.expandedcontrols

import android.view.Menu
import com.google.android.gms.cast.framework.media.widget.ExpandedControllerActivity
import com.google.sample.cast.refplayer.R
import com.google.android.gms.cast.framework.CastButtonFactory

class ExpandedControlsActivity : ExpandedControllerActivity() {
    override fun onCreateOptionsMenu(menu: Menu): Boolean {
        super.onCreateOptionsMenu(menu)
        menuInflater.inflate(R.menu.expanded_controller, menu)
        CastButtonFactory.setUpMediaRouteButton(this, menu, R.id.media_route_menu_item)
        return true
    }
}

Bây giờ, hãy khai báo ExpandedControlsActivity trong AndroidManifest.xml bên trong thẻ application phía trên OPTIONS_PROVIDER_CLASS_NAME:

<application>
    ...
    <activity
        android:name="com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity"
        android:label="@string/app_name"
        android:launchMode="singleTask"
        android:theme="@style/Theme.CastVideosDark"
        android:screenOrientation="portrait"
        android:exported="true">
        <intent-filter>
            <action android:name="android.intent.action.MAIN"/>
        </intent-filter>
        <meta-data
            android:name="android.support.PARENT_ACTIVITY"
            android:value="com.google.sample.cast.refplayer.VideoBrowserActivity"/>
    </activity>
    ...
</application>

Chỉnh sửa CastOptionsProvider và thay đổi NotificationOptions cũng như CastMediaOptions để đặt hoạt động mục tiêu thành ExpandedControlsActivity:

import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity

override fun getCastOptions(context: Context): CastOptions {
    val notificationOptions = NotificationOptions.Builder()
            .setTargetActivityClassName(ExpandedControlsActivity::class.java.name)
            .build()
    val mediaOptions = CastMediaOptions.Builder()
            .setNotificationOptions(notificationOptions)
            .setExpandedControllerActivityClassName(ExpandedControlsActivity::class.java.name)
            .build()
    return CastOptions.Builder()
            .setReceiverApplicationId(context.getString(R.string.app_id))
            .setCastMediaOptions(mediaOptions)
            .build()
}

Cập nhật phương thức LocalPlayerActivity loadRemoteMedia để hiển thị ExpandedControlsActivity khi phương tiện từ xa được tải:

import com.google.sample.cast.refplayer.expandedcontrols.ExpandedControlsActivity

private fun loadRemoteMedia(position: Int, autoPlay: Boolean) {
    if (mCastSession == null) {
        return
    }
    val remoteMediaClient = mCastSession!!.remoteMediaClient ?: return
    remoteMediaClient.registerCallback(object : RemoteMediaClient.Callback() {
        override fun onStatusUpdated() {
            val intent = Intent(this@LocalPlayerActivity, ExpandedControlsActivity::class.java)
            startActivity(intent)
            remoteMediaClient.unregisterCallback(this)
        }
    })
    remoteMediaClient.load(MediaLoadRequestData.Builder()
                .setMediaInfo(buildMediaInfo())
                .setAutoplay(autoPlay)
                .setCurrentTime(position.toLong()).build())
}

Nhấp vào nút Nút Chạy trong Android Studio, một hình tam giác màu xanh lục chỉ sang phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động và truyền video. Bạn sẽ thấy tay điều khiển mở rộng. Quay lại danh sách video và khi bạn nhấp vào bộ điều khiển thu nhỏ, bộ điều khiển mở rộng sẽ tải lại. Hãy rời khỏi ứng dụng để xem thông báo. Nhấp vào hình ảnh thông báo để tải bộ điều khiển mở rộng.

11. Thêm tính năng hỗ trợ Cast Connect

Thư viện Cast Connect cho phép các ứng dụng hiện có của người gửi giao tiếp với các ứng dụng Android TV thông qua giao thức Cast. Cast Connect được xây dựng dựa trên cơ sở hạ tầng Cast, trong đó ứng dụng Android TV hoạt động như một bộ thu.

Phần phụ thuộc

Lưu ý: Để triển khai Cast Connect, play-services-cast-framework cần phải từ 19.0.0 trở lên.

LaunchOptions

Để chạy ứng dụng Android TV, còn được gọi là Bộ thu Android, chúng ta cần đặt cờ setAndroidReceiverCompatible thành true trong đối tượng LaunchOptions. Đối tượng LaunchOptions này quy định cách khởi chạy receiver (trình thu nhận) và được truyền đến CastOptions do lớp CastOptionsProvider trả về. Việc đặt cờ đã đề cập ở trên thành false sẽ khởi chạy trình thu nhận web cho ID ứng dụng đã xác định trong Cast Developer Console.

Trong tệp CastOptionsProvider.kt, thêm nội dung sau vào phương thức getCastOptions:

import com.google.android.gms.cast.LaunchOptions
...
val launchOptions = LaunchOptions.Builder()
            .setAndroidReceiverCompatible(true)
            .build()
return new CastOptions.Builder()
        .setLaunchOptions(launchOptions)
        ...
        .build()

Đặt thông tin xác thực khi chạy

Ở phía người gửi, bạn có thể chỉ định CredentialsData để cho biết ai sẽ tham gia phiên này. credentials là một chuỗi có thể do người dùng xác định, miễn là ứng dụng ATV của bạn có thể hiểu được chuỗi đó. CredentialsData chỉ được truyền đến ứng dụng Android TV trong thời gian khởi chạy hoặc tham gia. Nếu bạn thiết lập lại khi đang kết nối thì mã đó sẽ không được chuyển tới ứng dụng Android TV.

Để thiết lập Thông tin đăng nhập khi chạy, bạn cần phải xác định và truyền CredentialsData đến đối tượng LaunchOptions. Thêm mã sau vào phương thức getCastOptions trong tệp CastOptionsProvider.kt:

import com.google.android.gms.cast.CredentialsData
...

val credentialsData = CredentialsData.Builder()
        .setCredentials("{\"userId\": \"abc\"}")
        .build()
val launchOptions = LaunchOptions.Builder()
       ...
       .setCredentialsData(credentialsData)
       .build()

Đặt thông tin xác thực trên LoadRequest

Trong trường hợp ứng dụng Web receiver và ứng dụng Android TV xử lý credentials theo cách khác nhau, bạn có thể cần phải xác định credentials riêng cho từng ứng dụng. Để xử lý vấn đề này, hãy thêm mã sau vào tệp LocalPlayerActivity.kt trong hàm loadRemoteMedia:

remoteMediaClient.load(MediaLoadRequestData.Builder()
       ...
       .setCredentials("user-credentials")
       .setAtvCredentials("atv-user-credentials")
       .build())

Tuỳ thuộc vào ứng dụng nhận mà người gửi đang truyền nội dung đến, SDK giờ đây sẽ tự động xử lý thông tin xác thực nào cần sử dụng cho phiên hiện tại.

Kiểm thử Cast Connect

Các bước cài đặt APK Android TV trên Chromecast có Google TV

  1. Tìm địa chỉ IP của thiết bị Android TV. Thông thường, bạn có thể tìm thấy thông tin này trong phần Cài đặt > Mạng và Internet > (Tên mạng mà thiết bị của bạn đang kết nối). Ở bên phải, màn hình sẽ hiển thị thông tin chi tiết và IP của thiết bị trên mạng.
  2. Sử dụng địa chỉ IP để thiết bị của bạn kết nối với thiết bị đó qua ADB bằng thiết bị đầu cuối:
$ adb connect <device_ip_address>:5555
  1. Trong cửa sổ dòng lệnh, hãy chuyển đến thư mục cấp cao nhất cho các mẫu lớp học lập trình mà bạn đã tải xuống khi bắt đầu lớp học lập trình này. Ví dụ:
$ cd Desktop/android_codelab_src
  1. Cài đặt tệp .apk trong thư mục này vào Android TV bằng cách chạy:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. Giờ đây, bạn có thể thấy một ứng dụng theo tên là Truyền video trong trình đơn Ứng dụng của bạn trên thiết bị Android TV.
  2. Quay lại dự án Android Studio rồi nhấp vào nút Run (Chạy) để cài đặt và chạy ứng dụng của người gửi trên thiết bị di động thực của bạn. Ở góc trên bên phải, hãy nhấp vào biểu tượng truyền và chọn thiết bị Android TV của bạn trong số các lựa chọn có sẵn. Giờ đây, bạn sẽ thấy ứng dụng Android TV đã chạy trên thiết bị Android TV. Việc phát video sẽ cho phép bạn điều khiển chế độ phát video bằng điều khiển từ xa cho Android TV.

12. Tùy chỉnh tiện ích Truyền

Bạn có thể tuỳ chỉnh Tiện ích truyền bằng cách đặt màu sắc, tạo kiểu cho nút, văn bản và giao diện hình thu nhỏ cũng như bằng cách chọn loại nút sẽ hiển thị.

Cập nhật res/values/styles_castvideo.xml

<style name="Theme.CastVideosTheme" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="mediaRouteTheme">@style/CustomMediaRouterTheme</item>
    <item name="castIntroOverlayStyle">@style/CustomCastIntroOverlay</item>
    <item name="castMiniControllerStyle">@style/CustomCastMiniController</item>
    <item name="castExpandedControllerStyle">@style/CustomCastExpandedController</item>
    <item name="castExpandedControllerToolbarStyle">
        @style/ThemeOverlay.AppCompat.ActionBar
    </item>
    ...
</style>

Khai báo các giao diện tuỳ chỉnh sau:

<!-- Customize Cast Button -->
<style name="CustomMediaRouterTheme" parent="Theme.MediaRouter">
    <item name="mediaRouteButtonStyle">@style/CustomMediaRouteButtonStyle</item>
</style>
<style name="CustomMediaRouteButtonStyle" parent="Widget.MediaRouter.Light.MediaRouteButton">
    <item name="mediaRouteButtonTint">#EEFF41</item>
</style>

<!-- Customize Introductory Overlay -->
<style name="CustomCastIntroOverlay" parent="CastIntroOverlay">
    <item name="castButtonTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Button</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.CustomCastIntroOverlay.Title</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Button" parent="android:style/TextAppearance">
    <item name="android:textColor">#FFFFFF</item>
</style>
<style name="TextAppearance.CustomCastIntroOverlay.Title" parent="android:style/TextAppearance.Large">
    <item name="android:textColor">#FFFFFF</item>
</style>

<!-- Customize Mini Controller -->
<style name="CustomCastMiniController" parent="CastMiniController">
    <item name="castShowImageThumbnail">true</item>
    <item name="castTitleTextAppearance">@style/TextAppearance.AppCompat.Subhead</item>
    <item name="castSubtitleTextAppearance">@style/TextAppearance.AppCompat.Caption</item>
    <item name="castBackground">@color/accent</item>
    <item name="castProgressBarColor">@color/orange</item>
</style>

<!-- Customize Expanded Controller -->
<style name="CustomCastExpandedController" parent="CastExpandedController">
    <item name="castButtonColor">#FFFFFF</item>
    <item name="castPlayButtonDrawable">@drawable/cast_ic_expanded_controller_play</item>
    <item name="castPauseButtonDrawable">@drawable/cast_ic_expanded_controller_pause</item>
    <item name="castStopButtonDrawable">@drawable/cast_ic_expanded_controller_stop</item>
</style>

13. Xin chúc mừng

Giờ đây, bạn đã biết cách bật tính năng Truyền ứng dụng video bằng các tiện ích SDK Truyền trên Android.

Để biết thêm thông tin chi tiết, hãy xem hướng dẫn dành cho nhà phát triển Người gửi trên Android.