Home | History | Annotate | Download | only in simple
      1 /*
      2  * Copyright 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.sampletvinput.simple;
     18 
     19 import android.content.Context;
     20 import android.content.res.AssetFileDescriptor;
     21 import android.database.Cursor;
     22 import android.media.MediaPlayer;
     23 import android.media.tv.TvContract;
     24 import android.media.tv.TvInputManager;
     25 import android.media.tv.TvInputService;
     26 import android.net.Uri;
     27 import android.view.Surface;
     28 
     29 import com.example.android.sampletvinput.R;
     30 
     31 import java.io.IOException;
     32 
     33 /**
     34  * Simple TV input service which provides two sample channels.
     35  * <p>
     36  * NOTE: The purpose of this sample is to provide a really simple TV input sample to the developers
     37  * so that they can understand the core APIs and when/how/where they should use them with ease.
     38  * This means lots of features including EPG, subtitles, multi-audio, parental controls, and overlay
     39  * view are missing here. So, to check the example codes for them, see {@link RichTvInputService}.
     40  * </p>
     41  */
     42 public class SimpleTvInputService extends TvInputService {
     43     @Override
     44     public Session onCreateSession(String inputId) {
     45         return new SimpleSessionImpl(this);
     46     }
     47 
     48     /**
     49      * Simple session implementation which plays local videos on the application's tune request.
     50      */
     51     private class SimpleSessionImpl extends TvInputService.Session {
     52         private static final int RESOURCE_1 =
     53                 R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_22050hz;
     54         private static final int RESOURCE_2 =
     55                 R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
     56 
     57         private MediaPlayer mPlayer;
     58         private float mVolume;
     59         private Surface mSurface;
     60 
     61         SimpleSessionImpl(Context context) {
     62             super(context);
     63         }
     64 
     65         @Override
     66         public void onRelease() {
     67             mPlayer.release();
     68         }
     69 
     70         @Override
     71         public boolean onSetSurface(Surface surface) {
     72             if (mPlayer != null) {
     73                 mPlayer.setSurface(surface);
     74             }
     75             mSurface = surface;
     76             return true;
     77         }
     78 
     79         @Override
     80         public void onSetStreamVolume(float volume) {
     81             if (mPlayer != null) {
     82                 mPlayer.setVolume(volume, volume);
     83             }
     84             mVolume = volume;
     85         }
     86 
     87         @Override
     88         public boolean onTune(Uri channelUri) {
     89             String[] projection = {TvContract.Channels.COLUMN_SERVICE_ID};
     90             int resource = RESOURCE_1;
     91             Cursor cursor = null;
     92             try {
     93                 cursor = getContentResolver().query(channelUri, projection, null, null, null);
     94                 if (cursor == null || cursor.getCount() == 0) {
     95                     return false;
     96                 }
     97                 cursor.moveToNext();
     98                 resource = (cursor.getInt(0) == SimpleTvInputSetupActivity.CHANNEL_1_SERVICE_ID ?
     99                         RESOURCE_1 : RESOURCE_2);
    100             } finally {
    101                 if (cursor != null) {
    102                     cursor.close();
    103                 }
    104             }
    105             return startPlayback(resource);
    106             // NOTE: To display the program information (e.g. title) properly in the channel banner,
    107             // The implementation needs to register the program metadata on TvProvider.
    108             // For the example implementation, please see {@link RichTvInputService}.
    109         }
    110 
    111         @Override
    112         public void onSetCaptionEnabled(boolean enabled) {
    113             // The sample content does not have caption. Nothing to do in this sample input.
    114             // NOTE: If the channel has caption, the implementation should turn on/off the caption
    115             // based on {@code enabled}.
    116             // For the example implementation for the case, please see {@link RichTvInputService}.
    117         }
    118 
    119         private boolean startPlayback(int resource) {
    120             if (mPlayer == null) {
    121                 mPlayer = new MediaPlayer();
    122                 mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
    123                     @Override
    124                     public boolean onInfo(MediaPlayer player, int what, int arg) {
    125                         // NOTE: TV input should notify the video playback state by using
    126                         // {@code notifyVideoAvailable()} and {@code notifyVideoUnavailable() so
    127                         // that the application can display back screen or spinner properly.
    128                         if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
    129                             notifyVideoUnavailable(
    130                                     TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING);
    131                             return true;
    132                         } else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END
    133                                 || what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
    134                             notifyVideoAvailable();
    135                             return true;
    136                         }
    137                         return false;
    138                     }
    139                 });
    140                 mPlayer.setSurface(mSurface);
    141                 mPlayer.setVolume(mVolume, mVolume);
    142             } else {
    143                 mPlayer.reset();
    144             }
    145             mPlayer.setLooping(true);
    146             AssetFileDescriptor afd = getResources().openRawResourceFd(resource);
    147             if (afd == null) {
    148                 return false;
    149             }
    150             try {
    151                 mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
    152                         afd.getDeclaredLength());
    153                 mPlayer.prepare();
    154                 mPlayer.start();
    155             } catch (IOException e) {
    156                 return false;
    157             } finally {
    158                 try {
    159                     afd.close();
    160                 } catch (IOException e) {
    161                     // Do nothing.
    162                 }
    163             }
    164             // The sample content does not have rating information. Just allow the content here.
    165             // NOTE: If the content might include problematic scenes, it should not be allowed.
    166             // Also, if the content has rating information, the implementation should allow the
    167             // content based on the current rating settings by using
    168             // {@link android.media.tv.TvInputManager#isRatingBlocked()}.
    169             // For the example implementation for the case, please see {@link RichTvInputService}.
    170             notifyContentAllowed();
    171             return true;
    172         }
    173     }
    174 }
    175