הפעלת העברה (cast) של אפליקציה ל-Android

1. סקירה כללית

הלוגו של Google Cast

בשיעור הזה תלמדו איך לשנות אפליקציית וידאו קיימת ב-Android כדי להפעיל Cast של תוכן במכשיר שתומך ב-Google Cast.

מה זה Google Cast?

מערכת Google Cast מאפשרת למשתמשים להעביר תוכן מטלפון נייד לטלוויזיה. המשתמשים יוכלו להשתמש בנייד שלהם כשלט רחוק להפעלת מדיה בטלוויזיה.

Google Cast SDK מאפשר לכם להרחיב את האפליקציה כדי לשלוט בטלוויזיה או במערכת סאונד. ה-SDK של Cast מאפשר לך להוסיף את רכיבי ממשק המשתמש הנחוצים על סמך רשימת המשימות לעיצוב של Google Cast.

רשימת המשימות לעיצוב של Google Cast מסופקת כדי להפוך את חוויית המשתמש של Cast לפשוטה וצפויה בכל הפלטפורמות הנתמכות.

מה אנחנו מתכוונים לבנות?

בסיום ה-Codelab הזה, תהיה לך אפליקציית וידאו ל-Android, שיכולה להעביר סרטונים למכשיר שתומך ב-Google Cast.

מה תלמדו

  • איך להוסיף את Google Cast SDK לאפליקציית סרטונים לדוגמה.
  • איך להוסיף את לחצן הפעלת Cast כדי לבחור מכשיר Google Cast.
  • איך להתחבר למכשיר Cast ולהפעיל מקלט מדיה.
  • איך להפעיל Cast של סרטון.
  • איך להוסיף שלט רחוק של Cast Mini לאפליקציה.
  • איך לתמוך בהתראות מדיה ובפקדי מסך הנעילה.
  • איך להוסיף בקר מורחב.
  • איך לספק שכבת-על בהקדמה
  • איך להתאים אישית ווידג'טים של הפעלת Cast.
  • איך משלבים את Cast Connect

מה נדרש

  • הגרסה העדכנית ביותר של Android SDK.
  • Android Studio בגרסה 3.2 ואילך
  • מכשיר נייד אחד עם Android 4.1+ Jelly Bean (רמת API 16).
  • כבל נתונים USB שבעזרתו אפשר לחבר את המכשיר הנייד למחשב הפיתוח.
  • מכשיר Google Cast, כמו Chromecast או Android TV, שמוגדר עם גישה לאינטרנט.
  • טלוויזיה או צג עם כניסת HDMI.
  • כדי לבדוק את השילוב של Cast Connect צריך מכשיר Chromecast with Google TV, אבל הוא אופציונלי בשאר הקורס Codelab. אם אין לכם תמיכה, אפשר לדלג על השלב הוספת תמיכה של Cast Connect בסוף המדריך.

ניסיון

  • נדרש ידע קודם בפיתוח Kotlin וב-Android.
  • נדרש גם ידע קודם על צפייה בטלוויזיה :)

איך תשתמשו במדריך הזה?

לקריאה בלבד לקרוא אותו ולבצע את התרגילים

איזה דירוג מגיע לדעתך לחוויה שלך בפיתוח אפליקציות ל-Android?

מתחילים בינונית בקיאים

איזה דירוג מגיע לדעתך לחוויה שלך עם הצפייה בטלוויזיה?

מתחילים בינונית בקיאים

2. לקבלת הקוד לדוגמה

אפשר להוריד את כל הקוד לדוגמה למחשב...

ופורקים את קובץ ה-ZIP שהורדתם.

3. הרצת האפליקציה לדוגמה

סמל של זוג מצפן

קודם כול נראה איך נראית האפליקציה לדוגמה שהושלמה. האפליקציה היא נגן וידאו בסיסי. המשתמש יכול לבחור סרטון מרשימה ואז להפעיל את הסרטון באופן מקומי במכשיר או להפעיל Cast שלו למכשיר Google Cast.

אחרי שהורדתם את הקוד, ההוראות הבאות מתארות איך לפתוח ולהפעיל את האפליקציה לדוגמה שהושלמה ב-Android Studio:

בוחרים באפשרות Import Project (ייבוא פרויקט) במסך הפתיחה או ולוחצים על File > (קובץ >) חדש > אפשרויות התפריט 'ייבוא פרויקט...'.

בוחרים את הספרייה סמל של תיקייהapp-done מתיקיית הקוד לדוגמה ולוחצים על 'אישור'.

לוחצים על קובץ > 'סנכרון פרויקט עם Gradle' ב-Android Studio לחצן סנכרון הפרויקט עם קובצי Gradle

מפעילים ניפוי באגים ב-USB במכשיר Android – ב-Android מגרסה 4.2 ואילך, מסך האפשרויות למפתחים מוסתר כברירת מחדל. כדי להפוך אותו לגלוי, יש לעבור אל הגדרות > מידע על הטלפון ומקישים על מספר Build שבע פעמים. חוזרים למסך הקודם, עוברים אל מערכת > מתקדם ומקישים על אפשרויות למפתחים בתחתית המסך, ואז מקישים על ניפוי באגים ב-USB כדי להפעיל אותה.

מחברים את מכשיר Android ולוחצים על הלחצן לחצן ההפעלה ב-Android Studio, משולש ירוק שמצביע ימינההפעלה ב-Android Studio. אפליקציית הווידאו בשם הפעלת Cast של סרטונים אמורה להופיע לאחר מספר שניות.

לוחצים על הלחצן להפעלת Cast באפליקציית הווידאו ובוחרים את מכשיר ה-Google Cast.

בוחרים סרטון ולוחצים על לחצן ההפעלה.

הסרטון יתחיל לפעול במכשיר Google Cast.

הבקר המורחב יוצג. אפשר להשתמש בלחצן ההפעלה וההשהיה כדי לשלוט בהפעלה.

חוזרים לרשימת הסרטונים.

מיני-בקר מוצג עכשיו בתחתית המסך. איור של טלפון Android שבו פועל 'הפעלת Cast של סרטונים' אפליקציה שבה המיני-בקר מופיע בתחתית המסך

אפשר ללחוץ על לחצן ההשהיה במיני-בקר כדי להשהות את הסרטון במקלט. לוחצים על לחצן ההפעלה במיני-בקר כדי להמשיך להפעיל את הסרטון שוב.

לוחצים על לחצן דף הבית של המכשיר הנייד. יש למשוך למטה התראות, ועכשיו אמורה להופיע התראה לגבי סשן הפעלת ה-Cast.

תוכלו לנעול את הטלפון, וכשמבטלים את הנעילה שלו אמורה להופיע התראה במסך הנעילה, עם הרשאה לשלוט בהפעלת המדיה או להפסיק את הפעלת ה-Cast.

חוזרים לאפליקציית הווידאו ולוחצים על לחצן הפעלת Cast כדי להפסיק את ההעברה למכשיר Google Cast.

שאלות נפוצות

4. מכינים את הפרויקט לתחילת העבודה

איור של טלפון Android שבו פועל 'הפעלת Cast של סרטונים' יישום

אנחנו צריכים להוסיף תמיכה ב-Google Cast לאפליקציה שהורדת. הנה כמה מונחים של Google Cast שנשתמש בהם ב-Codelab הזה:

  • אפליקציית שולח פועלת במכשיר נייד או במחשב נייד,
  • אפליקציית מקלט שפועלת במכשיר ה-Google Cast.

עכשיו אתם מוכנים להתחיל להשתמש בפרויקט לתחילת העבודה באמצעות Android Studio:

  1. בוחרים את הספרייה סמל של תיקייהapp-start מתוך הורדת הקוד לדוגמה (בוחרים באפשרות ייבוא פרויקט במסך הפתיחה או באפשרות בתפריט קובץ > חדש > ייבוא פרויקט...).
  2. לוחצים על הלחצן 'סנכרון פרויקט עם Gradle' ב-Android Studio לחצן Sync Project with Gradle Files.
  3. לוחצים על הלחצן לחצן 'הרצה' ב-Android Studio, משולש ירוק שמצביע ימינהRun כדי להפעיל את האפליקציה ולחקור את ממשק המשתמש.

עיצוב אפליקציות

האפליקציה מאחזרת רשימה של סרטונים משרת אינטרנט מרוחק ומספקת רשימה של סרטונים שהמשתמשים יכולים לעיין בהם. המשתמשים יכולים לבחור סרטון כדי לראות את הפרטים שלו או להפעיל אותו באופן מקומי בנייד.

האפליקציה מורכבת משתי פעילויות עיקריות: VideoBrowserActivity ו-LocalPlayerActivity. כדי לשלב את הפונקציונליות של Google Cast, הפעילויות צריכות לקבל בירושה מהAppCompatActivity או מההורה שלו את FragmentActivity. המגבלה הזו קיימת כי עלינו להוסיף את MediaRouteButton (שניתן בספריית התמיכה של MediaRouter) בתור MediaRouteActionProvider. ההגדרה הזו תפעל רק אם הפעילות עוברת בירושה מהמחלקות שהוזכרו למעלה. ספריית התמיכה של MediaRouter תלויה בספריית התמיכה של AppCompat, שמציעה את המחלקות הנדרשות.

VideoBrowserActivity

הפעילות הזו מכילה Fragment (VideoBrowserFragment). לרשימה הזו יש גיבוי על ידי ArrayAdapter (VideoListAdapter). רשימת הסרטונים והמטא-נתונים שלהם מתארחים בשרת מרוחק כקובץ JSON. AsyncTaskLoader (VideoItemLoader) מאחזר את קובץ ה-JSON הזה ומעבד אותו כדי ליצור רשימה של MediaItem אובייקטים.

אובייקט MediaItem יוצר מודל של סרטון ואת המטא-נתונים המשויכים אליו, כמו השם, התיאור, כתובת ה-URL של השידור, כתובת ה-URL של התמונות התומכות ורצועות הטקסט המשויכות (לכתוביות) אם יש. האובייקט MediaItem מועבר בין פעילויות, כך של-MediaItem יש שיטות עזר להמיר אותו ל-Bundle ולהפך.

כשהטעינה יוצרת את הרשימה של MediaItems, היא מעבירה את הרשימה הזו אל VideoListAdapter, ואז מוצגת הרשימה MediaItems ב-VideoBrowserFragment. למשתמש מוצגת רשימה של תמונות ממוזערות של סרטונים, עם תיאור קצר של כל סרטון. כשבוחרים פריט, הערך של MediaItem התואם מומר לBundle ומועבר אל LocalPlayerActivity.

LocalPlayerActivity

פעילות זו מציגה את המטא-נתונים של סרטון מסוים ומאפשרת למשתמש להפעיל את הסרטון באופן מקומי במכשיר הנייד.

בפעילות יש VideoView, פקדי מדיה מסוימים ואזור טקסט להצגת התיאור של הסרטון שנבחר. הנגן מכסה את החלק העליון של המסך, ומשאיר מקום לתיאור המפורט של הסרטון מתחתיו. המשתמש יכול להפעיל/להשהות או לבקש הפעלה מקומית של סרטונים.

יחסי תלות

בגלל שאנחנו משתמשים ב-AppCompatActivity, אנחנו זקוקים לספריית התמיכה של AppCompat. אנחנו משתמשים בספרייה Volley כדי לנהל את רשימת הסרטונים ולקבל באופן אסינכרוני את התמונות של הרשימה.

שאלות נפוצות

5. הוספת הלחצן להפעלת Cast

איור של החלק העליון של טלפון Android שאפליקציית Cast Video פועלת בו. לחצן הפעלת Cast מופיע בפינה השמאלית העליונה של המסך

אפליקציה שתומכת בהפעלת Cast מציגה את לחצן הפעלת Cast בכל אחת מהפעילויות שלה. לחיצה על הלחצן להפעלת Cast תציג רשימה של מכשירי Cast שהמשתמש יכול לבחור. אם המשתמש הפעיל תוכן באופן מקומי במכשיר השולח, הבחירה במכשיר Cast מפעילה או ממשיכה את ההפעלה במכשיר ה-Cast הזה. בכל שלב במהלך הפעלת Cast, המשתמש יכול ללחוץ על הלחצן להפעלת Cast ולהפסיק את ההעברה של האפליקציה למכשיר Cast. למשתמש צריכה להיות אפשרות להתחבר למכשיר Cast או להתנתק ממנו בכל פעילות באפליקציה, כפי שמתואר ברשימת המשימות לעיצוב של Google Cast.

יחסי תלות

מעדכנים את הקובץ build.gradle של האפליקציה כך שיכלול את יחסי התלות הנדרשים של הספרייה:

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"
}

צריך לסנכרן את הפרויקט כדי לאשר את פיתוח גרסת ה-build של הפרויקט ללא שגיאות.

אתחול

ל-Cast יש אובייקט גלובלי מסוג סינגלטון, CastContext, שמרכז את כל האינטראקציות של Cast.

עליכם להטמיע את הממשק OptionsProvider כדי לספק את ה-CastOptions הדרוש לאתחול הסינגלטון CastContext. האפשרות החשובה ביותר היא מזהה האפליקציה של המקבל, שמשמש לסינון תוצאות הגילוי של מכשירי Cast ולהפעלת אפליקציית המקבל כשמתחילים סשן Cast.

כשמפתחים אפליקציה משלכם שתומכת ב-Cast, צריך להירשם כמפתח Cast ולקבל מזהה אפליקציה לאפליקציה. ב-Codelab הזה, נשתמש במזהה אפליקציה לדוגמה.

מוסיפים את קובץ CastOptionsProvider.kt החדש הבא לחבילה com.google.sample.cast.refplayer של הפרויקט:

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

עכשיו צריך להצהיר על OptionsProvider בתוך ה-"application" תג האפליקציה AndroidManifest.xml:

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

מאתחלים באופן מדורג את CastContext במתודה VideoBrowserActivity onCreate:

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

צריך להוסיף את אותה לוגיקת אתחול גם ל-LocalPlayerActivity.

לחצן הפעלת Cast

עכשיו, לאחר אתחול של CastContext, צריך להוסיף את לחצן הפעלת Cast כדי לאפשר למשתמש לבחור מכשיר Cast. הלחצן להפעלת Cast מוטמע על ידי MediaRouteButton מספריית התמיכה של MediaRouter. כמו כל סמל פעולה שאפשר להוסיף לפעילות (באמצעות ActionBar או Toolbar), קודם צריך להוסיף את האפשרות המתאימה בתפריט.

עורכים את הקובץ res/menu/browse.xml ומוסיפים את הפריט MediaRouteActionProvider מהתפריט לפני פריט ההגדרות:

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

משנים את השיטה onCreateOptionsMenu() של VideoBrowserActivity על ידי שימוש ב-CastButtonFactory כדי לחבר את MediaRouteButton ל-framework של Cast:

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
}

שינוי של onCreateOptionsMenu ב-LocalPlayerActivity באופן דומה.

לחצו על הלחצן לחצן ההפעלה ב-Android Studio, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה במכשיר הנייד. הלחצן להפעלת Cast אמור להופיע בסרגל הפעולות של האפליקציה, וכשתלחצו עליו הוא יציג את רשימת מכשירי ה-Cast ברשת המקומית. גילוי המכשיר מנוהל באופן אוטומטי על ידי CastContext. עליך לבחור את מכשיר ה-Cast שלך ואפליקציית המקלט לדוגמה תיטען במכשיר ה-Cast. ניתן לנווט בין פעילות הגלישה לבין הפעילות המקומית בנגן, ומצב הלחצן להפעלת Cast נשמר באופן מסונכרן.

עדיין לא ביקשנו תמיכה בהפעלת מדיה, ולכן עדיין אי אפשר להפעיל סרטונים במכשיר Cast. אפשר ללחוץ על הלחצן להפעלת Cast כדי להתנתק.

6. העברה (cast) של תוכן וידאו

איור של טלפון Android שבו פועל &#39;הפעלת Cast של סרטונים&#39; יישום

נרחיב את האפליקציה לדוגמה כדי להפעיל סרטונים מרחוק במכשיר Cast. כדי לעשות זאת, עלינו להאזין לאירועים השונים שנוצרו על ידי ה-Cast framework.

הפעלת Cast של מדיה

ככלל, אם רוצים להפעיל מדיה במכשיר Cast, צריך לבצע את הפעולות הבאות:

  1. יוצרים אובייקט MediaInfo שמשמש ליצירת מודל של פריט מדיה.
  2. צריך להתחבר למכשיר Cast ולהפעיל את אפליקציית המקבל.
  3. טוענים את האובייקט MediaInfo במקלט ומפעילים את התוכן.
  4. עוקבים אחרי סטטוס המדיה.
  5. שליחת פקודות הפעלה למקלט על סמך אינטראקציות של המשתמש.

כבר ביצענו את שלב 2 בקטע הקודם. קל לבצע את שלב 3 עם Cast framework. שלב 1 מסתכם במיפוי של אובייקט אחד לאובייקט אחר; MediaInfo הוא משהו ש-Cast framework מבינה, ו-MediaItem הוא הסתרת פריט מדיה באפליקציה שלנו; אנחנו יכולים למפות בקלות MediaItem לMediaInfo.

האפליקציה לדוגמה LocalPlayerActivity כבר יוצרת הבחנה בין הפעלה מקומית לבין הפעלה מרחוק באמצעות enum הבא:

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

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

ב-Codelab הזה לא חשוב שתבינו בדיוק איך פועלת כל הלוגיקה של הנגן לדוגמה. חשוב להבין שיהיה צורך לשנות את נגן המדיה של האפליקציה כדי להיות מודעים לשני מיקומי ההפעלה באופן דומה.

הנגן המקומי תמיד נמצא במצב הפעלה מקומי, כי הוא עדיין לא יודע דבר על מצבי ההעברה. אנחנו צריכים לעדכן את ממשק המשתמש על סמך מעברי מצבים שמתרחשים ב-Cast framework. לדוגמה, אם אנחנו מתחילים להפעיל Cast, צריך להפסיק את ההפעלה המקומית ולהשבית חלק מהפקדים. באופן דומה, אם נפסיק את ההעברה במהלך פעילות זו, נצטרך לעבור להפעלה מקומית. כדי לטפל בכך, עלינו להאזין לאירועים השונים שנוצרו על ידי Cast framework.

ניהול הפעלת Cast

במסגרת Cast, סשן Cast משלב את שלבי החיבור למכשיר, הפעלה (או הצטרפות), התחברות לאפליקציית מקלט ואתחול ערוץ בקרת מדיה, במקרים הרלוונטיים. הערוץ של פקדי המדיה הוא האופן שבו מסגרת Cast שולחת ומקבלת הודעות מנגן המדיה של המקלט.

סשן הפעלת ה-Cast מתחיל באופן אוטומטי כשהמשתמש בוחר מכשיר בלחיצה על לחצן הפעלת Cast, והוא יופסק באופן אוטומטי כשהמשתמש יתנתק. התחברות מחדש לסשן של מַקְלֵט עקב בעיות רשת מטופלת באופן אוטומטי על ידי Cast SDK.

נוסיף SessionManagerListener ל-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()
       }
   }
}

בפעילות של LocalPlayerActivity, אנחנו רוצים לקבל הודעה כשאנחנו מתחברים ממכשיר ה-Cast או מתנתקים ממנו, כדי שנוכל לעבור לנגן המקומי או ממנו. שימו לב שהקישוריות יכולה להשתבש לא רק על ידי הפעלת האפליקציה במכשיר הנייד, אלא גם על ידי מופע אחר של האפליקציה (או אפליקציה אחרת) שפועלת במכשיר נייד אחר.

הסשן הפעיל כרגע זמין בתור SessionManager.getCurrentSession(). סשנים נוצרים ומסתיימים באופן אוטומטי בתגובה לאינטראקציות של המשתמשים עם תיבות הדו-שיח של Cast.

אנחנו צריכים לרשום את ה-session Listener ולאתחל כמה משתנים שנשתמש בהם בפעילות. שינוי השיטה onCreate LocalPlayerActivity ל:

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

המדיה בטעינה

ב-Cast SDK, RemoteMediaClient מספק קבוצה של ממשקי API נוחים לניהול הפעלת מדיה מרחוק במקלט. ב-CastSession שתומך בהפעלת מדיה, מופע של RemoteMediaClient ייווצר באופן אוטומטי על ידי ה-SDK. אפשר לגשת ל-method getRemoteMediaClient() במכונה CastSession. צריך להוסיף אל LocalPlayerActivity את השיטות הבאות כדי לטעון את הסרטון הנוכחי שנבחר במקלט:

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

עכשיו אפשר לעדכן את השיטות השונות הקיימות כדי להשתמש בלוגיקת הסשן של Cast שתומכת בהפעלה מרחוק:

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

ב-method updatePlayButton, משנים את הערך של המשתנה isConnected:

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

עכשיו לחצו על הלחצן לחצן ההפעלה ב-Android Studio, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה במכשיר הנייד. מחברים את מכשיר Cast ומתחילים להפעיל סרטון. הסרטון אמור לפעול במקלט.

7. מיני-בקר

לפי רשימת המשימות של עיצוב Cast, כל אפליקציית Cast צריכה לכלול שלט רחוק מיני שמופיע כשהמשתמש מנווט אל מחוץ לדף התוכן הנוכחי. המיני-בקר מאפשר גישה מיידית ותזכורת גלויה לסשן הנוכחי של הפעלת Cast.

איור של החלק התחתון של טלפון Android שבו מוצג המיני-נגן באפליקציית Cast videos

ה-Cast SDK מספק תצוגה מותאמת אישית, MiniControllerFragment, שניתן להוסיף לקובץ פריסת האפליקציה של הפעילויות שבהן רוצים להציג את המיני-בקר.

צריך להוסיף את הגדרת המקטעים הבאה בתחתית של res/layout/player_activity.xml ו-res/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"/>

לוחצים על הלחצן לחצן ההפעלה ב-Android Studio, משולש ירוק שמצביע ימינהRun כדי להפעיל את האפליקציה ולהעביר (cast) סרטון. כשההפעלה תתחיל במקלט, המיני-בקר יופיע בחלק התחתון של כל פעילות. אפשר לשלוט בהפעלה מרחוק באמצעות המיני-בקר. אם מנווטים בין פעילות העיון לפעילות הנגן המקומית, מצב המיני של הבקר אמור להישאר מסונכרן עם סטטוס הפעלת המדיה במקלט.

8. התראה ומסך הנעילה

כדי להשתמש ברשימת המשימות לעיצוב של Google Cast, צריך שאפליקציית השולח תטמיע פקדי מדיה מהתראה וממסך הנעילה.

איור של טלפון Android שמוצגים בו פקדי מדיה באזור ההתראות

ה-Cast SDK מספק MediaNotificationService כדי לעזור לאפליקציית השולח ליצור פקדי מדיה להתראות ולמסך הנעילה. השירות ממוזג באופן אוטומטי עם המניפסט של האפליקציה באמצעות GRid.

MediaNotificationService יפעל ברקע כשהשולח מעביר תוכן, ויציג התראה עם תמונה ממוזערת של התמונה ומטא-נתונים לגבי הפריט הנוכחי שניתן להפעיל Cast, לחצן הפעלה/השהיה ולחצן עצירה.

אפשר להפעיל את פקדי ההתראות ומסך הנעילה עם CastOptions באתחול של CastContext. בקרי המדיה להתראות ולמסך הנעילה מופעלים כברירת מחדל. תכונת מסך הנעילה פועלת כל עוד ההתראה מופעלת.

עורכים את CastOptionsProvider ומשנים את ההטמעה של getCastOptions כך שתתאים לקוד הזה:

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

לחצו על הלחצן לחצן ההפעלה ב-Android Studio, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה במכשיר הנייד. אפשר להפעיל Cast של סרטון ולנווט אל מחוץ לאפליקציה לדוגמה. אמורה להיות התראה לגבי הסרטון שמופעל עכשיו במקלט. צריך לנעול את המכשיר הנייד, ומסך הנעילה אמור להציג פקדים להפעלת המדיה במכשיר ה-Cast.

איור של טלפון Android שמוצגים בו לחצני מדיה במסך הנעילה

9. שכבת-על של סרטון היכרות

כדי להשתמש ברשימת המשימות לעיצוב של Google Cast, יש צורך באפליקציית שולח שתציג את לחצן הפעלת Cast למשתמשים קיימים, כדי להודיע להם שאפליקציית השולח תומכת עכשיו בהעברה וגם עוזרת למשתמשים חדשים ב-Google Cast.

איור שמציג את שכבת-העל של הפעלת Cast סביב הלחצן להפעלת Cast באפליקציית Cast ל-Android

ה-Cast SDK מספק תצוגה מותאמת אישית, IntroductoryOverlay, שאפשר להשתמש בה כדי להדגיש את לחצן הפעלת Cast כשהוא מוצג למשתמשים לראשונה. מוסיפים ל-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()
        }
    }
}

עכשיו, מוסיפים CastStateListener וקוראים ל-method showIntroductoryOverlay כשמכשיר Cast זמין. לשם כך, משנים את השיטה onCreate ומחליפים את השיטות onResume ו-onPause כדי להתאים לאפשרויות הבאות:

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

מנקים את נתוני האפליקציה או מסירים אותה מהמכשיר. לאחר מכן, לחצו על הלחצן לחצן &#39;הרצה&#39; ב-Android Studio, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה במכשיר הנייד. שכבת-העל אמורה להופיע (אם שכבת-העל לא מוצגת, נקו את נתוני האפליקציה).

10. בקר מורחב

כדי להשתמש ברשימת המשימות לעיצוב של Google Cast, אפליקציית השולח צריכה לספק בקר מורחב למדיה שמועברת. הבקר המורחב הוא גרסת מסך מלא של המיני-בקר.

איור של סרטון שמופעל בטלפון Android כשהבקר המורחב מכסה אותו

ה-Cast SDK מספק ווידג'ט לבקר המורחב שנקרא ExpandedControllerActivity. זהו כיתת מופשטת שצריך ליצור ממנה מחלקה משנית כדי להוסיף לחצן להפעלת Cast.

קודם כול, יוצרים קובץ חדש של משאבים לתפריט בשם expanded_controller.xml, כדי שהבקר המורחב יוכל לספק את הלחצן להפעלת Cast:

<?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>

יוצרים חבילה חדשה expandedcontrols בחבילה של com.google.sample.cast.refplayer. לאחר מכן, יוצרים קובץ חדש בשם ExpandedControlsActivity.kt בחבילה 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
    }
}

עכשיו מצהירים על ExpandedControlsActivity ב-AndroidManifest.xml בתוך התג application שמעל ל-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>

עורכים את CastOptionsProvider ומשנים את NotificationOptions ואת CastMediaOptions כדי להגדיר את פעילות היעד ל-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()
}

צריך לעדכן את ה-method LocalPlayerActivity loadRemoteMedia כדי להציג את ExpandedControlsActivity כשהמדיה המרוחקת נטענת:

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

לוחצים על הלחצן לחצן ההפעלה ב-Android Studio, משולש ירוק שמצביע ימינההפעלה כדי להפעיל את האפליקציה במכשיר הנייד ולהעביר סרטון. אתה אמור לראות את השלט הרחוק המורחב. חוזרים לרשימת הסרטונים ולוחצים על המיני-בקר, הבקר המורחב ייטען שוב. כדי לראות את ההתראה, צריך לנווט אל מחוץ לאפליקציה. כדי לטעון את הבקר המורחב, צריך ללחוץ על תמונת ההתראה.

11. הוספת תמיכה ב-Cast Connect

ספריית Cast Connect מאפשרת לאפליקציות שולח קיימות לתקשר עם אפליקציות ל-Android TV באמצעות פרוטוקול Cast. Cast Connect מבוסס על התשתית של Cast, כשאפליקציית Android TV פועלת כמקלט.

יחסי תלות

הערה: כדי להטמיע את Cast Connect, הערך של play-services-cast-framework צריך להיות 19.0.0 ומעלה.

LaunchOptions

כדי להפעיל את האפליקציה Android TV, שנקראת גם Android היעדים, צריך להגדיר את הדגל setAndroidReceiverCompatible כ-true באובייקט LaunchOptions. אובייקט LaunchOptions הזה קובע את אופן ההפעלה של המקבל ומועבר אל CastOptions שמוחזרת על ידי המחלקה CastOptionsProvider. הגדרת הסימון שלמעלה כ-false תפעיל את מקלט האינטרנט עבור מזהה האפליקציה המוגדר ב-Cast Console.

בקובץ CastOptionsProvider.kt, מוסיפים את הפקודה הבאה ל-method getCastOptions:

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

הגדרת פרטי הכניסה להפעלה

בצד השולח, אפשר לציין את CredentialsData כדי לייצג את מי שיצטרף לסשן. הערך credentials הוא מחרוזת שאפשר להגדיר על ידי המשתמש, כל עוד אפליקציית ATV יכולה להבין אותה. CredentialsData מועבר לאפליקציה ל-Android TV רק בזמן ההפעלה או ההצטרפות. אם תגדירו אותה שוב בזמן החיבור, היא לא תועבר לאפליקציה ל-Android TV.

כדי להגדיר את פרטי הכניסה להפעלה, צריך להגדיר ולהעביר את CredentialsData לאובייקט LaunchOptions. צריך להוסיף את הקוד הבא ל-method getCastOptions בקובץ CastOptionsProvider.kt:

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

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

הגדרת פרטי כניסה ב-LoadRequest

אם אפליקציית מקבל האינטרנט והאפליקציה ל-Android TV מטפלים בcredentials באופן שונה, יכול להיות שיהיה צורך להגדיר credentials נפרד לכל אחד מהם. כדי לטפל בבעיה, צריך להוסיף את הקוד הבא לקובץ LocalPlayerActivity.kt באמצעות הפונקציה loadRemoteMedia:

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

בהתאם לאפליקציית המקבל שאליה השולח מעביר את התוכן, עכשיו ה-SDK יטפל באופן אוטומטי בפרטי הכניסה שבהם ייעשה שימוש בסשן הנוכחי.

בדיקה של Cast Connect

שלבים להתקנת ה-APK של Android TV ב-Chromecast with Google TV

  1. מאתרים את כתובת ה-IP של מכשיר Android TV. בדרך כלל, המדיניות זמינה בקטע הגדרות > רשת ו אינטרנט > (שם הרשת שאליה המכשיר מחובר). בצד שמאל יוצגו הפרטים ואת כתובת ה-IP של המכשיר שלך ברשת.
  2. משתמשים בכתובת ה-IP של המכשיר כדי להתחבר אליו דרך ADB באמצעות הטרמינל:
$ adb connect <device_ip_address>:5555
  1. מחלון הטרמינל, עוברים לתיקייה ברמה העליונה של דוגמאות ה-Codelab שהורדתם בתחילת השיעור הזה ב-Codelab. לדוגמה:
$ cd Desktop/android_codelab_src
  1. כדי להתקין את קובץ ה-APK שבתיקייה הזו ב-Android TV, מריצים את:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. עכשיו אמורה להופיע אפליקציה בשם הפעלת Cast של סרטונים בתפריט האפליקציות שלך במכשיר Android TV.
  2. חוזרים לפרויקט Android Studio ולוחצים על לחצן ההפעלה כדי להתקין את & להריץ את אפליקציית השולח במכשיר הנייד הפיזי שלך. בפינה השמאלית העליונה, לוחצים על הסמל להפעלת Cast ובוחרים את מכשיר Android TV שלכם מבין האפשרויות הזמינות. עכשיו אתם אמורים לראות את האפליקציה ל-Android TV מופעלת במכשיר Android TV, והפעלת הסרטון אמורה לאפשר לכם לשלוט בהפעלת הסרטון באמצעות השלט הרחוק של Android TV.

12. התאמה אישית של ווידג'טים של הפעלת Cast

ניתן להתאים אישית את הווידג'טים של הפעלת Cast על ידי הגדרה של הצבעים, עיצוב הלחצנים, הטקסט והתמונות הממוזערות ובחירת סוגי הלחצנים להצגה.

עדכון של 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>

צריך להצהיר על העיצובים המותאמים אישית הבאים:

<!-- 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. מזל טוב

עכשיו אתם יודעים איך להפעיל Cast של אפליקציית וידאו באמצעות הווידג'טים של Cast SDK ב-Android.

לפרטים נוספים, אפשר לעיין במדריך למפתחים של Android Sender.