下面列出了怎么用android.media.tv.TvContract的API类实例代码及写法,或者点击链接到github查看源代码。
@Override
public void requestChannelBrowsable(Uri channelUri, int userId)
throws RemoteException {
final String callingPackageName = getCallingPackageName();
final long identity = Binder.clearCallingIdentity();
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "requestChannelBrowsable");
try {
Intent intent = new Intent(TvContract.ACTION_CHANNEL_BROWSABLE_REQUESTED);
List<ResolveInfo> list = getContext().getPackageManager()
.queryBroadcastReceivers(intent, 0);
if (list != null) {
for (ResolveInfo info : list) {
String receiverPackageName = info.activityInfo.packageName;
intent.putExtra(TvContract.EXTRA_CHANNEL_ID, ContentUris.parseId(
channelUri));
intent.putExtra(TvContract.EXTRA_PACKAGE_NAME, callingPackageName);
intent.setPackage(receiverPackageName);
getContext().sendBroadcastAsUser(intent, new UserHandle(resolvedUserId));
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
/**
* Returns the current list of programs on a given channel.
*
* @param resolver Application's ContentResolver.
* @param channelUri Channel's Uri.
* @return List of programs.
* @hide
*/
public static List<Program> getPrograms(ContentResolver resolver, Uri channelUri) {
if (channelUri == null) {
return null;
}
Uri uri = TvContract.buildProgramsUriForChannel(channelUri);
List<Program> programs = new ArrayList<>();
// TvProvider returns programs in chronological order by default.
Cursor cursor = null;
try {
cursor = resolver.query(uri, Program.PROJECTION, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return programs;
}
while (cursor.moveToNext()) {
programs.add(Program.fromCursor(cursor));
}
} catch (Exception e) {
Log.w(TAG, "Unable to get programs for " + channelUri, e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return programs;
}
@Override
public void onCreate() {
super.onCreate();
// Create background thread
mDbHandlerThread = new HandlerThread(getClass().getSimpleName());
mDbHandlerThread.start();
// Initialize the channel map and set observer for changes
mContentResolver = BaseTvInputService.this.getContentResolver();
updateChannelMap();
mChannelObserver =
new ContentObserver(new Handler(mDbHandlerThread.getLooper())) {
@Override
public void onChange(boolean selfChange) {
updateChannelMap();
}
};
mContentResolver.registerContentObserver(
TvContract.Channels.CONTENT_URI, true, mChannelObserver);
// Setup our BroadcastReceiver
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED);
intentFilter.addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
registerReceiver(mParentalControlsBroadcastReceiver, intentFilter);
}
@Test
public void testChannelsProgramSync() {
// Tests that programs and channels were correctly obtained from the EpgSyncJobService
Uri channelUri = TvContract.buildChannelUri(mChannelMap.keyAt(0));
Channel firstChannel = mChannelList.get(0);
assertEquals("Test Channel", firstChannel.getDisplayName());
assertNotNull(firstChannel.getInternalProviderData());
assertTrue(firstChannel.getInternalProviderData().isRepeatable());
mProgramList = mSampleJobService.getProgramsForChannel(channelUri, firstChannel, mStartMs,
mEndMs);
assertEquals(1, mProgramList.size());
channelUri = TvContract.buildChannelUri(mChannelMap.keyAt(1));
Channel secondChannel = mChannelList.get(1);
assertEquals("XML Test Channel", secondChannel.getDisplayName());
assertNotNull(secondChannel.getInternalProviderData());
assertTrue(secondChannel.getInternalProviderData().isRepeatable());
mProgramList = mSampleJobService.getProgramsForChannel(channelUri, secondChannel, mStartMs,
mEndMs);
assertEquals(5, mProgramList.size());
}
@Test
public void testRequestSync() throws InterruptedException {
// Tests that a sync can be requested and complete
LocalBroadcastManager.getInstance(getActivity()).registerReceiver(
mSyncStatusChangedReceiver,
new IntentFilter(EpgSyncJobService.ACTION_SYNC_STATUS_CHANGED));
mSyncStatusLatch = new CountDownLatch(2);
EpgSyncJobService.cancelAllSyncRequests(getActivity());
EpgSyncJobService.requestImmediateSync(getActivity(), TestTvInputService.INPUT_ID,
1000 * 60 * 60, // 1 hour sync period
new ComponentName(getActivity(), TestJobService.class));
mSyncStatusLatch.await();
// Sync is completed
List<Channel> channelList = ModelUtils.getChannels(getActivity().getContentResolver());
Log.d("TvContractUtils", channelList.toString());
assertEquals(2, channelList.size());
List<Program> programList = ModelUtils.getPrograms(getActivity().getContentResolver(),
TvContract.buildChannelUri(channelList.get(0).getId()));
assertEquals(5, programList.size());
}
public static List<Program> getPrograms(ContentResolver resolver, Uri channelUri) {
Uri uri = TvContract.buildProgramsUriForChannel(channelUri);
Cursor cursor = null;
List<Program> programs = new ArrayList<>();
try {
// TvProvider returns programs chronological order by default.
cursor = resolver.query(uri, null, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return programs;
}
while (cursor.moveToNext()) {
programs.add(Program.fromCursor(cursor));
}
} catch (Exception e) {
Log.w(TAG, "Unable to get programs for " + channelUri, e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return programs;
}
/**
* If you don't have access to an EPG or don't want to supply programs, you can simply
* add several instances of this generic program object.
*
* Note you will have to set the start and end times manually.
* @param channel The channel for which the program will be displayed
* @return A very generic program object
*/
public Program getGenericProgram(Channel channel) {
TvContentRating rating = RATING_PG;
return new Program.Builder()
.setTitle(channel.getName() + " Live")
.setProgramId(channel.getServiceId())
// .setEpisodeNumber(1)
// .setSeasonNumber(1)
// .setEpisodeTitle("Streaming")
.setDescription("Currently streaming")
.setLongDescription(channel.getName() + " is currently streaming live.")
.setCanonicalGenres(new String[]{TvContract.Programs.Genres.ENTERTAINMENT})
.setThumbnailUri(channel.getLogoUrl())
.setPosterArtUri(channel.getLogoUrl())
.setInternalProviderData(channel.getName())
.setContentRatings(new TvContentRating[] {rating})
.setVideoHeight(1080)
.setVideoWidth(1920)
.build();
}
private static void actuallyWriteData(final Context context, GoogleApiClient gapi) {
DriveSettingsManager sm = new DriveSettingsManager(context);
sm.setGoogleDriveSyncable(gapi, new DriveSettingsManager.GoogleDriveListener() {
@Override
public void onActionFinished(boolean cloudToLocal) {
Log.d(TAG, "Action finished " + cloudToLocal);
}
});
try {
sm.writeToGoogleDrive(DriveId.decodeFromString(sm.getString(R.string.sm_google_drive_id)),
ChannelDatabase.getInstance(context).toString());
GoogleDriveBroadcastReceiver.changeStatus(context,
GoogleDriveBroadcastReceiver.EVENT_UPLOAD_COMPLETE);
final String info = TvContract.buildInputId(TV_INPUT_SERVICE);
CumulusJobService.requestImmediateSync1(context, info, CumulusJobService.DEFAULT_IMMEDIATE_EPG_DURATION_MILLIS,
new ComponentName(context, CumulusJobService.class));
Log.d(TAG, "Data actually written");
// Toast.makeText(context, "Channels uploaded", Toast.LENGTH_SHORT).show();
} catch(Exception e) {
// Probably invalid drive id. No worries, just let someone know
Log.e(TAG, e.getMessage() + "");
Toast.makeText(context, R.string.invalid_file,
Toast.LENGTH_SHORT).show();
}
}
public String[] getGenres() {
if(getGenresString() == null) {
return new String[]{TvContract.Programs.Genres.MOVIES};
}
if(getGenresString().isEmpty()) {
return new String[]{TvContract.Programs.Genres.MOVIES};
}
else {
//Parse genres
CommaArray ca = new CommaArray(getGenresString());
Iterator<String> it = ca.getIterator();
ArrayList<String> arrayList = new ArrayList<>();
while(it.hasNext()) {
String i = it.next();
arrayList.add(i);
}
return arrayList.toArray(new String[arrayList.size()]);
}
}
@Before
public void insertChannels() {
Context context = getActivity();
ContentValues contentValues = new ContentValues();
contentValues.put(TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID, 1);
contentValues.put(TvContract.Channels.COLUMN_DISPLAY_NAME, "Hello");
contentValues.put(TvContract.Channels.COLUMN_DISPLAY_NUMBER, "123");
contentValues.put(TvContract.Channels.COLUMN_INPUT_ID,
ActivityUtils.TV_INPUT_SERVICE.flattenToString());
contentValues.put(TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA, MEDIA_URL);
Uri databaseUri = context.getContentResolver().insert(TvContract.Channels.CONTENT_URI,
contentValues);
Log.d(TAG, "Inserted in Uri " + databaseUri);
// Make sure we actually inserted something
ContentResolver contentResolver = context.getContentResolver();
Cursor cursor = contentResolver.query(TvContract.Channels.CONTENT_URI,
null, null, null, null);
assertNotNull(cursor);
assertEquals(1, cursor.getCount());
assertTrue(cursor.moveToNext());
assertEquals(1, cursor.getLong(cursor.getColumnIndex(
TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID)));
cursor.close();
}
/**
* Returns the current list of programs on a given channel.
*
* @param resolver Application's ContentResolver.
* @param channelUri Channel's Uri.
* @return List of programs.
* @hide
*/
public static List<Program> getPrograms(ContentResolver resolver, Uri channelUri) {
if (channelUri == null) {
return null;
}
Uri uri = TvContract.buildProgramsUriForChannel(channelUri);
List<Program> programs = new ArrayList<>();
// TvProvider returns programs in chronological order by default.
Cursor cursor = null;
try {
cursor = resolver.query(uri, Program.PROJECTION, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
return programs;
}
while (cursor.moveToNext()) {
programs.add(Program.fromCursor(cursor));
}
} catch (Exception e) {
Log.w(TAG, "Unable to get programs for " + channelUri, e);
} finally {
if (cursor != null) {
cursor.close();
}
}
return programs;
}
@Override
public void onCreate() {
super.onCreate();
// Create background thread
mDbHandlerThread = new HandlerThread(getClass().getSimpleName());
mDbHandlerThread.start();
// Initialize the channel map and set observer for changes
mContentResolver = BaseTvInputService.this.getContentResolver();
updateChannelMap();
mChannelObserver =
new ContentObserver(new Handler(mDbHandlerThread.getLooper())) {
@Override
public void onChange(boolean selfChange) {
updateChannelMap();
}
};
mContentResolver.registerContentObserver(
TvContract.Channels.CONTENT_URI, true, mChannelObserver);
// Setup our BroadcastReceiver
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(TvInputManager.ACTION_BLOCKED_RATINGS_CHANGED);
intentFilter.addAction(TvInputManager.ACTION_PARENTAL_CONTROLS_ENABLED_CHANGED);
registerReceiver(mParentalControlsBroadcastReceiver, intentFilter);
}
@Before
public void setUp() throws Exception {
super.setUp();
injectInstrumentation(InstrumentationRegistry.getInstrumentation());
getActivity();
// Delete all channels
getActivity().getContentResolver().delete(TvContract.buildChannelsUriForInput(mInputId),
null, null);
mSampleJobService = new TestJobService();
mSampleJobService.mContext = getActivity();
mChannelList = mSampleJobService.getChannels();
ModelUtils.updateChannels(getActivity(), mInputId, mChannelList, null);
mChannelMap = ModelUtils.buildChannelMap(getActivity().getContentResolver(), mInputId);
assertEquals(2, mChannelMap.size());
}
@Test
public void testOriginalChannelsProgramSync() throws EpgSyncException {
// Tests that programs and channels were correctly obtained from the EpgSyncJobService
Uri channelUri = TvContract.buildChannelUri(mChannelMap.keyAt(0));
Channel firstChannel = mChannelList.get(0);
assertEquals("Test Channel", firstChannel.getDisplayName());
assertNotNull(firstChannel.getInternalProviderData());
assertTrue(firstChannel.getInternalProviderData().isRepeatable());
mProgramList =
mSampleJobService.getOriginalProgramsForChannel(
channelUri, firstChannel, mStartMs, mEndMs);
assertEquals(1, mProgramList.size());
channelUri = TvContract.buildChannelUri(mChannelMap.keyAt(1));
Channel secondChannel = mChannelList.get(1);
assertEquals("XML Test Channel", secondChannel.getDisplayName());
assertNotNull(secondChannel.getInternalProviderData());
assertTrue(secondChannel.getInternalProviderData().isRepeatable());
mProgramList =
mSampleJobService.getOriginalProgramsForChannel(
channelUri, secondChannel, mStartMs, mEndMs);
assertEquals(5, mProgramList.size());
}
@Test
public void testRequestSync() throws InterruptedException {
// Tests that a sync can be requested and complete
LocalBroadcastManager.getInstance(getActivity())
.registerReceiver(
mSyncStatusChangedReceiver,
new IntentFilter(EpgSyncJobService.ACTION_SYNC_STATUS_CHANGED));
mSyncStatusLatch = new CountDownLatch(2);
EpgSyncJobService.cancelAllSyncRequests(getActivity());
EpgSyncJobService.requestImmediateSync(
getActivity(),
TestTvInputService.INPUT_ID,
1000 * 60 * 60, // 1 hour sync period
new ComponentName(getActivity(), TestJobService.class));
mSyncStatusLatch.await();
// Sync is completed
List<Channel> channelList = ModelUtils.getChannels(getActivity().getContentResolver());
Log.d("TvContractUtils", channelList.toString());
assertEquals(2, channelList.size());
List<Program> programList =
ModelUtils.getPrograms(
getActivity().getContentResolver(),
TvContract.buildChannelUri(channelList.get(0).getId()));
assertEquals(5, programList.size());
}
@Override
public void tune(IBinder sessionToken, final Uri channelUri, Bundle params, int userId) {
final int callingUid = Binder.getCallingUid();
final int resolvedUserId = resolveCallingUserId(Binder.getCallingPid(), callingUid,
userId, "tune");
final long identity = Binder.clearCallingIdentity();
try {
synchronized (mLock) {
try {
getSessionLocked(sessionToken, callingUid, resolvedUserId).tune(
channelUri, params);
if (TvContract.isChannelUriForPassthroughInput(channelUri)) {
// Do not log the watch history for passthrough inputs.
return;
}
UserState userState = getOrCreateUserStateLocked(resolvedUserId);
SessionState sessionState = userState.sessionStateMap.get(sessionToken);
if (sessionState.isRecordingSession) {
return;
}
// Log the start of watch.
SomeArgs args = SomeArgs.obtain();
args.arg1 = sessionState.componentName.getPackageName();
args.arg2 = System.currentTimeMillis();
args.arg3 = ContentUris.parseId(channelUri);
args.arg4 = params;
args.arg5 = sessionToken;
mWatchLogHandler.obtainMessage(WatchLogHandler.MSG_LOG_WATCH_START, args)
.sendToTarget();
} catch (RemoteException | SessionNotFoundException e) {
Slog.e(TAG, "error in tune", e);
}
}
} finally {
Binder.restoreCallingIdentity(identity);
}
}
@Override
protected void onPostExecute(Long channelId) {
Intent intent = new Intent(TvContract.ACTION_REQUEST_CHANNEL_BROWSABLE);
intent.putExtra(TvContractCompat.EXTRA_CHANNEL_ID, channelId);
try {
startActivityForResult(intent, ADD_CHANNEL_REQUEST);
} catch (ActivityNotFoundException e) {
Log.e(TAG, "could not start add channel approval UI", e);
}
}
private void loadChannels() {
// Iterate "cursor" through all the channels owned by this app.
try (Cursor cursor = mContext.getContentResolver().query(TvContract.Channels.CONTENT_URI,
SampleTvProvider.CHANNELS_MAP_PROJECTION, null, null, null)) {
if (cursor != null) {
while (cursor.moveToNext()) {
if (!cursor.isNull(SampleTvProvider
.CHANNELS_COLUMN_INTERNAL_PROVIDER_ID_INDEX)) {
long channelId = cursor.getLong(SampleTvProvider.CHANNELS_COLUMN_ID_INDEX);
if (cursor.getInt(SampleTvProvider.CHANNELS_COLUMN_BROWSABLE_INDEX) == 0) {
// This channel is not browsable as it was removed by the user from the
// launcher. Use this as an indication that the channel is not desired
// by the user and could relay this information to the server to act
// accordingly. Note that no intent is received when a channel is
// removed from the launcher and it's the app's responsibility to
// examine the browsable flag and act accordingly.
SampleTvProvider.deleteChannel(mContext, channelId);
} else {
// Found a row that contains a non-null provider id.
String id = cursor.getString(SampleTvProvider
.CHANNELS_COLUMN_INTERNAL_PROVIDER_ID_INDEX);
mChannelPlaylistIds.add(new ChannelPlaylistId(id, channelId));
}
}
}
}
}
}
/**
* Builds a map of available channels.
*
* @param resolver Application's ContentResolver.
* @param inputId The ID of the TV input service that provides this TV channel.
* @return LongSparseArray mapping each channel's {@link Channels#_ID} to the Channel object.
* @hide
*/
public static LongSparseArray<Channel> buildChannelMap(
@NonNull ContentResolver resolver, @NonNull String inputId) {
Uri uri = TvContract.buildChannelsUriForInput(inputId);
LongSparseArray<Channel> channelMap = new LongSparseArray<>();
Cursor cursor = null;
try {
cursor = resolver.query(uri, Channel.PROJECTION, null, null, null);
if (cursor == null || cursor.getCount() == 0) {
if (DEBUG) {
Log.d(TAG, "Cursor is null or found no results");
}
return null;
}
while (cursor.moveToNext()) {
Channel nextChannel = Channel.fromCursor(cursor);
channelMap.put(nextChannel.getId(), nextChannel);
}
} catch (Exception e) {
Log.d(TAG, "Content provider query: " + Arrays.toString(e.getStackTrace()));
return null;
} finally {
if (cursor != null) {
cursor.close();
}
}
return channelMap;
}
private static String[] getProjection() {
String[] baseColumns =
new String[] {
TvContract.Channels._ID,
TvContract.Channels.COLUMN_DESCRIPTION,
TvContract.Channels.COLUMN_DISPLAY_NAME,
TvContract.Channels.COLUMN_DISPLAY_NUMBER,
TvContract.Channels.COLUMN_INPUT_ID,
TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA,
TvContract.Channels.COLUMN_NETWORK_AFFILIATION,
TvContract.Channels.COLUMN_ORIGINAL_NETWORK_ID,
TvContract.Channels.COLUMN_PACKAGE_NAME,
TvContract.Channels.COLUMN_SEARCHABLE,
TvContract.Channels.COLUMN_SERVICE_ID,
TvContract.Channels.COLUMN_SERVICE_TYPE,
TvContract.Channels.COLUMN_TRANSPORT_STREAM_ID,
TvContract.Channels.COLUMN_TYPE,
TvContract.Channels.COLUMN_VIDEO_FORMAT,
};
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
String[] marshmallowColumns =
new String[] {
TvContract.Channels.COLUMN_APP_LINK_COLOR,
TvContract.Channels.COLUMN_APP_LINK_ICON_URI,
TvContract.Channels.COLUMN_APP_LINK_INTENT_URI,
TvContract.Channels.COLUMN_APP_LINK_POSTER_ART_URI,
TvContract.Channels.COLUMN_APP_LINK_TEXT
};
return CollectionUtils.concatAll(baseColumns, marshmallowColumns);
}
return baseColumns;
}
private void updateChannelMap() {
ComponentName component =
new ComponentName(
BaseTvInputService.this.getPackageName(),
BaseTvInputService.this.getClass().getName());
String inputId = TvContract.buildInputId(component);
mChannelMap = ModelUtils.buildChannelMap(mContentResolver, inputId);
}
/**
* Notify the TV app that the recording has ended.
*
* @param recordedProgram The program that was recorded and should be saved.
*/
public void notifyRecordingStopped(final RecordedProgram recordedProgram) {
mDbHandler.post(
new Runnable() {
@Override
public void run() {
Uri recordedProgramUri =
mContext.getContentResolver()
.insert(
TvContract.RecordedPrograms.CONTENT_URI,
recordedProgram.toContentValues());
notifyRecordingStopped(recordedProgramUri);
}
});
}
@Override
public void beforeActivityLaunched() {
super.beforeActivityLaunched();
getActivity();
// Delete all channels
getActivity().getContentResolver().delete(TvContract.buildChannelsUriForInput(mInputId),
null, null);
mSampleJobService = new TestJobService();
mSampleJobService.mContext = getActivity();
mChannelList = mSampleJobService.getChannels();
ModelUtils.updateChannels(getActivity(), mInputId, mChannelList, null);
mChannelMap = ModelUtils.buildChannelMap(getActivity().getContentResolver(), mInputId);
assertEquals(2, mChannelMap.size());
}
@Override
public void afterActivityFinished() {
super.afterActivityFinished();
LocalBroadcastManager.getInstance(getActivity())
.unregisterReceiver(mSyncStatusChangedReceiver);
// Delete these programs
getActivity().getContentResolver().delete(TvContract.buildChannelsUriForInput(mInputId),
null, null);
}
@After
public void afterActivityFinished() {
super.afterActivityFinished();
// Delete content
getActivity().getContentResolver().delete(TvContract.buildChannelsUriForInput(
TestTvInputService.INPUT_ID), null, null);
LocalBroadcastManager.getInstance(getActivity())
.unregisterReceiver(mSyncStatusChangedReceiver);
}
@RequiresApi(api = Build.VERSION_CODES.M) @Test
public void testFullyPopulatedProgram() {
// Tests cloning and database I/O of a program with every value being defined.
InternalProviderData internalProviderData = new InternalProviderData();
internalProviderData.setVideoType(TvContractUtils.SOURCE_TYPE_HLS);
internalProviderData.setVideoUrl("http://example.com/stream.m3u8");
Program fullyPopulatedProgram = new Program.Builder()
.setSearchable(false)
.setChannelId(3)
.setThumbnailUri("http://example.com/thumbnail.png")
.setInternalProviderData(internalProviderData)
.setAudioLanguages("en-us")
.setBroadcastGenres(new String[] {"Music", "Family"})
.setCanonicalGenres(new String[] {TvContract.Programs.Genres.MOVIES})
.setContentRatings(new TvContentRating[] {TvContentRating.UNRATED})
.setDescription("This is a sample program")
.setEndTimeUtcMillis(1000)
.setEpisodeNumber("Pilot", 0)
.setEpisodeTitle("Hello World")
.setLongDescription("This is a longer description than the previous description")
.setPosterArtUri("http://example.com/poster.png")
.setRecordingProhibited(false)
.setSeasonNumber("The Final Season", 7)
.setSeasonTitle("The Final Season")
.setStartTimeUtcMillis(0)
.setTitle("Google")
.setVideoHeight(1080)
.setVideoWidth(1920)
.build();
ContentValues contentValues = fullyPopulatedProgram.toContentValues();
compareProgram(fullyPopulatedProgram, Program.fromCursor(getProgramCursor(contentValues)));
Program clonedFullyPopulatedProgram = new Program.Builder(fullyPopulatedProgram).build();
compareProgram(fullyPopulatedProgram, clonedFullyPopulatedProgram);
}
@Override
public void afterActivityFinished() {
super.afterActivityFinished();
LocalBroadcastManager.getInstance(getActivity())
.unregisterReceiver(mSyncStatusChangedReceiver);
// Delete these programs
getActivity().getContentResolver().delete(TvContract.buildChannelsUriForInput(
TestTvInputService.INPUT_ID), null, null);
}
@Test
public void testEpgSyncTask_GetPrograms() {
// For repeating channels, test that the program list will continually repeat for the
// desired length of time
Uri channelUri = TvContract.buildChannelUri(mChannelMap.keyAt(0));
Channel firstChannel = mChannelList.get(0);
TestJobService.TestEpgSyncTask epgSyncTask = mSampleJobService.getDefaultEpgSyncTask();
mProgramList = mSampleJobService.getProgramsForChannel(channelUri, firstChannel, mStartMs,
mEndMs);
List<Program> continuousProgramsList = epgSyncTask.getPrograms(
firstChannel, mProgramList, mStartMs, mEndMs);
// There are 336 hours in a two week period, and each program is 15m long
assertEquals(336 * 60 / 15, continuousProgramsList.size());
}
@Test
public void testProgramParsing() throws XmlTvParser.XmlTvParseException {
String testXmlFile = "xmltv.xml";
String APRIL_FOOLS_SOURCE = "https://commondatastorage.googleapis.com/android-tv/Sample%2" +
"0videos/April%20Fool's%202013/Introducing%20Google%20Fiber%20to%20the%20Pole.mp4";
String ELEPHANTS_DREAM_POSTER_ART = "https://storage.googleapis.com/gtv-videos-bucket/sam" +
"ple/images_480x270/ElephantsDream.jpg";
InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(testXmlFile);
XmlTvParser.TvListing listings = XmlTvParser.parse(inputStream);
assertEquals(9, listings.getAllPrograms().size());
assertEquals("Introducing Gmail Blue", listings.getAllPrograms().get(0).getTitle());
assertEquals("Introducing Gmail Blue",
listings.getPrograms(listings.getChannels().get(0)).get(0).getTitle());
assertEquals(TvContract.Programs.Genres.TECH_SCIENCE,
listings.getAllPrograms().get(1).getCanonicalGenres()[1]);
assertEquals(listings.getAllPrograms().get(2).getChannelId(),
listings.getChannels().get(0).getOriginalNetworkId());
assertNotNull(listings.getAllPrograms().get(3).getInternalProviderData());
assertEquals(APRIL_FOOLS_SOURCE,
listings.getAllPrograms().get(3).getInternalProviderData().getVideoUrl());
assertEquals("Introducing Google Nose", listings.getAllPrograms().get(4).getDescription());
assertEquals(ELEPHANTS_DREAM_POSTER_ART,
listings.getAllPrograms().get(5).getPosterArtUri());
InternalProviderData internalProviderData = new InternalProviderData();
internalProviderData.setVideoType(TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE);
internalProviderData.setVideoUrl(APRIL_FOOLS_SOURCE);
assertEquals(internalProviderData,
listings.getAllPrograms().get(3).getInternalProviderData());
}
@RequiresApi(api = Build.VERSION_CODES.M) @Test
public void testFullyPopulatedProgram() {
// Tests cloning and database I/O of a program with every value being defined.
InternalProviderData internalProviderData = new InternalProviderData();
internalProviderData.setVideoType(TvContractUtils.SOURCE_TYPE_HLS);
internalProviderData.setVideoUrl("http://example.com/stream.m3u8");
Program fullyPopulatedProgram = new Program.Builder()
.setSearchable(false)
.setChannelId(3)
.setThumbnailUri("http://example.com/thumbnail.png")
.setInternalProviderData(internalProviderData)
.setAudioLanguages("en-us")
.setBroadcastGenres(new String[] {"Music", "Family"})
.setCanonicalGenres(new String[] {TvContract.Programs.Genres.MOVIES})
.setContentRatings(new TvContentRating[] {TvContentRating.UNRATED})
.setDescription("This is a sample program")
.setEndTimeUtcMillis(1000)
.setEpisodeNumber("Pilot", 0)
.setEpisodeTitle("Hello World")
.setLongDescription("This is a longer description than the previous description")
.setPosterArtUri("http://example.com/poster.png")
.setRecordingProhibited(false)
.setSeasonNumber("The Final Season", 7)
.setSeasonTitle("The Final Season")
.setStartTimeUtcMillis(0)
.setTitle("Google")
.setVideoHeight(1080)
.setVideoWidth(1920)
.build();
ContentValues contentValues = fullyPopulatedProgram.toContentValues();
compareProgram(fullyPopulatedProgram, Program.fromCursor(getProgramCursor(contentValues)));
Program clonedFullyPopulatedProgram = new Program.Builder(fullyPopulatedProgram).build();
compareProgram(fullyPopulatedProgram, clonedFullyPopulatedProgram);
}