Phát triển dịch vụ đầu vào TV

Dịch vụ đầu vào TV đại diện cho một nguồn luồng nội dung nghe nhìn và cho phép bạn trình bày nội dung nghe nhìn của mình trong một kiểu truyền hình truyền thống, phát sóng dưới dạng kênh và chương trình. Với dịch vụ đầu vào TV, bạn có thể cung cấp chế độ kiểm soát của cha mẹ, thông tin hướng dẫn chương trình và mức phân loại nội dung. Dịch vụ đầu vào TV hoạt động bằng ứng dụng Android trên TV. Ứng dụng này rốt cuộc sẽ kiểm soát và trình bày nội dung của kênh trên TV. Ứng dụng TV hệ thống được phát triển riêng cho thiết bị và không thể thay đổi theo các ứng dụng bên thứ ba. Để biết thêm thông tin về Khung đầu vào TV (TIF) cấu trúc và các thành phần của nó, xem Khung đầu vào TV.

Tạo dịch vụ đầu vào TV bằng Thư viện đồng hành TIF

Thư viện đồng hành TIF là một khung cung cấp khả năng mở rộng triển khai các tính năng phổ biến của dịch vụ đầu vào TV. API này dành cho nhà sản xuất thiết bị gốc (OEM) để tạo chỉ dành cho Android 5.0 (API cấp 21) đến Android 7.1 (API cấp 25).

Cập nhật dự án

Thư viện đồng hành TIF có sẵn để nhà sản xuất thiết bị gốc (OEM) sử dụng trong androidtv-sample-inputs kho lưu trữ. Hãy xem kho lưu trữ đó để biết ví dụ về cách đưa thư viện vào ứng dụng.

Khai báo dịch vụ đầu vào TV trong tệp kê khai

Ứng dụng của bạn phải cung cấp phiên bản tương thích với TvInputService mà hệ thống dùng để truy cập vào ứng dụng của bạn. TIF Thư viện đồng hành cung cấp lớp BaseTvInputService cung cấp phương thức triển khai mặc định của TvInputService mà bạn có thể tuỳ chỉnh. Tạo một lớp con của BaseTvInputService, và khai báo lớp con trong tệp kê khai dưới dạng dịch vụ.

Trong phần khai báo tệp kê khai, hãy chỉ định BIND_TV_INPUT để cho phép để kết nối đầu vào TV với hệ thống. Dịch vụ hệ thống thực hiện liên kết và có Quyền BIND_TV_INPUT. Ứng dụng TV của hệ thống gửi yêu cầu đến dịch vụ đầu vào TV thông qua giao diện TvInputManager.

Trong phần khai báo dịch vụ, hãy thêm một bộ lọc ý định chỉ định TvInputService làm hành động để thực hiện với ý định. Ngoài ra, hãy khai báo siêu dữ liệu dịch vụ dưới dạng một tài nguyên XML riêng. Chiến lược phát hành đĩa đơn Nội dung khai báo dịch vụ, bộ lọc ý định và khai báo siêu dữ liệu dịch vụ trong ví dụ sau:

<service android:name=".rich.RichTvInputService"
    android:label="@string/rich_input_label"
    android:permission="android.permission.BIND_TV_INPUT">
    <!-- Required filter used by the system to launch our account service. -->
    <intent-filter>
        <action android:name="android.media.tv.TvInputService" />
    </intent-filter>
    <!-- An XML file which describes this input. This provides pointers to
    the RichTvInputSetupActivity to the system/TV app. -->
    <meta-data
        android:name="android.media.tv.input"
        android:resource="@xml/richtvinputservice" />
</service>

Xác định siêu dữ liệu dịch vụ trong một tệp XML riêng. Dịch vụ Tệp XML siêu dữ liệu phải bao gồm giao diện thiết lập mô tả đầu vào TV cấu hình ban đầu và quét kênh. Tệp siêu dữ liệu cũng phải chứa gắn cờ cho biết người dùng có thể ghi lại nội dung hay không. Để biết thêm thông tin về cách hỗ trợ ghi lại nội dung trong ứng dụng của bạn, hãy xem Hỗ trợ ghi nội dung.

Tệp siêu dữ liệu dịch vụ nằm trong thư mục tài nguyên XML cho ứng dụng của bạn và phải khớp với tên của tài nguyên mà bạn đã khai báo trong tệp kê khai. Bằng cách sử dụng các mục nhập tệp kê khai từ ví dụ trước, bạn sẽ tạo tệp XML tại res/xml/richtvinputservice.xml, với phần tử những nội dung sau:

<?xml version="1.0" encoding="utf-8"?>
<tv-input xmlns:android="http://schemas.android.com/apk/res/android"
  android:canRecord="true"
  android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" />

Xác định các kênh và tạo hoạt động thiết lập của bạn

Dịch vụ đầu vào TV của bạn phải xác định ít nhất một kênh mà người dùng truy cập thông qua ứng dụng TV hệ thống. Bạn nên đăng ký kênh của mình trong cơ sở dữ liệu hệ thống và cung cấp hoạt động thiết lập mà hệ thống gọi khi không tìm thấy kênh cho ứng dụng của bạn.

Trước tiên, hãy cho phép ứng dụng của bạn đọc từ và ghi vào hệ thống Điện tử Hướng dẫn lập trình (EPG), trong đó dữ liệu bao gồm các kênh và chương trình có sẵn cho người dùng. Để cho phép ứng dụng của bạn thực hiện những tác vụ này và đồng bộ hoá với EPG sau khi khởi động lại thiết bị, hãy thêm các phần tử sau vào tệp kê khai ứng dụng:

<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/>

Hãy thêm phần tử sau đây để đảm bảo rằng ứng dụng của bạn sẽ xuất hiện trong Cửa hàng Google Play dưới dạng một ứng dụng cung cấp các kênh nội dung trong Android TV:

<uses-feature
    android:name="android.software.live_tv"
    android:required="true" />

Tiếp theo, hãy tạo một lớp mở rộng EpgSyncJobService . Lớp trừu tượng này giúp bạn dễ dàng tạo dịch vụ công việc tạo và cập nhật các kênh trong cơ sở dữ liệu hệ thống.

Trong lớp con, hãy tạo và trả về danh sách đầy đủ các kênh trong getChannels(). Nếu kênh của bạn đến từ một tệp XMLTV, hãy sử dụng lớp XmlTvParser. Nếu không, hãy tạo các kênh theo phương thức lập trình bằng lớp Channel.Builder.

Đối với mỗi kênh, hệ thống gọi getProgramsForChannel() khi dịch vụ này cần danh sách các chương trình có thể xem được trong một khoảng thời gian nhất định trên kênh. Trả về danh sách đối tượng Program cho của bạn. Dùng lớp XmlTvParser để tải các chương trình từ tệp XMLTV hoặc tạo tệp theo phương thức lập trình bằng Lớp Program.Builder.

Đối với mỗi đối tượng Program, hãy sử dụng một InternalProviderData để thiết lập thông tin chương trình, chẳng hạn như loại video của chương trình. Nếu chỉ giới hạn số lượng chương trình muốn kênh lặp lại trong một vòng lặp, hãy sử dụng phương thức Phương thức InternalProviderData.setRepeatable() có giá trị là true khi thiết lập thông tin về chương trình của bạn.

Sau khi bạn triển khai dịch vụ công việc, hãy thêm dịch vụ đó vào tệp kê khai ứng dụng:

<service
    android:name=".sync.SampleJobService"
    android:permission="android.permission.BIND_JOB_SERVICE"
    android:exported="true" />

Cuối cùng, hãy tạo một hoạt động thiết lập. Hoạt động thiết lập của bạn sẽ cung cấp một cách để đồng bộ hoá dữ liệu kênh và chương trình. Một cách để thực hiện việc này là để người dùng thực hiện thông qua giao diện người dùng trong hoạt động. Bạn cũng có thể để ứng dụng tự động thực hiện việc này khi hoạt động bắt đầu. Khi hoạt động thiết lập cần đồng bộ hoá kênh và thông tin chương trình, ứng dụng sẽ bắt đầu dịch vụ việc làm:

Kotlin

val inputId = getActivity().intent.getStringExtra(TvInputInfo.EXTRA_INPUT_ID)
EpgSyncJobService.cancelAllSyncRequests(getActivity())
EpgSyncJobService.requestImmediateSync(
        getActivity(),
        inputId,
        ComponentName(getActivity(), SampleJobService::class.java)
)

Java

String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
EpgSyncJobService.cancelAllSyncRequests(getActivity());
EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
        new ComponentName(getActivity(), SampleJobService.class));

Sử dụng phương thức requestImmediateSync() để đồng bộ hoá dịch vụ làm việc. Người dùng phải đợi quá trình đồng bộ hoá hoàn tất, vì vậy bạn nên hãy giữ cho khoảng thời gian yêu cầu tương đối ngắn.

Sử dụng phương thức setUpPeriodicSync() để có dịch vụ công việc đồng bộ hoá định kỳ dữ liệu kênh và chương trình trong nền:

Kotlin

EpgSyncJobService.setUpPeriodicSync(
        context,
        inputId,
        ComponentName(context, SampleJobService::class.java)
)

Java

EpgSyncJobService.setUpPeriodicSync(context, inputId,
        new ComponentName(context, SampleJobService.class));

Thư viện đồng hành TIF cung cấp một phương thức nạp chồng bổ sung của requestImmediateSync() cho phép bạn chỉ định thời lượng để đồng bộ hoá theo mili giây. Phương thức mặc định sẽ đồng bộ hoá giá trị của dữ liệu kênh.

Thư viện đồng hành TIF cũng cung cấp phương thức nạp chồng bổ sung của setUpPeriodicSync() cho phép bạn chỉ định thời lượng để đồng bộ hoá và tần suất đồng bộ hoá định kỳ. Chiến lược phát hành đĩa đơn mặc định đồng bộ hoá 48 giờ dữ liệu kênh mỗi 12 giờ.

Để biết thêm thông tin chi tiết về dữ liệu kênh và EPG, hãy xem Làm việc với dữ liệu kênh.

Xử lý các yêu cầu điều chỉnh và phát nội dung nghe nhìn

Khi người dùng chọn một kênh cụ thể, ứng dụng TV hệ thống sẽ sử dụng Session (do ứng dụng của bạn tạo) để chuyển sang kênh được yêu cầu và phát nội dung. Thư viện đồng hành TIF cung cấp một số bạn có thể mở rộng để xử lý lệnh gọi kênh và lệnh gọi phiên từ hệ thống.

Lớp con BaseTvInputService tạo các phiên xử lý yêu cầu điều chỉnh. Ghi đè onCreateSession(), tạo một phiên được mở rộng từ lớp BaseTvInputService.Session và gọi super.sessionCreated() với phiên mới của bạn. Trong phần sau Ví dụ: onCreateSession() trả về một Đối tượng RichTvInputSessionImpl mở rộng BaseTvInputService.Session:

Kotlin

override fun onCreateSession(inputId: String): Session =
        RichTvInputSessionImpl(this, inputId).apply {
            setOverlayViewEnabled(true)
        }

Java

@Override
public final Session onCreateSession(String inputId) {
    RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
    session.setOverlayViewEnabled(true);
    return session;
}

Khi người dùng sử dụng ứng dụng TV hệ thống để bắt đầu xem một trong các kênh của bạn, hệ thống sẽ gọi phương thức onPlayChannel() của phiên hoạt động. Ghi đè bằng phương thức này nếu bạn cần thực hiện bất kỳ hoạt động khởi tạo kênh đặc biệt nào trước khi bắt đầu phát.

Sau đó, hệ thống sẽ thu thập chương trình hiện đang được lên lịch và gọi phương thức onPlayProgram() của phiên, chỉ định chương trình và thời gian bắt đầu tính bằng mili giây. Sử dụng Giao diện TvPlayer để bắt đầu phát chương trình.

Mã trình phát nội dung đa phương tiện của bạn nên triển khai TvPlayer để xử lý các sự kiện phát cụ thể. Lớp TvPlayer xử lý các tính năng chẳng hạn như các chế độ điều khiển ghi dịch thời gian mà không khiến Triển khai BaseTvInputService.

Trong phương thức getTvPlayer() của phiên hoạt động, hãy trả về trình phát nội dung đa phương tiện triển khai TvPlayer. Chiến lược phát hành đĩa đơn Ứng dụng mẫu TV Input Service triển khai trình phát nội dung đa phương tiện sử dụng ExoPlayer.

Tạo dịch vụ đầu vào TV bằng khung đầu vào TV

Nếu dịch vụ đầu vào TV không thể sử dụng Thư viện đồng hành TIF, bạn cần để triển khai các thành phần sau:

  • TvInputService cung cấp khả năng hoạt động trong thời gian dài và ở chế độ nền cho đầu vào TV
  • TvInputService.Session duy trì trạng thái đầu vào TV và giao tiếp với ứng dụng lưu trữ
  • TvContract mô tả các kênh và chương trình có sẵn cho TV nguồn đầu vào
  • TvContract.Channels biểu thị thông tin về một kênh truyền hình
  • TvContract.Programs mô tả một chương trình truyền hình có dữ liệu như chương trình tiêu đề và thời gian bắt đầu
  • TvTrackInfo đại diện cho âm thanh, video hoặc bản phụ đề
  • TvContentRating mô tả mức phân loại nội dung, cho phép áp dụng nội dung tuỳ chỉnh hệ thống phân loại
  • TvInputManager cung cấp một API cho ứng dụng TV của hệ thống và quản lý sự tương tác với đầu vào và ứng dụng TV

Bạn cũng cần thực hiện các thao tác sau:

  1. Khai báo dịch vụ đầu vào TV trong tệp kê khai, như được mô tả trong Khai báo dịch vụ đầu vào TV trong tệp kê khai.
  2. Tạo tệp siêu dữ liệu về dịch vụ.
  3. Tạo và đăng ký thông tin kênh và chương trình của bạn.
  4. Tạo hoạt động thiết lập của bạn.

Xác định dịch vụ đầu vào TV

Đối với dịch vụ của mình, bạn mở rộng lớp TvInputService. Đáp Quá trình triển khai TvInputService là một dịch vụ ràng buộc, trong đó dịch vụ hệ thống là ứng dụng khách liên kết với nó. Các phương thức vòng đời dịch vụ 3 bước được minh hoạ trong hình 1.

Phương thức onCreate() khởi chạy và bắt đầu HandlerThread cung cấp một luồng quy trình tách biệt với luồng giao diện người dùng để xử lý các thao tác do hệ thống điều khiển. Trong ví dụ sau, onCreate() sẽ khởi chạy CaptioningManager và chuẩn bị xử lý ACTION_BLOCKED_RATINGS_CHANGEDACTION_PARENTAL_CONTROLS_ENABLED_CHANGED hành động. Các hành động mô tả ý định của hệ thống được kích hoạt khi người dùng thay đổi chế độ kiểm soát của cha mẹ, cũng như khi nhưng danh sách điểm xếp hạng bị chặn sẽ có sự thay đổi.

Kotlin

override fun onCreate() {
    super.onCreate()
    handlerThread = HandlerThread(javaClass.simpleName).apply {
        start()
    }
    dbHandler = Handler(handlerThread.looper)
    handler = Handler()
    captioningManager = getSystemService(Context.CAPTIONING_SERVICE) as CaptioningManager

    setTheme(android.R.style.Theme_Holo_Light_NoActionBar)

    sessions = mutableListOf<BaseTvInputSessionImpl>()
    val intentFilter = IntentFilter().apply {
        addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED)
        addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED)
    }
    registerReceiver(broadcastReceiver, intentFilter)
}

Java

@Override
public void onCreate() {
    super.onCreate();
    handlerThread = new HandlerThread(getClass()
      .getSimpleName());
    handlerThread.start();
    dbHandler = new Handler(handlerThread.getLooper());
    handler = new Handler();
    captioningManager = (CaptioningManager)
      getSystemService(Context.CAPTIONING_SERVICE);

    setTheme(android.R.style.Theme_Holo_Light_NoActionBar);

    sessions = new ArrayList<BaseTvInputSessionImpl>();
    IntentFilter intentFilter = new IntentFilter();
    intentFilter.addAction(TvInputManager
      .ACTION_BLOCKED_RATINGS_CHANGED);
    intentFilter.addAction(TvInputManager
      .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
    registerReceiver(broadcastReceiver, intentFilter);
}

Hình 1.Vòng đời của TVInputService.

Xem Kiểm soát nội dung để biết thêm thông tin về cách xử lý nội dung bị chặn và cung cấp chế độ kiểm soát của cha mẹ. Hãy xem TvInputManager để biết các thao tác khác do hệ thống điều khiển mà bạn có thể muốn xử lý trong dịch vụ đầu vào TV.

TvInputService tạo một TvInputService.Session triển khai Handler.Callback để xử lý các thay đổi về trạng thái của người chơi. Bằng onSetSurface(), TvInputService.Session sẽ thiết lập Surface với nội dung video. Xem Tích hợp trình phát với nền tảng để biết thêm thông tin về cách làm việc với Surface để kết xuất video.

TvInputService.Session xử lý onTune() khi người dùng chọn một kênh đồng thời thông báo cho ứng dụng TV của hệ thống về các thay đổi về nội dung và siêu dữ liệu nội dung. Các phương thức notify() này được mô tả trong Kiểm soát nội dungXử lý việc lựa chọn bản nhạc trong khoá đào tạo này.

Xác định hoạt động thiết lập

Ứng dụng TV hệ thống sẽ xử lý hoạt động thiết lập mà bạn xác định cho đầu vào TV. Chiến lược phát hành đĩa đơn hoạt động thiết lập là bắt buộc và phải cung cấp ít nhất một bản ghi kênh cho cơ sở dữ liệu hệ thống. Chiến lược phát hành đĩa đơn ứng dụng TV của hệ thống gọi hoạt động thiết lập khi không thể tìm thấy kênh cho đầu vào TV.

Hoạt động thiết lập mô tả cho ứng dụng truyền hình của hệ thống các kênh được cung cấp qua TV như minh hoạ trong bài học tiếp theo, Tạo và cập nhật dữ liệu của kênh.

Tài liệu tham khảo khác