Home | History | Annotate | Download | only in rich
      1 /*
      2  * Copyright 2015 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package com.example.android.sampletvinput.rich;
     18 
     19 import com.example.android.sampletvinput.rich.RichTvInputService.ChannelInfo;
     20 import com.example.android.sampletvinput.rich.RichTvInputService.ProgramInfo;
     21 import com.example.android.sampletvinput.rich.RichTvInputService.TvInput;
     22 import com.example.android.sampletvinput.TvContractUtils;
     23 import com.example.android.sampletvinput.player.TvInputPlayer;
     24 
     25 import org.xmlpull.v1.XmlPullParser;
     26 import org.xmlpull.v1.XmlPullParserException;
     27 
     28 import java.io.IOException;
     29 import java.text.SimpleDateFormat;
     30 import java.util.ArrayList;
     31 import java.util.List;
     32 
     33 /**
     34  * A parser for the channels and programs feed used in {@link RichTvInputService}.
     35  * <p>
     36  * NOTE: The feed format here is just an example. Developers may invent any new formats and parse
     37  * them in their own way.
     38  * </p>
     39  */
     40 public class ChannelXMLParser {
     41     private static String TAG = "ChannelXmlParser";
     42 
     43     private static final String TAG_TVINPUTS = "TvInputs";
     44     private static final String TAG_CHANNELS = "Channels";
     45     private static final String TAG_CHANNEL = "Channel";
     46     private static final String TAG_PROGRAM = "Program";
     47 
     48     private static final String ATTR_TVINPUT_DISPLAY_NAME = "display_name";
     49     private static final String ATTR_TVINPUT_NAME = "name";
     50     private static final String ATTR_TVINPUT_DESCRIPTION = "description";
     51     private static final String ATTR_LOGO_THUMB_URL = "logo_thumb_url";
     52     private static final String ATTR_LOGO_BACKGROUND_URL = "logo_background_url";
     53 
     54     private static final String ATTR_DISPLAY_NUMBER = "display_number";
     55     private static final String ATTR_DISPLAY_NAME = "display_name";
     56     private static final String ATTR_VIDEO_WIDTH = "video_width";
     57     private static final String ATTR_VIDEO_HEIGHT = "video_height";
     58     private static final String ATTR_LOGO_URL = "logo_url";
     59 
     60     private static final String ATTR_TITLE = "title";
     61     private static final String ATTR_POSTER_ART_URL = "poster_art_url";
     62     private static final String ATTR_DURATION_SEC = "duration_sec";
     63     private static final String ATTR_VIDEO_URL = "video_url";
     64     private static final String ATTR_VIDEO_TYPE = "video_type";
     65     private static final String ATTR_DESCRIPTION = "description";
     66     private static final String ATTR_CONTENT_RATING = "content_rating";
     67 
     68     private static final String VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE = "HTTP_PROGRESSIVE";
     69     private static final String VALUE_VIDEO_TYPE_HLS = "HLS";
     70     private static final String VALUE_VIDEO_TYPE_MPEG_DASH = "MPEG_DASH";
     71 
     72     public static TvInput parseTvInput(XmlPullParser parser)
     73             throws XmlPullParserException, IOException {
     74         parser.nextTag();
     75         parser.require(XmlPullParser.START_TAG, null, TAG_TVINPUTS);
     76         return parseTvInputDetail(parser);
     77     }
     78 
     79     private static TvInput parseTvInputDetail(XmlPullParser parser) {
     80         String displayName = null;
     81         String name = null;
     82         String description = null;
     83         String logoThumbUrl = null;
     84         String logoBackgroundUrl = null;
     85         for (int i = 0; i < parser.getAttributeCount(); ++i) {
     86             String attr = parser.getAttributeName(i);
     87             String value = parser.getAttributeValue(i);
     88             if (ATTR_TVINPUT_DISPLAY_NAME.equals(attr)) {
     89                 displayName = value;
     90             } else if (ATTR_TVINPUT_NAME.equals(attr)) {
     91                 name = value;
     92             } else if (ATTR_TVINPUT_DESCRIPTION.equals(attr)) {
     93                 description = value;
     94             } else if (ATTR_LOGO_THUMB_URL.equals(attr)) {
     95                 logoThumbUrl = value;
     96             } else if (ATTR_LOGO_BACKGROUND_URL.equals(attr)) {
     97                 logoBackgroundUrl = value;
     98             }
     99         }
    100         return new TvInput(displayName, name, description, logoThumbUrl, logoBackgroundUrl);
    101     }
    102 
    103     public static List<ChannelInfo> parseChannelXML(XmlPullParser parser)
    104             throws XmlPullParserException, IOException {
    105         List<ChannelInfo> list = new ArrayList<ChannelInfo>();
    106         parser.nextTag();
    107 
    108         parser.require(XmlPullParser.START_TAG, null, TAG_CHANNELS);
    109         while (parser.next() != XmlPullParser.END_DOCUMENT) {
    110             if (parser.getEventType() == XmlPullParser.START_TAG
    111                     && TAG_CHANNEL.equals(parser.getName())) {
    112                 list.add(parseChannel(parser));
    113             }
    114         }
    115         return list;
    116     }
    117 
    118     private static ChannelInfo parseChannel(XmlPullParser parser)
    119             throws XmlPullParserException, IOException {
    120         String displayNumber = null;
    121         String displayName = null;
    122         int videoWidth = 0;
    123         int videoHeight = 0;
    124         String logoUrl = null;
    125         StringBuilder hashString = new StringBuilder();
    126         for (int i = 0; i < parser.getAttributeCount(); ++i) {
    127             String attr = parser.getAttributeName(i);
    128             String value = parser.getAttributeValue(i);
    129             // Here we assume that other metadata except number and name may change when the feed
    130             // is updated.
    131             if (ATTR_DISPLAY_NUMBER.equals(attr)) {
    132                 displayNumber = value;
    133                 hashString.append(value).append(";");
    134             } else if (ATTR_DISPLAY_NAME.equals(attr)) {
    135                 displayName = value;
    136                 hashString.append(value).append(";");
    137             } else if (ATTR_VIDEO_WIDTH.equals(attr)) {
    138                 videoWidth = Integer.parseInt(value);
    139             } else if (ATTR_VIDEO_HEIGHT.equals(attr)) {
    140                 videoHeight = Integer.parseInt(value);
    141             } else if (ATTR_LOGO_URL.equals(attr)) {
    142                 logoUrl = value;
    143             }
    144         }
    145         List<ProgramInfo> programs = new ArrayList<>();
    146         while (parser.next() != XmlPullParser.END_DOCUMENT) {
    147             if (parser.getEventType() == XmlPullParser.START_TAG) {
    148                 if (TAG_PROGRAM.equals(parser.getName())) {
    149                     programs.add(parseProgram(parser));
    150                 }
    151             } else if (TAG_CHANNEL.equals(parser.getName())
    152                     && parser.getEventType() == XmlPullParser.END_TAG) {
    153                 break;
    154             }
    155         }
    156         // Developers should assign original network ID in the right way not using the fake ID.
    157         int fakeOriginalNetworkId = hashString.toString().hashCode();
    158         return new ChannelInfo(displayNumber, displayName, logoUrl, fakeOriginalNetworkId, 0, 0,
    159                 videoWidth, videoHeight, programs);
    160     }
    161 
    162     private static ProgramInfo parseProgram(XmlPullParser parser) {
    163         SimpleDateFormat format = new SimpleDateFormat("yyyy-MM-dd HH:mm");
    164         String title = null;
    165         long durationSec = 0;
    166         String videoUrl = null;
    167         int videoType = TvInputPlayer.SOURCE_TYPE_HTTP_PROGRESSIVE;
    168         String description = null;
    169         String posterArtUri = null;
    170         String contentRatings = null;
    171         for (int i = 0; i < parser.getAttributeCount(); ++i) {
    172             String attr = parser.getAttributeName(i);
    173             String value = parser.getAttributeValue(i);
    174             if (ATTR_TITLE.equals(attr)) {
    175                 title = value;
    176             } else if (ATTR_POSTER_ART_URL.equals(attr)) {
    177                 posterArtUri = value;
    178             } else if (ATTR_DURATION_SEC.equals(attr)) {
    179                 durationSec = Integer.parseInt(value);
    180             } else if (ATTR_VIDEO_URL.equals(attr)) {
    181                 videoUrl = value;
    182             } else if (ATTR_VIDEO_TYPE.equals(attr)) {
    183                 if (VALUE_VIDEO_TYPE_HTTP_PROGRESSIVE.equals(value)) {
    184                     videoType = TvInputPlayer.SOURCE_TYPE_HTTP_PROGRESSIVE;
    185                 } else if (VALUE_VIDEO_TYPE_HLS.equals(value)) {
    186                     videoType = TvInputPlayer.SOURCE_TYPE_HLS;
    187                 } else if (VALUE_VIDEO_TYPE_MPEG_DASH.equals(value)) {
    188                     videoType = TvInputPlayer.SOURCE_TYPE_MPEG_DASH;
    189                 }
    190             } else if (ATTR_DESCRIPTION.equals(attr)) {
    191                 description = value;
    192             } else if (ATTR_CONTENT_RATING.equals(attr)) {
    193                 contentRatings = value;
    194             }
    195         }
    196         return new ProgramInfo(title, posterArtUri, description, durationSec,
    197                 TvContractUtils.stringToContentRatings(contentRatings), videoUrl, videoType, 0);
    198     }
    199 }
    200