From c7f0e69e2893c4c935cc94edbe777bc26bd8a076 Mon Sep 17 00:00:00 2001 From: zaclimon Date: Sat, 17 Jun 2017 19:02:25 -0400 Subject: [PATCH 1/3] XmlTvParser: Null check the icon before adding to Program --- .../google/android/media/tv/companionlibrary/XmlTvParser.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) 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..cbe5e0ae 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 @@ -344,7 +344,7 @@ private static Program parseProgram(XmlPullParser parser) .setChannelId(channelId.hashCode()) .setTitle(title) .setDescription(description) - .setPosterArtUri(icon.src) + .setPosterArtUri(icon != null ? icon.src : null) .setCanonicalGenres(category.toArray(new String[category.size()])) .setStartTimeUtcMillis(startTimeUtcMillis) .setEndTimeUtcMillis(endTimeUtcMillis) From 697b3c0ced052840f992a89d989120b9e9b6798a Mon Sep 17 00:00:00 2001 From: zaclimon Date: Sat, 17 Jun 2017 19:07:48 -0400 Subject: [PATCH 2/3] EpgSyncJobService: Null check a Channel's available programs Some apps might not have the programs for a given channel. In that case, they might return a null on getProgramsForChannel(). Verify that it the list of programs is correct before continuing. --- .../companionlibrary/EpgSyncJobService.java | 39 ++++++++++--------- 1 file changed, 21 insertions(+), 18 deletions(-) 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); From 413b1ddb09a9bd40d4049d49076870675c4730a2 Mon Sep 17 00:00:00 2001 From: zaclimon Date: Sat, 1 Jul 2017 12:39:49 -0400 Subject: [PATCH 3/3] XmlTvParser: Skip a program if it's not valid when parsing Since it might not be possible to control the content coming from an XMLTV provider, if a program isn't valid after being parsed, simply skip it. Notify the user about the faulty program in case. --- .../tv/companionlibrary/XmlTvParser.java | 43 ++++++++++++------- 1 file changed, 27 insertions(+), 16 deletions(-) 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 cbe5e0ae..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 != 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(); + 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)