com.google.android.media.tv.companionlibrary.model.InternalProviderData Java Examples

The following examples show how to use com.google.android.media.tv.companionlibrary.model.InternalProviderData. You can vote up the ones you like or vote down the ones you don't like, and go to the original project or source file by following the links above each example. You may check out the related API usage on the sidebar.
Example #1
Source File: EpgSyncWithAdsJobService.java    From androidtv-sample-inputs with Apache License 2.0 6 votes vote down vote up
/**
 * Shift advertisement time to match program playback time. For channels with repeated program,
 * the time for current program may vary from what it was defined previously.
 *
 * @param oldProgramStartTimeMs Outdated program start time.
 * @param newProgramStartTimeMs Updated program start time.
 */
private static void shiftAdsTimeWithProgram(
        InternalProviderData internalProviderData,
        long oldProgramStartTimeMs,
        long newProgramStartTimeMs) {
    if (internalProviderData == null) {
        return;
    }
    long timeShift = newProgramStartTimeMs - oldProgramStartTimeMs;
    List<Advertisement> oldAds = internalProviderData.getAds();
    List<Advertisement> newAds = new ArrayList<>();
    for (Advertisement oldAd : oldAds) {
        newAds.add(
                new Advertisement.Builder(oldAd)
                        .setStartTimeUtcMillis(oldAd.getStartTimeUtcMillis() + timeShift)
                        .setStopTimeUtcMillis(oldAd.getStopTimeUtcMillis() + timeShift)
                        .build());
    }
    internalProviderData.setAds(newAds);
}
 
Example #2
Source File: EpgSyncWithAdsJobService.java    From xipl with Apache License 2.0 6 votes vote down vote up
/**
 * Shift advertisement time to match program playback time. For channels with repeated program,
 * the time for current program may vary from what it was defined previously.
 *
 * @param oldProgramStartTimeMs Outdated program start time.
 * @param newProgramStartTimeMs Updated program start time.
 */
private static void shiftAdsTimeWithProgram(
        InternalProviderData internalProviderData,
        long oldProgramStartTimeMs,
        long newProgramStartTimeMs) {
    if (internalProviderData == null) {
        return;
    }
    long timeShift = newProgramStartTimeMs - oldProgramStartTimeMs;
    List<Advertisement> oldAds = internalProviderData.getAds();
    List<Advertisement> newAds = new ArrayList<>();
    for (Advertisement oldAd : oldAds) {
        newAds.add(
                new Advertisement.Builder(oldAd)
                        .setStartTimeUtcMillis(oldAd.getStartTimeUtcMillis() + timeShift)
                        .setStopTimeUtcMillis(oldAd.getStopTimeUtcMillis() + timeShift)
                        .build());
    }
    internalProviderData.setAds(newAds);
}
 
Example #3
Source File: EpgSyncJobService.java    From xipl with Apache License 2.0 6 votes vote down vote up
/**
 * Shift advertisement time to match program playback time. For channels with repeated program,
 * the time for current program may vary from what it was defined previously.
 *
 * @param oldProgramStartTimeMs Outdated program start time.
 * @param newProgramStartTimeMs Updated program start time.
 */
private void shiftAdsTimeWithProgram(InternalProviderData internalProviderData,
                                     long oldProgramStartTimeMs, long newProgramStartTimeMs) {
    if (internalProviderData == null) {
        return;
    }
    long timeShift = newProgramStartTimeMs - oldProgramStartTimeMs;
    List<Advertisement> oldAds = internalProviderData.getAds();
    List<Advertisement> newAds = new ArrayList<>();
    for (Advertisement oldAd : oldAds) {
        newAds.add(new Advertisement.Builder(oldAd)
                .setStartTimeUtcMillis(oldAd.getStartTimeUtcMillis() + timeShift)
                .setStopTimeUtcMillis(oldAd.getStopTimeUtcMillis() + timeShift)
                .build());
    }
    internalProviderData.setAds(newAds);
}
 
Example #4
Source File: RichTvInputService.java    From androidtv-sample-inputs with Apache License 2.0 6 votes vote down vote up
@Override
public void onStopRecording(Program programToRecord) {
    if (DEBUG) {
        Log.d(TAG, "onStopRecording");
    }
    // In this sample app, since all of the content is VOD, the video URL is stored.
    // If the video was live, the start and stop times should be noted using
    // RecordedProgram.Builder.setStartTimeUtcMillis and .setEndTimeUtcMillis.
    // The recordingstart time will be saved in the InternalProviderData.
    // Additionally, the stream should be recorded and saved as
    // a new file.
    long currentTime = System.currentTimeMillis();
    InternalProviderData internalProviderData = programToRecord.getInternalProviderData();
    internalProviderData.setRecordingStartTime(mStartTimeMs);
    RecordedProgram recordedProgram = new RecordedProgram.Builder(programToRecord)
                .setInputId(mInputId)
                .setRecordingDataUri(
                        programToRecord.getInternalProviderData().getVideoUrl())
                .setRecordingDurationMillis(currentTime - mStartTimeMs)
                .setInternalProviderData(internalProviderData)
                .build();
    notifyRecordingStopped(recordedProgram);
}
 
Example #5
Source File: XmlTvParserTest.java    From androidtv-sample-inputs with Apache License 2.0 5 votes vote down vote up
@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());
}
 
Example #6
Source File: SampleJobService.java    From androidtv-sample-inputs with Apache License 2.0 5 votes vote down vote up
@Override
public List<Channel> getChannels() {
    // Add channels through an XMLTV file
    XmlTvParser.TvListing listings = RichFeedUtil.getRichTvListings(this);
    List<Channel> channelList = new ArrayList<>(listings.getChannels());

    // Build advertisement list for the channel.
    Advertisement channelAd = new Advertisement.Builder()
            .setType(Advertisement.TYPE_VAST)
            .setRequestUrl(TEST_AD_REQUEST_URL)
            .build();
    List<Advertisement> channelAdList = new ArrayList<>();
    channelAdList.add(channelAd);

    // Add a channel programmatically
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setRepeatable(true);
    internalProviderData.setAds(channelAdList);
    Channel channelTears = new Channel.Builder()
            .setDisplayName(MPEG_DASH_CHANNEL_NAME)
            .setDisplayNumber(MPEG_DASH_CHANNEL_NUMBER)
            .setChannelLogo(MPEG_DASH_CHANNEL_LOGO)
            .setOriginalNetworkId(MPEG_DASH_ORIGINAL_NETWORK_ID)
            .setInternalProviderData(internalProviderData)
            .build();
    channelList.add(channelTears);
    return channelList;
}
 
Example #7
Source File: CumulusJobService.java    From CumulusTV with MIT License 5 votes vote down vote up
@Override
    public List<Channel> getChannels() {
        // Build advertisement list for the channel.
        Advertisement channelAd = new Advertisement.Builder()
                .setType(Advertisement.TYPE_VAST)
                .setRequestUrl(TEST_AD_REQUEST_URL)
                .build();
        List<Advertisement> channelAdList = new ArrayList<>();
        channelAdList.add(channelAd);

        InternalProviderData ipd = new InternalProviderData();
//        ipd.setAds(channelAdList);
        ipd.setRepeatable(true);
        ipd.setVideoType(TvContractUtils.SOURCE_TYPE_HLS);

        try {
            List<Channel> channels = ChannelDatabase.getInstance(this).getChannels(ipd);
            // Add app linking
            for (int i = 0; i < channels.size(); i++) {
                JsonChannel jsonChannel =
                        ChannelDatabase.getInstance(this).findChannelByMediaUrl(
                                channels.get(i).getInternalProviderData().getVideoUrl());
                Channel channel = new Channel.Builder(channels.get(i))
                    .setAppLinkText(getString(R.string.quick_settings))
                    .setAppLinkIconUri("https://github.com/Fleker/CumulusTV/blob/master/app/src/m" +
                        "ain/res/drawable-xhdpi/ic_play_action_normal.png?raw=true")
                    .setAppLinkPosterArtUri(channels.get(i).getChannelLogo())
                    .setAppLinkIntent(PlaybackQuickSettingsActivity.getIntent(this, jsonChannel))
                    .build();
                Log.d(TAG, "Adding channel " + channel.getDisplayName());
                channels.set(i, channel);
            }
            Log.d(TAG, "Returning with " + channels.size() + " channels");
            return channels;
        } catch (JSONException e) {
            e.printStackTrace();
        }
        Log.w(TAG, "No channels found");
        return null;
    }
 
Example #8
Source File: TestJobService.java    From androidtv-sample-inputs with Apache License 2.0 5 votes vote down vote up
@Override
public List<Channel> getChannels() {
    Assert.assertNotNull("Please set the static mContext before running", mContext);
    // Wrap our list in an ArrayList so we will be able to make modifications if necessary
    Assert.assertNotNull("Set TestJobService.mContext.", mContext);
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setRepeatable(true);
    ArrayList<Channel> testChannels = new ArrayList<>();
    testChannels.add(
            new Channel.Builder()
                    .setOriginalNetworkId(0)
                    .setDisplayName("Test Channel")
                    .setDisplayNumber("1")
                    .setInternalProviderData(internalProviderData)
                    .build());

    // Add an XML parsed channel
    Uri xmlUri =
            Uri.parse("android.resource://" + mContext.getPackageName() + "/" + R.raw.xmltv)
                    .normalizeScheme();
    try {
        InputStream inputStream = mContext.getContentResolver().openInputStream(xmlUri);
        Assert.assertNotNull(inputStream);
        testChannels.addAll(XmlTvParser.parse(inputStream).getChannels());
    } catch (FileNotFoundException | XmlTvParser.XmlTvParseException e) {
        throw new RuntimeException(
                "Exception found of type "
                        + e.getClass().getCanonicalName()
                        + ": "
                        + e.getMessage());
    }

    return testChannels;
}
 
Example #9
Source File: XmlTvAdvertisementTest.java    From androidtv-sample-inputs with Apache License 2.0 5 votes vote down vote up
@Test
public void testAdvertisementParsing() throws XmlTvParser.XmlTvParseException, ParseException {
    long epochStartTime = 0;
    String requestUrl1 = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480" +
            "&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s" +
            "&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1" +
            "&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=";
    String requestUrl2 = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480" +
            "&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s" +
            "&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1" +
            "&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirectlinear&correlator=";
    String testXmlFile = "xmltv.xml";
    InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(testXmlFile);
    XmlTvParser.TvListing listings = XmlTvParser.parse(inputStream);
    // Channel 1 should have one VAST advertisement.
    Channel adChannel = listings.getChannels().get(1);
    assertNotNull(adChannel.getInternalProviderData());
    List<Advertisement> adChannelAds = adChannel.getInternalProviderData().getAds();
    assertEquals(1, adChannelAds.size());
    assertEquals(epochStartTime, adChannelAds.get(0).getStartTimeUtcMillis());
    assertEquals(epochStartTime, adChannelAds.get(0).getStopTimeUtcMillis());
    assertEquals(Advertisement.TYPE_VAST, adChannelAds.get(0).getType());
    // Channel 0 should not have any advertisement.
    Channel noAdChannel = listings.getChannels().get(0);
    assertNotNull(noAdChannel.getInternalProviderData());
    List<Advertisement> noAdChannelAds = noAdChannel.getInternalProviderData().getAds();
    assertEquals(0, noAdChannelAds.size());
    // Program 7 should have 2 advertisements with different request tags.
    Program adProgram = listings.getAllPrograms().get(7);
    assertNotNull(adProgram.getInternalProviderData());
    InternalProviderData adProgramData = adProgram.getInternalProviderData();
    List<Advertisement> adProgramAds = adProgramData.getAds();
    assertEquals(2, adProgramAds.size());
    assertEquals(requestUrl1, adProgramAds.get(0).getRequestUrl());
    assertEquals(requestUrl2, adProgramAds.get(1).getRequestUrl());
}
 
Example #10
Source File: JsonChannel.java    From CumulusTV with MIT License 5 votes vote down vote up
public Channel toChannel(InternalProviderData providerData) {
    providerData.setVideoUrl(getMediaUrl());
    // TODO Add app linking
    return new Channel.Builder()
            .setDisplayName(getName())
            .setDisplayNumber(getNumber())
            .setChannelLogo(getLogo())
            .setInternalProviderData(providerData)
            .setOriginalNetworkId(getMediaUrl().hashCode())
            .build();
}
 
Example #11
Source File: JsonChannel.java    From CumulusTV with MIT License 5 votes vote down vote up
public Channel toChannel() {
    InternalProviderData ipd = new InternalProviderData();
    ipd.setVideoUrl(getMediaUrl());
    ipd.setVideoType(TvContractUtils.SOURCE_TYPE_HLS);
    return new Channel.Builder()
            .setDisplayName(getName())
            .setDisplayNumber(getNumber())
            .setChannelLogo(getLogo())
            .setInternalProviderData(ipd)
            .setOriginalNetworkId(getMediaUrl().hashCode())
            .build();
}
 
Example #12
Source File: ChannelDatabase.java    From CumulusTV with MIT License 5 votes vote down vote up
/**
 * Creates a link between the database Uris and the JSONChannels
 * @param context The application's context for the {@link ContentResolver}.
 */
protected void initializeHashMap(final Context context) {
    mWorker = new Thread(new Runnable() {
        @Override
        public void run() {
            ContentResolver contentResolver = context.getContentResolver();
            Uri channelsUri = TvContract.buildChannelsUriForInput(
                    ActivityUtils.TV_INPUT_SERVICE.flattenToString());
            Cursor cursor = contentResolver.query(channelsUri, null, null, null, null);
            mDatabaseHashMap = new HashMap<>();
            Log.d(TAG, "Initialize CD HashMap");
            if (cursor != null) {
                while (cursor.moveToNext()) {
                    try {
                        InternalProviderData ipd = new InternalProviderData(
                                cursor.getBlob(cursor.getColumnIndex(
                                TvContract.Channels.COLUMN_INTERNAL_PROVIDER_DATA)));
                        String mediaUrl = ipd.getVideoUrl();
                        long rowId = cursor.getLong(cursor.getColumnIndex(TvContract.Channels._ID));
                        Log.d(TAG, "Try to match " + mediaUrl + " " + rowId);
                        for (JsonChannel jsonChannel : getJsonChannels()) {
                            if (jsonChannel.getMediaUrl().equals(mediaUrl)) {
                                mDatabaseHashMap.put(jsonChannel.getMediaUrl(), rowId);
                            }
                        }
                    } catch (InternalProviderData.ParseException e) {
                        e.printStackTrace();
                    } catch (JSONException ignored) {
                    }
                }
                cursor.close();
            }
        }
    });
    mWorker.start();
}
 
Example #13
Source File: ChannelDatabase.java    From CumulusTV with MIT License 5 votes vote down vote up
public List<Channel> getChannels(InternalProviderData providerData) throws JSONException {
    List<JsonChannel> jsonChannelList = getJsonChannels();
    List<Channel> channelList = new ArrayList<>();
    for (int i = 0; i < jsonChannelList.size(); i++) {
        JsonChannel jsonChannel = jsonChannelList.get(i);
        Channel channel = jsonChannel.toChannel(providerData);
        channelList.add(channel);
    }
    return channelList;
}
 
Example #14
Source File: ProviderChannelUtil.java    From xipl with Apache License 2.0 5 votes vote down vote up
/**
 * Creates a {@link Channel} that can be used by the Android TV framework and the Live Channels application.
 *
 * @param displayName   the display name of the channel
 * @param displayNumber the display number of the channel
 * @param epgId         the id as defined in {@link com.google.android.media.tv.companionlibrary.xmltv.XmlTvParser}
 * @param logo          the logo url link
 * @param url           the video url link
 * @return the channel to be used by the system.
 */
private static Channel createChannel(String displayName, String displayNumber, int epgId, String logo, String url, String group, String[] genres) {

    /*
     In order to map correctly the programs to a given channel, store the EPG id somewhere in the
     channel so we can retrieve it when we'll need to find programs

     Using the EPG ID as a good way to have an original network id but it might create channel
     duplicates. Since some channels either don't have an EPG id (which makes 0 as a hash) or might
     share the same id altogether, (same channel in SD/HD for example) they get recreated
     as their original id isn't really original anymore...

     In that case, let's use the display name as the original network id instead of the EPG id.
     Let's also retrieve the an example genre for the channel so it can be passed on the side
     of the EPG guide.
    */

    Channel.Builder builder = new Channel.Builder();
    InternalProviderData internalProviderData = new InternalProviderData();

    try {
        JSONArray genresJsonArray = new JSONArray(genres);
        internalProviderData.put(Constants.EPG_ID_PROVIDER, epgId);
        internalProviderData.put(Constants.CHANNEL_GENRES_PROVIDER, genresJsonArray);
    } catch (InternalProviderData.ParseException ps) {
        // Can't do anything about this...
    } catch (JSONException json) {
        json.printStackTrace();
    }

    internalProviderData.setVideoUrl(url);
    builder.setDisplayName(displayName);
    builder.setDisplayNumber(displayNumber);
    builder.setOriginalNetworkId(displayName.hashCode());
    builder.setChannelLogo(logo);
    builder.setNetworkAffiliation(group);
    builder.setInternalProviderData(internalProviderData);
    return (builder.build());
}
 
Example #15
Source File: XmlTvParserTest.java    From xipl with Apache License 2.0 5 votes vote down vote up
@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());
}
 
Example #16
Source File: XmlTvAdvertisementTest.java    From xipl with Apache License 2.0 5 votes vote down vote up
@Test
public void testAdvertisementParsing() throws XmlTvParser.XmlTvParseException, ParseException {
    long epochStartTime = 0;
    String requestUrl1 = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480" +
            "&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s" +
            "&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1" +
            "&cust_params=deployment%3Ddevsite%26sample_ct%3Dlinear&correlator=";
    String requestUrl2 = "https://pubads.g.doubleclick.net/gampad/ads?sz=640x480" +
            "&iu=/124319096/external/single_ad_samples&ciu_szs=300x250&impl=s" +
            "&gdfp_req=1&env=vp&output=vast&unviewed_position_start=1" +
            "&cust_params=deployment%3Ddevsite%26sample_ct%3Dredirectlinear&correlator=";
    String testXmlFile = "xmltv.xml";
    InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(testXmlFile);
    XmlTvParser.TvListing listings = XmlTvParser.parse(inputStream);
    // Channel 1 should have one VAST advertisement.
    Channel adChannel = listings.getChannels().get(1);
    assertNotNull(adChannel.getInternalProviderData());
    List<Advertisement> adChannelAds = adChannel.getInternalProviderData().getAds();
    assertEquals(1, adChannelAds.size());
    assertEquals(epochStartTime, adChannelAds.get(0).getStartTimeUtcMillis());
    assertEquals(epochStartTime, adChannelAds.get(0).getStopTimeUtcMillis());
    assertEquals(Advertisement.TYPE_VAST, adChannelAds.get(0).getType());
    // Channel 0 should not have any advertisement.
    Channel noAdChannel = listings.getChannels().get(0);
    assertNotNull(noAdChannel.getInternalProviderData());
    List<Advertisement> noAdChannelAds = noAdChannel.getInternalProviderData().getAds();
    assertEquals(0, noAdChannelAds.size());
    // Program 7 should have 2 advertisements with different request tags.
    Program adProgram = listings.getAllPrograms().get(7);
    assertNotNull(adProgram.getInternalProviderData());
    InternalProviderData adProgramData = adProgram.getInternalProviderData();
    List<Advertisement> adProgramAds = adProgramData.getAds();
    assertEquals(2, adProgramAds.size());
    assertEquals(requestUrl1, adProgramAds.get(0).getRequestUrl());
    assertEquals(requestUrl2, adProgramAds.get(1).getRequestUrl());
}
 
Example #17
Source File: TestJobService.java    From xipl with Apache License 2.0 5 votes vote down vote up
@Override
public List<Channel> getChannels() {
    Assert.assertNotNull("Please set the static mContext before running", mContext);
    // Wrap our list in an ArrayList so we will be able to make modifications if necessary
    Assert.assertNotNull("Set TestJobService.mContext.", mContext);
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setRepeatable(true);
    ArrayList<Channel> testChannels = new ArrayList<>();
    testChannels.add(new Channel.Builder()
            .setOriginalNetworkId(0)
            .setDisplayName("Test Channel")
            .setDisplayNumber("1")
            .setInternalProviderData(internalProviderData)
            .build());

    // Add an XML parsed channel
    Uri xmlUri = Uri.parse("android.resource://" + mContext.getPackageName()
            + "/" + com.google.android.media.tv.companionlibrary.test.R.raw.xmltv)
            .normalizeScheme();
    try {
        InputStream inputStream = mContext.getContentResolver()
                .openInputStream(xmlUri);
        Assert.assertNotNull(inputStream);
        testChannels.addAll(XmlTvParser.parse(inputStream).getChannels());
    } catch (FileNotFoundException | XmlTvParser.XmlTvParseException e) {
        throw new RuntimeException("Exception found of type " + e.getClass().getCanonicalName()
                + ": " + e.getMessage());
    }

    return testChannels;
}
 
Example #18
Source File: CumulusXmlParser.java    From CumulusTV with MIT License 4 votes vote down vote up
private static Channel parseChannel(XmlPullParser parser)
        throws IOException, XmlPullParserException, ParseException {
    String id = null;
    boolean repeatPrograms = false;
    for (int i = 0; i < parser.getAttributeCount(); ++i) {
        String attr = parser.getAttributeName(i);
        String value = parser.getAttributeValue(i);
        if (ATTR_ID.equalsIgnoreCase(attr)) {
            id = value;
        } else if (ATTR_REPEAT_PROGRAMS.equalsIgnoreCase(attr)) {
            repeatPrograms = "TRUE".equalsIgnoreCase(value);
        }
    }
    String displayName = null;
    String displayNumber = null;
    XmlTvIcon icon = null;
    XmlTvAppLink appLink = null;
    Advertisement advertisement = null;
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        if (parser.getEventType() == XmlPullParser.START_TAG) {
            if (TAG_DISPLAY_NAME.equalsIgnoreCase(parser.getName())
                    && displayName == null) {
                displayName = parser.nextText();
            } else if (TAG_DISPLAY_NUMBER.equalsIgnoreCase(parser.getName())
                    && displayNumber == null) {
                displayNumber = parser.nextText();
            } else if (TAG_ICON.equalsIgnoreCase(parser.getName()) && icon == null) {
                icon = parseIcon(parser);
            } else if (TAG_APP_LINK.equalsIgnoreCase(parser.getName()) && appLink == null) {
                appLink = parseAppLink(parser);
            } else if (TAG_AD.equalsIgnoreCase(parser.getName()) && advertisement == null) {
                advertisement = parseAd(parser, TAG_CHANNEL);
            }
        } else if (TAG_CHANNEL.equalsIgnoreCase(parser.getName())
                && parser.getEventType() == XmlPullParser.END_TAG) {
            break;
        }
    }
    if (TextUtils.isEmpty(id) || TextUtils.isEmpty(displayName)) {
        throw new IllegalArgumentException("id and display-name can not be null.");
    }

    // Developers should assign original network ID in the right way not using the fake ID.
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setRepeatable(repeatPrograms);
    Channel.Builder builder = new Channel.Builder()
            .setDisplayName(displayName)
            .setDisplayNumber(displayNumber)
            .setOriginalNetworkId(id.hashCode())
            .setInternalProviderData(internalProviderData)
            .setTransportStreamId(0)
            .setServiceId(0);
    if (icon != null) {
        builder.setChannelLogo(icon.src);
    }
    if (appLink != null) {
        builder.setAppLinkColor(appLink.color)
                .setAppLinkIconUri(appLink.icon.src)
                .setAppLinkIntentUri(appLink.intentUri)
                .setAppLinkPosterArtUri(appLink.posterUri)
                .setAppLinkText(appLink.text);
    }
    if (advertisement != null) {
        List<Advertisement> advertisements = new ArrayList<>(1);
        advertisements.add(advertisement);
        internalProviderData.setAds(advertisements);
        builder.setInternalProviderData(internalProviderData);
    }
    return builder.build();
}
 
Example #19
Source File: XmlTvParser.java    From androidtv-sample-inputs with Apache License 2.0 4 votes vote down vote up
private static Program parseProgram(XmlPullParser parser)
        throws IOException, XmlPullParserException, ParseException {
    String channelId = null;
    Long startTimeUtcMillis = null;
    Long endTimeUtcMillis = null;
    String videoSrc = null;
    int videoType = TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE;
    for (int i = 0; i < parser.getAttributeCount(); ++i) {
        String attr = parser.getAttributeName(i);
        String value = parser.getAttributeValue(i);
        if (ATTR_CHANNEL.equalsIgnoreCase(attr)) {
            channelId = value;
        } else if (ATTR_START.equalsIgnoreCase(attr)) {
            startTimeUtcMillis = DATE_FORMAT.parse(value).getTime();
        } else if (ATTR_STOP.equalsIgnoreCase(attr)) {
            endTimeUtcMillis = DATE_FORMAT.parse(value).getTime();
        } else if (ATTR_VIDEO_SRC.equalsIgnoreCase(attr)) {
            videoSrc = value;
        } else if (ATTR_VIDEO_TYPE.equalsIgnoreCase(attr)) {
            if (VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE;
            } else if (VALUE_VIDEO_TYPE_HLS.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_HLS;
            } else if (VALUE_VIDEO_TYPE_MPEG_DASH.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_MPEG_DASH;
            }
        }
    }
    String title = null;
    String description = null;
    XmlTvIcon icon = null;
    List<String> category = new ArrayList<>();
    List<TvContentRating> rating = new ArrayList<>();
    List<Advertisement> ads = new ArrayList<>();
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        String tagName = parser.getName();
        if (parser.getEventType() == XmlPullParser.START_TAG) {
            if (TAG_TITLE.equalsIgnoreCase(parser.getName())) {
                title = parser.nextText();
            } else if (TAG_DESC.equalsIgnoreCase(tagName)) {
                description = parser.nextText();
            } else if (TAG_ICON.equalsIgnoreCase(tagName)) {
                icon = parseIcon(parser);
            } else if (TAG_CATEGORY.equalsIgnoreCase(tagName)) {
                category.add(parser.nextText());
            } else if (TAG_RATING.equalsIgnoreCase(tagName)) {
                TvContentRating xmlTvRating = xmlTvRatingToTvContentRating(parseRating(parser));
                if (xmlTvRating != null) {
                    rating.add(xmlTvRating);
                }
            } else if (TAG_AD.equalsIgnoreCase(tagName)) {
                ads.add(parseAd(parser, TAG_PROGRAM));
            }
        } else if (TAG_PROGRAM.equalsIgnoreCase(tagName)
                && parser.getEventType() == XmlPullParser.END_TAG) {
            break;
        }
    }
    if (TextUtils.isEmpty(channelId)
            || startTimeUtcMillis == null
            || endTimeUtcMillis == null) {
        throw new IllegalArgumentException("channel, start, and end can not be null.");
    }
    InternalProviderData internalProviderData = new InternalProviderData();
    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();
}
 
Example #20
Source File: XmlTvParser.java    From androidtv-sample-inputs with Apache License 2.0 4 votes vote down vote up
private static Channel parseChannel(XmlPullParser parser)
        throws IOException, XmlPullParserException, ParseException {
    String id = null;
    boolean repeatPrograms = false;
    for (int i = 0; i < parser.getAttributeCount(); ++i) {
        String attr = parser.getAttributeName(i);
        String value = parser.getAttributeValue(i);
        if (ATTR_ID.equalsIgnoreCase(attr)) {
            id = value;
        } else if (ATTR_REPEAT_PROGRAMS.equalsIgnoreCase(attr)) {
            repeatPrograms = "TRUE".equalsIgnoreCase(value);
        }
    }
    String displayName = null;
    String displayNumber = null;
    XmlTvIcon icon = null;
    XmlTvAppLink appLink = null;
    Advertisement advertisement = null;
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        if (parser.getEventType() == XmlPullParser.START_TAG) {
            if (TAG_DISPLAY_NAME.equalsIgnoreCase(parser.getName()) && displayName == null) {
                displayName = parser.nextText();
            } else if (TAG_DISPLAY_NUMBER.equalsIgnoreCase(parser.getName())
                    && displayNumber == null) {
                displayNumber = parser.nextText();
            } else if (TAG_ICON.equalsIgnoreCase(parser.getName()) && icon == null) {
                icon = parseIcon(parser);
            } else if (TAG_APP_LINK.equalsIgnoreCase(parser.getName()) && appLink == null) {
                appLink = parseAppLink(parser);
            } else if (TAG_AD.equalsIgnoreCase(parser.getName()) && advertisement == null) {
                advertisement = parseAd(parser, TAG_CHANNEL);
            }
        } else if (TAG_CHANNEL.equalsIgnoreCase(parser.getName())
                && parser.getEventType() == XmlPullParser.END_TAG) {
            break;
        }
    }
    if (TextUtils.isEmpty(id) || TextUtils.isEmpty(displayName)) {
        throw new IllegalArgumentException("id and display-name can not be null.");
    }

    // Developers should assign original network ID in the right way not using the fake ID.
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setRepeatable(repeatPrograms);
    Channel.Builder builder =
            new Channel.Builder()
                    .setDisplayName(displayName)
                    .setDisplayNumber(displayNumber)
                    .setOriginalNetworkId(id.hashCode())
                    .setInternalProviderData(internalProviderData)
                    .setTransportStreamId(0)
                    .setServiceId(0);
    if (icon != null) {
        builder.setChannelLogo(icon.src);
    }
    if (appLink != null) {
        builder.setAppLinkColor(appLink.color)
                .setAppLinkIconUri(appLink.icon.src)
                .setAppLinkIntentUri(appLink.intentUri)
                .setAppLinkPosterArtUri(appLink.posterUri)
                .setAppLinkText(appLink.text);
    }
    if (advertisement != null) {
        List<Advertisement> advertisements = new ArrayList<>(1);
        advertisements.add(advertisement);
        internalProviderData.setAds(advertisements);
        builder.setInternalProviderData(internalProviderData);
    }
    return builder.build();
}
 
Example #21
Source File: SampleJobService.java    From androidtv-sample-inputs with Apache License 2.0 4 votes vote down vote up
@Override
public List<Program> getOriginalProgramsForChannel(Uri channelUri, Channel channel,
        long startMs, long endMs) {
    if (!channel.getDisplayName().equals(MPEG_DASH_CHANNEL_NAME)) {
        // Is an XMLTV Channel
        XmlTvParser.TvListing listings = RichFeedUtil.getRichTvListings(getApplicationContext());
        return listings.getPrograms(channel);
    } else {
        // Build Advertisement list for the program.
        Advertisement programAd1 = new Advertisement.Builder()
                .setStartTimeUtcMillis(TEST_AD_1_START_TIME_MS)
                .setStopTimeUtcMillis(TEST_AD_1_START_TIME_MS + TEST_AD_DURATION_MS)
                .setType(Advertisement.TYPE_VAST)
                .setRequestUrl(TEST_AD_REQUEST_URL)
                .build();
        Advertisement programAd2 = new Advertisement.Builder(programAd1)
                .setStartTimeUtcMillis(TEST_AD_2_START_TIME_MS)
                .setStopTimeUtcMillis(TEST_AD_2_START_TIME_MS + TEST_AD_DURATION_MS)
                .build();
        List<Advertisement> programAdList = new ArrayList<>();
        programAdList.add(programAd1);
        programAdList.add(programAd2);

        // Programatically add channel
        List<Program> programsTears = new ArrayList<>();
        InternalProviderData internalProviderData = new InternalProviderData();
        internalProviderData.setVideoType(Util.TYPE_DASH);
        internalProviderData.setVideoUrl(TEARS_OF_STEEL_SOURCE);
        internalProviderData.setAds(programAdList);
        programsTears.add(new Program.Builder()
                .setTitle(TEARS_OF_STEEL_TITLE)
                .setStartTimeUtcMillis(TEARS_OF_STEEL_START_TIME_MS)
                .setEndTimeUtcMillis(TEARS_OF_STEEL_START_TIME_MS + TEARS_OF_STEEL_DURATION_MS)
                .setDescription(TEARS_OF_STEEL_DESCRIPTION)
                .setCanonicalGenres(new String[] {TvContract.Programs.Genres.TECH_SCIENCE,
                        TvContract.Programs.Genres.MOVIES})
                .setPosterArtUri(TEARS_OF_STEEL_ART)
                .setThumbnailUri(TEARS_OF_STEEL_ART)
                .setInternalProviderData(internalProviderData)
                .build());
        return programsTears;
    }
}
 
Example #22
Source File: CumulusXmlParser.java    From CumulusTV with MIT License 4 votes vote down vote up
private static Program parseProgram(XmlPullParser parser)
        throws IOException, XmlPullParserException, ParseException {
    String channelId = null;
    Long startTimeUtcMillis = null;
    Long endTimeUtcMillis = null;
    String videoSrc = null;
    int videoType = TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE;
    for (int i = 0; i < parser.getAttributeCount(); ++i) {
        String attr = parser.getAttributeName(i);
        String value = parser.getAttributeValue(i);
        if (ATTR_CHANNEL.equalsIgnoreCase(attr)) {
            channelId = value;
        } else if (ATTR_START.equalsIgnoreCase(attr)) {
            startTimeUtcMillis = DATE_FORMAT.parse(value).getTime();
        } else if (ATTR_STOP.equalsIgnoreCase(attr)) {
            endTimeUtcMillis = DATE_FORMAT.parse(value).getTime();
        } else if (ATTR_VIDEO_SRC.equalsIgnoreCase(attr)) {
            videoSrc = value;
        } else if (ATTR_VIDEO_TYPE.equalsIgnoreCase(attr)) {
            if (VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE;
            } else if (VALUE_VIDEO_TYPE_HLS.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_HLS;
            } else if (VALUE_VIDEO_TYPE_MPEG_DASH.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_MPEG_DASH;
            }
        }
    }
    String title = null;
    String description = null;
    XmlTvIcon icon = null;
    List<String> category = new ArrayList<>();
    List<TvContentRating> rating = new ArrayList<>();
    List<Advertisement> ads = new ArrayList<>();
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        String tagName = parser.getName();
        if (parser.getEventType() == XmlPullParser.START_TAG) {
            if (TAG_TITLE.equalsIgnoreCase(parser.getName())) {
                title = parser.nextText();
            } else if (TAG_DESC.equalsIgnoreCase(tagName)) {
                description = parser.nextText();
            } else if (TAG_ICON.equalsIgnoreCase(tagName)) {
                icon = parseIcon(parser);
            } else if (TAG_CATEGORY.equalsIgnoreCase(tagName)) {
                category.add(parser.nextText());
            } else if (TAG_RATING.equalsIgnoreCase(tagName)) {
                TvContentRating xmlTvRating = xmlTvRatingToTvContentRating(parseRating(parser));
                if (xmlTvRating != null)
                    rating.add(xmlTvRating);
            } else if (TAG_AD.equalsIgnoreCase(tagName)) {
                ads.add(parseAd(parser, TAG_PROGRAM));
            }
        } else if (TAG_PROGRAM.equalsIgnoreCase(tagName)
                && parser.getEventType() == XmlPullParser.END_TAG) {
            break;
        }
    }
    if (TextUtils.isEmpty(channelId) || startTimeUtcMillis == null
            || endTimeUtcMillis == null) {
        throw new IllegalArgumentException("channel, start, and end can not be null.");
    }
    InternalProviderData internalProviderData = new InternalProviderData();
    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();
}
 
Example #23
Source File: XmlTvParser.java    From xipl with Apache License 2.0 4 votes vote down vote up
private static Channel parseChannel(XmlPullParser parser)
        throws IOException, XmlPullParserException, ParseException {
    String id = null;
    boolean repeatPrograms = false;
    for (int i = 0; i < parser.getAttributeCount(); ++i) {
        String attr = parser.getAttributeName(i);
        String value = parser.getAttributeValue(i);
        if (ATTR_ID.equalsIgnoreCase(attr)) {
            id = value;
        } else if (ATTR_REPEAT_PROGRAMS.equalsIgnoreCase(attr)) {
            repeatPrograms = "TRUE".equalsIgnoreCase(value);
        }
    }
    String displayName = null;
    String displayNumber = null;
    XmlTvIcon icon = null;
    XmlTvAppLink appLink = null;
    Advertisement advertisement = null;
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        if (parser.getEventType() == XmlPullParser.START_TAG) {
            if (TAG_DISPLAY_NAME.equalsIgnoreCase(parser.getName()) && displayName == null) {
                displayName = parser.nextText();
            } else if (TAG_DISPLAY_NUMBER.equalsIgnoreCase(parser.getName())
                    && displayNumber == null) {
                displayNumber = parser.nextText();
            } else if (TAG_ICON.equalsIgnoreCase(parser.getName()) && icon == null) {
                icon = parseIcon(parser);
            } else if (TAG_APP_LINK.equalsIgnoreCase(parser.getName()) && appLink == null) {
                appLink = parseAppLink(parser);
            } else if (TAG_AD.equalsIgnoreCase(parser.getName()) && advertisement == null) {
                advertisement = parseAd(parser, TAG_CHANNEL);
            }
        } else if (TAG_CHANNEL.equalsIgnoreCase(parser.getName())
                && parser.getEventType() == XmlPullParser.END_TAG) {
            break;
        }
    }
    if (TextUtils.isEmpty(id) || TextUtils.isEmpty(displayName)) {
        // In this case, the channel is simply invalid so skip it...
        return null;
    }

    // Developers should assign original network ID in the right way not using the fake ID.
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setRepeatable(repeatPrograms);
    Channel.Builder builder =
            new Channel.Builder()
                    .setDisplayName(displayName)
                    .setDisplayNumber(displayNumber)
                    .setOriginalNetworkId(id.hashCode())
                    .setInternalProviderData(internalProviderData)
                    .setTransportStreamId(0)
                    .setServiceId(0);
    if (icon != null) {
        builder.setChannelLogo(icon.src);
    }
    if (appLink != null) {
        builder.setAppLinkColor(appLink.color)
                .setAppLinkIconUri(appLink.icon.src)
                .setAppLinkIntentUri(appLink.intentUri)
                .setAppLinkPosterArtUri(appLink.posterUri)
                .setAppLinkText(appLink.text);
    }
    if (advertisement != null) {
        List<Advertisement> advertisements = new ArrayList<>(1);
        advertisements.add(advertisement);
        internalProviderData.setAds(advertisements);
        builder.setInternalProviderData(internalProviderData);
    }
    return builder.build();
}
 
Example #24
Source File: XmlTvParser.java    From xipl with Apache License 2.0 4 votes vote down vote up
private static Program parseProgram(XmlPullParser parser)
        throws IOException, XmlPullParserException, ParseException {
    String channelId = null;
    Long startTimeUtcMillis = null;
    Long endTimeUtcMillis = null;
    String videoSrc = null;
    int videoType = TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE;
    for (int i = 0; i < parser.getAttributeCount(); ++i) {
        String attr = parser.getAttributeName(i);
        String value = parser.getAttributeValue(i);
        if (ATTR_CHANNEL.equalsIgnoreCase(attr)) {
            channelId = value;
        } else if (ATTR_START.equalsIgnoreCase(attr)) {
            startTimeUtcMillis = DATE_FORMAT.parse(value).getTime();
        } else if (ATTR_STOP.equalsIgnoreCase(attr)) {
            endTimeUtcMillis = DATE_FORMAT.parse(value).getTime();
        } else if (ATTR_VIDEO_SRC.equalsIgnoreCase(attr)) {
            videoSrc = value;
        } else if (ATTR_VIDEO_TYPE.equalsIgnoreCase(attr)) {
            if (VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_HTTP_PROGRESSIVE;
            } else if (VALUE_VIDEO_TYPE_HLS.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_HLS;
            } else if (VALUE_VIDEO_TYPE_MPEG_DASH.equals(value)) {
                videoType = TvContractUtils.SOURCE_TYPE_MPEG_DASH;
            }
        }
    }
    String title = null;
    String description = null;
    XmlTvIcon icon = null;
    List<String> category = new ArrayList<>();
    List<TvContentRating> rating = new ArrayList<>();
    List<Advertisement> ads = new ArrayList<>();
    while (parser.next() != XmlPullParser.END_DOCUMENT) {
        String tagName = parser.getName();
        if (parser.getEventType() == XmlPullParser.START_TAG) {
            if (TAG_TITLE.equalsIgnoreCase(parser.getName())) {
                title = parser.nextText();
            } else if (TAG_DESC.equalsIgnoreCase(tagName)) {
                description = parser.nextText();
            } else if (TAG_ICON.equalsIgnoreCase(tagName)) {
                icon = parseIcon(parser);
            } else if (TAG_CATEGORY.equalsIgnoreCase(tagName)) {
                category.add(parser.nextText());
            } else if (TAG_RATING.equalsIgnoreCase(tagName)) {
                TvContentRating xmlTvRating = xmlTvRatingToTvContentRating(parseRating(parser));
                if (xmlTvRating != null) {
                    rating.add(xmlTvRating);
                }
            } else if (TAG_AD.equalsIgnoreCase(tagName)) {
                ads.add(parseAd(parser, TAG_PROGRAM));
            }
        } else if (TAG_PROGRAM.equalsIgnoreCase(tagName)
                && parser.getEventType() == XmlPullParser.END_TAG) {
            break;
        }
    }
    if (TextUtils.isEmpty(channelId)
            || startTimeUtcMillis == null
            || endTimeUtcMillis == null) {
        throw new IllegalArgumentException("channel, start, and end can not be null.");
    }
    InternalProviderData internalProviderData = new InternalProviderData();
    internalProviderData.setVideoType(videoType);
    internalProviderData.setVideoUrl(videoSrc);
    internalProviderData.setAds(ads);
    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);
    }
}