Home | History | Annotate | Download | only in tif
      1 page.title=Developing a TV Input Service
      2 page.tags=tv, tif
      3 helpoutsWidget=true
      4 
      5 trainingnavtop=true
      6 
      7 @jd:body
      8 
      9 <div id="tb-wrapper">
     10 <div id="tb">
     11   <h2>This lesson teaches you to</h2>
     12   <ol>
     13     <li><a href="#TIFCompanion">Create a TV Input Service Using the TIF Companion Library</a></li>
     14     <li><a href="#NoTIFCompanion">Create a TV Input Service Using the TIF Framework</a></li>
     15   </ol>
     16   <h2>You should also read</h2>
     17   <ul>
     18     <li><a href="{@docRoot}reference/android/media/tv/package-summary.html">
     19       android.media.tv</a></li>
     20     <li><a class="external-lin" href="http://source.android.com/devices/tv/index.html">
     21       TV Input Framework</a></li>
     22   </ul>
     23   <h2>Try It Out</h2>
     24   <ul>
     25     <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
     26       TV Input Service sample app</a></li>
     27   </ul>
     28 </div>
     29 </div>
     30 
     31 <p>A TV input service represents a media stream source, and lets you present your media content in a
     32 linear, broadcast TV fashion as channels and programs. With a TV input service, you can provide
     33 parental controls, program guide information, and content ratings. The TV input service works
     34 with the Android system TV app. This app ultimately controls and presents channel content
     35 on the TV. The system TV app is developed specifically for the device and immutable
     36 by third-party apps. For more information about the TV Input Framework (TIF)
     37 architecture and its components, see
     38 <a class="external-link" href="http://source.android.com/devices/tv/index.html">
     39 TV Input Framework</a>.</p>
     40 
     41 <h2 id="TIFCompanion">Create a TV Input Service Using the TIF Companion Library</h2>
     42 
     43 <p>
     44 The TIF Companion Library is a framework that provides extensible
     45 implementations of common TV input service features. Use the TIF Companion
     46 Library to quickly and easily create your own TV input service that follows
     47 best practices for Android TV.
     48 </p>
     49 
     50 <h3 id="build">Update your build.gradle file</h3>
     51 
     52 <p>
     53 To get started using the TIF Companion Library, add the following line to your
     54 app's <code>build.gradle</code> file:
     55 </p>
     56 
     57 <pre>
     58 compile 'com.google.android.media.tv.companionlibrary:1.0.0'
     59 </pre>
     60 
     61 <p>The TIF Companion Library is not currently part of the Android
     62 framework. It is distributed as part of the <a class="external-link"
     63 href="https://github.com/googlesamples/androidtv-sample-inputs">
     64 TV Input Service sample app</a>, and not with the Android SDK.
     65 </p>
     66 
     67 <h3 id="manifest">Declare your TV input service in the manifest</h3>
     68 
     69 <p>Your app must provide a {@link android.media.tv.TvInputService}-compatible
     70 service that the system uses to access your app. The TIF
     71 Companion Library provides the <code>BaseTvInputService</code> class, which
     72 provides a default implementation of {@link android.media.tv.TvInputService}
     73 that you can customize. Create a subclass of <code>BaseTvInputService</code>,
     74 and declare the subclass in your manifest as a service.</p>
     75 
     76 <p>Within the manifest declaration, specify the
     77 {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the
     78 service to connect the TV input to the system. A system service
     79 performs the binding and has the
     80 {@link android.Manifest.permission#BIND_TV_INPUT} permission.
     81 The system TV app sends requests to TV input services
     82 via the {@link android.media.tv.TvInputManager} interface.</p>
     83 
     84 <p>In your service declaration, include an intent filter that specifies
     85 {@link android.media.tv.TvInputService} as the action to perform with the
     86 intent. Also declare the service metadata as a separate XML resource. The
     87 service declaration, intent filter, and service metadata declaration are shown
     88 in the following example:</p>
     89 
     90 <pre>
     91 &lt;service android:name=".rich.RichTvInputService"
     92     android:label="@string/rich_input_label"
     93     android:permission="android.permission.BIND_TV_INPUT"&gt;
     94     &lt;!-- Required filter used by the system to launch our account service. --&gt;
     95     &lt;intent-filter&gt;
     96         &lt;action android:name="android.media.tv.TvInputService" /&gt;
     97     &lt;/intent-filter&gt;
     98     &lt;!-- An XML file which describes this input. This provides pointers to
     99     the RichTvInputSetupActivity to the system/TV app. --&gt;
    100     &lt;meta-data
    101         android:name="android.media.tv.input"
    102         android:resource="@xml/richtvinputservice" /&gt;
    103 &lt;/service&gt;
    104 </pre>
    105 
    106 <p>Define the service metadata in a separate XML file. The service
    107 metadata XML file must include a setup interface that describes the TV input's
    108 initial configuration and channel scan. The metadata file should also contain a
    109 flag stating whether or not users are able to record content. For more
    110 information on how to support recording content in your app, see
    111 <a href="{@docRoot}preview/features/tv-recording-api.html">TV Recording</a>.
    112 </p>
    113 
    114 <p>The service metadata file is located in the XML resources directory
    115 for your app and must match the name of the resource you declared in the
    116 manifest. Using the manifest entries from the previous example, you would
    117 create the XML file at <code>res/xml/richtvinputservice.xml</code>, with the
    118 following contents:</p>
    119 
    120 <pre>
    121 &lt;?xml version="1.0" encoding="utf-8"?&gt;
    122 &lt;tv-input xmlns:android="http://schemas.android.com/apk/res/android"
    123   android:canRecord="true"
    124   android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" /&gt;
    125 </pre>
    126 
    127 <h3 id="setup">Define channels and create your setup activity</h3>
    128 
    129 <p>Your TV input service must define at least one channel that users
    130 access via the system TV app. You should register your channels
    131 in the system database, and provide a setup activity that the system
    132 invokes when it cannot find a channel for your app.</p>
    133 
    134 <p>First, enable your app to read from and write to the system Electronic
    135 Programming Guide (EPG), whose data includes channels and programs available
    136 to the user. To enable your app to perform these actions, and sync with the
    137 EPG after device restart, add the following elements to your app manifest:</p>
    138 
    139 <pre>
    140 &lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
    141 &lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
    142 &lt;uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/&gt;
    143 </pre>
    144 
    145 <p>Add the following element to ensure that your app shows up in the
    146 Google Play Store as an app that provides content channels in Android TV:</p>
    147 
    148 <pre>
    149 &lt;uses-feature
    150     android:name="android.software.live_tv"
    151     android:required="true" /&gt;
    152 </pre>
    153 
    154 <p>Next, create a class which extends the <code>EpgSyncJobService</code>
    155 class. This abstract class makes it easy to create a job service that
    156 creates and updates channels in the system database.</p>
    157 
    158 <p>In your subclass, create and return your full list of channels in
    159 <code>getChannels()</code>. If your channels come from an XMLTV file,
    160 use the <code>XmlTvParser</code> class. Otherwise generate
    161 channels programmatically using the <code>Channel.Builder</code> class.
    162 </p>
    163 
    164 <p>For each channel, the system calls <code>getProgramsForChannel()</code>
    165 when it needs a list of programs that can be viewed within a given time window
    166 on the channel. Return a list of <code>Program</code> objects for the
    167 channel. Use the <code>XmlTvParser</code> class to obtain programs from an
    168 XMLTV file, or generate them programmatically using the
    169 <code>Program.Builder</code> class.</p>
    170 
    171 <p>For each <code>Program</code> object, use an
    172 <code>InternalProviderData</code> object to set program information such as the
    173 program's video type. If you only have a limited number of programs that you
    174 want the channel to repeat in a loop, use the
    175 <code>InternalProviderData.setRepeatable()</code> method with a value of
    176 <code>true</code> when setting information about your program.</p>
    177 
    178 <p>After you've implemented the job service, add it to your app manifest:</p>
    179 
    180 <pre>
    181 &lt;service
    182     android:name=".sync.SampleJobService"
    183     android:permission="android.permission.BIND_JOB_SERVICE"
    184     android:exported="true" /&gt;
    185 </pre>
    186 
    187 <p>Finally, create a setup activity. Your setup activity should provide a way
    188 to sync channel and program data. One way to do this is for the user to do it
    189 via the UI in the activity. You might also have the app do it automatically
    190 when the activity starts. When the setup activity needs to sync channel and
    191 program info, the app should start the job service:</p>
    192 
    193 <pre>
    194 String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID);
    195 EpgSyncJobService.cancelAllSyncRequests(getActivity());
    196 EpgSyncJobService.requestImmediateSync(getActivity(), inputId,
    197         new ComponentName(getActivity(), SampleJobService.class));
    198 </pre>
    199 
    200 <p>Use the <code>requestImmediateSync()</code> method to sync
    201 the job service. The user must wait for the sync to finish, so you should
    202 keep your request period relatively short.</p>
    203 
    204 <p>Use the <code>setUpPeriodicSync()</code> method to have the job service
    205 periodically sync channel and program data in the background:</p>
    206 
    207 <pre>
    208 EpgSyncJobService.setUpPeriodicSync(context, inputId,
    209         new ComponentName(context, SampleJobService.class));
    210 </pre>
    211 
    212 <p>The TIF Companion Library provides an additional overloaded method of
    213 <code>requestImmediateSync()</code> that lets you specify the duration of
    214 channel data to sync in milliseconds. The default method syncs one hour's
    215 worth of channel data.
    216 </p>
    217 
    218 <p>The TIF Companion Library also provides an additional overloaded method of
    219 <code>setUpPeriodicSync()</code> that lets you specify the duration of
    220 channel data to sync, and how often the periodic sync should occur. The
    221 default method syncs 48 hours of channel data every 12 hours.
    222 </p>
    223 
    224 <p>For more details about channel data and the EPG, see
    225 <a href="{@docRoot}training/tv/tif/channel.html"> Working with Channel Data</a>.
    226 </p>
    227 
    228 <h3 id="playback">Handle tuning requests and media playback</h3>
    229 
    230 <p>When a user selects a specific channel, the system TV app uses a
    231 <code>Session</code>, created by your app, to tune to the requested channel
    232 and play content. The TIF Companion Library provides several
    233 classes you can extend to handle channel and session calls from the system.</p>
    234 
    235 <p>Your <code>BaseTvInputService</code> subclass creates sessions which handle
    236 tuning requests. Override the
    237 <code>onCreateSession()</code> method, create a session extended from
    238 the <code>BaseTvInputService.Session</code> class, and call
    239 <code>super.sessionCreated()</code> with your new session. In the following
    240 example, <code>onCreateSession()</code> returns a
    241 <code>RichTvInputSessionImpl</code> object that extends
    242 <code>BaseTvInputService.Session</code>:</p>
    243 
    244 <pre>
    245 &#64;Override
    246 public final Session onCreateSession(String inputId) {
    247     RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId);
    248     session.setOverlayViewEnabled(true);
    249     return super.sessionCreated(session);
    250 }
    251 </pre>
    252 
    253 <p>When the user uses the system TV app to start viewing one of your channels,
    254 the system calls your session's <code>onPlayChannel()</code> method. Override
    255 this method if you need to do any special channel initialization before the
    256 program starts playing.</p>
    257 
    258 <p>The system then obtains the currently scheduled program and calls your
    259 session's <code>onPlayProgram()</code> method, specifying the program
    260 information and start time in milliseconds. Use the
    261 <code>TvPlayer</code> interface to start playing the program.</p>
    262 
    263 <p>Your media player code should implement <code>TvPlayer</code> to handle
    264 specific playback events. The <code>TvPlayer</code> class handles features
    265 like time-shifting controls without adding complexity to your
    266 <code>BaseTvInputService</code> implementation.</p>
    267 
    268 <p>In your session's <code>getTvPlayer()</code> method, return
    269 your media player that implements <code>TvPlayer</code>. The
    270 <a class="external-link"
    271 href="https://github.com/googlesamples/androidtv-sample-inputs">
    272 TV Input Service sample app</a> implements a media player that uses
    273 <a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p>
    274 
    275 <h2 id="NoTIFCompanion">Create a TV Input Service Using the TIF Framework</h2>
    276 
    277 <p>If your TV input service can't use the TIF Companion Library, you need
    278 to implement the following components:</p>
    279 
    280 <ul>
    281   <li>{@link android.media.tv.TvInputService} provides long-running and background availability for
    282   the TV input</li>
    283   <li>{@link android.media.tv.TvInputService.Session} maintains the TV input state and communicates
    284   with the hosting app</li>
    285   <li>{@link android.media.tv.TvContract} describes the channels and programs available to the TV
    286   input</li>
    287   <li>{@link android.media.tv.TvContract.Channels} represents information about a TV channel</li>
    288   <li>{@link android.media.tv.TvContract.Programs} describes a TV program with data such as program
    289   title and start time</li>
    290   <li>{@link android.media.tv.TvTrackInfo} represents an audio, video, or subtitle track</li>
    291   <li>{@link android.media.tv.TvContentRating} describes a content rating, allows for custom content
    292   rating schemes</li>
    293   <li>{@link android.media.tv.TvInputManager} provides an API to the system TV app and manages
    294   the interaction with TV inputs and apps</li>
    295 </ul>
    296 
    297 <p>You also need to do the following:</p>
    298 
    299 <ol>
    300 <li>Declare your TV input service in the manifest, as
    301 described in <a href="#manifest">Declare your TV input service in the
    302 manifest</a>.</li>
    303 <li>Create the service metadata file.</li>
    304 <li>Create and register your channel and program information.</li>
    305 <li>Create your setup activity.</li>
    306 </ol>
    307 
    308 <h3 id="tvinput">Define your TV input service</h3>
    309 
    310 <div class="figure">
    311 <img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/>
    312 <p class="img-caption"><strong>Figure 1.</strong>TvInputService lifecycle.</p>
    313 </div>
    314 
    315 <p>For your service, you extend the {@link android.media.tv.TvInputService} class. A
    316 {@link android.media.tv.TvInputService} implementation is a
    317 <a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service
    318 is the client that binds to it. The service life cycle methods
    319 you need to implement are illustrated in figure 1.</p>
    320 
    321 <p>The {@link android.app.Service#onCreate()} method initializes and starts the
    322 {@link android.os.HandlerThread} which provides a process thread separate from the UI thread to
    323 handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()}
    324 method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle
    325 the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED}
    326 and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These
    327 actions describe system intents fired when the user changes the parental control settings, and when
    328 there is a change on the list of blocked ratings.</p>
    329 
    330 <pre>
    331 &#64;Override
    332 public void onCreate() {
    333     super.onCreate();
    334     mHandlerThread = new HandlerThread(getClass()
    335       .getSimpleName());
    336     mHandlerThread.start();
    337     mDbHandler = new Handler(mHandlerThread.getLooper());
    338     mHandler = new Handler();
    339     mCaptioningManager = (CaptioningManager)
    340       getSystemService(Context.CAPTIONING_SERVICE);
    341 
    342     setTheme(android.R.style.Theme_Holo_Light_NoActionBar);
    343 
    344     mSessions = new ArrayList&lt;BaseTvInputSessionImpl&gt;();
    345     IntentFilter intentFilter = new IntentFilter();
    346     intentFilter.addAction(TvInputManager
    347       .ACTION_BLOCKED_RATINGS_CHANGED);
    348     intentFilter.addAction(TvInputManager
    349       .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
    350     registerReceiver(mBroadcastReceiver, intentFilter);
    351 }
    352 </pre>
    353 
    354 <p> See <a href="{@docRoot}training/tv/tif/ui.html#control">
    355 Control Content</a> for more information about working with blocked content and providing
    356 parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that
    357 you may want to handle in your TV input service.</p>
    358 
    359 <p>The {@link android.media.tv.TvInputService} creates a
    360 {@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback}
    361 to handle player state changes. With
    362 {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()},
    363 the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the
    364 video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a>
    365 for more information about working with {@link android.view.Surface} to render video.</p>
    366 
    367 <p>The {@link android.media.tv.TvInputService.Session} handles the
    368 {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()}
    369 event when the user selects a channel, and notifies the system TV app for changes in the content and
    370 content metadata. These <code>notify()</code> methods are described in
    371 <a href="{@docRoot}training/tv/tif/ui.html#control">
    372 Control Content</a> and <a href="{@docRoot}training/tv/tif/ui.html#track">Handle Track Selection</a>
    373 further in this training.</p>
    374 
    375 <h3 id="setup">Define your setup activity</h3>
    376 
    377 <p>The system TV app works with the setup activity you define for your TV input. The
    378 setup activity is required and must provide at least one channel record for the system database. The
    379 system TV app invokes the setup activity when it cannot find a channel for the TV input.
    380 <p>The setup activity describes to the system TV app the channels made available through the TV
    381 input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating
    382 and Updating Channel Data</a>.</p>