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

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

הלוגו של Google Cast

Codelab זה ילמד אתכם איך לשנות אפליקציית Android TV קיימת כדי לתמוך בהפעלת Cast ובתקשורת מאפליקציות שולחות קיימות של Cast.

מה זה Google Cast ו-Cast Connect?

עם Google Cast, משתמשים יכולים להפעיל Cast של תוכן מנייד לטלוויזיה. סשן טיפוסי של Google Cast מורכב משני רכיבים – אפליקציית שליחה ואפליקציית קבלה. אפליקציות ששולחות תוכן, כמו אפליקציה לנייד או אתר כמו Youtube.com, מתחילות את ההפעלה של אפליקציית מקלט Cast ושולטות בה. אפליקציות של Cast receiver הן אפליקציות HTML 5 שפועלות במכשירי Chromecast ו-Android TV.

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

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

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

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

מה תלמדו

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

הדרישות

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

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

ומחלצים את קובץ ה-ZIP שהורד.

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

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

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

רישום מכשירים למפתחים

כדי להפעיל את היכולות של Cast Connect לפיתוח אפליקציות, צריך לרשום את המספר הסידורי של Google Cast במכשיר Android TV שבו אתם מתכוונים להשתמש ב-Cast Developer Console. כדי למצוא את המספר הסידורי, עוברים אל הגדרות > העדפות המכשיר > Google Cast > מספר סידורי ב-Android TV. לתשומת ליבכם, זה לא המספר הסידורי של המכשיר הפיזי, וצריך לקבל אותו באמצעות השיטה שמתוארת למעלה.

תמונה של מסך Android TV שבו מוצג המסך 'Google Cast', מספר הגרסה והמספר הסידורי

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

התקנת אפליקציית השליחה ל-Android

כדי לבדוק שליחת בקשות ממכשירים ניידים, סיפקנו אפליקציית שולח פשוטה בשם Cast Videos כקובץ mobile-sender-0629.apk בהורדה של קובץ ה-ZIP של קוד המקור. נשתמש ב-ADB כדי להתקין את ה-APK. אם כבר התקנתם גרסה אחרת של Cast Videos, עליכם להסיר את הגרסה הזו מכל הפרופילים במכשיר לפני שתמשיכו.

  1. מפעילים את האפשרויות למפתחים ואת ניפוי הבאגים ב-USB בטלפון Android.
  2. מחברים כבל USB להעברת נתונים כדי לחבר את טלפון Android למחשב הפיתוח.
  3. מתקינים את mobile-sender-0629.apk בטלפון Android.

תמונה של חלון טרמינל שבו מופעלת הפקודה adb install להתקנת mobile-sender.apk

  1. אפשר למצוא את אפליקציית השולח Cast Videos בטלפון Android. סמל אפליקציית השליחה של סרטונים ל-Cast

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

התקנת אפליקציה ל-Android TV

בהוראות הבאות מוסבר איך לפתוח ולהריץ את אפליקציית הדוגמה המלאה ב-Android Studio:

  1. בוחרים באפשרות Import Project (ייבוא פרויקט) במסך הפתיחה או באפשרויות התפריט File > New > Import Project...‎ (קובץ > חדש > ייבוא פרויקט…).
  2. בוחרים את הספרייה סמל תיקייהapp-done מתיקיית קוד הדוגמה ולוחצים על OK (אישור).
  3. לוחצים על File > לחצן 'סנכרון הפרויקט עם Gradle' ב-Android App Studio Sync Project with Gradle Files (קובץ > סנכרון הפרויקט עם קובצי Gradle).
  4. מפעילים את האפשרויות למפתחים ואת ניפוי הבאגים ב-USB במכשיר Android TV.
  5. מתחברים באמצעות ADB למכשיר Android TV. המכשיר אמור להופיע ב-Android Studio. תמונה שבה מכשיר Android TV מופיע בסרגל הכלים של Android Studio
  6. לוחצים על הלחצן לחצן ההפעלה של Android Studio, משולש ירוק שמצביע ימינהRun (הפעלה). אחרי כמה שניות, אפליקציית ה-ATV בשם Cast Connect Codelab אמורה להופיע.

בואו נשחק Cast Connect עם אפליקציית ATV

  1. עוברים למסך הבית של Android TV.
  2. פותחים את אפליקציית השליחה של סרטונים ל-Cast בטלפון Android. לוחצים על הכפתור להפעלת Cast סמל של כפתור הפעלת Cast ובוחרים את מכשיר ATV.
  3. אפליקציית Cast Connect Codelab ATV תופעל ב-ATV והכפתור להפעלת Cast באפליקציית השולח יציין שהיא מחוברת סמל של הכפתור להפעלת Cast עם צבעים הפוכים.
  4. בוחרים סרטון באפליקציית ATV והסרטון יתחיל לפעול ב-ATV.
  5. בטלפון הנייד, מיני-בקר מופיע עכשיו בחלק התחתון של אפליקציית השולח. אפשר להשתמש בלחצן ההפעלה/ההשהיה כדי לשלוט בהפעלה.
  6. בוחרים סרטון מהטלפון הנייד ומפעילים אותו. הסרטון יתחיל לפעול ב-ATV והשלט המורחב יוצג בנייד השולח.
  7. נועלים את הטלפון, וכשפותחים את הנעילה אמורה להופיע התראה במסך הנעילה לשליטה בהפעלת המדיה או להפסקת ה-Cast.

תמונה של חלק ממסך של טלפון Android עם מיני-נגן שמפעיל סרטון

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

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

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

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

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

האפליקציה מספקת למשתמש רשימה של סרטונים שאפשר לעיין בהם. המשתמשים יכולים לבחור סרטון להפעלה ב-Android TV. האפליקציה מורכבת משתי פעילויות עיקריות: MainActivity ו-PlaybackActivity.

MainActivity

הפעילות הזו מכילה Fragment ‏ (MainFragment). רשימת הסרטונים והמטא-נתונים המשויכים שלהם מוגדרים במחלקה MovieList, והשיטה setupMovies() נקראת כדי ליצור רשימה של אובייקטים מסוג Movie.

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

כשבוחרים פריט, האובייקט המתאים Movie מועבר אל PlaybackActivity.

PlaybackActivity

הפעילות הזו מכילה מקטע (fragment) ‏(PlaybackVideoFragment) שמארח VideoView עם ExoPlayer, ממשק השליטה במדיה ואזור הטקסט להצגת התיאור של הסרטון שנבחר, ומאפשר למשתמש להפעיל את הסרטון ב-Android TV. המשתמש יכול להשתמש בשלט רחוק כדי להפעיל או להשהות את הסרטונים או להריץ אותם קדימה.

דרישות מוקדמות לשימוש ב-Cast Connect

‫Cast Connect משתמש בגרסאות חדשות של Google Play Services, שדורשות שהאפליקציה ל-ATV תעודכן כדי להשתמש במרחב השמות AndroidX.

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

5. הגדרת תמיכה ב-Cast

תלויות

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

dependencies {
    ....

    // Cast Connect libraries
    implementation 'com.google.android.gms:play-services-cast-tv:20.0.0'
    implementation 'com.google.android.gms:play-services-cast:21.1.0'
}

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

אתחול

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

יוצרים קובץ CastReceiverOptionsProvider.kt ומוסיפים את המחלקה הבאה לפרויקט:

package com.google.sample.cast.castconnect

import android.content.Context
import com.google.android.gms.cast.tv.ReceiverOptionsProvider
import com.google.android.gms.cast.tv.CastReceiverOptions

class CastReceiverOptionsProvider : ReceiverOptionsProvider {
    override fun getOptions(context: Context): CastReceiverOptions {
        return CastReceiverOptions.Builder(context)
                .setStatusText("Cast Connect Codelab")
                .build()
    }
}

לאחר מכן מציינים את ספק אפשרויות המקלט בתג <application> של קובץ האפליקציה AndroidManifest.xml:

<application>
  ...
  <meta-data
    android:name="com.google.android.gms.cast.tv.RECEIVER_OPTIONS_PROVIDER_CLASS_NAME"
    android:value="com.google.sample.cast.castconnect.CastReceiverOptionsProvider" />
</application>

כדי להתחבר לאפליקציית ATV מהמכשיר ששולח את התוכן ל-Cast, בוחרים פעילות שרוצים להפעיל. ב-codelab הזה, נפעיל את MainActivity של האפליקציה כשמתחיל סשן Cast. בקובץ AndroidManifest.xml, מוסיפים את מסנן ה-Intent להפעלה ב-MainActivity.

<activity android:name=".MainActivity">
  ...
  <intent-filter>
    <action android:name="com.google.android.gms.cast.tv.action.LAUNCH" />
    <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

מחזור החיים של ההקשר של מקלט Cast

צריך להפעיל את CastReceiverContext כשהאפליקציה מופעלת ולהפסיק את CastReceiverContext כשהאפליקציה מועברת לרקע. מומלץ להשתמש ב-LifecycleObserver מתוך ספריית androidx.lifecycle כדי לנהל את הקריאה ל-CastReceiverContext.start() ול-CastReceiverContext.stop()

פותחים את הקובץ MyApplication.kt ומאתחלים את הקשר של Cast על ידי קריאה ל-initInstance() בשיטה onCreate של האפליקציה. במחלקת AppLifeCycleObserver start() הפונקציה CastReceiverContext כשממשיכים את השימוש באפליקציה וstop() כשמשהים את השימוש באפליקציה:

package com.google.sample.cast.castconnect

import com.google.android.gms.cast.tv.CastReceiverContext
...

class MyApplication : Application() {
    override fun onCreate() {
        super.onCreate()
        CastReceiverContext.initInstance(this)
        ProcessLifecycleOwner.get().lifecycle.addObserver(AppLifecycleObserver())
    }

    class AppLifecycleObserver : DefaultLifecycleObserver {
        override fun onResume(owner: LifecycleOwner) {
            Log.d(LOG_TAG, "onResume")
            CastReceiverContext.getInstance().start()
        }

        override fun onPause(owner: LifecycleOwner) {
            Log.d(LOG_TAG, "onPause")
            CastReceiverContext.getInstance().stop()
        }
    }
}

קישור של MediaSession ל-MediaManager

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

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

import com.google.android.gms.cast.tv.CastReceiverContext
import com.google.android.gms.cast.tv.media.MediaManager
...

class PlaybackVideoFragment : VideoSupportFragment() {
    private var castReceiverContext: CastReceiverContext? = null
    ...

    private fun initializePlayer() {
        if (mPlayer == null) {
            ...
            mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
            ...
            castReceiverContext = CastReceiverContext.getInstance()
            if (castReceiverContext != null) {
                val mediaManager: MediaManager = castReceiverContext!!.getMediaManager()
                mediaManager.setSessionCompatToken(mMediaSession!!.getSessionToken())
            }

        }
    }
}

כשמשחררים את MediaSession בגלל השמעה לא פעילה, צריך להגדיר אסימון null ב-MediaManager:

private fun releasePlayer() {
    mMediaSession?.release()
    castReceiverContext?.mediaManager?.setSessionCompatToken(null)
    ...
}

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

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

6. טעינת מדיה

פקודת הטעינה נשלחת באמצעות intent עם שם החבילה שהגדרתם ב-Developer Console. כדי לציין את פעילות היעד שתקבל את ה-Intent הזה, צריך להוסיף את מסנן ה-Intent המוגדר מראש הבא לאפליקציה ל-Android TV. בקובץ AndroidManifest.xml, מוסיפים את מסנן ה-Intent של הטעינה אל PlayerActivity:

<activity android:name="com.google.sample.cast.castconnect.PlaybackActivity"
          android:launchMode="singleTask"
          android:exported="true">
  <intent-filter>
     <action android:name="com.google.android.gms.cast.tv.action.LOAD"/>
     <category android:name="android.intent.category.DEFAULT" />
  </intent-filter>
</activity>

טיפול בבקשות טעינה ב-Android TV

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

האפליקציה קוראת לשיטה פרטית בשם processIntent כשהפעילות מתחילה. השיטה הזו מכילה את הלוגיקה לעיבוד כוונות נכנסות. כדי לטפל בבקשת טעינה, נשנה את ה-method הזה ונשלח את הכוונה לעיבוד נוסף על ידי קריאה ל-method‏ onNewIntent של המופע MediaManager. אם MediaManager מזהה שהכוונה היא בקשת טעינה, הוא מחלץ את אובייקט MediaLoadRequestData מהכוונה ומפעיל את MediaLoadCommandCallback.onLoad(). משנים את שיטת processIntent בקובץ PlaybackVideoFragment.kt כדי לטפל בכוונת המשתמש שמכילה את בקשת הטעינה:

fun processIntent(intent: Intent?) {
    val mediaManager: MediaManager = CastReceiverContext.getInstance().getMediaManager()
    // Pass intent to Cast SDK
    if (mediaManager.onNewIntent(intent)) {
        return
    }

    // Clears all overrides in the modifier.
    mediaManager.getMediaStatusModifier().clear()

    // If the SDK doesn't recognize the intent, handle the intent with your own logic.
    ...
}

בשלב הבא נרחיב את המחלקה המופשטת MediaLoadCommandCallback, שתבטל את השיטה onLoad() שנקראת על ידי MediaManager. השיטה הזו מקבלת את הנתונים של בקשת הטעינה וממירה אותם לאובייקט Movie. אחרי ההמרה, הסרט מופעל על ידי הנגן המקומי. לאחר מכן, MediaManager מתעדכן עם MediaLoadRequest ומשדר את MediaStatus לשולחים המחוברים. יוצרים מחלקה פרטית מקוננת בשם MyMediaLoadCommandCallback בקובץ PlaybackVideoFragment.kt:

import com.google.android.gms.cast.MediaLoadRequestData
import com.google.android.gms.cast.MediaInfo
import com.google.android.gms.cast.MediaMetadata
import com.google.android.gms.cast.MediaError
import com.google.android.gms.cast.tv.media.MediaException
import com.google.android.gms.cast.tv.media.MediaCommandCallback
import com.google.android.gms.cast.tv.media.QueueUpdateRequestData
import com.google.android.gms.cast.tv.media.MediaLoadCommandCallback
import com.google.android.gms.tasks.Task
import com.google.android.gms.tasks.Tasks
import android.widget.Toast
...

private inner class MyMediaLoadCommandCallback :  MediaLoadCommandCallback() {
    override fun onLoad(
        senderId: String?, mediaLoadRequestData: MediaLoadRequestData): Task<MediaLoadRequestData> {
        Toast.makeText(activity, "onLoad()", Toast.LENGTH_SHORT).show()
        return if (mediaLoadRequestData == null) {
            // Throw MediaException to indicate load failure.
            Tasks.forException(MediaException(
                MediaError.Builder()
                    .setDetailedErrorCode(MediaError.DetailedErrorCode.LOAD_FAILED)
                    .setReason(MediaError.ERROR_REASON_INVALID_REQUEST)
                    .build()))
        } else Tasks.call {
            play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
            // Update media metadata and state
            val mediaManager = castReceiverContext!!.mediaManager
            mediaManager.setDataFromLoad(mediaLoadRequestData)
            mediaLoadRequestData
        }
    }
}

private fun convertLoadRequestToMovie(mediaLoadRequestData: MediaLoadRequestData?): Movie? {
    if (mediaLoadRequestData == null) {
        return null
    }
    val mediaInfo: MediaInfo = mediaLoadRequestData.getMediaInfo() ?: return null
    var videoUrl: String = mediaInfo.getContentId()
    if (mediaInfo.getContentUrl() != null) {
        videoUrl = mediaInfo.getContentUrl()
    }
    val metadata: MediaMetadata = mediaInfo.getMetadata()
    val movie = Movie()
    movie.videoUrl = videoUrl
    movie.title = metadata?.getString(MediaMetadata.KEY_TITLE)
    movie.description = metadata?.getString(MediaMetadata.KEY_SUBTITLE)
    if(metadata?.hasImages() == true) {
        movie.cardImageUrl = metadata.images[0].url.toString()
    }
    return movie
}

אחרי שהגדרנו את הקריאה החוזרת, צריך לרשום אותה ב-MediaManager. צריך לרשום את פונקציית הקריאה החוזרת לפני שקוראים ל-MediaManager.onNewIntent(). הוספת setMediaLoadCommandCallback כשמפעילים את הנגן:

private fun initializePlayer() {
    if (mPlayer == null) {
        ...
        mMediaSession = MediaSessionCompat(getContext(), LOG_TAG)
        ...
        castReceiverContext = CastReceiverContext.getInstance()
        if (castReceiverContext != null) {
            val mediaManager: MediaManager = castReceiverContext.getMediaManager()
            mediaManager.setSessionCompatToken(mMediaSession.getSessionToken())
            mediaManager.setMediaLoadCommandCallback(MyMediaLoadCommandCallback())
        }
    }
}

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

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

7. תמיכה בפקודות של Cast

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

מוסיפים את MyMediaCommandCallback למופע MediaManager באמצעות setMediaCommandCallback כשהנגן מאותחל:

private fun initializePlayer() {
    ...
    castReceiverContext = CastReceiverContext.getInstance()
    if (castReceiverContext != null) {
        val mediaManager = castReceiverContext!!.mediaManager
        ...
        mediaManager.setMediaCommandCallback(MyMediaCommandCallback())
    }
}

יוצרים מחלקה MyMediaCommandCallback כדי לבטל את השיטות, כמו onQueueUpdate(), כדי לתמוך בפקודות השליטה הבאות ב-Cast:

private inner class MyMediaCommandCallback : MediaCommandCallback() {
    override fun onQueueUpdate(
        senderId: String?,
        queueUpdateRequestData: QueueUpdateRequestData
    ): Task<Void> {
        Toast.makeText(getActivity(), "onQueueUpdate()", Toast.LENGTH_SHORT).show()
        // Queue Prev / Next
        if (queueUpdateRequestData.getJump() != null) {
            Toast.makeText(
                getActivity(),
                "onQueueUpdate(): Jump = " + queueUpdateRequestData.getJump(),
                Toast.LENGTH_SHORT
            ).show()
        }
        return super.onQueueUpdate(senderId, queueUpdateRequestData)
    }
}

8. עבודה עם סטטוס המדיה

שינוי סטטוס המדיה

‫Cast Connect מקבל את סטטוס המדיה הבסיסי מסשן המדיה. כדי לתמוך בתכונות מתקדמות, אפליקציה ל-Android TV יכולה לציין ולשנות מאפייני סטטוס נוספים באמצעות MediaStatusModifier. ‫MediaStatusModifier תמיד יפעל על MediaSession שהגדרתם ב-CastReceiverContext.

לדוגמה, כדי לציין setMediaCommandSupported כשמופעלת onLoad קריאה חוזרת (callback):

import com.google.android.gms.cast.MediaStatus
...
private class MyMediaLoadCommandCallback : MediaLoadCommandCallback() {
    fun onLoad(
        senderId: String?,
        mediaLoadRequestData: MediaLoadRequestData
    ): Task<MediaLoadRequestData> {
        Toast.makeText(getActivity(), "onLoad()", Toast.LENGTH_SHORT).show()
        ...
        return Tasks.call({
            play(convertLoadRequestToMovie(mediaLoadRequestData)!!)
            ...
            // Use MediaStatusModifier to provide additional information for Cast senders.
            mediaManager.getMediaStatusModifier()
                .setMediaCommandSupported(MediaStatus.COMMAND_QUEUE_NEXT, true)
                .setIsPlayingAd(false)
            mediaManager.broadcastMediaStatus()
            // Return the resolved MediaLoadRequestData to indicate load success.
            mediaLoadRequestData
        })
    }
}

יירוט של MediaStatus לפני השליחה

בדומה ל-MessageInterceptor ב-SDK של Web Receiver, אפשר לציין MediaStatusWriter ב-MediaManager כדי לבצע שינויים נוספים ב-MediaStatus לפני שהוא משודר לשולחים המחוברים.

לדוגמה, אפשר להגדיר נתונים מותאמים אישית ב-MediaStatus לפני ששולחים אותם לשולחים בנייד:

import com.google.android.gms.cast.tv.media.MediaManager.MediaStatusInterceptor
import com.google.android.gms.cast.tv.media.MediaStatusWriter
import org.json.JSONObject
import org.json.JSONException
...

private fun initializePlayer() {
    if (mPlayer == null) {
        ...
        if (castReceiverContext != null) {
            ...
            val mediaManager: MediaManager = castReceiverContext.getMediaManager()
            ...
            // Use MediaStatusInterceptor to process the MediaStatus before sending out.
            mediaManager.setMediaStatusInterceptor(
                MediaStatusInterceptor { mediaStatusWriter: MediaStatusWriter ->
                    try {
                        mediaStatusWriter.setCustomData(JSONObject("{myData: 'CustomData'}"))
                    } catch (e: JSONException) {
                        Log.e(LOG_TAG,e.message,e);
                    }
            })
        }
    }
}        

9. מזל טוב

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

פרטים נוספים זמינים במדריך למפתחים: /cast/docs/android_tv_receiver.