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

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

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

บทนำ

  • เนื่องจากการออกแบบ CAF Sender ได้รับอิทธิพลจาก Cast Companion Library การย้ายข้อมูลจาก CCL ไปยัง CAF Sender เกี่ยวข้องกับการแมปชั้นเรียนและเมธอดเหล่านั้นแบบตัวต่อตัว
  • ผู้ส่ง CAF จะยังกระจายอยู่ในบริการ Google Play โดยใช้ตัวจัดการ SDK ของ Android
  • แพ็กเกจใหม่ (com.google.android.gms.cast.framework.*) ที่เพิ่มลงใน GoogleF Sender ด้วยฟังก์ชันที่คล้ายกับ CCL มีหน้าที่รับผิดชอบต่อการปฏิบัติตามรายการตรวจสอบการออกแบบ Google Cast
  • ผู้ส่ง CAF มีวิดเจ็ตที่สอดคล้องกับข้อกําหนดของ Cast UX วิดเจ็ตเหล่านี้คล้ายกับวิดเจ็ตที่ CCL ระบุไว้
  • ผู้ส่ง CAF มีการโค้ดเรียกกลับแบบไม่พร้อมกันซึ่งคล้ายกับ CCL เพื่อติดตามสถานะและรับข้อมูล CAF Sender ต่างจากการใช้ 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 (Gingerburger) เวอร์ชัน 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 Singleton โดยใช้ OptionsProvider ที่เหมาะสมเพื่อระบุรหัสแอปพลิเคชันของผู้รับและตัวเลือกอื่นๆ ทั่วโลก CastContext มีบทบาทคล้ายกับ CCL VideoCastManager โดยการระบุ Singleton ที่ลูกค้าโต้ตอบด้วย OptionsProvider คล้ายกับ CastConfiguration ของ CCL เพื่อช่วยให้คุณกําหนดค่าฟีเจอร์เฟรมเวิร์กแคสต์ได้

หาก 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;
    }
}

อ่านแอปตัวอย่างเพื่อดูการใช้งาน 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 ด้วยตนเองในเมธอด 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 เพื่อต่อ MediaMediaButton กับเฟรมเวิร์ก "แคสต์"

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 ใน CF การควบคุมอุปกรณ์ส่วนใหญ่ได้รับการจัดการโดยเฟรมเวิร์ก แอปพลิเคชันของผู้ส่งไม่จําเป็นต้องจัดการ (และไม่ควรลองจัดการ) การเชื่อมต่อกับอุปกรณ์และเปิดใช้งานแอปพลิเคชันตัวรับโดยใช้ 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 โค้ดเรียกกลับของเซสชันของ ManagerManagerListener กําหนดเมธอดเรียกกลับสําหรับเหตุการณ์อายุการใช้งานของเซสชันทั้งหมด

วิธีSessionManagerListenerต่อไปนี้แมปจากอินเทอร์เฟซ VideoCastConsumer ของ CCL

  • 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 การแจ้งเตือนการเปลี่ยนแปลงระดับเสียง/ปิดเสียงจะยังส่งผ่านเมธอดเรียกกลับใน Cast.Listener โดยผู้ฟังเหล่านี้ลงทะเบียนกับ CastSession การแจ้งเตือนสถานะอุปกรณ์ที่เหลือทั้งหมดจะส่งผ่านการเรียกกลับ CastStateListener ผู้ฟังเหล่านี้ลงทะเบียนกับ CastSession ตรวจสอบว่าคุณยังคงยกเลิกการลงทะเบียนผู้ฟังเมื่อส่วน กิจกรรม หรือแอปที่เชื่อมโยงอยู่เบื้องหลัง

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

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

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 ซึ่งจะเรียกใช้ใน SessionManager โดยอัตโนมัติ

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

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

  • CastConfiguration ให้คุณระบุเนมสเปซหลายรายการ แล้ว CCL จะสร้างช่องให้คุณ
  • DataCastManager คล้ายกับ VideoCastManager แต่มุ่งเน้นกรณีการใช้งานที่ไม่ใช่สื่อ

CAF ทั้ง 2 วิธีนี้ไม่รองรับการสร้างแชแนลที่กําหนดเอง ดังนั้นคุณต้องทําตามขั้นตอน เพิ่มแชแนลที่กําหนดเองสําหรับแอปของผู้ส่งแทน

เช่นเดียวกับ 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);

จํานวน Listener จํานวนมากสามารถลงทะเบียนกับ 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();

การวางซ้อนที่แนะนํา

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

แทนที่จะใช้วิธี VideoCastConsumer onCastAvailabilityChanged ของ 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 ด้วย

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

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

CAF คล้ายกับ VideoCastNotificationService ของ CCL โดยให้บริการ 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 จะติดตามระดับการเข้าถึงกิจกรรมเพื่อตัดสินใจว่าจะแสดงการแจ้งเตือนสื่อเมื่อใด ยกเว้น Gingerburger (สําหรับ Gingerburger โปรดดูหมายเหตุก่อนหน้า การใช้ registerLifecycleCallbacksBeforeIceCreamSandwich(); CCL VideoCastManager incrementUiCounter และ decrementUiCounter ควรนําออก)

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

ตัวควบคุมแบบขยาย

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

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

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

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

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

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

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

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

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

คำบรรยาย

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

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

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

API คําบรรยาย ใน CAF คล้ายกับ v2

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

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

อื่นๆ

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

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

แอปตัวอย่าง

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

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