blob: a442481fd3670a7879f3e0e42fca65b8d7f95d49 [file] [log] [blame]
/*
* Copyright 2015 The Android Open Source Project
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package com.example.android.sampletvinput.simple;
import android.content.Context;
import android.content.res.AssetFileDescriptor;
import android.database.Cursor;
import android.media.MediaPlayer;
import android.media.tv.TvContract;
import android.media.tv.TvInputManager;
import android.media.tv.TvInputService;
import android.net.Uri;
import android.view.Surface;
import com.example.android.sampletvinput.R;
import java.io.IOException;
/**
* Simple TV input service which provides two sample channels.
* <p>
* NOTE: The purpose of this sample is to provide a really simple TV input sample to the developers
* so that they can understand the core APIs and when/how/where they should use them with ease.
* This means lots of features including EPG, subtitles, multi-audio, parental controls, and overlay
* view are missing here. So, to check the example codes for them, see {@link RichTvInputService}.
* </p>
*/
public class SimpleTvInputService extends TvInputService {
@Override
public Session onCreateSession(String inputId) {
return new SimpleSessionImpl(this);
}
/**
* Simple session implementation which plays local videos on the application's tune request.
*/
private class SimpleSessionImpl extends TvInputService.Session {
private static final int RESOURCE_1 =
R.raw.video_176x144_3gp_h263_300kbps_25fps_aac_stereo_128kbps_22050hz;
private static final int RESOURCE_2 =
R.raw.video_480x360_mp4_h264_1350kbps_30fps_aac_stereo_192kbps_44100hz;
private MediaPlayer mPlayer;
private float mVolume;
private Surface mSurface;
SimpleSessionImpl(Context context) {
super(context);
}
@Override
public void onRelease() {
mPlayer.release();
}
@Override
public boolean onSetSurface(Surface surface) {
if (mPlayer != null) {
mPlayer.setSurface(surface);
}
mSurface = surface;
return true;
}
@Override
public void onSetStreamVolume(float volume) {
if (mPlayer != null) {
mPlayer.setVolume(volume, volume);
}
mVolume = volume;
}
@Override
public boolean onTune(Uri channelUri) {
String[] projection = {TvContract.Channels.COLUMN_SERVICE_ID};
int resource = RESOURCE_1;
Cursor cursor = null;
try {
cursor = getContentResolver().query(channelUri, projection, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return false;
}
cursor.moveToNext();
resource = (cursor.getInt(0) == SimpleTvInputSetupActivity.CHANNEL_1_SERVICE_ID ?
RESOURCE_1 : RESOURCE_2);
} finally {
if (cursor != null) {
cursor.close();
}
}
return startPlayback(resource);
// NOTE: To display the program information (e.g. title) properly in the channel banner,
// The implementation needs to register the program metadata on TvProvider.
// For the example implementation, please see {@link RichTvInputService}.
}
@Override
public void onSetCaptionEnabled(boolean enabled) {
// The sample content does not have caption. Nothing to do in this sample input.
// NOTE: If the channel has caption, the implementation should turn on/off the caption
// based on {@code enabled}.
// For the example implementation for the case, please see {@link RichTvInputService}.
}
private boolean startPlayback(int resource) {
if (mPlayer == null) {
mPlayer = new MediaPlayer();
mPlayer.setOnInfoListener(new MediaPlayer.OnInfoListener() {
@Override
public boolean onInfo(MediaPlayer player, int what, int arg) {
// NOTE: TV input should notify the video playback state by using
// {@code notifyVideoAvailable()} and {@code notifyVideoUnavailable() so
// that the application can display back screen or spinner properly.
if (what == MediaPlayer.MEDIA_INFO_BUFFERING_START) {
notifyVideoUnavailable(
TvInputManager.VIDEO_UNAVAILABLE_REASON_BUFFERING);
return true;
} else if (what == MediaPlayer.MEDIA_INFO_BUFFERING_END
|| what == MediaPlayer.MEDIA_INFO_VIDEO_RENDERING_START) {
notifyVideoAvailable();
return true;
}
return false;
}
});
mPlayer.setSurface(mSurface);
mPlayer.setVolume(mVolume, mVolume);
} else {
mPlayer.reset();
}
mPlayer.setLooping(true);
AssetFileDescriptor afd = getResources().openRawResourceFd(resource);
if (afd == null) {
return false;
}
try {
mPlayer.setDataSource(afd.getFileDescriptor(), afd.getStartOffset(),
afd.getDeclaredLength());
mPlayer.prepare();
mPlayer.start();
} catch (IOException e) {
return false;
} finally {
try {
afd.close();
} catch (IOException e) {
// Do nothing.
}
}
// The sample content does not have rating information. Just allow the content here.
// NOTE: If the content might include problematic scenes, it should not be allowed.
// Also, if the content has rating information, the implementation should allow the
// content based on the current rating settings by using
// {@link android.media.tv.TvInputManager#isRatingBlocked()}.
// For the example implementation for the case, please see {@link RichTvInputService}.
notifyContentAllowed();
return true;
}
}
}