یک سرویس ورودی تلویزیون ایجاد کنید

سرویس ورودی تلویزیون، یک منبع جریان رسانه را نشان می‌دهد و به شما امکان می‌دهد محتوای رسانه‌ای خود را به صورت خطی و پخش تلویزیونی به صورت کانال‌ها و برنامه‌ها ارائه دهید. با یک سرویس ورودی تلویزیون، می‌توانید کنترل‌های والدین، اطلاعات راهنمای برنامه و رتبه‌بندی محتوا را ارائه دهید. سرویس ورودی تلویزیون با برنامه تلویزیون سیستم اندروید کار می‌کند. این برنامه در نهایت محتوای کانال را در تلویزیون کنترل و ارائه می‌دهد. برنامه تلویزیون سیستم به طور خاص برای دستگاه توسعه داده شده است و توسط برنامه‌های شخص ثالث تغییرناپذیر است. برای اطلاعات بیشتر در مورد معماری چارچوب ورودی تلویزیون (TIF) و اجزای آن، به چارچوب ورودی تلویزیون مراجعه کنید.

ایجاد سرویس ورودی تلویزیون با استفاده از کتابخانه همراه TIF

کتابخانه همراه TIF چارچوبی است که پیاده‌سازی‌های قابل توسعه‌ای از ویژگی‌های رایج سرویس ورودی تلویزیون را ارائه می‌دهد. این کتابخانه قرار است توسط تولیدکنندگان اصلی تجهیزات (OEM) برای ساخت کانال‌ها فقط برای اندروید ۵.۰ (سطح API ۲۱) تا اندروید ۷.۱ (سطح API ۲۵) استفاده شود.

پروژه خود را به‌روزرسانی کنید

کتابخانه همراه TIF برای استفاده قدیمی توسط تولیدکنندگان اصلی تجهیزات (OEM) در مخزن androidtv-sample-inputs موجود است. برای مثالی از نحوه گنجاندن کتابخانه در یک برنامه، به آن مخزن مراجعه کنید.

سرویس ورودی تلویزیون خود را در مانیفست تعریف کنید

برنامه شما باید یک سرویس سازگار با TvInputService ارائه دهد که سیستم برای دسترسی به برنامه شما از آن استفاده کند. کتابخانه همراه TIF کلاس BaseTvInputService را ارائه می‌دهد که پیاده‌سازی پیش‌فرض TvInputService را ارائه می‌دهد که می‌توانید آن را سفارشی کنید. یک زیرکلاس از BaseTvInputService ایجاد کنید و زیرکلاس را در مانیفست خود به عنوان یک سرویس اعلام کنید.

در داخل اعلان مانیفست، مجوز BIND_TV_INPUT را مشخص کنید تا به سرویس اجازه دهید ورودی تلویزیون را به سیستم متصل کند. یک سرویس سیستمی این اتصال را انجام می‌دهد و مجوز BIND_TV_INPUT را دارد. برنامه تلویزیون سیستمی از طریق رابط TvInputManager درخواست‌هایی را به سرویس‌های ورودی تلویزیون ارسال می‌کند.

در تعریف سرویس خود، یک فیلتر intent قرار دهید که TvInputService به عنوان عملی که باید با intent انجام شود، مشخص کند. همچنین metadata سرویس را به عنوان یک منبع XML جداگانه تعریف کنید. تعریف سرویس، فیلتر intent و تعریف metadata سرویس در مثال زیر نشان داده شده است:

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

فراداده سرویس را در یک فایل XML جداگانه تعریف کنید. فایل XML فراداده سرویس باید شامل یک رابط راه‌اندازی باشد که پیکربندی اولیه ورودی تلویزیون و اسکن کانال را شرح می‌دهد. فایل فراداده همچنین باید حاوی یک پرچم باشد که نشان می‌دهد آیا کاربران قادر به ضبط محتوا هستند یا خیر. برای اطلاعات بیشتر در مورد نحوه پشتیبانی از ضبط محتوا در برنامه خود، به پشتیبانی از ضبط محتوا مراجعه کنید.

فایل فراداده سرویس در دایرکتوری منابع XML برنامه شما قرار دارد و باید با نام منبعی که در مانیفست اعلام کرده‌اید، مطابقت داشته باشد. با استفاده از ورودی‌های مانیفست از مثال قبلی، فایل XML را در res/xml/richtvinputservice.xml با محتوای زیر ایجاد می‌کنید:

<?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" />

کانال‌ها را تعریف کنید و فعالیت راه‌اندازی خود را ایجاد کنید

سرویس ورودی تلویزیون شما باید حداقل یک کانال تعریف کند که کاربران از طریق برنامه تلویزیون سیستم به آن دسترسی داشته باشند. شما باید کانال‌های خود را در پایگاه داده سیستم ثبت کنید و یک فعالیت راه‌اندازی ارائه دهید که سیستم در صورت عدم یافتن کانال برای برنامه شما، آن را فراخوانی کند.

ابتدا، برنامه خود را برای خواندن و نوشتن از سیستم راهنمای برنامه‌نویسی الکترونیکی (EPG) فعال کنید، که داده‌های آن شامل کانال‌ها و برنامه‌های موجود برای کاربر است. برای فعال کردن برنامه خود برای انجام این اقدامات و همگام‌سازی با EPG پس از راه‌اندازی مجدد دستگاه، عناصر زیر را به مانیفست برنامه خود اضافه کنید:

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

برای اطمینان از اینکه برنامه شما در فروشگاه Google Play به عنوان برنامه‌ای که کانال‌های محتوا را در Android TV ارائه می‌دهد، نمایش داده می‌شود، عنصر زیر را اضافه کنید:

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

در مرحله بعد، یک کلاس ایجاد کنید که کلاس EpgSyncJobService را ارث بری کند. این کلاس انتزاعی به شما امکان می‌دهد یک سرویس کاری ایجاد کنید که کانال‌ها را در پایگاه داده سیستم ایجاد و به‌روزرسانی کند.

در زیرکلاس خود، لیست کامل کانال‌های خود را در getChannels ایجاد و برگردانید. اگر کانال‌های شما از یک فایل XMLTV می‌آیند، از کلاس XmlTvParser استفاده کنید. در غیر این صورت، کانال‌ها را به صورت برنامه‌نویسی شده با استفاده از کلاس Channel.Builder تولید کنید.

برای هر کانال، سیستم وقتی به لیستی از برنامه‌هایی که می‌توانند در یک پنجره زمانی مشخص در کانال مشاهده شوند نیاز دارد، تابع getProgramsForChannel را فراخوانی می‌کند. لیستی از اشیاء Program را برای کانال برمی‌گرداند. از کلاس XmlTvParser برای دریافت برنامه‌ها از یک فایل XMLTV استفاده کنید، یا آنها را با استفاده از کلاس Program.Builder به صورت برنامه‌نویسی تولید کنید.

برای هر شیء Program ، از یک شیء InternalProviderData برای تنظیم اطلاعات برنامه مانند نوع ویدیوی برنامه استفاده کنید. اگر فقط تعداد محدودی برنامه دارید که می‌خواهید کانال در یک حلقه تکرار کند، هنگام تنظیم اطلاعات مربوط به برنامه خود، از متد InternalProviderData.setRepeatable با مقدار true استفاده کنید.

پس از پیاده‌سازی سرویس کار، آن را به مانیفست برنامه خود اضافه کنید:

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

در نهایت، یک فعالیت راه‌اندازی (setup activity) ایجاد کنید. فعالیت راه‌اندازی شما باید راهی برای همگام‌سازی داده‌های کانال و برنامه فراهم کند. یک راه برای انجام این کار این است که کاربر این کار را با استفاده از رابط کاربری (UI) در فعالیت انجام دهد. همچنین می‌توانید کاری کنید که برنامه هنگام شروع فعالیت، این کار را به طور خودکار انجام دهد. وقتی فعالیت راه‌اندازی نیاز به همگام‌سازی اطلاعات کانال و برنامه دارد، برنامه باید سرویس کار (job service) را شروع کند:

کاتلین

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

جاوا

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

از متد requestImmediateSync برای همگام‌سازی سرویس کار استفاده کنید. کاربر باید منتظر بماند تا همگام‌سازی تمام شود، بنابراین باید دوره درخواست خود را نسبتاً کوتاه نگه دارید.

از متد setUpPeriodicSync برای همگام‌سازی دوره‌ای داده‌های کانال و برنامه توسط سرویس job در پس‌زمینه استفاده کنید:

کاتلین

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

جاوا

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

کتابخانه همراه TIF یک متد overload شده اضافی از requestImmediateSync ارائه می‌دهد که به شما امکان می‌دهد مدت زمان همگام‌سازی داده‌های کانال را بر حسب میلی‌ثانیه مشخص کنید. متد پیش‌فرض، داده‌های کانال را به مدت یک ساعت همگام‌سازی می‌کند.

کتابخانه همراه TIF همچنین یک متد overload شده اضافی از setUpPeriodicSync ارائه می‌دهد که به شما امکان می‌دهد مدت زمان همگام‌سازی داده‌های کانال و اینکه همگام‌سازی دوره‌ای چند وقت یکبار باید رخ دهد را مشخص کنید. متد پیش‌فرض، داده‌های کانال را هر ۱۲ ساعت، ۴۸ ساعت همگام‌سازی می‌کند.

برای جزئیات بیشتر در مورد داده‌های کانال و EPG، به «کار با داده‌های کانال» مراجعه کنید.

مدیریت درخواست‌های تنظیم و پخش رسانه

وقتی کاربر کانال خاصی را انتخاب می‌کند، برنامه تلویزیون سیستمی از یک Session که توسط برنامه شما ایجاد شده است، برای تنظیم کانال درخواستی و پخش محتوا استفاده می‌کند. کتابخانه همراه TIF چندین کلاس را ارائه می‌دهد که می‌توانید برای مدیریت فراخوانی‌های کانال و جلسه از سیستم، آنها را گسترش دهید.

زیرکلاس BaseTvInputService شما، sessionهایی ایجاد می‌کند که درخواست‌های تنظیم را مدیریت می‌کنند. متد onCreateSession را بازنویسی کنید، یک session توسعه‌یافته از کلاس BaseTvInputService.Session ایجاد کنید و super.sessionCreated با session جدید خود فراخوانی کنید. در مثال زیر، onCreateSession یک شیء RichTvInputSessionImpl را برمی‌گرداند که BaseTvInputService.Session را توسعه می‌دهد:

کاتلین

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

جاوا

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

وقتی کاربر از برنامه‌ی تلویزیون سیستمی برای شروع تماشای یکی از کانال‌های شما استفاده می‌کند، سیستم متد onPlayChannel مربوط به سشن شما را فراخوانی می‌کند. اگر نیاز به مقداردهی اولیه‌ی کانال خاصی قبل از شروع پخش برنامه دارید، این متد را بازنویسی کنید.

سپس سیستم برنامه‌ی زمان‌بندی‌شده‌ی فعلی را دریافت کرده و متد onPlayProgram مربوط به جلسه‌ی شما را فراخوانی می‌کند و اطلاعات برنامه و زمان شروع را بر حسب میلی‌ثانیه مشخص می‌کند. از رابط TvPlayer برای شروع پخش برنامه استفاده کنید.

کد پخش‌کننده‌ی رسانه‌ی شما باید TvPlayer برای مدیریت رویدادهای پخش خاص پیاده‌سازی کند. کلاس TvPlayer ویژگی‌هایی مانند کنترل‌های تغییر زمان را بدون افزودن پیچیدگی به پیاده‌سازی BaseTvInputService شما مدیریت می‌کند.

در متد getTvPlayer مربوط به سشن خود، پخش‌کننده‌ی رسانه‌ای که TvPlayer را پیاده‌سازی کرده است، برگردانید. برنامه‌ی نمونه‌ی TV Input Service یک پخش‌کننده‌ی رسانه‌ای را پیاده‌سازی می‌کند که از ExoPlayer استفاده می‌کند.

ایجاد یک سرویس ورودی تلویزیون با استفاده از چارچوب ورودی تلویزیون

اگر سرویس ورودی تلویزیون شما نمی‌تواند از کتابخانه همراه TIF استفاده کند، باید اجزای زیر را پیاده‌سازی کنید:

  • TvInputService دسترسی طولانی مدت و پس زمینه را برای ورودی تلویزیون فراهم می‌کند.
  • TvInputService.Session وضعیت ورودی تلویزیون را حفظ کرده و با برنامه میزبانی ارتباط برقرار می‌کند.
  • TvContract کانال‌ها و برنامه‌های موجود در ورودی تلویزیون را شرح می‌دهد.
  • TvContract.Channels اطلاعات مربوط به یک کانال تلویزیونی را نشان می‌دهد.
  • TvContract.Programs یک برنامه تلویزیونی را با داده‌هایی مانند عنوان برنامه و زمان شروع توصیف می‌کند.
  • TvTrackInfo نشان دهنده یک آهنگ صوتی، تصویری یا زیرنویس است
  • TvContentRating رتبه‌بندی محتوا را توصیف می‌کند و امکان طرح‌های رتبه‌بندی محتوای سفارشی را فراهم می‌کند.
  • TvInputManager یک API برای برنامه تلویزیون سیستم فراهم می‌کند و تعامل با ورودی‌ها و برنامه‌های تلویزیون را مدیریت می‌کند.

همچنین لازم است موارد زیر را انجام دهید:

  1. سرویس ورودی تلویزیون خود را در مانیفست، همانطور که در بخش «سرویس ورودی تلویزیون خود را در مانیفست اعلام کنید» توضیح داده شده است، تعریف کنید.
  2. فایل متادیتای سرویس را ایجاد کنید.
  3. اطلاعات کانال و برنامه خود را ایجاد و ثبت کنید.
  4. فعالیت راه‌اندازی خود را ایجاد کنید.

سرویس ورودی تلویزیون خود را تعریف کنید

برای سرویس خود، شما کلاس TvInputService را ارث بری می‌کنید. پیاده‌سازی TvInputService یک سرویس مقید است که در آن سرویس سیستم، کلاینتی است که به آن متصل می‌شود. متدهای چرخه حیات سرویس که باید پیاده‌سازی کنید در شکل 1 نشان داده شده است.

متد onCreate HandlerThread مقداردهی اولیه و اجرا می‌کند که یک thread پردازشی جدا از thread UI برای مدیریت اقدامات سیستم محور فراهم می‌کند. در مثال زیر، متد onCreate ، CaptioningManager مقداردهی اولیه کرده و برای مدیریت اقدامات ACTION_BLOCKED_RATINGS_CHANGED و ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED آماده می‌کند. این اقدامات، intentهای سیستمی را توصیف می‌کنند که هنگام تغییر تنظیمات کنترل والدین توسط کاربر و هنگامی که تغییری در لیست رتبه‌بندی‌های مسدود شده ایجاد می‌شود، اجرا می‌شوند.

کاتلین

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

جاوا

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

شکل ۱. چرخه حیات سرویس TvInputService.

برای اطلاعات بیشتر در مورد کار با محتوای مسدود شده و ارائه کنترل والدین، به بخش «کنترل محتوا» مراجعه کنید. برای اقدامات سیستمی بیشتری که ممکن است بخواهید در سرویس ورودی تلویزیون خود مدیریت کنید، به TvInputManager مراجعه کنید.

TvInputService یک TvInputService.Session ایجاد می‌کند که Handler.Callback را برای مدیریت تغییرات وضعیت پخش‌کننده پیاده‌سازی می‌کند. با onSetSurface ، TvInputService.Session Surface با محتوای ویدیو تنظیم می‌کند. برای اطلاعات بیشتر در مورد کار با Surface برای رندر ویدیو، به بخش «ادغام پخش‌کننده با سطح» مراجعه کنید.

TvInputService.Session رویداد onTune را هنگامی که کاربر یک کانال را انتخاب می‌کند، مدیریت می‌کند و برنامه تلویزیون سیستم را از تغییرات در محتوا و فراداده‌های محتوا مطلع می‌سازد. این متدهای notify در بخش «کنترل محتوا» و «مدیریت انتخاب مسیر» در این آموزش بیشتر توضیح داده شده‌اند.

فعالیت راه‌اندازی خود را تعریف کنید

برنامه‌ی تلویزیون سیستمی با فعالیت راه‌اندازی که برای ورودی تلویزیون خود تعریف می‌کنید، کار می‌کند. فعالیت راه‌اندازی الزامی است و باید حداقل یک رکورد کانال برای پایگاه داده‌ی سیستم ارائه دهد. برنامه‌ی تلویزیون سیستمی وقتی نمی‌تواند کانالی برای ورودی تلویزیون پیدا کند، فعالیت راه‌اندازی را فراخوانی می‌کند.

فعالیت راه‌اندازی، کانال‌های موجود از طریق ورودی تلویزیون را برای برنامه تلویزیون سیستمی توصیف می‌کند، همانطور که در درس بعدی، ایجاد و به‌روزرسانی داده‌های کانال ، نشان داده شده است.

منابع اضافی

،

سرویس ورودی تلویزیون، یک منبع جریان رسانه را نشان می‌دهد و به شما امکان می‌دهد محتوای رسانه‌ای خود را به صورت خطی و پخش تلویزیونی به صورت کانال‌ها و برنامه‌ها ارائه دهید. با یک سرویس ورودی تلویزیون، می‌توانید کنترل‌های والدین، اطلاعات راهنمای برنامه و رتبه‌بندی محتوا را ارائه دهید. سرویس ورودی تلویزیون با برنامه تلویزیون سیستم اندروید کار می‌کند. این برنامه در نهایت محتوای کانال را در تلویزیون کنترل و ارائه می‌دهد. برنامه تلویزیون سیستم به طور خاص برای دستگاه توسعه داده شده است و توسط برنامه‌های شخص ثالث تغییرناپذیر است. برای اطلاعات بیشتر در مورد معماری چارچوب ورودی تلویزیون (TIF) و اجزای آن، به چارچوب ورودی تلویزیون مراجعه کنید.

ایجاد سرویس ورودی تلویزیون با استفاده از کتابخانه همراه TIF

کتابخانه همراه TIF چارچوبی است که پیاده‌سازی‌های قابل توسعه‌ای از ویژگی‌های رایج سرویس ورودی تلویزیون را ارائه می‌دهد. این کتابخانه قرار است توسط تولیدکنندگان اصلی تجهیزات (OEM) برای ساخت کانال‌ها فقط برای اندروید ۵.۰ (سطح API ۲۱) تا اندروید ۷.۱ (سطح API ۲۵) استفاده شود.

پروژه خود را به‌روزرسانی کنید

کتابخانه همراه TIF برای استفاده قدیمی توسط تولیدکنندگان اصلی تجهیزات (OEM) در مخزن androidtv-sample-inputs موجود است. برای مثالی از نحوه گنجاندن کتابخانه در یک برنامه، به آن مخزن مراجعه کنید.

سرویس ورودی تلویزیون خود را در مانیفست تعریف کنید

برنامه شما باید یک سرویس سازگار با TvInputService ارائه دهد که سیستم برای دسترسی به برنامه شما از آن استفاده کند. کتابخانه همراه TIF کلاس BaseTvInputService را ارائه می‌دهد که پیاده‌سازی پیش‌فرض TvInputService را ارائه می‌دهد که می‌توانید آن را سفارشی کنید. یک زیرکلاس از BaseTvInputService ایجاد کنید و زیرکلاس را در مانیفست خود به عنوان یک سرویس اعلام کنید.

در داخل اعلان مانیفست، مجوز BIND_TV_INPUT را مشخص کنید تا به سرویس اجازه دهید ورودی تلویزیون را به سیستم متصل کند. یک سرویس سیستمی این اتصال را انجام می‌دهد و مجوز BIND_TV_INPUT را دارد. برنامه تلویزیون سیستمی از طریق رابط TvInputManager درخواست‌هایی را به سرویس‌های ورودی تلویزیون ارسال می‌کند.

در تعریف سرویس خود، یک فیلتر intent قرار دهید که TvInputService به عنوان عملی که باید با intent انجام شود، مشخص کند. همچنین metadata سرویس را به عنوان یک منبع XML جداگانه تعریف کنید. تعریف سرویس، فیلتر intent و تعریف metadata سرویس در مثال زیر نشان داده شده است:

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

فراداده سرویس را در یک فایل XML جداگانه تعریف کنید. فایل XML فراداده سرویس باید شامل یک رابط راه‌اندازی باشد که پیکربندی اولیه ورودی تلویزیون و اسکن کانال را شرح می‌دهد. فایل فراداده همچنین باید حاوی یک پرچم باشد که نشان می‌دهد آیا کاربران قادر به ضبط محتوا هستند یا خیر. برای اطلاعات بیشتر در مورد نحوه پشتیبانی از ضبط محتوا در برنامه خود، به پشتیبانی از ضبط محتوا مراجعه کنید.

فایل فراداده سرویس در دایرکتوری منابع XML برنامه شما قرار دارد و باید با نام منبعی که در مانیفست اعلام کرده‌اید، مطابقت داشته باشد. با استفاده از ورودی‌های مانیفست از مثال قبلی، فایل XML را در res/xml/richtvinputservice.xml با محتوای زیر ایجاد می‌کنید:

<?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" />

کانال‌ها را تعریف کنید و فعالیت راه‌اندازی خود را ایجاد کنید

سرویس ورودی تلویزیون شما باید حداقل یک کانال تعریف کند که کاربران از طریق برنامه تلویزیون سیستم به آن دسترسی داشته باشند. شما باید کانال‌های خود را در پایگاه داده سیستم ثبت کنید و یک فعالیت راه‌اندازی ارائه دهید که سیستم در صورت عدم یافتن کانال برای برنامه شما، آن را فراخوانی کند.

ابتدا، برنامه خود را برای خواندن و نوشتن از سیستم راهنمای برنامه‌نویسی الکترونیکی (EPG) فعال کنید، که داده‌های آن شامل کانال‌ها و برنامه‌های موجود برای کاربر است. برای فعال کردن برنامه خود برای انجام این اقدامات و همگام‌سازی با EPG پس از راه‌اندازی مجدد دستگاه، عناصر زیر را به مانیفست برنامه خود اضافه کنید:

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

برای اطمینان از اینکه برنامه شما در فروشگاه Google Play به عنوان برنامه‌ای که کانال‌های محتوا را در Android TV ارائه می‌دهد، نمایش داده می‌شود، عنصر زیر را اضافه کنید:

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

در مرحله بعد، یک کلاس ایجاد کنید که کلاس EpgSyncJobService را ارث بری کند. این کلاس انتزاعی به شما امکان می‌دهد یک سرویس کاری ایجاد کنید که کانال‌ها را در پایگاه داده سیستم ایجاد و به‌روزرسانی کند.

در زیرکلاس خود، لیست کامل کانال‌های خود را در getChannels ایجاد و برگردانید. اگر کانال‌های شما از یک فایل XMLTV می‌آیند، از کلاس XmlTvParser استفاده کنید. در غیر این صورت، کانال‌ها را به صورت برنامه‌نویسی شده با استفاده از کلاس Channel.Builder تولید کنید.

برای هر کانال، سیستم وقتی به لیستی از برنامه‌هایی که می‌توانند در یک پنجره زمانی مشخص در کانال مشاهده شوند نیاز دارد، تابع getProgramsForChannel را فراخوانی می‌کند. لیستی از اشیاء Program را برای کانال برمی‌گرداند. از کلاس XmlTvParser برای دریافت برنامه‌ها از یک فایل XMLTV استفاده کنید، یا آنها را با استفاده از کلاس Program.Builder به صورت برنامه‌نویسی تولید کنید.

برای هر شیء Program ، از یک شیء InternalProviderData برای تنظیم اطلاعات برنامه مانند نوع ویدیوی برنامه استفاده کنید. اگر فقط تعداد محدودی برنامه دارید که می‌خواهید کانال در یک حلقه تکرار کند، هنگام تنظیم اطلاعات مربوط به برنامه خود، از متد InternalProviderData.setRepeatable با مقدار true استفاده کنید.

پس از پیاده‌سازی سرویس کار، آن را به مانیفست برنامه خود اضافه کنید:

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

در نهایت، یک فعالیت راه‌اندازی (setup activity) ایجاد کنید. فعالیت راه‌اندازی شما باید راهی برای همگام‌سازی داده‌های کانال و برنامه فراهم کند. یک راه برای انجام این کار این است که کاربر این کار را با استفاده از رابط کاربری (UI) در فعالیت انجام دهد. همچنین می‌توانید کاری کنید که برنامه هنگام شروع فعالیت، این کار را به طور خودکار انجام دهد. وقتی فعالیت راه‌اندازی نیاز به همگام‌سازی اطلاعات کانال و برنامه دارد، برنامه باید سرویس کار (job service) را شروع کند:

کاتلین

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

جاوا

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

از متد requestImmediateSync برای همگام‌سازی سرویس کار استفاده کنید. کاربر باید منتظر بماند تا همگام‌سازی تمام شود، بنابراین باید دوره درخواست خود را نسبتاً کوتاه نگه دارید.

از متد setUpPeriodicSync برای همگام‌سازی دوره‌ای داده‌های کانال و برنامه توسط سرویس job در پس‌زمینه استفاده کنید:

کاتلین

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

جاوا

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

کتابخانه همراه TIF یک متد overload شده اضافی از requestImmediateSync ارائه می‌دهد که به شما امکان می‌دهد مدت زمان همگام‌سازی داده‌های کانال را بر حسب میلی‌ثانیه مشخص کنید. متد پیش‌فرض، داده‌های کانال را به مدت یک ساعت همگام‌سازی می‌کند.

کتابخانه همراه TIF همچنین یک متد overload شده اضافی از setUpPeriodicSync ارائه می‌دهد که به شما امکان می‌دهد مدت زمان همگام‌سازی داده‌های کانال و اینکه همگام‌سازی دوره‌ای چند وقت یکبار باید رخ دهد را مشخص کنید. متد پیش‌فرض، داده‌های کانال را هر ۱۲ ساعت، ۴۸ ساعت همگام‌سازی می‌کند.

برای جزئیات بیشتر در مورد داده‌های کانال و EPG، به «کار با داده‌های کانال» مراجعه کنید.

مدیریت درخواست‌های تنظیم و پخش رسانه

وقتی کاربر کانال خاصی را انتخاب می‌کند، برنامه تلویزیون سیستمی از یک Session که توسط برنامه شما ایجاد شده است، برای تنظیم کانال درخواستی و پخش محتوا استفاده می‌کند. کتابخانه همراه TIF چندین کلاس را ارائه می‌دهد که می‌توانید برای مدیریت فراخوانی‌های کانال و جلسه از سیستم، آنها را گسترش دهید.

زیرکلاس BaseTvInputService شما، sessionهایی ایجاد می‌کند که درخواست‌های تنظیم را مدیریت می‌کنند. متد onCreateSession را بازنویسی کنید، یک session توسعه‌یافته از کلاس BaseTvInputService.Session ایجاد کنید و super.sessionCreated با session جدید خود فراخوانی کنید. در مثال زیر، onCreateSession یک شیء RichTvInputSessionImpl را برمی‌گرداند که BaseTvInputService.Session را توسعه می‌دهد:

کاتلین

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

جاوا

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

وقتی کاربر از برنامه‌ی تلویزیون سیستمی برای شروع تماشای یکی از کانال‌های شما استفاده می‌کند، سیستم متد onPlayChannel مربوط به سشن شما را فراخوانی می‌کند. اگر نیاز به مقداردهی اولیه‌ی کانال خاصی قبل از شروع پخش برنامه دارید، این متد را بازنویسی کنید.

سپس سیستم برنامه‌ی زمان‌بندی‌شده‌ی فعلی را دریافت کرده و متد onPlayProgram مربوط به جلسه‌ی شما را فراخوانی می‌کند و اطلاعات برنامه و زمان شروع را بر حسب میلی‌ثانیه مشخص می‌کند. از رابط TvPlayer برای شروع پخش برنامه استفاده کنید.

کد پخش‌کننده‌ی رسانه‌ی شما باید TvPlayer برای مدیریت رویدادهای پخش خاص پیاده‌سازی کند. کلاس TvPlayer ویژگی‌هایی مانند کنترل‌های تغییر زمان را بدون افزودن پیچیدگی به پیاده‌سازی BaseTvInputService شما مدیریت می‌کند.

در متد getTvPlayer مربوط به سشن خود، پخش‌کننده‌ی رسانه‌ای که TvPlayer را پیاده‌سازی کرده است، برگردانید. برنامه‌ی نمونه‌ی TV Input Service یک پخش‌کننده‌ی رسانه‌ای را پیاده‌سازی می‌کند که از ExoPlayer استفاده می‌کند.

ایجاد یک سرویس ورودی تلویزیون با استفاده از چارچوب ورودی تلویزیون

اگر سرویس ورودی تلویزیون شما نمی‌تواند از کتابخانه همراه TIF استفاده کند، باید اجزای زیر را پیاده‌سازی کنید:

  • TvInputService دسترسی طولانی مدت و پس زمینه را برای ورودی تلویزیون فراهم می‌کند.
  • TvInputService.Session وضعیت ورودی تلویزیون را حفظ کرده و با برنامه میزبانی ارتباط برقرار می‌کند.
  • TvContract کانال‌ها و برنامه‌های موجود در ورودی تلویزیون را شرح می‌دهد.
  • TvContract.Channels اطلاعات مربوط به یک کانال تلویزیونی را نشان می‌دهد.
  • TvContract.Programs یک برنامه تلویزیونی را با داده‌هایی مانند عنوان برنامه و زمان شروع توصیف می‌کند.
  • TvTrackInfo نشان دهنده یک آهنگ صوتی، تصویری یا زیرنویس است
  • TvContentRating رتبه‌بندی محتوا را توصیف می‌کند و امکان طرح‌های رتبه‌بندی محتوای سفارشی را فراهم می‌کند.
  • TvInputManager یک API برای برنامه تلویزیون سیستم فراهم می‌کند و تعامل با ورودی‌ها و برنامه‌های تلویزیون را مدیریت می‌کند.

همچنین لازم است موارد زیر را انجام دهید:

  1. سرویس ورودی تلویزیون خود را در مانیفست، همانطور که در بخش «سرویس ورودی تلویزیون خود را در مانیفست اعلام کنید» توضیح داده شده است، تعریف کنید.
  2. فایل متادیتای سرویس را ایجاد کنید.
  3. اطلاعات کانال و برنامه خود را ایجاد و ثبت کنید.
  4. فعالیت راه‌اندازی خود را ایجاد کنید.

سرویس ورودی تلویزیون خود را تعریف کنید

برای سرویس خود، شما کلاس TvInputService را ارث بری می‌کنید. پیاده‌سازی TvInputService یک سرویس مقید است که در آن سرویس سیستم، کلاینتی است که به آن متصل می‌شود. متدهای چرخه حیات سرویس که باید پیاده‌سازی کنید در شکل 1 نشان داده شده است.

متد onCreate HandlerThread مقداردهی اولیه و اجرا می‌کند که یک thread پردازشی جدا از thread UI برای مدیریت اقدامات سیستم محور فراهم می‌کند. در مثال زیر، متد onCreate ، CaptioningManager مقداردهی اولیه کرده و برای مدیریت اقدامات ACTION_BLOCKED_RATINGS_CHANGED و ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED آماده می‌کند. این اقدامات، intentهای سیستمی را توصیف می‌کنند که هنگام تغییر تنظیمات کنترل والدین توسط کاربر و هنگامی که تغییری در لیست رتبه‌بندی‌های مسدود شده ایجاد می‌شود، اجرا می‌شوند.

کاتلین

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

جاوا

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

شکل ۱. چرخه حیات سرویس TvInputService.

برای اطلاعات بیشتر در مورد کار با محتوای مسدود شده و ارائه کنترل والدین، به بخش «کنترل محتوا» مراجعه کنید. برای اقدامات سیستمی بیشتری که ممکن است بخواهید در سرویس ورودی تلویزیون خود مدیریت کنید، به TvInputManager مراجعه کنید.

TvInputService یک TvInputService.Session ایجاد می‌کند که Handler.Callback را برای مدیریت تغییرات وضعیت پخش‌کننده پیاده‌سازی می‌کند. با onSetSurface ، TvInputService.Session Surface با محتوای ویدیو تنظیم می‌کند. برای اطلاعات بیشتر در مورد کار با Surface برای رندر ویدیو، به بخش «ادغام پخش‌کننده با سطح» مراجعه کنید.

TvInputService.Session رویداد onTune را هنگامی که کاربر یک کانال را انتخاب می‌کند، مدیریت می‌کند و برنامه تلویزیون سیستم را از تغییرات در محتوا و فراداده‌های محتوا مطلع می‌سازد. این متدهای notify در بخش «کنترل محتوا» و «مدیریت انتخاب مسیر» در این آموزش بیشتر توضیح داده شده‌اند.

فعالیت راه‌اندازی خود را تعریف کنید

برنامه‌ی تلویزیون سیستمی با فعالیت راه‌اندازی که برای ورودی تلویزیون خود تعریف می‌کنید، کار می‌کند. فعالیت راه‌اندازی الزامی است و باید حداقل یک رکورد کانال برای پایگاه داده‌ی سیستم ارائه دهد. برنامه‌ی تلویزیون سیستمی وقتی نمی‌تواند کانالی برای ورودی تلویزیون پیدا کند، فعالیت راه‌اندازی را فراخوانی می‌کند.

فعالیت راه‌اندازی، کانال‌های موجود از طریق ورودی تلویزیون را برای برنامه تلویزیون سیستمی توصیف می‌کند، همانطور که در درس بعدی، ایجاد و به‌روزرسانی داده‌های کانال ، نشان داده شده است.

منابع اضافی