Di chuyển ứng dụng người gửi CCL sang Khung ứng dụng truyền (CAF)

Quy trình sau đây cho phép bạn chuyển đổi ứng dụng người gửi trên Android từ SDK truyền phiên bản 2 bằng CCL sang CAF. Tất cả các chức năng của CCL đã được triển khai trong CAF, vì vậy sau khi di chuyển, bạn sẽ không cần sử dụng CCL nữa.

SDK Người gửi CAF truyền sử dụng CastContext để quản lý GoogleAPIClient thay mặt bạn. CastContext quản lý vòng đời, lỗi và lệnh gọi lại cho bạn, giúp đơn giản hoá quá trình phát triển ứng dụng Truyền.

Giới thiệu

  • Vì thiết kế Người gửi CAF chịu ảnh hưởng của Thư viện đồng hành Truyền, nên việc di chuyển từ CCL sang Người gửi CAF chủ yếu bao gồm việc liên kết 1:1 các lớp và phương thức.
  • Người gửi CAF vẫn được phân phối dưới dạng một phần của Dịch vụ Google Play bằng cách sử dụng trình quản lý SDK Android.
  • Các gói mới (com.google.android.gms.cast.framework.*) đã được thêm vào Trình gửi CAF, với chức năng tương tự như CCL, sẽ chịu trách nhiệm tuân thủ Danh sách kiểm tra trong Google Cast Design.
  • Người gửi CAF cung cấp các tiện ích tuân thủ các yêu cầu về Trải nghiệm người dùng (Cast UX); các tiện ích này tương tự như các tiện ích do CCL cung cấp.
  • Người gửi CAF cung cấp các lệnh gọi lại không đồng bộ tương tự như CCL, để theo dõi trạng thái và lấy dữ liệu. Không giống như CCL, CAF Sender không cung cấp bất kỳ phương thức triển khai nào không hoạt động cho nhiều phương thức giao diện.

Trong các phần sau, chúng ta sẽ chủ yếu tập trung vào các ứng dụng tập trung vào video dựa trên VideoCastManager của CCL, nhưng trong nhiều trường hợp, các khái niệm tương tự cũng áp dụng cho DataCastManager.

Phần phụ thuộc

CCL và CAF có các phần phụ thuộc giống nhau đối với thư viện hỗ trợ AppCompat, thư viện hỗ trợ MediaRouter v7 và các dịch vụ của Google Play. Tuy nhiên, điểm khác biệt là CAF phụ thuộc vào khung Truyền mới có trong Dịch vụ Google Play phiên bản 9.2.0 trở lên.

Trong tệp build.gradle của bạn, hãy xoá các phần phụ thuộc trên com.google.android.gms:play-services-castcom.google.android.libraries.cast.companionlibrary:ccl, sau đó thêm khung Truyền mới:

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

Bạn cũng có thể xoá siêu dữ liệu của dịch vụ Google Play:

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

Mọi dịch vụ, hoạt động và tài nguyên trong phạm vi của CAF sẽ tự động được hợp nhất với tệp kê khai và tài nguyên của ứng dụng.

Phiên bản SDK Android tối thiểu mà CAF hỗ trợ là 9 (Gingerbread); phiên bản SDK Android tối thiểu của CCL là 10.

CCL cung cấp một phương thức thuận tiện là BaseCastManager.checkGooglePlayServices(activity) để xác minh rằng thiết bị của bạn có phiên bản tương thích của Dịch vụ Google Play. CAF không cung cấp tính năng này như một phần của SDK truyền. Làm theo quy trình Đảm bảo APK của Dịch vụ Google Play có tệp APK Dịch vụ Google Play để đảm bảo rằng APK Dịch vụ Google Play chính xác được cài đặt trên thiết bị của người dùng vì các bản cập nhật có thể không tiếp cận được tất cả người dùng ngay lập tức.

Bạn vẫn phải sử dụng một biến thể của Theme.AppCompat cho giao diện của ứng dụng.

Khởi chạy

Đối với CCL, bạn phải gọi VideoCastManager.initialize() trong phương thức onCreate() của thực thể Application. Logic này sẽ bị xóa khỏi mã lớp Application.

Trong CAF, cũng cần có một bước khởi động rõ ràng cho khung Truyền. Điều này liên quan đến việc khởi chạy singleton CastContext, sử dụng OptionsProvider phù hợp để chỉ định mã nhận dạng ứng dụng của người nhận và mọi tuỳ chọn chung khác. CastContext đóng vai trò tương tự như VideoCastManager của CCL bằng cách cung cấp một singleton mà khách hàng tương tác. OptionsProvider tương tự như CastConfiguration của CCL để cho phép bạn định cấu hình các tính năng của khung Cast.

Nếu CCL hiện tại của bạn CastConfiguration.Builder có dạng như sau:

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

Sau đó, trong CAF, CastOptionsProvider sau đây sử dụng CastOptions.Builder sẽ tương tự như:

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

Hãy xem ứng dụng mẫu của chúng tôi để biết cách triển khai hoàn chỉnh OptionsProvider.

Khai báo OptionsProvider trong phần tử "application" của tệp 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>

Khởi tạo từng phần CastContext trong phương thức onCreate của từng Activity (không phải thực thể Application):

private CastContext mCastContext;

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

    mCastContext = CastContext.getSharedInstance(this);
}

Cách truy cập vào singleton CastContext:

mCastContext = CastContext.getSharedInstance(this);

Khám phá thiết bị

Bạn nên xoá VideoCastManager incrementUiCounterdecrementUiCounter của CCL khỏi phương thức onResumeonPause của Activities.

Trong CAF, quá trình khám phá bắt đầu và dừng tự động bằng khung khi ứng dụng chạy ở nền trước và chuyển sang nền tương ứng.

Nút Truyền và hộp thoại Truyền

Giống như CCL, các thành phần này do thư viện hỗ trợ MediaRouter v7 cung cấp.

Nút Truyền vẫn được MediaRouteButton triển khai và có thể được thêm vào hoạt động của bạn (sử dụng ActionBar hoặc Toolbar) làm mục trong trình đơn.

Nội dung khai báo của MediaRouteActionProvider trong xml trình đơn cũng giống như với 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"/>

Tương tự như CCL, hãy ghi đè phương thức onCreateOptionMenu() của từng Hoạt động, nhưng thay vì sử dụng CastManager.addMediaRouterButton, hãy sử dụng CastButtonFactory của CAF để kết nối MediaRouteButton với khung Truyền:

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

Điều khiển thiết bị

Tương tự như CCL, trong CAF, việc kiểm soát thiết bị phần lớn là do khung xử lý. Ứng dụng của người gửi không cần xử lý (và không nên cố gắng xử lý) kết nối với thiết bị và chạy ứng dụng nhận bằng GoogleApiClient.

Sự tương tác giữa người gửi và người nhận hiện được biểu thị dưới dạng "phiên". Lớp SessionManager xử lý vòng đời phiên và tự động bắt đầu và dừng các phiên để phản hồi cử chỉ của người dùng: một phiên bắt đầu khi người dùng chọn một Thiết bị truyền trong hộp thoại Truyền và kết thúc khi người dùng nhấn vào nút "Dừng truyền" trong hộp thoại Truyền hoặc khi chính ứng dụng người gửi chấm dứt.

Trong CCL, bạn phải mở rộng lớp VideoCastConsumerImpl để theo dõi trạng thái truyền của phiên:

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

Trong CAF, ứng dụng của người gửi có thể được thông báo về các sự kiện trong vòng đời của phiên bằng cách đăng ký SessionManagerListener với SessionManager. Các lệnh gọi lại SessionManagerListener xác định các phương thức gọi lại cho tất cả các sự kiện trong vòng đời của phiên.

Các phương thức SessionManagerListener sau đây được liên kết từ giao diện VideoCastConsumer của CCL:

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

Khai báo một lớp triển khai giao diện SessionManagerListener và di chuyển logic VideoCastConsumerImpl sang các phương thức so khớp:

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) {}
  ...
}

Lớp CastSession đại diện cho một phiên hoạt động có Thiết bị truyền. Lớp này có các phương thức để điều khiển âm lượng thiết bị và tắt tiếng trạng thái, mà CCL thực hiện trong BaseCastManager.

Thay vì sử dụng CCL VideoCastManager để thêm người tiêu dùng:

VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);

Bây giờ, hãy đăng ký SessionManagerListener:

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

Cách dừng nghe các sự kiện trong CCL:

VideoCastManager.getInstance().removeVideoCastConsumer(mCastConsumer);

Bây giờ, hãy sử dụng SessionManager để dừng nghe các sự kiện trong phiên:

mCastSessionManager.removeSessionManagerListener(mCastSessionManagerListener,
                    CastSession.class);

Để ngắt kết nối một cách rõ ràng khỏi thiết bị Truyền, CCL đã sử dụng:

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

Đối với CAF, hãy sử dụng SessionManager:

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

Để xác định xem người gửi có được kết nối với người nhận hay không, CCL sẽ cung cấp VideoCastManager.getInstance().isConnected(), nhưng trong CAF, hãy sử dụng SessionManager:

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

Trong CAF, thông báo thay đổi âm lượng/tắt tiếng vẫn được phân phối thông qua các phương thức gọi lại trong Cast.Listener; những trình nghe này được đăng ký với CastSession. Tất cả các thông báo trạng thái thiết bị còn lại sẽ được gửi qua các lệnh gọi lại CastStateListener; các trình nghe này được đăng ký với CastSession. Hãy đảm bảo bạn vẫn hủy đăng ký trình nghe khi các mảnh, hoạt động hoặc ứng dụng liên quan chuyển sang chạy ở chế độ nền.

Logic kết nối lại

CAF cố gắng thiết lập lại các kết nối mạng bị mất do Mất tín hiệu Wi-Fi tạm thời hoặc lỗi mạng khác. Hiện tại, việc này được thực hiện ở cấp phiên. Phiên có thể chuyển sang trạng thái "đã tạm ngưng" khi mất kết nối và sẽ chuyển về trạng thái "đã kết nối" khi kết nối được khôi phục. Khung này đảm nhận việc kết nối lại với ứng dụng của thiết bị nhận và kết nối lại bất kỳ kênh Truyền nào trong quá trình này.

CAF cung cấp dịch vụ kết nối lại riêng, vì vậy, bạn có thể xoá CCL ReconnectionService khỏi tệp kê khai:

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

Bạn cũng không cần các quyền sau đây trong tệp kê khai cho logic kết nối lại:

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

Dịch vụ kết nối lại CAF được bật theo mặc định nhưng có thể bị tắt bằng cách sử dụng CastOptions.

Ngoài ra, CAF cũng thêm tính năng tiếp tục phiên tự động được bật theo mặc định (và có thể huỷ kích hoạt qua CastOptions). Nếu ứng dụng của người gửi được chuyển sang chế độ nền hoặc bị chấm dứt (bằng cách vuốt đi hoặc do sự cố) trong khi phiên Truyền đang diễn ra, thì khung sẽ cố gắng tiếp tục phiên đó khi ứng dụng người gửi quay lại nền trước hoặc được xử lý tự động trên các lệnh gọi lại SessionManagerListener.

Đăng ký kênh tuỳ chỉnh

CCL cung cấp hai cách tạo kênh thông báo tuỳ chỉnh cho người nhận:

  • CastConfiguration cho phép bạn chỉ định nhiều vùng chứa tên và CCL sẽ tạo kênh cho bạn.
  • DataCastManager tương tự như VideoCastManager nhưng tập trung vào các trường hợp sử dụng không phải phương tiện.

Cả hai cách tạo kênh tuỳ chỉnh này đều không được CAF hỗ trợ – bạn phải làm theo quy trình Thêm Kênh tuỳ chỉnh cho ứng dụng của người gửi.

Tương tự như CCL, đối với các ứng dụng đa phương tiện, bạn không cần đăng ký rõ ràng kênh điều khiển nội dung nghe nhìn.

Điều khiển phương tiện

Trong CAF, lớp RemoteMediaClient tương đương với các phương thức nội dung đa phương tiện VideoCastManager. RemoteMediaClient.Listener tương đương với các phương thức VideoCastConsumer. Cụ thể, phương thức onRemoteMediaPlayerMetadataUpdatedonRemoteMediaPlayerStatusUpdated của VideoCastConsumer liên kết với phương thức onMetadataUpdatedonStatusUpdated của 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() {
    }
}

Bạn không cần phải khởi tạo hoặc đăng ký đối tượng RemoteMediaClient một cách rõ ràng; khung sẽ tự động tạo thực thể cho đối tượng và đăng ký kênh nội dung nghe nhìn cơ bản tại thời điểm bắt đầu phiên nếu ứng dụng nhận được kết nối để hỗ trợ vùng chứa tên phương tiện.

Bạn có thể truy cập RemoteMediaClient dưới dạng phương thức getRemoteMediaClient của đối tượng CastSession.

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

Thay vì sử dụng CCL:

VideoCastManager.getInstance().addVideoCastConsumer(mCastConsumer);

Giờ hãy sử dụng CAF:

mRemoteMediaClient.addListener(mRemoteMediaClientListener);

Bạn có thể đăng ký bất kỳ số lượng trình nghe nào bằng RemoteMediaClient, cho phép nhiều thành phần người gửi chia sẻ một bản sao của RemoteMediaClient được liên kết với phiên hoạt động đó.

VideoCastManager của CCL cung cấp các phương thức để xử lý chế độ phát nội dung đa phương tiện:

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

Các thao tác này hiện được RemoteMediaClient triển khai trong CAF:

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

Trong CAF, tất cả yêu cầu nội dung đa phương tiện đưa ra trên RemoteMediaClient đều trả về RemoteMediaClient.MediaChannelResult thông qua lệnh gọi lại PendingResult có thể dùng để theo dõi tiến trình và kết quả cuối cùng của yêu cầu đó.

Cả CCL và CAF đều sử dụng lớp MediaInfoMediaMetadata để biểu thị các mục nội dung đa phương tiện và để tải nội dung nghe nhìn.

Để tải nội dung đa phương tiện trong CCL, VideoCastManager được sử dụng:

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

Trong CAF, RemoteMediaClient được dùng để tải nội dung nghe nhìn:

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

Để nhận thông tin Media và trạng thái của một phiên phát nội dung đa phương tiện hiện tại trên trình nhận, CCL sử dụng VideoCastManager:

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

Trong CAF, hãy sử dụng RemoteMediaClient để nhận thông tin tương tự:

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

Lớp phủ giới thiệu

Tương tự như CCL, CAF cung cấp thành phần hiển thị tuỳ chỉnh IntroductoryOverlay để làm nổi bật nút Truyền khi hiển thị cho người dùng lần đầu.

Thay vì sử dụng phương thức VideoCastConsumer onCastAvailabilityChanged của CCL để biết thời điểm hiển thị lớp phủ, hãy khai báo CastStateListener để xác định thời điểm hiển thị nút Truyền sau khi thiết bị Truyền được phát hiện trên mạng cục bộ bằng 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);
    ...
}

Theo dõi phiên bản 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;
}

Kiểm tra xem MediaRouteButton có hiển thị hay không để lớp phủ giới thiệu có thể hiển thị:

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

Hãy xem ứng dụng mẫu của chúng tôi để biết mã hoạt động hoàn chỉnh để hiển thị lớp phủ giới thiệu.

Để tuỳ chỉnh kiểu của lớp phủ giới thiệu, hãy làm theo quy trình Tuỳ chỉnh Lớp phủ giới thiệu.

Bộ điều khiển nhỏ

Thay vì MiniController của CCL, hãy sử dụng MiniControllerFragment của CAF trong tệp bố cục ứng dụng của hoạt động bạn muốn hiển thị bộ điều khiển nhỏ:

<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 không hỗ trợ cấu hình thủ công được MiniController của CCL hỗ trợ và cũng không hỗ trợ tính năng Autoplay.

Để tuỳ chỉnh kiểu và các nút của bộ điều khiển nhỏ, hãy làm theo quy trình Tuỳ chỉnh Bộ điều khiển nhỏ.

Thông báo và màn hình khoá

Tương tự như VideoCastNotificationService của CCL, CAF cung cấp một MediaNotificationService để quản lý việc hiển thị thông báo về nội dung nghe nhìn khi truyền.

Bạn cần xóa những nội dung sau khỏi tệp kê khai:

  • VideoIntentReceiver
  • VideoCastNotificationService

CCL hỗ trợ cung cấp dịch vụ thông báo tuỳ chỉnh bằng CastConfiguration.Builder; không được CAF hỗ trợ.

Hãy cân nhắc khởi chạy CastManager bằng CCL như sau:

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());

Đối với cấu hình tương đương trong CAF, SDK sẽ cung cấp NotificationsOptions.Builder để giúp bạn xây dựng các chế độ điều khiển nội dung nghe nhìn cho thông báo và màn hình khoá vào ứng dụng của người gửi. Bạn có thể bật các chế độ điều khiển màn hình thông báo và khoá bằng CastOptions khi khởi chạy 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();
}

Thông báo và các chế độ kiểm soát màn hình khoá luôn bật trong CAF. Ngoài ra, xin lưu ý rằng nút phát/tạm dừng và nút truyền được cung cấp theo mặc định. CAF sẽ tự động theo dõi mức độ hiển thị của Hoạt động để quyết định thời điểm hiển thị thông báo về nội dung nghe nhìn, ngoại trừ Gingerbread. (Đối với Gingerbread, vui lòng xem ghi chú trước đó về cách sử dụng registerLifecycleCallbacksBeforeIceCreamSandwich(); các lệnh gọi VideoCastManager incrementUiCounterdecrementUiCounter của CCL cần được xoá.)

Để tuỳ chỉnh các nút hiển thị trong thông báo, hãy làm theo quy trình Thêm nội dung điều khiển nội dung nghe nhìn vào thông báo và Màn hình khoá.

Mở rộng bộ điều khiển

CCL cung cấp VideoCastControllerActivityVideoCastControllerFragment để hiển thị bộ điều khiển mở rộng khi truyền nội dung nghe nhìn.

Bạn có thể xoá phần khai báo VideoCastControllerActivity trong tệp kê khai.

Trong CAF, bạn phải mở rộng ActivityControllerActivity và thêm nút Cast.

Để tuỳ chỉnh kiểu và nút xuất hiện trong tay điều khiển mở rộng, hãy làm theo quy trình Tuỳ chỉnh Bộ điều khiển mở rộng.

Tập trung âm thanh

Giống như CCL, tiêu điểm âm thanh được quản lý tự động.

Chỉnh âm lượng

Đối với Gingerbread, dispatchKeyEvent là bắt buộc giống như với CCL. Trong ICS trở lên cho cả việc điều khiển âm lượng CCL và CAF được xử lý tự động.

CAF cho phép kiểm soát âm lượng truyền thông qua nút âm lượng cứng trên điện thoại bên trong các hoạt động của ứng dụng, đồng thời hiển thị thanh âm lượng trực quan khi truyền trên các phiên bản được hỗ trợ. CAF cũng xử lý việc thay đổi âm lượng thông qua âm lượng cứng ngay cả khi ứng dụng của bạn không ở trước, bị khóa hoặc ngay cả khi màn hình tắt.

Phụ đề

Trong Android KitKat trở lên, bạn có thể tuỳ chỉnh phụ đề thông qua phần Cài đặt phụ đề trong phần Cài đặt > Hỗ trợ tiếp cận. Tuy nhiên, các phiên bản Android cũ hơn không có tính năng này. CCL xử lý vấn đề này bằng cách cung cấp chế độ cài đặt tuỳ chỉnh cho các phiên bản cũ và uỷ quyền cho các chế độ cài đặt hệ thống trên KitKat trở lên.

CAF không cung cấp các chế độ cài đặt tuỳ chỉnh để thay đổi các lựa chọn ưu tiên về phụ đề. Bạn nên xoá các tệp tham chiếu CaptionsPreferenceActivity trong tệp kê khai và XML tuỳ chọn.

TracksChooserDialog của CCL không còn cần thiết vì việc thay đổi các bản phụ đề do giao diện người dùng của bộ điều khiển mở rộng xử lý.

API phụ đề chi tiết trong CAF tương tự như phiên bản 2.

Ghi nhật ký gỡ lỗi

CAF không cung cấp chế độ cài đặt ghi nhật ký gỡ lỗi.

Khác

Các tính năng CCL sau đây không được hỗ trợ trong CAF:

  • Nhận được sự uỷ quyền trước khi phát bằng cách cung cấp một MediaAuthService
  • Thông báo giao diện người dùng có thể định cấu hình

Ứng dụng mẫu

Hãy xem khác biệt về việc di chuyển ứng dụng mẫu Universal Music Player cho Android (uamp) từ CCL sang CAF.

Chúng tôi cũng có hướng dẫn về lớp học lập trìnhứng dụng mẫu sử dụng CAF.