blob: b2561cf3904e62b7892780a80d291d78889901ed [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.rich;
import com.example.android.sampletvinput.rich.RichTvInputService.ChannelInfo;
import com.example.android.sampletvinput.rich.RichTvInputService.ProgramInfo;
import com.example.android.sampletvinput.rich.RichTvInputService.TvInput;
import com.example.android.sampletvinput.TvContractUtils;
import com.example.android.sampletvinput.player.TvInputPlayer;
import org.xmlpull.v1.XmlPullParser;
import org.xmlpull.v1.XmlPullParserException;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
/**
* A parser for the channels and programs feed used in {@link RichTvInputService}.
* <p>
* NOTE: The feed format here is just an example. Developers may invent any new formats and parse
* them in their own way.
* </p>
*/
public class ChannelXMLParser {
private static String TAG = "ChannelXmlParser";
private static final String TAG_TVINPUTS = "TvInputs";
private static final String TAG_CHANNELS = "Channels";
private static final String TAG_CHANNEL = "Channel";
private static final String TAG_PROGRAM = "Program";
private static final String ATTR_TVINPUT_DISPLAY_NAME = "display_name";
private static final String ATTR_TVINPUT_NAME = "name";
private static final String ATTR_TVINPUT_DESCRIPTION = "description";
private static final String ATTR_LOGO_THUMB_URL = "logo_thumb_url";
private static final String ATTR_LOGO_BACKGROUND_URL = "logo_background_url";
private static final String ATTR_DISPLAY_NUMBER = "display_number";
private static final String ATTR_DISPLAY_NAME = "display_name";
private static final String ATTR_VIDEO_WIDTH = "video_width";
private static final String ATTR_VIDEO_HEIGHT = "video_height";
private static final String ATTR_LOGO_URL = "logo_url";
private static final String ATTR_TITLE = "title";
private static final String ATTR_POSTER_ART_URL = "poster_art_url";
private static final String ATTR_DURATION_SEC = "duration_sec";
private static final String ATTR_VIDEO_URL = "video_url";
private static final String ATTR_VIDEO_TYPE = "video_type";
private static final String ATTR_DESCRIPTION = "description";
private static final String ATTR_CONTENT_RATING = "content_rating";
private static final String VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE = "HTTP_PROGRESSIVE";
private static final String VALUE_VIDEO_TYPE_HLS = "HLS";
private static final String VALUE_VIDEO_TYPE_MPEG_DASH = "MPEG_DASH";
public static TvInput parseTvInput(XmlPullParser parser)
throws XmlPullParserException, IOException {
parser.nextTag();
parser.require(XmlPullParser.START_TAG, null, TAG_TVINPUTS);
return parseTvInputDetail(parser);
}
private static TvInput parseTvInputDetail(XmlPullParser parser) {
String displayName = null;
String name = null;
String description = null;
String logoThumbUrl = null;
String logoBackgroundUrl = null;
for (int i = 0; i < parser.getAttributeCount(); ++i) {
String attr = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
if (ATTR_TVINPUT_DISPLAY_NAME.equals(attr)) {
displayName = value;
} else if (ATTR_TVINPUT_NAME.equals(attr)) {
name = value;
} else if (ATTR_TVINPUT_DESCRIPTION.equals(attr)) {
description = value;
} else if (ATTR_LOGO_THUMB_URL.equals(attr)) {
logoThumbUrl = value;
} else if (ATTR_LOGO_BACKGROUND_URL.equals(attr)) {
logoBackgroundUrl = value;
}
}
return new TvInput(displayName, name, description, logoThumbUrl, logoBackgroundUrl);
}
public static List<ChannelInfo> parseChannelXML(XmlPullParser parser)
throws XmlPullParserException, IOException {
List<ChannelInfo> list = new ArrayList<ChannelInfo>();
parser.nextTag();
parser.require(XmlPullParser.START_TAG, null, TAG_CHANNELS);
while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() == XmlPullParser.START_TAG
&& TAG_CHANNEL.equals(parser.getName())) {
list.add(parseChannel(parser));
}
}
return list;
}
private static ChannelInfo parseChannel(XmlPullParser parser)
throws XmlPullParserException, IOException {
String displayNumber = null;
String displayName = null;
int videoWidth = 0;
int videoHeight = 0;
String logoUrl = null;
StringBuilder hashString = new StringBuilder();
for (int i = 0; i < parser.getAttributeCount(); ++i) {
String attr = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
// Here we assume that other metadata except number and name may change when the feed
// is updated.
if (ATTR_DISPLAY_NUMBER.equals(attr)) {
displayNumber = value;
hashString.append(value).append(";");
} else if (ATTR_DISPLAY_NAME.equals(attr)) {
displayName = value;
hashString.append(value).append(";");
} else if (ATTR_VIDEO_WIDTH.equals(attr)) {
videoWidth = Integer.parseInt(value);
} else if (ATTR_VIDEO_HEIGHT.equals(attr)) {
videoHeight = Integer.parseInt(value);
} else if (ATTR_LOGO_URL.equals(attr)) {
logoUrl = value;
}
}
List<ProgramInfo> programs = new ArrayList<>();
while (parser.next() != XmlPullParser.END_DOCUMENT) {
if (parser.getEventType() == XmlPullParser.START_TAG) {
if (TAG_PROGRAM.equals(parser.getName())) {
programs.add(parseProgram(parser));
}
} else if (TAG_CHANNEL.equals(parser.getName())
&& parser.getEventType() == XmlPullParser.END_TAG) {
break;
}
}
// Developers should assign original network ID in the right way not using the fake ID.
int fakeOriginalNetworkId = hashString.toString().hashCode();
return new ChannelInfo(displayNumber, displayName, logoUrl, fakeOriginalNetworkId, 0, 0,
videoWidth, videoHeight, programs);
}
private static ProgramInfo parseProgram(XmlPullParser parser) {
SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
String title = null;
long durationSec = 0;
String videoUrl = null;
int videoType = TvInputPlayer.SOURCE_TYPE_HTTP_PROGRESSIVE;
String description = null;
String posterArtUri = null;
String contentRatings = null;
for (int i = 0; i < parser.getAttributeCount(); ++i) {
String attr = parser.getAttributeName(i);
String value = parser.getAttributeValue(i);
if (ATTR_TITLE.equals(attr)) {
title = value;
} else if (ATTR_POSTER_ART_URL.equals(attr)) {
posterArtUri = value;
} else if (ATTR_DURATION_SEC.equals(attr)) {
durationSec = Integer.parseInt(value);
} else if (ATTR_VIDEO_URL.equals(attr)) {
videoUrl = value;
} else if (ATTR_VIDEO_TYPE.equals(attr)) {
if (VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE.equals(value)) {
videoType = TvInputPlayer.SOURCE_TYPE_HTTP_PROGRESSIVE;
} else if (VALUE_VIDEO_TYPE_HLS.equals(value)) {
videoType = TvInputPlayer.SOURCE_TYPE_HLS;
} else if (VALUE_VIDEO_TYPE_MPEG_DASH.equals(value)) {
videoType = TvInputPlayer.SOURCE_TYPE_MPEG_DASH;
}
} else if (ATTR_DESCRIPTION.equals(attr)) {
description = value;
} else if (ATTR_CONTENT_RATING.equals(attr)) {
contentRatings = value;
}
}
return new ProgramInfo(title, posterArtUri, description, durationSec,
TvContractUtils.stringToContentRatings(contentRatings), videoUrl, videoType, 0);
}
}