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

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

הלוגו של Google Cast

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

מה זה Google Cast?

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

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

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

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

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

מה תלמדו

  • איך להוסיף את Google Cast SDK לאפליקציית וידאו לדוגמה.
  • כיצד להוסיף את לחצן הפעלת Cast כדי לבחור מכשיר Google 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.
  • נדרש מכשיר Chromecast with Google TV כדי לבדוק את השילוב של Cast Connect, אבל הוא אופציונלי בשאר ה-Codelab. אם אין לכם חשבון Google, אפשר לדלג על השלב הוספת תמיכה ב-Cast Connect לקראת סוף המדריך.

ניסיון

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

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

קריאה בלבד קריאה והשלמה של התרגילים

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

מתחילים בינוני ידע

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

מתחילים בינוני ידע

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

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

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

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

סמל של זוג מצפנים

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

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

בוחרים באפשרות ייבוא פרויקט במסך הפתיחה או באפשרויות התפריט קובץ > חדש > ייבוא פרויקט....

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

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

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

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

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

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

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

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

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

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

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

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

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

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

שאלות נפוצות

4. הכנת הפרויקט להתחלה

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

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

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

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

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

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

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

האפליקציה מורכבת משתי פעילויות עיקריות: 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 או להתנתק ממנו במהלך כל פעילות באפליקציה, כפי שמתואר ברשימת המשימות לעיצוב 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) כוללת אובייקט גלובלי מסוג singleton, ה-CastContext, שמתאם את כל האינטראקציות של ההעברה.

צריך להטמיע את הממשק של OptionsProvider כדי לספק CastOptions שנדרש כדי לאתחל את הסינגלטון CastContext. האפשרות החשובה ביותר היא מזהה האפליקציה של המקבל. המזהה הזה משמש לסינון תוצאות החיפוש של מכשירי 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 ל-Cast ל-framework:

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 באופן דומה.

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

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

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

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

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

העברה (cast) של מדיה

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

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

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

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

private var mLocation: PlaybackLocation? = null

enum class PlaybackLocation {
    LOCAL, REMOTE
}

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

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

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

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

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. אפשר לגשת אליה על ידי קריאה לשיטה 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()
}

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

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

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

7. מיני שלט רחוק

רשימת המשימות לעיצוב 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"/>

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

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

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

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

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

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

ניתן להפעיל את פקדי ההתראות ומסך הנעילה באמצעות 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()
}

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

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

9. שכבת-על למתחילים

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

איור שמציג את שכבת-העל שמשמשת כמבוא מסביב ללחצן &#39;העברה&#39; באפליקציית 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 ולהפעיל את השיטה 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()
}

צריך לעדכן את השיטה 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())
}

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

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

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

יחסי תלות

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

LaunchOptions

כדי להפעיל את אפליקציית Android TV, שנקראת גם Android Receiver, עלינו להגדיר את הדגל setAndroidReceiverCompatible כ-true באובייקט LaunchOptions. אובייקט LaunchOptions הזה מכתיב את אופן ההפעלה של המקבל ומועבר אל ה-CastOptions שמוחזר על ידי המחלקה CastOptionsProvider. הגדרת הדגל שהוזכר למעלה ל-false תפעיל את מקלט האינטרנט עבור מזהה האפליקציה שהוגדר ב-Cast Developer 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. צריך להוסיף את הקוד הבא לשיטת 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

אם אפליקציית Web Receiver ואפליקציית 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. מחלון ה-Terminal, עוברים לתיקייה ברמה העליונה של דוגמאות Codelab שהורדתם בתחילת ה-Codelab הזה. לדוגמה:
$ cd Desktop/android_codelab_src
  1. מתקינים את קובץ ה- .apk בתיקייה הזו ב-Android TV על ידי הפעלת:
$ adb -s <device_ip_address>:5555 install android-tv-app.apk
  1. עכשיו אמורה להופיע אפליקציה בשם העברת סרטונים בתפריט האפליקציות שלך במכשיר Android TV.
  2. חוזרים לפרויקט Android Studio ולוחצים על הלחצן 'הפעלה' כדי להתקין ולהפעיל את אפליקציית השולח במכשיר הנייד הפיזי. בפינה השמאלית העליונה, לוחצים על סמל ההעברה ובוחרים את מכשיר 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.