העברת האפליקציה של שולח ה-CCL ל-Cast Application Framework (CAF)

ההליך הבא מאפשר להמיר את אפליקציית השולח של Android מ-Cast SDK v2 ל-CCL ל-CAF. כל הפונקציונליות של CCL הוטמעה ב-CAF, כך שלאחר ההעברה לא תצטרכו יותר להשתמש ב-CCL.

ה-SDK של שולח CAF Cast משתמש ב-CastContext כדי לנהל בשמך את GoogleAPIClient. ב-CastContext מנהלים מחזורי חיים, שגיאות וקריאות חוזרות (callback) שמפשטים מאוד את הפיתוח של אפליקציית Cast.

מבוא

  • מאחר שהעיצוב של שולח CAF הושפע על ידי הספרייה הנלווית של Cast, המיגרציה מ-CCL ל-CAF כוללת בעיקר מיפוי אחד-לאחד של הכיתות והשיטות שלהן.
  • באמצעות מנהל ה-SDK ל-Android, מפתח CAF עדיין מופץ כחלק משירותי Google Play.
  • חבילות חדשות (com.google.android.gms.cast.framework.*) שנוספו ל-CAF Sender, עם פונקציונליות דומה ל-CCL, אחראיות לציות לרשימת המשימות לעיצוב של Google Cast.
  • שולח ה-CAF מספק ווידג'טים שעומדים בדרישות של חוויית המשתמש ב-Cast. הווידג'טים האלה דומים לווידג'טים של CCL.
  • שולח ה-CAF מספק קריאות חוזרות אסינכרוניות הדומות ל-CCL, כדי לעקוב אחר מצבים ולקבל נתונים. בשונה מ-CCL, שולח ה-CAF לא מספק הטמעות "no-op" של שיטות הממשק השונות.

בסעיפים הבאים נתמקד בעיקר באפליקציות וידאו שמתמקדות ב-VideoCastManager של CCL, אבל במקרים רבים אותם קונספטים חלים גם על DataCastManager.

יחסי תלות

ל-CCL ול-CAF יש קשרי תלות זהים בספריית התמיכה של AppCompat, בספריית התמיכה של MediaRouter v7 ובשירותי Google Play. עם זאת, ההבדל הוא שמסגרת CAF משתנה בהתאם למסגרת ההעברה החדשה שזמינה בשירותי Google Play בגרסה 9.2.0 ואילך.

בקובץ build.gradle, מסירים את התלות ב-com.google.android.gms:play-services-cast וב-com.google.android.libraries.cast.companionlibrary:ccl ומוסיפים את מסגרת Cast החדשה:

dependencies {
    compile 'com.android.support:appcompat-v7:23.4.0'
    compile 'com.android.support:mediarouter-v7:23.4.0'
    compile 'com.google.android.gms:play-services-cast-framework:9.4.0'
}

אפשר גם להסיר את המטא-נתונים של שירות Google Play:

<meta‐data android:name="com.google.android.gms.version"
android:value="@integer/google_play_services_version"/>

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

גרסת ה-SDK המינימלית ל-Android שנתמכת ב-CAF היא 9 (Gingerbread). גרסת ה-SDK המינימלית ל-Android של CCL היא 10.

בעזרת CCL אפשר להשתמש באמצעי BaseCastManager.checkGooglePlayServices(activity) נוחות כדי לוודא שיש במכשיר גרסה תואמת של שירותי Google Play. CAF לא מספק זאת כחלק מ-Cast SDK. צריך לפעול לפי ההוראות כדי לוודא שבמכשיר ה-APK של שירותי Google Play יש מכשירים כדי לוודא שה-APK הנכון של שירותי Google Play מותקן במכשיר של המשתמש, כי ייתכן שהעדכונים לא יגיעו מיד לכל המשתמשים.

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

אתחול

עבור CCL, היה צורך בקריאה ל-VideoCastManager.initialize() בשיטה onCreate() של המכונה Application. יש להסיר את הלוגיקה הזו מקוד הסיווג של האפליקציה.

ב-CAF נדרש גם שלב אתחול מפורש למסגרת ההעברה (cast). כדי לבצע את הפעולה צריך להפעיל את ה-singleton של CastContext, ולהשתמש ב-OptionsProvider המתאים כדי לציין את מזהה האפליקציה של המקבל ואת כל האפשרויות הגלובליות האחרות. ל-CastContext יש תפקיד דומה לזה של CCL VideoCastManager כי הוא מספק סינגל שהלקוחות מקיימים איתו אינטראקציה. ה-OptionsProvider דומה ל-CastConfiguration של ה-CCL המאפשר לך להגדיר את תכונות ה-Cast framework.

אם ערך ה-CCL הנוכחי CastConfiguration.Builder נראה כך:

VideoCastManager.initialize(
   getApplicationContext(),
   new CastConfiguration.Builder(context.getString(R.string.app_id))
       .enableWifiReconnection()
       .enableAutoReconnect()
       .build());

לאחר מכן, ב-CAD CastOptionsProvider, באמצעות CastOptions.Builder יהיה דומה:

public class CastOptionsProvider implements OptionsProvider {

    @Override
    public CastOptions getCastOptions(Context context) {
        return new CastOptions.Builder()
                .setReceiverApplicationId(context.getString(R.string.app_id))
                .build();
    }

    @Override
    public List<SessionProvider> getAdditionalSessionProviders(
            Context context) {
        return null;
    }
}

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

יש להצהיר על ה-OptionProvider ברכיב "application" של הקובץAndroidManifest.xml:

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

אתחל את CastContext ב-Z בשיטה של Activity לכל onCreate (ולא במופע Application):

private CastContext mCastContext;

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.video_browser);
    setupActionBar();

    mCastContext = CastContext.getSharedInstance(this);
}

כדי לגשת לסינגל CastContext, משתמשים ב:

mCastContext = CastContext.getSharedInstance(this);

גילוי מכשירים

צריך להסיר את VideoCastManager של incrementUiCounter ואת decrementUiCounter של CCL משיטות onResume ו-onPause של Activities.

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

לחצן Cast ותיבת דו-שיח להעברה

בדומה ל-CCL, הרכיבים האלה מסופקים על ידי ספריית התמיכה של MediaRouter v7.

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

ההצהרה על MediaRouteActionProvider ב-xml של התפריט זהה ל-CCL:

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

בדומה ל-CCL, יש לבטל את שיטת onCreateOptionMenu() של כל פעילות, אבל במקום להשתמש ב-CastManager.addMediaRouterButton, משתמשים ב-CastButtonRESULT של CAF כדי להעביר את MediaRouteButton למסגרת Cast:

public boolean onCreateOptionsMenu(Menu menu) {
    super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.browse, menu);
    CastButtonFactory.setUpMediaRouteButton(getApplicationContext(),
                                                menu,
                                                R.id.media_route_menu_item);
    return true;
}

שליטה במכשיר

בדומה ל-CCL, ב-CAF, השליטה במכשיר מטופלת ברובה במסגרת. אפליקציית השולח לא צריכה להתחבר (ולא לנסות לטפל בה) בהתחברות למכשיר ולהפעיל את אפליקציית המקלט באמצעות GoogleApiClient.

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

ב-CCL צריך להרחיב את המחלקה VideoCastConsumerImpl כדי לעקוב אחרי סטטוס סשן ההעברה (cast):

private final VideoCastConsumer mCastConsumer = new VideoCastConsumerImpl() {
  public void onApplicationConnected(ApplicationMetadata appMetadata, 
                                     String sessionId,
                                     boolean wasLaunched) {}
  public void onDisconnectionReason(int reason) {}
  public void onDisconnected() {}
}

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

השיטות הבאות של SessionManagerListener ממופות מהממשק של CCL:VideoCastConsumer

  • VideoCastConsumer.onApplicationConnected-> SessionManagerListener.onSessionStarted
  • VideoCastConsumer.onDisconnected-> SessionManagerListener.onSessionEnded

יש להצהיר על מחלקה שמטמיעה את הממשק של SessionManagerListener ולהעביר את הלוגיקה של VideoCastConsumerImpl לשיטות ההתאמה:

private class CastSessionManagerListener implements SessionManagerListener<CastSession> {
  public void onSessionEnded(CastSession session, int error) {}
  public void onSessionStarted(CastSession session, String sessionId) {}
  public void onSessionEnding(CastSession session) {}
  ...
}

הכיתה CastSession מייצגת ביקור עם מכשיר CAST. למחלקה יש שיטות לשליטה בעוצמת הקול של המכשירים ולהשתקת המכשירים, כפי שאפשר לעשות ב-BaseCastManager.

במקום להשתמש ב-CCL VideoCastManager כדי להוסיף צרכן:

VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);

עכשיו עליך לרשום את SessionManagerListener:

mCastSessionManager = 
    CastContext.getSharedInstance(this).getSessionManager();
mCastSessionManagerListener = new CastSessionManagerListener();
mCastSessionManager.addSessionManagerListener(mCastSessionManagerListener,
                  CastSession.class);

כדי להפסיק להאזין לאירועים ב-CCL:

VideoCastManager.getInstance().removeVideoCastConsumer(mCastConsumer);

עכשיו אפשר להשתמש ב-SessionManager כדי להפסיק להאזין לאירועים בסשן:

mCastSessionManager.removeSessionManagerListener(mCastSessionManagerListener,
                    CastSession.class);

כדי להתנתק ממכשיר ה-Cast, צריך להשתמש ב-CCL:

VideoCastManager.disconnectDevice(boolean stopAppOnExit, 
            boolean clearPersistedConnectionData,
            boolean setDefaultRoute)

ל-CAF, יש להשתמש ב-SessionManager:

CastContext.getSharedInstance(this).getSessionManager()
                                   .endCurrentSession(true);

כדי לדעת אם השולח מחובר למקלט, CCL מספק את VideoCastManager.getInstance().isConnected() אבל ב-CF משתמשים בערך SessionManager:

public boolean isConnected() {
    CastSession castSession = CastContext.getSharedInstance(mAppContext)
                                  .getSessionManager()
                                  .getCurrentCastSession();
    return (castSession != null && castSession.isConnected());
}

ב-CAF, התראות על שינוי עוצמת קול/השתקה עדיין נשלחות בשיטות התקשרות חזרה בCast.Listener. מאזינים אלה רשומים ב-CastSession. כל ההתראות הנותרות במצב המכשיר נשלחות באמצעות CastStateListener קריאות חוזרות (callback). המאזינים האלה רשומים ב-CastSession. הקפידו לבטל את הרישום של מאזינים כאשר הקטעים, הפעילויות או האפליקציות המשויכים אליהם עוברים ברקע.

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

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

CAF מספק שירות חיבור מחדש משלו, כך שתוכלו להסיר את ה-CCL ReconnectionService מהמניפסט שלכם:

<service android:name="com.google.android.libraries.cast.companionlibrary.cast.reconnection.ReconnectionService"/>

כמו כן, אין צורך בהרשאות הבאות במניפסט שלכם ללוגיקת החיבור:

<uses‐permission android:name="android.permission.ACCESS_NETWORK_STATE"/>
<uses‐permission android:name="android.permission.ACCESS_WIFI_STATE"/>

שירות החיבור מחדש של CAF מופעל כברירת מחדל, אבל אפשר להשבית אותו באמצעות CastOptions.

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

רישום ערוץ מותאם אישית

ב-CCL יש שתי דרכים ליצור ערוץ הודעות מותאם אישית למקבל:

  • באמצעות CastConfiguration תוכלו להגדיר כמה שמות של מרחבים משותפים, והכלי CCL ייצור עבורכם את הערוץ.
  • השם DataCastManager דומה ל-VideoCastManager, אבל הוא מתמקד בתרחישים לדוגמה שאינם בפורמט מדיה.

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

בדומה ל-CCL, באפליקציות מדיה אין צורך לרשום במפורש את ערוץ בקרת המדיה.

פקד מדיה

ב-CAF, המחלקה RemoteMediaClient היא המקבילה לשיטות המדיה של VideoCastManager. הפונקציה RemoteMediaClient.Listener מקבילה לשיטות VideoCastConsumer. בפרט, השיטות onRemoteMediaPlayerMetadataUpdated ו-onRemoteMediaPlayerStatusUpdated VideoCastConsumer ממפות את השיטות onMetadataUpdated ו-onStatusUpdated של RemoteMediaClient.Listener בהתאמה:

private class CastMediaClientListener implements RemoteMediaClient.Listener {

    @Override
    public void onMetadataUpdated() {
        setMetadataFromRemote();
    }

    @Override
    public void onStatusUpdated() {
        updatePlaybackState();
    }

    @Override
    public void onSendingRemoteMediaRequest() {
    }

    @Override
    public void onQueueStatusUpdated() {
    }

    @Override
    public void onPreloadStatusUpdated() {
    }
}

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

אפשר לגשת אל RemoteMediaClient בתור השיטה getRemoteMediaClient של האובייקט CastSession.

CastSession castSession = CastContext.getSharedInstance(mAppContext)
                                     .getSessionManager()
                                     .getCurrentCastSession();
mRemoteMediaClient = castSession.getRemoteMediaClient();
mRemoteMediaClientListener = new CastMediaClientListener();

במקום ה-CCL:

VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);

עכשיו משתמשים ב-CAF:

mRemoteMediaClient.addListener(mRemoteMediaClientListener);

אפשר לרשום כל מספר של מאזינים דרך RemoteMediaClient, כדי לאפשר למספר רכיבי שולחים לשתף את המופע היחיד של RemoteMediaClient המשויך לסשן.

VideoCastManager של CCL מספק שיטות לטיפול בהפעלת מדיה:

VideoCastManager manager = VideoCastManager.getInstance();
if (manager.isRemoteMediaLoaded()) {
    manager.pause();
    mCurrentPosition = (int) manager.getCurrentMediaPosition();
}

תוכלו להטמיע אותן ב-CVR:

if (mRemoteMediaClient.hasMediaSession()) {
    mRemoteMediaClient.pause();
    mCurrentPosition = 
        (int)mRemoteMediaClient.getApproximateStreamPosition();
}

ב-CAF, כל בקשות המדיה שמקורן ב-RemoteMediaClient מחזירות RemoteMediaClient.MediaChannelResult באמצעות קריאה חוזרת (callback) של PendingResult, שניתן להשתמש בה כדי לעקוב אחר ההתקדמות והתוצאה הסופית של הבקשה.

גם ב-CCL וגם ב-CAF יש דירוגים ב-MediaInfo וב-MediaMetadata כדי לייצג פריטי מדיה וטעינת מדיה.

כדי לטעון מדיה ב-CCL, נעשה שימוש ב-VideoCastManager:

VideoCastManager.getInstance().loadMedia(media, autoPlay, mCurrentPosition, customData);

ב-CAF, RemoteMediaClient משמש לטעינת המדיה:

mRemoteMediaClient.load(media, autoPlay, mCurrentPosition, customData);

כדי לקבל את המידע והסטטוס של Media עבור סשן מדיה נוכחי במקלט, CCL משתמש בVideoCastManager:

MediaInfo mediaInfo = VideoCastManager.getInstance()
                                      .getRemoteMediaInformation();
int status = VideoCastManager.getInstance().getPlaybackStatus();
int idleReason = VideoCastManager.getInstance().getIdleReason();

ב-CAF, יש להשתמש ב-RemoteMediaClient כדי לקבל את אותו מידע:

MediaInfo mediaInfo = mRemoteMediaClient.getMediaInfo();
int status = mRemoteMediaClient.getPlayerState();
int idleReason = mRemoteMediaClient.getIdleReason();

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

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

במקום להשתמש בשיטת VideoCastConsumer onCastAvailabilityChanged של CCL כדי לדעת מתי להציג את שכבת-העל, צריך להצהיר על CastStateListener כדי לקבוע מתי לחצן ההעברה יהיה גלוי אחרי שמכשירי Cast יגלו ברשת המקומית עד MediaRouter:

private IntroductoryOverlay mIntroductoryOverlay;
private MenuItem mMediaRouteMenuItem;

protected void onCreate(Bundle savedInstanceState) {
    ...
    mCastStateListener = new CastStateListener() {
        @Override
        public void onCastStateChanged(int newState) {
            if (newState != CastState.NO_DEVICES_AVAILABLE) {
                showIntroductoryOverlay();
            }
        }
    };
    mCastContext = CastContext.getSharedInstance(this);
    mCastContext.registerLifecycleCallbacksBeforeIceCreamSandwich(this, 
        savedInstanceState);
}

protected void onResume() {
    mCastContext.addCastStateListener(mCastStateListener);
    ...
}

protected void onPause() {
    mCastContext.removeCastStateListener(mCastStateListener);
    ...
}

מעקב אחר המכונה של MediaRouteMenuItem:

public boolean onCreateOptionsMenu(Menu menu) {
   super.onCreateOptionsMenu(menu);
    getMenuInflater().inflate(R.menu.browse, menu);
    mMediaRouteMenuItem = CastButtonFactory.setUpMediaRouteButton(
            getApplicationContext(), menu,
            R.id.media_route_menu_item);
    showIntroductoryOverlay();
    return true;
}

בדקו אם אפשר לראות את MediaRouteButton כדי שיהיה אפשר להציג את שכבת-העל של הפתיח:

private void showIntroductoryOverlay() {
    if (mIntroductoryOverlay != null) {
        mIntroductoryOverlay.remove();
    }
    if ((mMediaRouteMenuItem != null) && mMediaRouteMenuItem.isVisible()) {
        new Handler().post(new Runnable() {
            @Override
            public void run() {
                mIntroductoryOverlay = new IntroductoryOverlay.Builder(
                        VideoBrowserActivity.this, mMediaRouteMenuItem)
                        .setTitleText(getString(R.string.introducing_cast))
                        .setOverlayColor(R.color.primary)
                        .setSingleTime()
                        .setOnOverlayDismissedListener(
                                new IntroductoryOverlay
                                    .OnOverlayDismissedListener() {
                                        @Override
                                        public void onOverlayDismissed() {
                                            mIntroductoryOverlay = null;
                                        }
                                })
                        .build();
                mIntroductoryOverlay.show();
            }
        });
    }
}

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

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

מיני-בקר

במקום ה-MiniController של ה-CCL, יש להשתמש בקובץ MiniControllerFragment של CAF בקובץ הפריסה של האפליקציה כדי לראות את הפעולות שבהן רוצים להציג את הבקר המקוצר:

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

CAF לא תומך בהגדרה הידנית שנתמכת ב-MiniController CCL וגם לא בפיצ'ר של Autoplay.

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

הודעה ומסך נעילה

בדומה ל-CCL של VideoCastNotificationService, CAF מספק MediaNotificationService כדי לנהל את התצוגה של התראות מדיה בזמן העברה.

עליך להסיר מהמניפסט את המידע הבא:

  • VideoIntentReceiver
  • VideoCastNotificationService

CCL תומך באספקת שירות התראות מותאם אישית באמצעות CastConfiguration.Builder. אין תמיכה בשירות CAF.

כדאי להשתמש באתחול הבא של CastManager באמצעות CCL:

VideoCastManager.initialize(
   getApplicationContext(),
   new CastConfiguration.Builder(
           context.getString(R.string.app_id))
       .addNotificationAction(
           CastConfiguration.NOTIFICATION_ACTION_PLAY_PAUSE,true)
       .addNotificationAction(
           CastConfiguration.NOTIFICATION_ACTION_DISCONNECT,true)
       .build());

לתצורה המקבילה ב-CAF, ערכת ה-SDK מספקת NotificationsOptions.Builder כדי לעזור לך ליצור פקדי מדיה למסך ההתראות ולמסך הנעילה באפליקציית השולח. ניתן להפעיל את פקדי ההתראות ומסך הנעילה באמצעות CastOptions כשמפעילים את CastContext.

public CastOptions getCastOptions(Context context) {
    NotificationOptions notificationOptions = 
        new NotificationOptions.Builder()
            .setActions(Arrays.asList(
                MediaIntentReceiver.ACTION_TOGGLE_PLAYBACK,
                MediaIntentReceiver.ACTION_STOP_CASTING), new int[]{0, 1})
            .build();
    CastMediaOptions mediaOptions = new CastMediaOptions.Builder()
             .setNotificationOptions(notificationOptions)
             .build();
    return new CastOptions.Builder()
             .setReceiverApplicationId(context.getString(R.string.app_id))
             .setCastMediaOptions(mediaOptions)
             .build();
}

התראות ופקדי נעילת מסך תמיד מופעלים ב-CAF. כמו כן, חשוב לזכור שלחצני ההפעלה/השהייה וההעברה (cast) מסופקים כברירת מחדל. CAF יעקוב באופן אוטומטי אחר החשיפה של הפעילויות כדי להחליט מתי להציג את התראת המדיה, חוץ מ-Gingerbread. (עבור Gingerbread, ראו הערה קודמת לגבי השימוש ב-registerLifecycleCallbacksBeforeIceCreamSandwich(), יש להסיר את ה-CLI של VideoCastManager incrementUiCounter ו-decrementUiCounter שיחות של CCL).

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

בקר מורחב

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

אפשר להסיר את ההצהרה VideoCastControllerActivity במניפסט.

ב-CF, עליכם להרחיב את הרחבת ההרחבה פעילות ולהוסיף את לחצן הפעלת Cast.

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

מיקוד אודיו

כמו ב-CCL, מיקוד האודיו מנוהל באופן אוטומטי.

בקרת עוצמת הקול

עבור Gingerbread, dispatchKeyEvent נדרש כמו ב-CCL. ב-ICS ואילך, הטיפול בפקדי CCL ו-CAF מטופל באופן אוטומטי.

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

כתוביות

ב-Android KitKat ואילך, ניתן להתאים אישית את הכתוביות באמצעות 'הגדרות כתוביות', שנמצאות ב'הגדרות' > 'נגישות'. עם זאת, לגרסאות קודמות של Android אין את היכולת הזו. CCL מטפל בכך על ידי מתן הגדרות מותאמות אישית עבור גרסאות קודמות והענקת גישה להגדרות המערכת ב-KitKat ומעלה.

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

ממשק ה-TracksChooserDialog של CCL אינו נחוץ יותר מכיוון ששינוי רצועות הכתוביות הסגורות מתבצע על ידי ממשק המשתמש המורחב של הבקר.

ה-API של הכתוביות ב-CAF דומה ל-v2.

רישום באגים לניפוי באגים

CAF לא מספק הגדרות רישום ביומן של ניפוי באגים.

שונות

תכונות ה-CCL הבאות לא נתמכות ב-CAF:

  • קבלת הרשאה לפני ההפעלה על ידי ציון MediaAuthService
  • הודעות הניתנות להגדרה בממשק המשתמש

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

כדי לבדוק אם העברת את האפליקציה לדוגמה Universal Music Player for Android (uamp) מ-CCL ל-CAF, כדאי לעיין בהבדלים.

יש לנו גם מדריכי Codelab ואפליקציות לדוגמה שמשתמשות ב-CAF.