• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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&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
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&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
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&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
146Google 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>
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&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
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&#64;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&#64;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&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">
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>