• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1page.title=Working with Channel Data
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="#permission">Get Permission</a></li>
14    <li><a href="#register">Register Channels in the Database</a></li>
15    <li><a href="#update">Update Channel Data</a></li>
16    <li><a href="#applink">Add App Link Information</a></li>
17  </ol>
18  <h2>Try It Out</h2>
19  <ul>
20    <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs">
21      TV Input Service sample app</a></li>
22  </ul>
23</div>
24</div>
25
26<p>Your TV input must provide Electronic Program Guide (EPG) data for at least
27one channel in its setup activity. You should also periodically update that
28data, with consideration for the size of the update and the processing thread
29that handles it. Additionally, you can provide app links for channels
30that guide the user to related content and activities.
31This lesson discusses creating and updating channel and program data on the
32system database with these considerations in mind.</p>
33
34<p>&nbsp;</p>
35
36<h2 id="permission">Get Permission</h2>
37
38<p>In order for your TV input to work with EPG data, it must declare the
39read and write permissions in its Android manifest file as follows:</p>
40
41<pre>
42&lt;uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /&gt;
43&lt;uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /&gt;
44</pre>
45
46<h2 id="register">Register Channels in the Database</h2>
47
48<p>The Android TV system database maintains records of channel data for TV inputs. In your setup
49activity, for each of your channels, you must map your channel data to the following fields of the
50{@link android.media.tv.TvContract.Channels} class:</p>
51
52<ul>
53  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NAME} - the displayed name of the
54  channel</li>
55  <li>{@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER} - the displayed channel
56  number</li>
57  <li>{@link android.media.tv.TvContract.Channels#COLUMN_INPUT_ID} - the ID of the TV input service</li>
58  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_TYPE} - the channel's service type</li>
59  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TYPE} - the channel's broadcast standard
60  type</li>
61  <li>{@link android.media.tv.TvContract.Channels#COLUMN_VIDEO_FORMAT} - the default video format
62  for the channel</li>
63</ul>
64
65<p>Although the TV input framework is generic enough to handle both traditional broadcast and
66over-the-top (OTT) content without any distinction, you may want to define the following columns in
67addition to those above to better identify traditional broadcast channels:</p>
68
69<ul>
70  <li>{@link android.media.tv.TvContract.Channels#COLUMN_ORIGINAL_NETWORK_ID} - the television
71  network ID</li>
72  <li>{@link android.media.tv.TvContract.Channels#COLUMN_SERVICE_ID} - the service ID</li>
73  <li>{@link android.media.tv.TvContract.Channels#COLUMN_TRANSPORT_STREAM_ID} - the transport stream
74  ID</li>
75</ul>
76
77<p>If you want to provide app link details for your channels, you need to
78update some additional fields. For more information on app link fields, see
79<a href="#applink">Add App Link Information</a>.
80
81<p>For internet streaming based TV inputs, assign your own values to the above accordingly so that
82each channel can be identified uniquely.</p>
83
84<p>Pull your channel metadata (in XML, JSON, or whatever) from your backend server, and in your setup
85activity map the values to the system database as follows:</p>
86
87<pre>
88ContentValues values = new ContentValues();
89
90values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.mNumber);
91values.put(Channels.COLUMN_DISPLAY_NAME, channel.mName);
92values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.mOriginalNetworkId);
93values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.mTransportStreamId);
94values.put(Channels.COLUMN_SERVICE_ID, channel.mServiceId);
95values.put(Channels.COLUMN_VIDEO_FORMAT, channel.mVideoFormat);
96
97Uri uri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI, values);
98</pre>
99
100<p>In the example above, <code>channel</code> is an object which holds channel metadata from the
101backend server.</p>
102
103<h3 id="art">Present Channel and Program Information</h2>
104
105<p>The system TV app presents channel and program information to users as they flip through channels,
106as shown in figure 1. To make sure the channel and program information works with the system TV app's
107channel and program information presenter, follow the guidelines below.</p>
108
109<ol>
110<li><strong>Channel number</strong> ({@link android.media.tv.TvContract.Channels#COLUMN_DISPLAY_NUMBER})
111<li><strong>Icon</strong>
112(<a href="guide/topics/manifest/application-element.html#icon"><code>android:icon</code></a> in the
113TV input's manifest)</li>
114<li><strong>Program description</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_SHORT_DESCRIPTION})
115<li><strong>Program title</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_TITLE})</li>
116<li><strong>Channel logo</strong> ({@link android.media.tv.TvContract.Channels.Logo})
117  <ul>
118    <li>Use the color #EEEEEE to match the surrounding text</li>
119    <li>Don't include padding
120  </ul></li>
121<li><strong>Poster art</strong> ({@link android.media.tv.TvContract.Programs#COLUMN_POSTER_ART_URI})
122  <ul>
123    <li>Aspect ratio between 16:9 and 4:3</li>
124  </ul>
125</ol>
126
127<img src="{@docRoot}images/tv/channel-info.png" id="figure1">
128<p class="img-caption">
129  <strong>Figure 1.</strong> The system TV app channel and program information presenter.
130</p>
131
132<p>The system TV app provides the same information through the program guide, including poster art,
133as shown in figure 2.</p>
134
135<img src="{@docRoot}images/tv/prog-guide.png" id="figure2">
136<p class="img-caption">
137  <strong>Figure 2.</strong> The system TV app program guide.
138</p>
139
140<h2 id="update">Update Channel Data</h2>
141
142<p>When updating existing channel data, use the
143{@link android.content.ContentProvider#update(android.net.Uri, android.content.ContentValues,
144java.lang.String, java.lang.String[]) update()}
145method instead of deleting and re-adding the data. You can identify the current version of the data
146by using {@link android.media.tv.TvContract.Channels#COLUMN_VERSION_NUMBER Channels.COLUMN_VERSION_NUMBER}
147and {@link android.media.tv.TvContract.Programs#COLUMN_VERSION_NUMBER Programs.COLUMN_VERSION_NUMBER}
148when choosing the records to update.</p>
149
150<p class="note"><strong>Note:</strong> Adding channel data to the {@link android.content.ContentProvider}
151can take time. Only add current programs (those within two hours of the current time) when you update,
152and use a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">Sync Adapter</a> to
153update the rest of the channel data in the background. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
154Android TV Live TV Sample App</a> for an example.</p>
155
156<h3 id="batch">Batch Loading Channel Data</h3>
157
158<p>When updating the system database with a large amount of channel data, use the {@link android.content.ContentResolver}
159{@link android.content.ContentResolver#applyBatch applyBatch()}
160or
161{@link android.content.ContentResolver#bulkInsert(android.net.Uri, android.content.ContentValues[]) bulkInsert()}
162method. Here's an example using {@link android.content.ContentResolver#applyBatch applyBatch()}:<p>
163
164<pre>
165ArrayList&lt;ContentProviderOperation&gt; ops = new ArrayList&lt;&gt;();
166int programsCount = mChannelInfo.mPrograms.size();
167for (int j = 0; j &lt; programsCount; ++j) {
168    ProgramInfo program = mChannelInfo.mPrograms.get(j);
169    ops.add(ContentProviderOperation.newInsert(
170            TvContract.Programs.CONTENT_URI)
171            .withValues(programs.get(j))
172            .withValue(Programs.COLUMN_START_TIME_UTC_MILLIS,
173                    programStartSec * 1000)
174            .withValue(Programs.COLUMN_END_TIME_UTC_MILLIS,
175                    (programStartSec + program.mDurationSec) * 1000)
176            .build());
177    programStartSec = programStartSec + program.mDurationSec;
178    if (j % 100 == 99 || j == programsCount - 1) {
179        try {
180            <strong>getContentResolver().applyBatch(TvContract.AUTHORITY, ops);</strong>
181        } catch (RemoteException | OperationApplicationException e) {
182            Log.e(TAG, "Failed to insert programs.", e);
183            return;
184        }
185        ops.clear();
186    }
187}
188</pre>
189
190<h3 id="async">Processing Channel Data Asynchronously</h3>
191
192<p>Data manipulation, such as fetching a stream from the server or accessing the database, should
193not block the UI thread. Using an {@link android.os.AsyncTask} is one
194way to perform updates asynchronously.  For example, when loading channel info from a backend server,
195you can use {@link android.os.AsyncTask} as follows:</p>
196
197<pre>
198private static class LoadTvInputTask extends AsyncTask&lt;Uri, Void, Void>&gt; {
199
200    private Context mContext;
201
202    public LoadTvInputTask(Context context) {
203        mContext = context;
204    }
205
206    &#64;Override
207    protected Void doInBackground(Uri... uris) {
208        try {
209            fetchUri(uris[0]);
210        } catch (IOException e) {
211          Log.d(“LoadTvInputTask”, “fetchUri error”);
212        }
213        return null;
214    }
215
216    private void fetchUri(Uri videoUri) throws IOException {
217        InputStream inputStream = null;
218        try {
219            inputStream = mContext.getContentResolver().openInputStream(videoUri);
220            XmlPullParser parser = Xml.newPullParser();
221            try {
222                parser.setFeature(XmlPullParser.FEATURE_PROCESS_NAMESPACES, false);
223                parser.setInput(inputStream, null);
224                sTvInput = ChannelXMLParser.parseTvInput(parser);
225                sSampleChannels = ChannelXMLParser.parseChannelXML(parser);
226            } catch (XmlPullParserException e) {
227                e.printStackTrace();
228            }
229        } finally {
230            if (inputStream != null) {
231                inputStream.close();
232            }
233        }
234    }
235}
236</pre>
237
238<p>If you need to update EPG data on a regular basis, consider using
239a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">
240Sync Adapter</a> or {@link android.app.job.JobScheduler} to run the update process during idle time,
241such as every day at 3:00 a.m. See the <a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs/blob/master/app/src/main/java/com/example/android/sampletvinput/syncadapter/SyncAdapter.java">
242Android TV live TV sample app</a> for an example.</p>
243
244<p>Other techniques to separate the data update tasks from the UI thread include using the
245{@link android.os.HandlerThread} class, or you may implement your own using {@link android.os.Looper}
246and {@link android.os.Handler} classes.  See <a href="{@docRoot}guide/components/processes-and-threads.html">
247Processes and Threads</a> for more information.</p>
248
249<h2 id="applink">Add App Link Information</h2>
250
251<p>Channels can use <em>app links</em> to let users easily launch a related
252activity while they are watching channel content. Channel apps use
253app links to extend user engagement by launching activities that show
254related information or additional content. For example, you can use app links
255to do the following:</p>
256
257<ul>
258<li>Guide the user to discover and purchase related content.</li>
259<li>Provide additional information about currently playing content.</li>
260<li>While viewing episodic content, start viewing the next episode in a
261series.</li>
262<li>Let the user interact with content&mdash;for example, rate or review
263content&mdash;without interrupting content playback.</li>
264</ul>
265
266<p>App links are displayed when the user presses <b>Select</b> to show the
267TV menu while watching channel content.</p>
268
269<img alt="" src="{@docRoot}images/training/tv/tif/app-link.png"
270srcset="{@docRoot}images/training/tv/tif/app-link.png 1x,
271{@docRoot}images/training/tv/tif/app-link-2x.png 2x" id="figure1"/>
272<p class="img-caption"><strong>Figure 1.</strong> An example app link
273displayed on the <b>Channels</b> row while channel content is shown.</p>
274
275<p>When the user selects the app link, the system starts an activity using
276an intent URI specified by the channel app. Channel content continues to play
277while the app link activity is active. The user can return to the channel
278content by pressing <b>Back</b>.</p>
279
280<h3 id="card">Provide App Link Channel Data</h4>
281
282<p>Android TV automatically creates an app link for each channel,
283using information from the channel data. To provide app link information,
284specify the following details in your
285{@link android.media.tv.TvContract.Channels} fields:
286</p>
287
288<ul>
289<li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_COLOR} - The
290accent color of the app link for this channel. For an example accent color,
291see figure 2, callout 3.
292</li>
293<li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_ICON_URI} -
294The URI for the app badge icon of the app link for this channel. For an
295example app badge icon, see figure 2, callout 2.
296</li>
297<li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_INTENT_URI} -
298The intent URI of the app link for this channel. You can create the URI
299using {@link android.content.Intent#toUri(int) toUri(int)} with
300{@link android.content.Intent#URI_INTENT_SCHEME URI_INTENT_SCHEME} and
301convert the URI back to the original intent with
302{@link android.content.Intent#parseUri parseUri()}.
303</li>
304<li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_POSTER_ART_URI}
305- The URI for the poster art used as the background of the app link
306for this channel. For an example poster image, see figure 2, callout 1.</li>
307<li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_TEXT} -
308The descriptive link text of the app link for this channel. For an example
309app link description, see the text in figure 2, callout 3.</li>
310</ul>
311
312<img alt="" src="{@docRoot}images/training/tv/tif/app-link-diagram.png"/>
313<p class="img-caption"><strong>Figure 2.</strong> App link details.</p>
314
315<p>If the channel data doesn't specify app link information, the system
316creates a default app link. The system chooses default details as follows:</p>
317
318<ul>
319<li>For the intent URI
320({@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_INTENT_URI}),
321the system uses the {@link android.content.Intent#ACTION_MAIN ACTION_MAIN}
322activity for the {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER
323CATEGORY_LEANBACK_LAUNCHER} category, typically defined in the app manifest.
324If this activity is not defined, a non-functioning app link appears&mdash;if
325the user clicks it, nothing happens.</li>
326<li>For the descriptive text
327({@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_TEXT}), the system
328uses "Open <var>app-name</var>". If no viable app link intent URI is defined,
329the system uses "No link available".</li>
330<li>For the accent color
331({@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_COLOR}),
332the system uses the default app color.</li>
333<li>For the poster image
334({@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_POSTER_ART_URI}),
335the system uses the app's home screen banner. If the app doesn't provide a
336banner, the system uses a default TV app image.</li>
337<li>For the badge icon
338({@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_ICON_URI}), the
339system uses a badge that shows the app name. If the system is also using the
340app banner or default app image for the poster image, no app badge is shown.
341</li>
342</ul>
343
344<p>You specify app link details for your channels in your app's
345setup activity. You can update these app link details at any point, so
346if an app link needs to match channel changes, update app
347link details and call
348{@link android.content.ContentResolver#update(android.net.Uri,
349android.content.ContentValues, java.lang.String, java.lang.String[])
350ContentResolver.update()} as needed. For more details on updating
351channel data, see <a href="#update">Update Channel Data</a>.
352</p>
353
354
355
356