| page.title=Developing a TV Input Service |
| page.tags=tv, tif |
| helpoutsWidget=true |
| |
| trainingnavtop=true |
| |
| @jd:body |
| |
| <div id="tb-wrapper"> |
| <div id="tb"> |
| <h2>This lesson teaches you to</h2> |
| <ol> |
| <li><a href="#TIFCompanion">Create a TV Input Service Using the TIF Companion Library</a></li> |
| <li><a href="#NoTIFCompanion">Create a TV Input Service Using the TIF Framework</a></li> |
| </ol> |
| <h2>You should also read</h2> |
| <ul> |
| <li><a href="{@docRoot}reference/android/media/tv/package-summary.html"> |
| android.media.tv</a></li> |
| <li><a class="external-lin" href="http://source.android.com/devices/tv/index.html"> |
| TV Input Framework</a></li> |
| </ul> |
| <h2>Try It Out</h2> |
| <ul> |
| <li><a class="external-link" href="https://github.com/googlesamples/androidtv-sample-inputs"> |
| TV Input Service sample app</a></li> |
| </ul> |
| </div> |
| </div> |
| |
| <p>A TV input service represents a media stream source, and lets you present your media content in a |
| linear, broadcast TV fashion as channels and programs. With a TV input service, you can provide |
| parental controls, program guide information, and content ratings. The TV input service works |
| with the Android system TV app. This app ultimately controls and presents channel content |
| on the TV. The system TV app is developed specifically for the device and immutable |
| by third-party apps. For more information about the TV Input Framework (TIF) |
| architecture and its components, see |
| <a class="external-link" href="http://source.android.com/devices/tv/index.html"> |
| TV Input Framework</a>.</p> |
| |
| <h2 id="TIFCompanion">Create a TV Input Service Using the TIF Companion Library</h2> |
| |
| <p> |
| The TIF Companion Library is a framework that provides extensible |
| implementations of common TV input service features. Use the TIF Companion |
| Library to quickly and easily create your own TV input service that follows |
| best practices for Android TV. |
| </p> |
| |
| <h3 id="build">Update your build.gradle file</h3> |
| |
| <p> |
| To get started using the TIF Companion Library, add the following line to your |
| app's <code>build.gradle</code> file: |
| </p> |
| |
| <pre> |
| compile 'com.google.android.media.tv.companionlibrary:1.0.0' |
| </pre> |
| |
| <p>The TIF Companion Library is not currently part of the Android |
| framework. It is distributed as part of the <a class="external-link" |
| href="https://github.com/googlesamples/androidtv-sample-inputs"> |
| TV Input Service sample app</a>, and not with the Android SDK. |
| </p> |
| |
| <h3 id="manifest">Declare your TV input service in the manifest</h3> |
| |
| <p>Your app must provide a {@link android.media.tv.TvInputService}-compatible |
| service that the system uses to access your app. The TIF |
| Companion Library provides the <code>BaseTvInputService</code> class, which |
| provides a default implementation of {@link android.media.tv.TvInputService} |
| that you can customize. Create a subclass of <code>BaseTvInputService</code>, |
| and declare the subclass in your manifest as a service.</p> |
| |
| <p>Within the manifest declaration, specify the |
| {@link android.Manifest.permission#BIND_TV_INPUT} permission to allow the |
| service to connect the TV input to the system. A system service |
| performs the binding and has the |
| {@link android.Manifest.permission#BIND_TV_INPUT} permission. |
| The system TV app sends requests to TV input services |
| via the {@link android.media.tv.TvInputManager} interface.</p> |
| |
| <p>In your service declaration, include an intent filter that specifies |
| {@link android.media.tv.TvInputService} as the action to perform with the |
| intent. Also declare the service metadata as a separate XML resource. The |
| service declaration, intent filter, and service metadata declaration are shown |
| in the following example:</p> |
| |
| <pre> |
| <service android:name=".rich.RichTvInputService" |
| android:label="@string/rich_input_label" |
| android:permission="android.permission.BIND_TV_INPUT"> |
| <!-- Required filter used by the system to launch our account service. --> |
| <intent-filter> |
| <action android:name="android.media.tv.TvInputService" /> |
| </intent-filter> |
| <!-- An XML file which describes this input. This provides pointers to |
| the RichTvInputSetupActivity to the system/TV app. --> |
| <meta-data |
| android:name="android.media.tv.input" |
| android:resource="@xml/richtvinputservice" /> |
| </service> |
| </pre> |
| |
| <p>Define the service metadata in a separate XML file. The service |
| metadata XML file must include a setup interface that describes the TV input's |
| initial configuration and channel scan. The metadata file should also contain a |
| flag stating whether or not users are able to record content. For more |
| information on how to support recording content in your app, see |
| <a href="{@docRoot}preview/features/tv-recording-api.html">TV Recording</a>. |
| </p> |
| |
| <p>The service metadata file is located in the XML resources directory |
| for your app and must match the name of the resource you declared in the |
| manifest. Using the manifest entries from the previous example, you would |
| create the XML file at <code>res/xml/richtvinputservice.xml</code>, with the |
| following contents:</p> |
| |
| <pre> |
| <?xml version="1.0" encoding="utf-8"?> |
| <tv-input xmlns:android="http://schemas.android.com/apk/res/android" |
| android:canRecord="true" |
| android:setupActivity="com.example.android.sampletvinput.rich.RichTvInputSetupActivity" /> |
| </pre> |
| |
| <h3 id="setup">Define channels and create your setup activity</h3> |
| |
| <p>Your TV input service must define at least one channel that users |
| access via the system TV app. You should register your channels |
| in the system database, and provide a setup activity that the system |
| invokes when it cannot find a channel for your app.</p> |
| |
| <p>First, enable your app to read from and write to the system Electronic |
| Programming Guide (EPG), whose data includes channels and programs available |
| to the user. To enable your app to perform these actions, and sync with the |
| EPG after device restart, add the following elements to your app manifest:</p> |
| |
| <pre> |
| <uses-permission android:name="com.android.providers.tv.permission.READ_EPG_DATA" /> |
| <uses-permission android:name="com.android.providers.tv.permission.WRITE_EPG_DATA" /> |
| <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED "/> |
| </pre> |
| |
| <p>Add the following element to ensure that your app shows up in the |
| Google Play Store as an app that provides content channels in Android TV:</p> |
| |
| <pre> |
| <uses-feature |
| android:name="android.software.live_tv" |
| android:required="true" /> |
| </pre> |
| |
| <p>Next, create a class which extends the <code>EpgSyncJobService</code> |
| class. This abstract class makes it easy to create a job service that |
| creates and updates channels in the system database.</p> |
| |
| <p>In your subclass, create and return your full list of channels in |
| <code>getChannels()</code>. If your channels come from an XMLTV file, |
| use the <code>XmlTvParser</code> class. Otherwise generate |
| channels programmatically using the <code>Channel.Builder</code> class. |
| </p> |
| |
| <p>For each channel, the system calls <code>getProgramsForChannel()</code> |
| when it needs a list of programs that can be viewed within a given time window |
| on the channel. Return a list of <code>Program</code> objects for the |
| channel. Use the <code>XmlTvParser</code> class to obtain programs from an |
| XMLTV file, or generate them programmatically using the |
| <code>Program.Builder</code> class.</p> |
| |
| <p>For each <code>Program</code> object, use an |
| <code>InternalProviderData</code> object to set program information such as the |
| program's video type. If you only have a limited number of programs that you |
| want the channel to repeat in a loop, use the |
| <code>InternalProviderData.setRepeatable()</code> method with a value of |
| <code>true</code> when setting information about your program.</p> |
| |
| <p>After you've implemented the job service, add it to your app manifest:</p> |
| |
| <pre> |
| <service |
| android:name=".sync.SampleJobService" |
| android:permission="android.permission.BIND_JOB_SERVICE" |
| android:exported="true" /> |
| </pre> |
| |
| <p>Finally, create a setup activity. Your setup activity should provide a way |
| to sync channel and program data. One way to do this is for the user to do it |
| via the UI in the activity. You might also have the app do it automatically |
| when the activity starts. When the setup activity needs to sync channel and |
| program info, the app should start the job service:</p> |
| |
| <pre> |
| String inputId = getActivity().getIntent().getStringExtra(TvInputInfo.EXTRA_INPUT_ID); |
| EpgSyncJobService.cancelAllSyncRequests(getActivity()); |
| EpgSyncJobService.requestImmediateSync(getActivity(), inputId, |
| new ComponentName(getActivity(), SampleJobService.class)); |
| </pre> |
| |
| <p>Use the <code>requestImmediateSync()</code> method to sync |
| the job service. The user must wait for the sync to finish, so you should |
| keep your request period relatively short.</p> |
| |
| <p>Use the <code>setUpPeriodicSync()</code> method to have the job service |
| periodically sync channel and program data in the background:</p> |
| |
| <pre> |
| EpgSyncJobService.setUpPeriodicSync(context, inputId, |
| new ComponentName(context, SampleJobService.class)); |
| </pre> |
| |
| <p>The TIF Companion Library provides an additional overloaded method of |
| <code>requestImmediateSync()</code> that lets you specify the duration of |
| channel data to sync in milliseconds. The default method syncs one hour's |
| worth of channel data. |
| </p> |
| |
| <p>The TIF Companion Library also provides an additional overloaded method of |
| <code>setUpPeriodicSync()</code> that lets you specify the duration of |
| channel data to sync, and how often the periodic sync should occur. The |
| default method syncs 48 hours of channel data every 12 hours. |
| </p> |
| |
| <p>For more details about channel data and the EPG, see |
| <a href="{@docRoot}training/tv/tif/channel.html"> Working with Channel Data</a>. |
| </p> |
| |
| <h3 id="playback">Handle tuning requests and media playback</h3> |
| |
| <p>When a user selects a specific channel, the system TV app uses a |
| <code>Session</code>, created by your app, to tune to the requested channel |
| and play content. The TIF Companion Library provides several |
| classes you can extend to handle channel and session calls from the system.</p> |
| |
| <p>Your <code>BaseTvInputService</code> subclass creates sessions which handle |
| tuning requests. Override the |
| <code>onCreateSession()</code> method, create a session extended from |
| the <code>BaseTvInputService.Session</code> class, and call |
| <code>super.sessionCreated()</code> with your new session. In the following |
| example, <code>onCreateSession()</code> returns a |
| <code>RichTvInputSessionImpl</code> object that extends |
| <code>BaseTvInputService.Session</code>:</p> |
| |
| <pre> |
| @Override |
| public final Session onCreateSession(String inputId) { |
| RichTvInputSessionImpl session = new RichTvInputSessionImpl(this, inputId); |
| session.setOverlayViewEnabled(true); |
| return super.sessionCreated(session); |
| } |
| </pre> |
| |
| <p>When the user uses the system TV app to start viewing one of your channels, |
| the system calls your session's <code>onPlayChannel()</code> method. Override |
| this method if you need to do any special channel initialization before the |
| program starts playing.</p> |
| |
| <p>The system then obtains the currently scheduled program and calls your |
| session's <code>onPlayProgram()</code> method, specifying the program |
| information and start time in milliseconds. Use the |
| <code>TvPlayer</code> interface to start playing the program.</p> |
| |
| <p>Your media player code should implement <code>TvPlayer</code> to handle |
| specific playback events. The <code>TvPlayer</code> class handles features |
| like time-shifting controls without adding complexity to your |
| <code>BaseTvInputService</code> implementation.</p> |
| |
| <p>In your session's <code>getTvPlayer()</code> method, return |
| your media player that implements <code>TvPlayer</code>. The |
| <a class="external-link" |
| href="https://github.com/googlesamples/androidtv-sample-inputs"> |
| TV Input Service sample app</a> implements a media player that uses |
| <a href="{@docRoot}guide/topics/media/exoplayer.html">ExoPlayer</a>.</p> |
| |
| <h2 id="NoTIFCompanion">Create a TV Input Service Using the TIF Framework</h2> |
| |
| <p>If your TV input service can't use the TIF Companion Library, you need |
| to implement the following components:</p> |
| |
| <ul> |
| <li>{@link android.media.tv.TvInputService} provides long-running and background availability for |
| the TV input</li> |
| <li>{@link android.media.tv.TvInputService.Session} maintains the TV input state and communicates |
| with the hosting app</li> |
| <li>{@link android.media.tv.TvContract} describes the channels and programs available to the TV |
| input</li> |
| <li>{@link android.media.tv.TvContract.Channels} represents information about a TV channel</li> |
| <li>{@link android.media.tv.TvContract.Programs} describes a TV program with data such as program |
| title and start time</li> |
| <li>{@link android.media.tv.TvTrackInfo} represents an audio, video, or subtitle track</li> |
| <li>{@link android.media.tv.TvContentRating} describes a content rating, allows for custom content |
| rating schemes</li> |
| <li>{@link android.media.tv.TvInputManager} provides an API to the system TV app and manages |
| the interaction with TV inputs and apps</li> |
| </ul> |
| |
| <p>You also need to do the following:</p> |
| |
| <ol> |
| <li>Declare your TV input service in the manifest, as |
| described in <a href="#manifest">Declare your TV input service in the |
| manifest</a>.</li> |
| <li>Create the service metadata file.</li> |
| <li>Create and register your channel and program information.</li> |
| <li>Create your setup activity.</li> |
| </ol> |
| |
| <h3 id="tvinput">Define your TV input service</h3> |
| |
| <div class="figure"> |
| <img id="tvinputlife" src="{@docRoot}images/tv/tvinput-life.png" alt=""/> |
| <p class="img-caption"><strong>Figure 1.</strong>TvInputService lifecycle.</p> |
| </div> |
| |
| <p>For your service, you extend the {@link android.media.tv.TvInputService} class. A |
| {@link android.media.tv.TvInputService} implementation is a |
| <a href="{@docRoot}guide/components/bound-services.html">bound service</a> where the system service |
| is the client that binds to it. The service life cycle methods |
| you need to implement are illustrated in figure 1.</p> |
| |
| <p>The {@link android.app.Service#onCreate()} method initializes and starts the |
| {@link android.os.HandlerThread} which provides a process thread separate from the UI thread to |
| handle system-driven actions. In the following example, the {@link android.app.Service#onCreate()} |
| method initializes the {@link android.view.accessibility.CaptioningManager} and prepares to handle |
| the {@link android.media.tv.TvInputManager#ACTION_BLOCKED_RATINGS_CHANGED} |
| and {@link android.media.tv.TvInputManager#ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED} actions. These |
| actions describe system intents fired when the user changes the parental control settings, and when |
| there is a change on the list of blocked ratings.</p> |
| |
| <pre> |
| @Override |
| public void onCreate() { |
| super.onCreate(); |
| mHandlerThread = new HandlerThread(getClass() |
| .getSimpleName()); |
| mHandlerThread.start(); |
| mDbHandler = new Handler(mHandlerThread.getLooper()); |
| mHandler = new Handler(); |
| mCaptioningManager = (CaptioningManager) |
| getSystemService(Context.CAPTIONING_SERVICE); |
| |
| setTheme(android.R.style.Theme_Holo_Light_NoActionBar); |
| |
| mSessions = new ArrayList<BaseTvInputSessionImpl>(); |
| IntentFilter intentFilter = new IntentFilter(); |
| intentFilter.addAction(TvInputManager |
| .ACTION_BLOCKED_RATINGS_CHANGED); |
| intentFilter.addAction(TvInputManager |
| .ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED); |
| registerReceiver(mBroadcastReceiver, intentFilter); |
| } |
| </pre> |
| |
| <p> See <a href="{@docRoot}training/tv/tif/ui.html#control"> |
| Control Content</a> for more information about working with blocked content and providing |
| parental control. See {@link android.media.tv.TvInputManager} for more system-driven actions that |
| you may want to handle in your TV input service.</p> |
| |
| <p>The {@link android.media.tv.TvInputService} creates a |
| {@link android.media.tv.TvInputService.Session} that implements {@link android.os.Handler.Callback} |
| to handle player state changes. With |
| {@link android.media.tv.TvInputService.Session#onSetSurface(android.view.Surface) onSetSurface()}, |
| the {@link android.media.tv.TvInputService.Session} sets the {@link android.view.Surface} with the |
| video content. See <a href="{@docRoot}training/tv/tif/ui.html#surface">Integrate Player with Surface</a> |
| for more information about working with {@link android.view.Surface} to render video.</p> |
| |
| <p>The {@link android.media.tv.TvInputService.Session} handles the |
| {@link android.media.tv.TvInputService.Session#onTune(android.net.Uri) onTune()} |
| event when the user selects a channel, and notifies the system TV app for changes in the content and |
| content metadata. These <code>notify()</code> methods are described in |
| <a href="{@docRoot}training/tv/tif/ui.html#control"> |
| Control Content</a> and <a href="{@docRoot}training/tv/tif/ui.html#track">Handle Track Selection</a> |
| further in this training.</p> |
| |
| <h3 id="setup">Define your setup activity</h3> |
| |
| <p>The system TV app works with the setup activity you define for your TV input. The |
| setup activity is required and must provide at least one channel record for the system database. The |
| system TV app invokes the setup activity when it cannot find a channel for the TV input. |
| <p>The setup activity describes to the system TV app the channels made available through the TV |
| input, as demonstrated in the next lesson, <a href="{@docRoot}training/tv/tif/channel.html">Creating |
| and Updating Channel Data</a>.</p> |