diff --git a/library/src/main/java/com/google/android/media/tv/companionlibrary/EpgSyncJobService.java b/library/src/main/java/com/google/android/media/tv/companionlibrary/EpgSyncJobService.java index a05d1da3..429ff4e6 100644 --- a/library/src/main/java/com/google/android/media/tv/companionlibrary/EpgSyncJobService.java +++ b/library/src/main/java/com/google/android/media/tv/companionlibrary/EpgSyncJobService.java @@ -399,27 +399,30 @@ public Void doInBackground(Void... voids) { } List programs = getProgramsForChannel(channelUri, channelMap.valueAt(i), startMs, endMs); - if (DEBUG) { - Log.d(TAG, programs.toString()); - } - for (int index = 0; index < programs.size(); index++) { - if (programs.get(index).getChannelId() == -1) { - // Automatically set the channel id if not set - programs.set(index, - new Program.Builder(programs.get(index)) - .setChannelId(channelMap.valueAt(i).getId()) - .build()); + + if (programs != null) { + if (DEBUG) { + Log.d(TAG, programs.toString()); + } + for (int index = 0; index < programs.size(); index++) { + if (programs.get(index).getChannelId() == -1) { + // Automatically set the channel id if not set + programs.set(index, + new Program.Builder(programs.get(index)) + .setChannelId(channelMap.valueAt(i).getId()) + .build()); + } } - } - // Double check if the job is cancelled, so that this task can be finished faster - // after cancel() is called. - if (isCancelled()) { - broadcastError(ERROR_EPG_SYNC_CANCELED); - return null; + // Double check if the job is cancelled, so that this task can be finished faster + // after cancel() is called. + if (isCancelled()) { + broadcastError(ERROR_EPG_SYNC_CANCELED); + return null; + } + updatePrograms(channelUri, + getPrograms(channelMap.valueAt(i), programs, startMs, endMs)); } - updatePrograms(channelUri, - getPrograms(channelMap.valueAt(i), programs, startMs, endMs)); Intent intent = new Intent(ACTION_SYNC_STATUS_CHANGED); intent.putExtra(EpgSyncJobService.BUNDLE_KEY_INPUT_ID, mInputId); intent.putExtra(EpgSyncJobService.BUNDLE_KEY_CHANNELS_SCANNED, i); diff --git a/library/src/main/java/com/google/android/media/tv/companionlibrary/XmlTvParser.java b/library/src/main/java/com/google/android/media/tv/companionlibrary/XmlTvParser.java index 5446a243..aed08735 100644 --- a/library/src/main/java/com/google/android/media/tv/companionlibrary/XmlTvParser.java +++ b/library/src/main/java/com/google/android/media/tv/companionlibrary/XmlTvParser.java @@ -198,7 +198,10 @@ private static TvListing parseTvListings(XmlPullParser parser) } if (parser.getEventType() == XmlPullParser.START_TAG && TAG_PROGRAM.equalsIgnoreCase(parser.getName())) { - programs.add(parseProgram(parser)); + Program program = parseProgram(parser); + if (program != null) { + programs.add(program); + } } } return new TvListing(channels, programs); @@ -340,21 +343,29 @@ private static Program parseProgram(XmlPullParser parser) internalProviderData.setVideoType(videoType); internalProviderData.setVideoUrl(videoSrc); internalProviderData.setAds(ads); - return new Program.Builder() - .setChannelId(channelId.hashCode()) - .setTitle(title) - .setDescription(description) - .setPosterArtUri(icon.src) - .setCanonicalGenres(category.toArray(new String[category.size()])) - .setStartTimeUtcMillis(startTimeUtcMillis) - .setEndTimeUtcMillis(endTimeUtcMillis) - .setContentRatings(rating.toArray(new TvContentRating[rating.size()])) - // NOTE: {@code COLUMN_INTERNAL_PROVIDER_DATA} is a private field - // where TvInputService can store anything it wants. Here, we store - // video type and video URL so that TvInputService can play the - // video later with this field. - .setInternalProviderData(internalProviderData) - .build(); + try { + return new Program.Builder() + .setChannelId(channelId.hashCode()) + .setTitle(title) + .setDescription(description) + .setPosterArtUri(icon != null ? icon.src : null) + .setCanonicalGenres(category.toArray(new String[category.size()])) + .setStartTimeUtcMillis(startTimeUtcMillis) + .setEndTimeUtcMillis(endTimeUtcMillis) + .setContentRatings(rating.toArray(new TvContentRating[rating.size()])) + // NOTE: {@code COLUMN_INTERNAL_PROVIDER_DATA} is a private field + // where TvInputService can store anything it wants. Here, we store + // video type and video URL so that TvInputService can play the + // video later with this field. + .setInternalProviderData(internalProviderData) + .build(); + } catch (IllegalArgumentException e) { + // The program might not have valid start/end time. + // If that's the case, skip it... + Log.e(TAG, "Program not valid: Channel id: " + channelId.hashCode() + ", Title: " + title + + ", Start time: " + startTimeUtcMillis + ", End time: " + endTimeUtcMillis); + return (null); + } } private static XmlTvIcon parseIcon(XmlPullParser parser)