ย้ายข้อมูลแอปผู้ส่ง CCL ไปยังเฟรมเวิร์กแอปพลิเคชันแคสต์ (CAF)

ขั้นตอนต่อไปนี้จะช่วยให้คุณสามารถแปลงแอปผู้ส่งของ Android จาก Cast SDK v2 ด้วย CCL ไปยัง CAF ฟังก์ชันทั้งหมดของ CCL ใช้ใน CAF ดังนั้นเมื่อย้ายข้อมูลแล้ว คุณก็ไม่จำเป็นต้องใช้ CCL อีกต่อไป

Cast CAF Sender SDK ใช้ CastContext เพื่อจัดการ GoogleAPIClient ในนามของคุณ CastContext จะจัดการวงจร ข้อผิดพลาด และ Callback ให้คุณ ทำให้การพัฒนาแอป Cast ง่ายขึ้น

บทนำ

  • เนื่องจากการออกแบบผู้ส่ง CAF ได้รับอิทธิพลจากไลบรารีที่ใช้ร่วมกันของการแคสต์ การย้ายข้อมูลจาก CCL ไปยังผู้ส่ง CAF มักมีการแมปแบบหนึ่งต่อหนึ่ง และวิธีการสอน
  • ผู้ส่ง CAF ยังคงได้รับการแจกจ่ายโดยเป็นส่วนหนึ่งของบริการ Google Play โดยใช้โปรแกรมจัดการ Android SDK
  • แพ็กเกจใหม่ (com.google.android.gms.cast.framework.*) ที่ เพิ่มไปยังผู้ส่ง CAF แล้ว โดยมีฟังก์ชันการทำงานคล้ายกับ CCL จะมีการดำเนินการ ในการปฏิบัติตามข้อกำหนด รายการตรวจสอบการออกแบบของ Google Cast
  • ผู้ส่ง CAF มีวิดเจ็ตที่เป็นไปตามข้อกำหนด Cast UX วิดเจ็ตเหล่านี้คล้ายกับวิดเจ็ตที่ CCL
  • ผู้ส่ง CAF มี Callback แบบไม่พร้อมกันซึ่งคล้ายกับ CCL เพื่อติดตาม สถานะต่างๆ และรับข้อมูล ผู้ส่ง CAF จะไม่ดำเนินการใดๆ ซึ่งต่างจาก CCL การนำวิธีการติดต่อต่างๆ ไปใช้

ในส่วนต่อไปนี้ เราจะเน้นไปที่การเน้นวิดีโอเป็นหลัก จาก VideoCastManager ของ CCL แต่ในหลายกรณี แนวคิดต่างๆ จะนำไปใช้กับ DataCastManager ด้วยเช่นกัน

การอ้างอิง

CCL และ CAF มีทรัพยากร Dependency เดียวกันในไลบรารีการสนับสนุนของ AppCompat ไลบรารีสนับสนุน MediaRouter v7 และบริการ Google Play อย่างไรก็ตาม ความแตกต่าง CAF ขึ้นอยู่กับเฟรมเวิร์ก Cast ใหม่ที่มีให้บริการใน Google Play หรือไม่ บริการ 9.2.0 ขึ้นไป

ในไฟล์ build.gradle ให้นำทรัพยากร Dependency ใน 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 ออก ผสานเข้ากับไฟล์ Manifest และทรัพยากรของแอป

Android SDK เวอร์ชันขั้นต่ำที่ CAF รองรับคือ 9 (Gingerbread); เวอร์ชัน Android SDK ขั้นต่ำของ CCL คือ 10

CCL มอบวิธีการอำนวยความสะดวก BaseCastManager.checkGooglePlayServices(activity) เพื่อยืนยันว่า เวอร์ชันของบริการ Google Play ที่มีอยู่ในอุปกรณ์ CAF ไม่ ให้ข้อมูลนี้เป็นส่วนหนึ่งของ Cast SDK ทำตามขั้นตอน ตรวจสอบว่าอุปกรณ์มี APK ของบริการ Google Play เพื่อให้แน่ใจว่ามีการติดตั้ง APK ของบริการ Google Play ที่ถูกต้องใน อุปกรณ์เนื่องจากการอัปเดตอาจ ไม่ได้เข้าถึงผู้ใช้ทั้งหมดในทันที

คุณยังคงต้องใช้ธีมของ Theme.AppCompat กับแอปพลิเคชัน

การเริ่มต้น

สำหรับ CCL ต้องมีการเรียกใช้ VideoCastManager.initialize() ใน onCreate() ของอินสแตนซ์แอปพลิเคชัน ตรรกะนี้ควรเป็น นำออกจากรหัสชั้นเรียนของแอปพลิเคชันแล้ว

ใน CAF จำเป็นต้องมีขั้นตอนการเริ่มต้นอย่างชัดแจ้งสำหรับการแคสต์ ขั้นตอนนี้เกี่ยวข้องกับการเริ่มต้นซิงเกิลตันของ CastContext โดยใช้ OptionsProvider ที่เหมาะสมเพื่อระบุรหัสแอปพลิเคชันของผู้รับและ อื่นๆ ทั่วโลก CastContext มีบทบาทคล้ายกับ CCL VideoCastManager ด้วยการระบุ Singleton ที่ลูกค้าโต้ตอบด้วย OptionsProvider คล้ายกับ CastConfiguration ของ CCL เพื่อให้คุณ เพื่อกำหนดค่าฟีเจอร์เฟรมเวิร์กของ Cast

หาก CCL ปัจจุบัน CastConfiguration.Builder มีลักษณะเช่นนี้

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

จากนั้นใน CAF ให้ 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;
    }
}

ดูตัวอย่างแอปของเรา สำหรับการติดตั้งใช้งาน OptionsProvider อย่างสมบูรณ์

ประกาศ OptionsProvider ภายใน "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 แบบ Lazy Loading ในเมธอด onCreate ของ Activity แต่ละรายการ (และไม่ใช่อินสแตนซ์ Application):

private CastContext mCastContext;

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

    mCastContext = CastContext.getSharedInstance(this);
}

วิธีเข้าถึงการใช้ Singleton ของ CastContext

mCastContext = CastContext.getSharedInstance(this);

การค้นหาอุปกรณ์

VideoCastManager incrementUiCounter และ decrementUiCounter ของ CCL จะถูกลบออกจากเมธอด onResume และ onPause ของ Activities ของคุณ

ใน CAF ขั้นตอนการค้นหาจะเริ่มต้นและหยุดโดยอัตโนมัติโดย เมื่อแอปทำงานเบื้องหน้า และไปที่เบื้องหลัง ตามลำดับ

ปุ่ม "แคสต์" และกล่องโต้ตอบ "แคสต์"

เช่นเดียวกับ CCL คอมโพเนนต์เหล่านี้มีให้บริการโดยการสนับสนุน MediaRouter v7 ไลบรารี

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 ให้ใช้ CastButtonFactory ของ CAF แทน เพื่อกำหนดเส้นทาง MediaRouteButton ไปยังเฟรมเวิร์กการแคสต์ ดังนี้

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

ควบคุมอุปกรณ์

ใน CAF การควบคุมอุปกรณ์ส่วนใหญ่จะจัดการโดยเฟรมเวิร์กเช่นเดียวกับ CCL แอปพลิเคชันของผู้ส่งไม่จำเป็นต้องจัดการ (และไม่ควรพยายามจัดการ) เชื่อมต่อกับอุปกรณ์และเปิดแอปพลิเคชันตัวรับโดยใช้ GoogleApiClient

ตอนนี้การโต้ตอบระหว่างผู้ส่งและผู้รับแสดงเป็น "เซสชัน" คลาส SessionManager จะจัดการวงจรเซสชันและจะเริ่มต้นโดยอัตโนมัติ และหยุดเซสชันตามท่าทางสัมผัสของผู้ใช้: เซสชันจะเริ่มต้นเมื่อ ผู้ใช้เลือกอุปกรณ์แคสต์ในกล่องโต้ตอบ "แคสต์" และจะสิ้นสุดลงเมื่อผู้ใช้แตะ "หยุดแคสต์" ในกล่องโต้ตอบ "แคสต์" หรือเมื่อแอปของผู้ส่งเอง สิ้นสุด

ใน CCL คุณต้องขยายคลาส VideoCastConsumerImpl เพื่อติดตามการแคสต์ สถานะเซสชัน:

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 Callback ของ SessionManagerListener จะกำหนดเมธอด Callback สำหรับเซสชันทั้งหมด ในวงจร

เมธอด 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 แสดงเซสชันที่มีอุปกรณ์แคสต์ ชั้นเรียนมี ในการควบคุมระดับเสียงของอุปกรณ์และสถานะปิดเสียง ซึ่ง CCL ทำใน 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);

หากต้องการยกเลิกการเชื่อมต่อจากอุปกรณ์แคสต์อย่างชัดเจน CCL จะใช้สิ่งต่อไปนี้

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

สำหรับ CAF ให้ใช้ SessionManager

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

CCL จะให้ข้อมูลในการพิจารณาว่าผู้ส่งเชื่อมต่อกับผู้รับหรือไม่ VideoCastManager.getInstance().isConnected() แต่ใน CAF ให้ใช้โอเปอเรเตอร์ SessionManager:

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

ใน CAF การแจ้งเตือนการเปลี่ยนแปลงระดับเสียง/ปิดเสียงจะยังคงส่งผ่าน Callback ใน Cast.Listener ผู้ฟังเหล่านี้ลงทะเบียนด้วย CastSession การแจ้งเตือนสถานะอุปกรณ์ที่เหลืออยู่ทั้งหมดจะส่งผ่านทาง Callback CastStateListener รายการ ผู้ฟังเหล่านี้จะลงทะเบียนกับ CastSession ตรวจดูว่าคุณยังคงยกเลิกการลงทะเบียน Listener เมื่อลิงก์ ส่วนย่อย กิจกรรม หรือแอปไปยังพื้นหลัง

ตรรกะการเชื่อมต่ออีกครั้ง

CAF พยายามเชื่อมต่อเครือข่ายที่สูญหายเนื่องจากการเชื่อมต่ออีกครั้ง การสูญเสียสัญญาณ Wi-Fi ชั่วคราวหรือข้อผิดพลาดอื่นๆ ของเครือข่าย ซึ่งขณะนี้ดำเนินการได้ที่ ระดับเซสชัน เซสชันสามารถป้อนคำว่า "ถูกระงับ" เมื่อมีการเชื่อมต่อ สูญหาย และจะเปลี่ยนกลับเป็น "เชื่อมต่อแล้ว" สถานะเมื่อมีการเชื่อมต่อ กู้คืนแล้ว เฟรมเวิร์กจะเริ่มเชื่อมต่อกับแอปพลิเคชันตัวรับอีกครั้ง และเชื่อมต่อช่อง Cast ใหม่ อันเป็นส่วนหนึ่งของกระบวนการนี้

CAF มีบริการเชื่อมต่อใหม่ของตัวเอง คุณจึงสามารถนำออก CCL ReconnectionService จากไฟล์ Manifest ของคุณ:

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

นอกจากนี้ คุณไม่จำเป็นต้องมีสิทธิ์ต่อไปนี้ในไฟล์ Manifest สำหรับ ตรรกะการเชื่อมต่อใหม่:

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

บริการเชื่อมต่อ CAF อีกครั้งจะเปิดใช้โดยค่าเริ่มต้น แต่สามารถปิดใช้ได้โดยใช้ CastOptions

นอกจากนี้ CAF ยังเพิ่มการเริ่มเซสชันอัตโนมัติอีกครั้ง ซึ่งเปิดใช้งานโดย ค่าเริ่มต้น (และปิดใช้งานได้ผ่าน CastOptions) หากแอปพลิเคชันของผู้ส่งคือ ถูกส่งไปยังพื้นหลังหรือถูกยกเลิกการใช้งาน (ด้วยการกวาดออกไปหรือเกิดการชน) ขณะที่เซสชันการแคสต์กำลังดำเนินอยู่ เฟรมเวิร์กจะพยายามทำงานนั้นต่อ เซสชันเมื่อแอปพลิเคชันผู้ส่งกลับไปที่เบื้องหน้าหรือเปิดอีกครั้ง ปัญหานี้จะได้รับการจัดการโดย SessionManager โดยอัตโนมัติ ซึ่งจะออก Callback ที่เหมาะสมในอินสแตนซ์ SessionManagerListener ที่ลงทะเบียนไว้

การลงทะเบียนแชแนลที่กำหนดเอง

CCL มีวิธีสร้างแชแนลข้อความที่กำหนดเองให้กับผู้รับ 2 วิธี ดังนี้

  • 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 อย่างชัดแจ้ง object; เฟรมเวิร์กจะสร้างอินสแตนซ์ของออบเจ็กต์โดยอัตโนมัติและลงทะเบียน ช่องทางสื่อที่สำคัญ ณ เวลาเริ่มต้นเซสชัน หากแอปพลิเคชันตัวรับถูก เชื่อมต่ออยู่เพื่อให้รองรับเนมสเปซสื่อ

สามารถเข้าถึง 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();
}

ขณะนี้ RemoteMediaClient ใน CAF ได้นำมาใช้งาน:

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

ใน CAF คำขอสื่อทั้งหมดที่ออกโดย RemoteMediaClient จะแสดงผล RemoteMediaClient.MediaChannelResult ผ่านการโทรกลับของ 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();

การวางซ้อนบทนำ

CAF จะแสดงมุมมองที่กำหนดเอง IntroductoryOverlay เพื่อไฮไลต์เช่นเดียวกับ CCL ปุ่ม "แคสต์" เมื่อแสดงต่อผู้ใช้เป็นครั้งแรก

แทนที่จะใช้เมธอด onCastAvailabilityChanged VideoCastConsumer ของ CCL ถ้าต้องการทราบว่าจะแสดงการวางซ้อนเมื่อใด ให้ประกาศ CastStateListener เพื่อกำหนด เมื่อระบบแสดงปุ่ม "แคสต์" เมื่อพบอุปกรณ์แคสต์ใน เครือข่ายภายในจาก 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 ด้วย

หากต้องการปรับแต่งการจัดรูปแบบและปุ่มของตัวควบคุมขนาดเล็ก ให้ทำตาม กระบวนการ ปรับแต่ง Mini Controller

การแจ้งเตือนและหน้าจอล็อก

เช่นเดียวกับ VideoCastNotificationService ของ CCL โดย CAF จะให้ MediaNotificationService เพื่อจัดการการแสดงการแจ้งเตือนสื่อ เมื่อแคสต์

คุณต้องนำรายการต่อไปนี้ออกจากไฟล์ Manifest

  • 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 และโปรดทราบว่า ปุ่มเล่น/หยุดชั่วคราว และหยุดแคสต์จะมีให้โดยค่าเริ่มต้น CAF จะติดตามการมองเห็นกิจกรรมโดยอัตโนมัติเพื่อการตัดสินใจ เวลาที่ควรแสดงการแจ้งเตือนสื่อ ยกเว้น Gingerbread (สำหรับ Gingerbread โปรดดูหมายเหตุก่อนหน้านี้เกี่ยวกับ โดยใช้ registerLifecycleCallbacksBeforeIceCreamSandwich(); CCL VideoCastManager incrementUiCounter และ decrementUiCounter สาย ควรนำออก)

หากต้องการปรับแต่งปุ่มที่แสดงในการแจ้งเตือน ให้ทำตาม กระบวนการ เพิ่มการควบคุมสื่อลงในการแจ้งเตือนและหน้าจอล็อก

ตัวควบคุมที่ขยาย

CCL จะให้ VideoCastControllerActivity และ VideoCastControllerFragment เพื่อแสดงตัวควบคุมที่ขยายเมื่อแคสต์สื่อ

คุณจะนำการประกาศ VideoCastControllerActivity ในไฟล์ Manifest ออกได้

ใน CAF คุณจะต้อง ขยายExpandedControllerActivity และเพิ่มปุ่ม "แคสต์"

หากต้องการปรับแต่งรูปแบบและปุ่มที่แสดงในส่วนขยาย ควบคุม โปรดปฏิบัติตามขั้นตอน ปรับแต่งตัวควบคุมที่ขยาย

โฟกัสอัตโนมัติ

การโฟกัสเสียงจะได้รับการจัดการโดยอัตโนมัติเช่นเดียวกับ CCL

การควบคุมระดับเสียง

สำหรับ Gingerbread จำเป็นต้องใช้ dispatchKeyEvent เช่นเดียวกับ CCL ใน ICS ขึ้นไป สำหรับการควบคุมระดับเสียงทั้ง CCL และ CAF โดยอัตโนมัติ

CAF ให้คุณควบคุมระดับเสียงของการแคสต์ผ่านปุ่มปรับระดับเสียงบน โทรศัพท์ภายในกิจกรรมแอปและแสดงแถบระดับเสียงเมื่อ กำลังแคสต์ในเวอร์ชันที่รองรับ CAF ยังจัดการการเปลี่ยนแปลงปริมาณผ่าน ระดับเสียงยากแม้แอปของคุณจะไม่ได้อยู่ด้านหน้า ล็อกอยู่ หรือแม้ว่าหน้าจอจะ ปิดอยู่

คำบรรยาย

ใน Android KitKat ขึ้นไป คุณจะปรับแต่งคำบรรยายแทนเสียงผ่านคำบรรยายแทนเสียงได้ การตั้งค่า ซึ่งอยู่ในการตั้งค่า > การช่วยเหลือพิเศษ Android เวอร์ชันก่อนหน้านี้ แต่ไม่มีความสามารถนี้ CCL จัดการเรื่องนี้โดยการระบุ การตั้งค่าสำหรับเวอร์ชันก่อนหน้าและการมอบสิทธิ์ไปยังการตั้งค่าระบบใน KitKat และสูงกว่า

CAF ไม่ได้ระบุการตั้งค่าที่กำหนดเองเพื่อเปลี่ยนค่ากำหนดของคำบรรยาย คุณ ควรนำการอ้างอิง CaptionsPreferenceActivity ในไฟล์ Manifest ออก และ XML ค่ากำหนดของคุณ

ไม่จำเป็นต้องใช้ TracksChooserDialog ของ CCL แล้วนับตั้งแต่เปลี่ยน แทร็กคำบรรยายแทนเสียงจะจัดการโดย UI ตัวควบคุมที่ขยาย

closed captioning API ใน CAF จะคล้ายกับ v2

การบันทึกการแก้ไขข้อบกพร่อง

CAF ไม่มีการตั้งค่าการบันทึกการแก้ไขข้อบกพร่อง

อื่นๆ

CAF ไม่รองรับฟีเจอร์ CCL ต่อไปนี้

  • การขออนุญาตก่อนเล่นด้วยการให้ MediaAuthService
  • ข้อความ UI ที่กำหนดค่าได้

แอปตัวอย่าง

ดูความแตกต่างในการย้ายข้อมูลแอปตัวอย่าง Universal Music Player สำหรับ Android (uamp) จาก CCL ไปยัง CAF

นอกจากนี้ เรายังมีบทแนะนำเกี่ยวกับ Codelab และตัวอย่างแอปที่ใช้ CAF