1page.title=Developing a TV Input Service 2page.tags=tv, tif 3helpoutsWidget=true 4 5trainingnavtop=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 32linear, broadcast TV fashion as channels and programs. With a TV input service, you can provide 33parental controls, program guide information, and content ratings. The TV input service works 34with the Android system TV app. This app ultimately controls and presents channel content 35on the TV. The system TV app is developed specifically for the device and immutable 36by third-party apps. For more information about the TV Input Framework (TIF) 37architecture and its components, see 38<a class="external-link" href="http://source.android.com/devices/tv/index.html"> 39TV Input Framework</a>.</p> 40 41<h2 id="TIFCompanion">Create a TV Input Service Using the TIF Companion Library</h2> 42 43<p> 44The TIF Companion Library is a framework that provides extensible 45implementations of common TV input service features. Use the TIF Companion 46Library to quickly and easily create your own TV input service that follows 47best practices for Android TV. 48</p> 49 50<h3 id="build">Update your build.gradle file</h3> 51 52<p> 53To get started using the TIF Companion Library, add the following line to your 54app's <code>build.gradle</code> file: 55</p> 56 57<pre> 58compile '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 62framework. It is distributed as part of the <a class="external-link" 63href="https://github.com/googlesamples/androidtv-sample-inputs"> 64TV 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 70service that the system uses to access your app. The TIF 71Companion Library provides the <code>BaseTvInputService</code> class, which 72provides a default implementation of {@link android.media.tv.TvInputService} 73that you can customize. Create a subclass of <code>BaseTvInputService</code>, 74and 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 78service to connect the TV input to the system. A system service 79performs the binding and has the 80{@link android.Manifest.permission#BIND_TV_INPUT} permission. 81The system TV app sends requests to TV input services 82via 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 86intent. Also declare the service metadata as a separate XML resource. The 87service declaration, intent filter, and service metadata declaration are shown 88in the following example:</p> 89 90<pre> 91<service android:name=".rich.RichTvInputService" 92 android:label="@string/rich_input_label" 93 android:permission="android.permission.BIND_TV_INPUT"> 94 <!-- Required filter used by the system to launch our account service. --> 95 <intent-filter> 96 <action android:name="android.media.tv.TvInputService" /> 97 </intent-filter> 98 <!-- An XML file which describes this input. This provides pointers to 99 the RichTvInputSetupActivity to the system/TV app. --> 100 <meta-data 101 android:name="android.media.tv.input" 102 android:resource="@xml/richtvinputservice" /> 103</service> 104</pre> 105 106<p>Define the service metadata in a separate XML file. The service 107metadata XML file must include a setup interface that describes the TV input's 108initial configuration and channel scan. The metadata file should also contain a 109flag stating whether or not users are able to record content. For more 110information 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 115for your app and must match the name of the resource you declared in the 116manifest. Using the manifest entries from the previous example, you would 117create the XML file at <code>res/xml/richtvinputservice.xml</code>, with the 118following contents:</p> 119 120<pre> 121<?xml version="1.0" encoding="utf-8"?> 122<tv-input xmlns:android="http://schemas.android.com/apk/res/android" 123 android:canRecord="true" 124 android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" /> 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 130access via the system TV app. You should register your channels 131in the system database, and provide a setup activity that the system 132invokes 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 135Programming Guide (EPG), whose data includes channels and programs available 136to the user. To enable your app to perform these actions, and sync with the 137EPG after device restart, add the following elements to your app manifest:</p> 138 139<pre> 140<uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> 141<uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> 142<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/> 143</pre> 144 145<p>Add the following element to ensure that your app shows up in the 146Google Play Store as an app that provides content channels in Android TV:</p> 147 148<pre> 149<uses-feature 150 android:name="android.software.live_tv" 151 android:required="true" /> 152</pre> 153 154<p>Next, create a class which extends the <code>EpgSyncJobService</code> 155class. This abstract class makes it easy to create a job service that 156creates 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, 160use the <code>XmlTvParser</code> class. Otherwise generate 161channels programmatically using the <code>Channel.Builder</code> class. 162</p> 163 164<p>For each channel, the system calls <code>getProgramsForChannel()</code> 165when it needs a list of programs that can be viewed within a given time window 166on the channel. Return a list of <code>Program</code> objects for the 167channel. Use the <code>XmlTvParser</code> class to obtain programs from an 168XMLTV 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 173program's video type. If you only have a limited number of programs that you 174want 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<service 182 android:name=".sync.SampleJobService" 183 android:permission="android.permission.BIND_JOB_SERVICE" 184 android:exported="true" /> 185</pre> 186 187<p>Finally, create a setup activity. Your setup activity should provide a way 188to sync channel and program data. One way to do this is for the user to do it 189via the UI in the activity. You might also have the app do it automatically 190when the activity starts. When the setup activity needs to sync channel and 191program info, the app should start the job service:</p> 192 193<pre> 194String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID); 195EpgSyncJobService.cancelAllSyncRequests(getActivity()); 196EpgSyncJobService.requestImmediateSync(getActivity(), inputId, 197 new ComponentName(getActivity(), SampleJobService.class)); 198</pre> 199 200<p>Use the <code>requestImmediateSync()</code> method to sync 201the job service. The user must wait for the sync to finish, so you should 202keep your request period relatively short.</p> 203 204<p>Use the <code>setUpPeriodicSync()</code> method to have the job service 205periodically sync channel and program data in the background:</p> 206 207<pre> 208EpgSyncJobService.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 214channel data to sync in milliseconds. The default method syncs one hour's 215worth 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 220channel data to sync, and how often the periodic sync should occur. The 221default 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 232and play content. The TIF Companion Library provides several 233classes 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 236tuning requests. Override the 237<code>onCreateSession()</code> method, create a session extended from 238the <code>BaseTvInputService.Session</code> class, and call 239<code>super.sessionCreated()</code> with your new session. In the following 240example, <code>onCreateSession()</code> returns a 241<code>RichTvInputSessionImpl</code> object that extends 242<code>BaseTvInputService.Session</code>:</p> 243 244<pre> 245@Override 246public 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, 254the system calls your session's <code>onPlayChannel()</code> method. Override 255this method if you need to do any special channel initialization before the 256program starts playing.</p> 257 258<p>The system then obtains the currently scheduled program and calls your 259session's <code>onPlayProgram()</code> method, specifying the program 260information 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 264specific playback events. The <code>TvPlayer</code> class handles features 265like 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 269your media player that implements <code>TvPlayer</code>. The 270<a class="external-link" 271href="https://github.com/googlesamples/androidtv-sample-inputs"> 272TV 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 278to 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 301described in <a href="#manifest">Declare your TV input service in the 302manifest</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 318is the client that binds to it. The service life cycle methods 319you 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 323handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()} 324method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle 325the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED} 326and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These 327actions describe system intents fired when the user changes the parental control settings, and when 328there is a change on the list of blocked ratings.</p> 329 330<pre> 331@Override 332public 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<BaseTvInputSessionImpl>(); 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"> 355Control Content</a> for more information about working with blocked content and providing 356parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that 357you 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} 361to handle player state changes. With 362{@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()}, 363the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the 364video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a> 365for 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()} 369event when the user selects a channel, and notifies the system TV app for changes in the content and 370content metadata. These <code>notify()</code> methods are described in 371<a href="{@docRoot}training/tv/tif/ui.html#control"> 372Control Content</a> and <a href="{@docRoot}training/tv/tif/ui.html#track">Handle Track Selection</a> 373further 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 378setup activity is required and must provide at least one channel record for the system database. The 379system 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 381input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating 382and Updating Channel Data</a>.</p>