Home | History | Annotate | Download | only in tif
      1 page.title=Working with Channel Data
      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="#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
     27 one channel in its setup activity. You should also periodically update that
     28 data, with consideration for the size of the update and the processing thread
     29 that handles it. Additionally, you can provide app links for channels
     30 that guide the user to related content and activities.
     31 This lesson discusses creating and updating channel and program data on the
     32 system 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
     39 read 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
     49 activity, 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
     66 over-the-top (OTT) content without any distinction, you may want to define the following columns in
     67 addition 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
     78 update 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
     82 each 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
     85 activity map the values to the system database as follows:</p>
     86 
     87 <pre>
     88 ContentValues values = new ContentValues();
     89 
     90 values.put(Channels.COLUMN_DISPLAY_NUMBER, channel.mNumber);
     91 values.put(Channels.COLUMN_DISPLAY_NAME, channel.mName);
     92 values.put(Channels.COLUMN_ORIGINAL_NETWORK_ID, channel.mOriginalNetworkId);
     93 values.put(Channels.COLUMN_TRANSPORT_STREAM_ID, channel.mTransportStreamId);
     94 values.put(Channels.COLUMN_SERVICE_ID, channel.mServiceId);
     95 values.put(Channels.COLUMN_VIDEO_FORMAT, channel.mVideoFormat);
     96 
     97 Uri 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
    101 backend 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,
    106 as shown in figure 1. To make sure the channel and program information works with the system TV app's
    107 channel 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
    113 TV 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,
    133 as 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,
    144 java.lang.String, java.lang.String[]) update()}
    145 method instead of deleting and re-adding the data. You can identify the current version of the data
    146 by using {@link android.media.tv.TvContract.Channels#COLUMN_VERSION_NUMBER Channels.COLUMN_VERSION_NUMBER}
    147 and {@link android.media.tv.TvContract.Programs#COLUMN_VERSION_NUMBER Programs.COLUMN_VERSION_NUMBER}
    148 when choosing the records to update.</p>
    149 
    150 <p class="note"><strong>Note:</strong> Adding channel data to the {@link android.content.ContentProvider}
    151 can take time. Only add current programs (those within two hours of the current time) when you update,
    152 and use a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">Sync Adapter</a> to
    153 update 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">
    154 Android 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()}
    160 or
    161 {@link android.content.ContentResolver#bulkInsert(android.net.Uri, android.content.ContentValues[]) bulkInsert()}
    162 method. Here's an example using {@link android.content.ContentResolver#applyBatch applyBatch()}:<p>
    163 
    164 <pre>
    165 ArrayList&lt;ContentProviderOperation&gt; ops = new ArrayList&lt;&gt;();
    166 int programsCount = mChannelInfo.mPrograms.size();
    167 for (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
    193 not block the UI thread. Using an {@link android.os.AsyncTask} is one
    194 way to perform updates asynchronously.  For example, when loading channel info from a backend server,
    195 you can use {@link android.os.AsyncTask} as follows:</p>
    196 
    197 <pre>
    198 private 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
    239 a <a href="{@docRoot}training/sync-adapters/creating-sync-adapter.html">
    240 Sync Adapter</a> or {@link android.app.job.JobScheduler} to run the update process during idle time,
    241 such 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">
    242 Android 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}
    246 and {@link android.os.Handler} classes.  See <a href="{@docRoot}guide/components/processes-and-threads.html">
    247 Processes 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
    252 activity while they are watching channel content. Channel apps use
    253 app links to extend user engagement by launching activities that show
    254 related information or additional content. For example, you can use app links
    255 to 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
    261 series.</li>
    262 <li>Let the user interact with content&mdash;for example, rate or review
    263 content&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
    267 TV menu while watching channel content.</p>
    268 
    269 <img alt="" src="{@docRoot}images/training/tv/tif/app-link.png"
    270 srcset="{@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
    273 displayed 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
    276 an intent URI specified by the channel app. Channel content continues to play
    277 while the app link activity is active. The user can return to the channel
    278 content 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,
    283 using information from the channel data. To provide app link information,
    284 specify 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
    290 accent color of the app link for this channel. For an example accent color,
    291 see figure 2, callout 3.
    292 </li>
    293 <li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_ICON_URI} -
    294 The URI for the app badge icon of the app link for this channel. For an
    295 example app badge icon, see figure 2, callout 2.
    296 </li>
    297 <li>{@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_INTENT_URI} -
    298 The intent URI of the app link for this channel. You can create the URI
    299 using {@link android.content.Intent#toUri(int) toUri(int)} with
    300 {@link android.content.Intent#URI_INTENT_SCHEME URI_INTENT_SCHEME} and
    301 convert 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
    306 for 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} -
    308 The descriptive link text of the app link for this channel. For an example
    309 app 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
    316 creates 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}),
    321 the system uses the {@link android.content.Intent#ACTION_MAIN ACTION_MAIN}
    322 activity for the {@link android.content.Intent#CATEGORY_LEANBACK_LAUNCHER
    323 CATEGORY_LEANBACK_LAUNCHER} category, typically defined in the app manifest.
    324 If this activity is not defined, a non-functioning app link appears&mdash;if
    325 the 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
    328 uses "Open <var>app-name</var>". If no viable app link intent URI is defined,
    329 the system uses "No link available".</li>
    330 <li>For the accent color
    331 ({@link android.media.tv.TvContract.Channels#COLUMN_APP_LINK_COLOR}),
    332 the 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}),
    335 the system uses the app's home screen banner. If the app doesn't provide a
    336 banner, 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
    339 system uses a badge that shows the app name. If the system is also using the
    340 app 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
    345 setup activity. You can update these app link details at any point, so
    346 if an app link needs to match channel changes, update app
    347 link details and call
    348 {@link android.content.ContentResolver#update(android.net.Uri,
    349 android.content.ContentValues, java.lang.String, java.lang.String[])
    350 ContentResolver.update()} as needed. For more details on updating
    351 channel data, see <a href="#update">Update Channel Data</a>.
    352 </p>
    353 
    354 
    355 
    356