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

1. Tổng quan

Biểu tượng của Google Cast

Lớp học lập trình này sẽ hướng dẫn bạn cách sửa đổi ứng dụng video hiện có trên Android để truyền nội dung trên thiết bị có 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 lên 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 nghe nhìn trên TV.

SDK Google Cast 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. SDK Truyền 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 về 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 Truyền đơn giản và dễ dự đoán trên tất cả các nền tảng được hỗ trợ.

Chúng ta sẽ xây dự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ó khả năng truyền video sang thiết bị hỗ trợ Google Cast.

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

  • Cách thêm SDK Google Cast 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 một thiết bị truyền và chạy trình nhận nội dung nghe nhìn.
  • Cách truyền video.
  • Cách thêm tay điều khiển nhỏ của Cast vào ứng dụng.
  • Cách hỗ trợ thông báo đa phương tiện và các nút đ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 tùy chỉnh tiện ích Truyền.
  • Cách tích hợp với Cast Connect

Những gì bạn cần

  • 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 của bạn với máy tính phát triển.
  • Thiết bị Google Cast, chẳng hạn 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ó cổng HDMI.
  • Cần có Chromecast có Google TV để kiểm tra việc tích hợp Cast Connect nhưng không bắt buộc đối với 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, hãy bỏ qua bước Thêm hỗ trợ Cast Connect ở cuối phần 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 trước đó.
  • Bạn cũng sẽ cần phải có kiến thức trước đây về việc xem TV :)

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

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

Bạn xếp hạng trải nghiệm xây dựng ứng dụng Android như thế nào?

Người mới Trung cấp Thành thạo

Bạn xếp hạng trải nghiệm xem TV như thế nào?

Người mới Trung cấp Thành thạo

2. Lấy 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...

và giải nén tệp zip đã tải xuống.

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

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

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

Khi tải mã xuống, các hướng dẫn sau mô tả cách mở và chạy ứng dụng mẫu đã hoàn tất trong Android Studio:

Chọn Nhập dự án trên màn hình chào mừng hoặc tùy chọn 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 Android Studio ' Sync Project với Gradle' Sync Project with Gradle Files (Đồng bộ hoá dự án với tệp Gradle).

Bật tính năng gỡ lỗi USB trên thiết bị Android – trên Android 4.2 trở lên, màn hình Tùy 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 vào Số bản dựng bảy lần. Quay lại màn hình trước, chuyển đến mục Hệ thống và gt (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 USB để bật.

Cắm thiết bị Android vào rồi nhấp vào nút Nút Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên 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 rồi 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ẽ hiển thị. Bạn có thể sử dụng nút phát/tạm dừng để điều khiển chế độ phát.

Quay lại danh sách video.

Một bộ điều khiển nhỏ giờ đây sẽ xuất hiện ở cuối màn hình. Hình minh họa một chiếc điện thoại Android đang chạy ứng dụng 'Cast Video\39; với bộ điều khiển cỡ nhỏ xuất hiện ở cuối màn hình

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

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

Khóa điện thoại và khi mở khóa, bạn sẽ thấy một thông báo trên màn hình khóa để điều khiển nội dung nghe nhìn phát lại 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 bắt đầu

Hình minh họa một chiếc điện thoại Android đang chạy ứng dụng &hl=vi;Cast 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. Dưới đây là một số thuật ngữ của Google Cast mà chúng tôi sẽ sử dụng trong lớp học lập trình này:

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

Bây giờ, bạn đã sẵn sàng xây dựng dựa trên dự án ban đầu bằng Android Studio:

  1. Chọn thư mục biểu tượng thư mụcapp-start trong mã tải xuống mẫu của bạn (Chọn Import Project (Nhập dự án) trên màn hình chào mừng hoặc File > New > Import Project... (Trình đơn nhập).
  2. Nhấp vào nút Nút Android Studio ' Sync Project với Gradle' Đồng bộ hóa dự án với tệp Gradle.
  3. Nhấp vào nút Nút Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên 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 tìm nạp danh sách video từ máy chủ web từ xa và cung cấp danh sách cho người dùng duyệt qua. 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 của Google Cast, các Hoạt động cần kế thừa từ AppCompatActivity hoặc mẹ của nó . Hạn chế 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) làm MediaRouteActionProvider và điều này sẽ 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 bắt buộc.

Hoạt động trên trình duyệt video

Hoạt động này chứa Fragment (VideoBrowserFragment). Danh sách này được hỗ trợ bởi ArrayAdapter (VideoListAdapter). Danh sách các 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 và xử lý JSON để tạo danh sách đối tượng MediaItem.

Đối tượng MediaItem mô hình hóa một video và siêu dữ liệu liên kết của video đó, 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à các Video văn bản liên quan (đối với 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ẽ chuyển danh sách đó đến VideoListAdapter, sau đó trình bày danh sách MediaItems trong VideoBrowserFragment. Người dùng sẽ thấy một danh sách hình thu nhỏ video, trong đó có một đoạn mô tả ngắn cho mỗi video. Khi một mục được chọn, MediaItem tương ứng sẽ được chuyển đổi thành Bundle và được chuyển vào LocalPlayerActivity.

Hoạt động trên LocalPlayer

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

Phần phụ thuộc

Vì đang dùng AppCompatActivity nên chúng ta cần thư viện hỗ trợ AppCompat. Để quản lý danh sách video và nhận hình ảnh không đồng bộ cho danh sách, chúng tôi đ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 họa phần trên cùng 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 của màn hình

Ứng dụng hỗ trợ Cast sẽ hiển thị nút Truyền trong từng hoạt động của ứng dụng. Nhấp vào nút Truyền sẽ hiển thị 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 cục bộ trên thiết bị của người gửi, việ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 đó. Tại bất kỳ thời điểm nào trong một 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ó thể kết nối hoặc ngắt kết nối khỏi Thiết bị truyền khi đang ở trong bất kỳ hoạt động nào của ứng dụng, như được mô tả trong Danh sách kiểm tra thiết kế truyền của Google.

Phần phụ thuộc

Cập nhật tệp build.gradle của ứng dụng để bao gồm các phần phụ thuộc cần thiết trong 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 rằng các bản dựng của dự án không có lỗi.

Khởi chạy

Khung Truyền có một đối tượng singleton toàn cầu, CastContext, điều phối mọi hoạt động tương tác với Cast.

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

Khi phát triển ứng dụng hỗ trợ Cast của riêng mình, bạn phải đăng ký làm nhà phát triển tính năng Truyền rồi lấy mã ứng dụng cho ứng dụng đó. Đố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 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 trong ứ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" />

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 tạo tương tự vào LocalPlayerActivity.

Nút truyền

Bây giờ, CastContext đã được khởi tạo, chúng ta cần thêm nút Truyền để cho phép người dùng chọn một thiết bị Truyền. Nút Truyền được MediaRouteButton triển khai từ thư viện hỗ trợ MediaRouter. Giống như biểu tượng thao tác bất kỳ 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.

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 Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên 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 hành động của ứng dụng. Khi nhấp vào nút đó, thiết bị sẽ được liệt kê trên các thiết bị truyền của bạn. CastContext khám phá thiết bị được quản lý tự động. Chọn Thiết bị truyền của bạn và ứng dụng bộ thu mẫu sẽ tải trên Thiết bị truyền. Bạn có thể chuyển đổi giữa hoạt động duyệt web và hoạt động của người chơi trên máy và trạng thái của nút Truyền được đồng bộ hoá.

Chúng tôi chưa kết nối với chế độ hỗ trợ phát nội dung đa phương tiệ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 họa một chiếc điện thoại Android đang chạy ứng dụng &hl=vi;Cast Video&#39;

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 điều đó, chúng ta cần theo dõi các sự kiện khác nhau do Khung truyền tạo ra.

Truyền nội dung nghe nhìn

Ở cấp độ cao, 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 mô hình hoá 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 bộ thu.
  3. Tải đối tượng MediaInfo vào trình nhận và phát nội dung đó.
  4. Theo dõi trạng thái phương tiện.
  5. Gửi lệnh phát cho người nhận dựa trên hoạt động 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 với khung Truyền. Bước 1 tương ứng với việc liên kết một đối tượng với đối tượng khác; MediaInfo là khung mà Cast truyền hiểu và MediaItem là sự đóng gói ứng dụng của chúng tôi 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 tính năng phát cục bộ và phát từ xa bằng cách sử dụng enum sau:

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

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

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

Hiện tại, trình phát cục bộ luôn ở trạng thái phát trên thiết bị cục bộ vì chưa biết thông tin nào 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 chuyển đổi trạng thái xảy ra trong khung Truyền. Ví dụ: nếu bắt đầu truyền, chúng ta sẽ dừng quá trình phát trên cục bộ và tắt một số nút điều khiển. Tương tự, nếu dừng truyền khi đang ở hoạt động này, chúng ta sẽ cần chuyển sang chế độ phát trên máy. Để xử lý điều đó, chúng ta cần theo dõi các sự kiện khác nhau do khung Truyền tạo ra.

Quản lý phiên truyền

Đối với khung Truyền, một phiên Truyền kết hợp các bước kết nối với thiết bị, 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. SDK truyền lại sẽ kết nối lại với phiên người nhận do sự cố kết nối mạng.

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 trên LocalPlayerActivity, chúng ta muốn nhận 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 kết nối không chỉ bị gián đoạn bởi phiên bản ứng dụng đang chạy trên thiết bị di động của bạn, mà còn có thể bị gián đoạn bởi một phiên bản khác của ứng dụng (hoặc một ứng dụng khác) chạy trên thiết bị di động khác.

Phiên hiện đang hoạt động có thể truy cập được dưới dạng SessionManager.getCurrentSession(). Phiên được tạo và chia nhỏ tự động để phản hồi 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 xử lý phiên và khởi động 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 SDK Truyền, RemoteMediaClient cung cấp một tập hợp các API thuận tiện để quản lý chế độ phát nội dung nghe nhìn từ xa trên receiver. Đối với CastSession hỗ trợ tính năng phát nội dung đa phương tiện, SDK sẽ tự động tạo phiên bản RemoteMediaClient. Bạn có thể truy cập phương thức này bằng cách gọi phương thức getRemoteMediaClient() trên bản sao CastSession. Thêm các phương thức sau vào LocalPlayerActivity để tải video hiện đã chọn trên trình nhận:

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 để 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 Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động. Kết nối với Thiết bị truyền của bạ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 nhỏ

Danh sách kiểm tra thiết kế truyền yêu cầu tất 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 thu nhỏ cho phép truy cập tức thì và hiển thị lời nhắc cho phiên Truyền hiện tại.

Hình minh họa phần dưới cùng của điện thoại Android cho thấy trình phát thu nhỏ trong ứng dụng Truyền video

SDK Truyền cung cấp một chế độ xem tùy chỉnh, MiniControllerFragment, có thể được thêm vào tệp bố cục ứng dụng của những hoạt động mà bạn muốn hiển thị bộ điều khiển nhỏ.

Thêm khai báo mảnh sau đâ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 Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên phảiRun (Chạy) để chạy ứng dụng và truyền video. Khi quá trình phát bắt đầu trên trình nhận, bạn sẽ thấy bộ điều khiển 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 bộ điều khiển nhỏ. Nếu bạn chuyển đổi giữa hoạt động duyệt web và hoạt động của trình phát cục bộ, trạng thái của tay điều khiển nhỏ sẽ luôn đồng bộ với trạng thái phát nội dung nghe nhìn của người 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 người gửi triển khai các điều khiển phương tiện từ thông báomàn hình khóa.

Hình minh họa một chiếc điện thoại Android hiển thị các nút điều khiển nội dung nghe nhìn trong khu vực thông báo

SDK truyền cung cấp một MediaNotificationService để giúp ứng dụng gửi dữ liệu điều khiển nội dung nghe nhìn cho thông báo và màn hình khóa. Dịch vụ này được tự động hợp nhất vào tệp kê khai của ứng dụng theo gradle.

MediaNotificationService sẽ chạy trong 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 hình ảnh về mục 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 tính năng kiểm soát màn hình thông báo và màn hình khoá bằng CastOptions khi khởi chạy CastContext. Theo mặc định, các nút điều khiển nội dung nghe nhìn cho màn hình thông báo và màn hình khóa sẽ bật. Tính năng màn hình khoá sẽ bật ngay khi bạn bật thông báo.

Chỉnh sửa CastOptionsProvider và thay đổi cách triển khai getCastOptions cho 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 Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên phảiRun (Chạy) để chạy ứng dụng trên thiết bị di động. Truyền video và rời khỏi ứng dụng mẫu. Bạn cần nhận thông báo về video hiện đang phát trên bộ thu. Khóa thiết bị di động và màn hình khóa giờ đây sẽ hiển thị các nút điều khiển để phát nội dung nghe nhìn trên thiết bị truyền.

Hình minh họa một chiếc điện thoại Android đang hiển thị nút điều khiển nội dung nghe nhìn trên màn hình khóa

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 người gửi giới thiệu nút Truyền cho người dùng hiện tại để họ biết rằng ứng dụng 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 họa lớp phủ Truyền giới thiệu xung quanh nút Truyền trên ứng dụng Truyền video

SDK Truyền cung cấp một chế độ xem tùy chỉnh, IntroductoryOverlay, có thể được dùng để làm nổi bật nút Truyền khi người dùng nhìn thấy nút này lần đầu tiên. 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 một CastStateListener rồi gọi phương thức showIntroductoryOverlay khi có một 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 để 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 xoá ứng dụng khỏi thiết bị của bạn. Sau đó, hãy nhấp vào nút Nút Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên 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 xuất hiện).

10. Bộ điều khiển mở rộng

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

Hình minh họa một video đang phát trên điện thoại Android và tay điều khiển mở rộng phủ lên video

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

Trước tiên, tạo tệp tài nguyên trình đơn mới, có tên là expanded_controller.xml để trình đ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 mới expandedcontrols trong gói com.google.sample.cast.refplayer. Tiếp theo, 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 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 rồi thay đổi NotificationOptionsCastMediaOptions để đặ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 Run (Chạy) của Android Studio, một hình tam giác màu xanh lục chỉ về bên 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 bộ điều khiển mở rộng. Quay lại danh sách video. Khi bạn nhấp vào bộ điều khiển 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 người gửi hiện có giao tiếp với các ứng dụng Android TV thông qua giao thức Truyền. Cast Connect được xây dựng dựa trên cơ sở hạ tầng Truyền, với ứng dụng Android TV của bạn 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 từ 19.0.0 trở lên.

Tùy chọn khởi chạy

Để chạy ứng dụng Android TV, còn gọi là Bộ thu Android, chúng ta cần đặt cờ setAndroidReceiverCompatible thành đúng (true) trong đối tượng LaunchOptions. Đối tượng LaunchOptions này chỉ định cách khởi chạy trình nhận và được chuyể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 nhận web cho mã ứ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 đăng nhập để chạy

Ở phía người gửi, bạn có thể chỉ định CredentialsData để thể hiện ai đang tham gia phiên. 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 chuyển đến ứng dụng Android TV trong thời gian chạy hoặc tham gia. Nếu bạn đặt lại mật khẩu khi đang kết nối, thì thẻ sẽ không được chuyển vào ứng dụng Android TV.

Để thiết lập Thông tin đăng nhập khởi chạy CredentialsData, bạn cần xác định và truyền thông tin này đế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 đăng nhập trên LoadRequest

Trong trường hợp ứng dụng Bộ thu web và ứng dụng Android TV xử lý credentials theo cách khác nhau, bạn có thể cần xác định credentials riêng cho mỗi ứng dụng. Để xử lý vấn đề đó, 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())

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

Kiểm tra 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, tên này có trong phần Cài đặt > Mạng & Internet > (Tên mạng mà thiết bị của bạn được kết nối). Ở bên phải, thanh này 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 qua ADB bằng thiết bị đầu cuối:
$ adb connect <device_ip_address>:5555
  1. Trên cửa sổ dòng lệnh, hãy chuyển đến thư mục cấp cao nhất của các mẫu lớp học lập trình mà bạn đã tải xuống ở đầ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. Bây giờ, bạn có thể thấy ứng dụng theo tên Truyền video trong menu Ứ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à amp; chạy ứng dụng 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 trong số các tùy chọn có sẵn. Bây giờ, bạn sẽ thấy ứng dụng Android TV chạy trên thiết bị Android TV và 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 các tiện ích truyền

Bạn có thể tùy chỉnh Tiện ích Truyền bằng cách đặt màu, tạo kiểu cho các nút, văn bản và hình thu nhỏ cũng như bằng cách chọn các loại nút để 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 ứng dụng video bằng cách dùng 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 Android.