Home | History | Annotate | Download | only in model
      1 /*
      2  * Copyright (C) 2008 Esmertec AG.
      3  * Copyright (C) 2008 The Android Open Source Project
      4  *
      5  * Licensed under the Apache License, Version 2.0 (the "License");
      6  * you may not use this file except in compliance with the License.
      7  * You may obtain a copy of the License at
      8  *
      9  *      http://www.apache.org/licenses/LICENSE-2.0
     10  *
     11  * Unless required by applicable law or agreed to in writing, software
     12  * distributed under the License is distributed on an "AS IS" BASIS,
     13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     14  * See the License for the specific language governing permissions and
     15  * limitations under the License.
     16  */
     17 
     18 package com.android.mms.model;
     19 
     20 import com.android.mms.UnsupportContentTypeException;
     21 import com.android.mms.LogTag;
     22 import com.android.mms.MmsConfig;
     23 import android.drm.mobile1.DrmException;
     24 import com.android.mms.drm.DrmWrapper;
     25 import com.google.android.mms.ContentType;
     26 import com.google.android.mms.MmsException;
     27 import com.google.android.mms.pdu.CharacterSets;
     28 import com.google.android.mms.pdu.PduBody;
     29 import com.google.android.mms.pdu.PduPart;
     30 
     31 import org.w3c.dom.smil.SMILMediaElement;
     32 import org.w3c.dom.smil.SMILRegionElement;
     33 import org.w3c.dom.smil.SMILRegionMediaElement;
     34 import org.w3c.dom.smil.Time;
     35 import org.w3c.dom.smil.TimeList;
     36 
     37 import android.content.Context;
     38 import android.util.Log;
     39 
     40 import java.io.IOException;
     41 
     42 public class MediaModelFactory {
     43     private static final String TAG = "Mms:media";
     44 
     45     public static MediaModel getMediaModel(Context context,
     46             SMILMediaElement sme, LayoutModel layouts, PduBody pb)
     47             throws DrmException, IOException, IllegalArgumentException, MmsException {
     48         String tag = sme.getTagName();
     49         String src = sme.getSrc();
     50         PduPart part = findPart(pb, src);
     51 
     52         if (sme instanceof SMILRegionMediaElement) {
     53             return getRegionMediaModel(
     54                     context, tag, src, (SMILRegionMediaElement) sme, layouts, part);
     55         } else {
     56             return getGenericMediaModel(
     57                     context, tag, src, sme, part, null);
     58         }
     59     }
     60 
     61     private static PduPart findPart(PduBody pb, String src) {
     62         PduPart part = null;
     63 
     64         if (src != null) {
     65             src = unescapeXML(src);
     66             if (src.startsWith("cid:")) {
     67                 part = pb.getPartByContentId("<" + src.substring("cid:".length()) + ">");
     68             } else {
     69                 part = pb.getPartByName(src);
     70                 if (part == null) {
     71                     part = pb.getPartByFileName(src);
     72                     if (part == null) {
     73                         part = pb.getPartByContentLocation(src);
     74                     }
     75                 }
     76             }
     77         }
     78 
     79         if (part != null) {
     80             return part;
     81         }
     82 
     83         throw new IllegalArgumentException("No part found for the model.");
     84     }
     85 
     86     private static String unescapeXML(String str) {
     87         return str.replaceAll("&lt;","<")
     88             .replaceAll("&gt;", ">")
     89             .replaceAll("&quot;","\"")
     90             .replaceAll("&apos;","'")
     91             .replaceAll("&amp;", "&");
     92     }
     93 
     94     private static MediaModel getRegionMediaModel(Context context,
     95             String tag, String src, SMILRegionMediaElement srme,
     96             LayoutModel layouts, PduPart part) throws DrmException, IOException, MmsException {
     97         SMILRegionElement sre = srme.getRegion();
     98         if (sre != null) {
     99             RegionModel region = layouts.findRegionById(sre.getId());
    100             if (region != null) {
    101                 return getGenericMediaModel(context, tag, src, srme, part, region);
    102             }
    103         } else {
    104             String rId = null;
    105 
    106             if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
    107                 rId = LayoutModel.TEXT_REGION_ID;
    108             } else {
    109                 rId = LayoutModel.IMAGE_REGION_ID;
    110             }
    111 
    112             RegionModel region = layouts.findRegionById(rId);
    113             if (region != null) {
    114                 return getGenericMediaModel(context, tag, src, srme, part, region);
    115             }
    116         }
    117 
    118         throw new IllegalArgumentException("Region not found or bad region ID.");
    119     }
    120 
    121     // When we encounter a content type we can't handle, such as "application/vnd.smaf", instead
    122     // of throwing an exception and crashing, insert an empty TextModel in its place.
    123     private static MediaModel createEmptyTextModel(Context context, DrmWrapper wrapper,
    124             RegionModel regionModel) throws IOException {
    125         return wrapper != null ?
    126                 new TextModel(context, ContentType.TEXT_PLAIN, null, CharacterSets.ANY_CHARSET,
    127                         wrapper, regionModel) :
    128                 new TextModel(context, ContentType.TEXT_PLAIN, null, regionModel);
    129     }
    130 
    131     private static MediaModel getGenericMediaModel(Context context,
    132             String tag, String src, SMILMediaElement sme, PduPart part,
    133             RegionModel regionModel) throws DrmException, IOException, MmsException {
    134         byte[] bytes = part.getContentType();
    135         if (bytes == null) {
    136             throw new IllegalArgumentException(
    137                     "Content-Type of the part may not be null.");
    138         }
    139 
    140         String contentType = new String(bytes);
    141         MediaModel media = null;
    142         if (ContentType.isDrmType(contentType)) {
    143             DrmWrapper wrapper = new DrmWrapper(
    144                     contentType, part.getDataUri(), part.getData());
    145             if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
    146                 media = new TextModel(context, contentType, src,
    147                         part.getCharset(), wrapper, regionModel);
    148             } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) {
    149                 media = new ImageModel(context, contentType, src,
    150                         wrapper, regionModel);
    151             } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) {
    152                 media = new VideoModel(context, contentType, src,
    153                         wrapper, regionModel);
    154             } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
    155                 media = new AudioModel(context, contentType, src,
    156                         wrapper);
    157             } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) {
    158                 String drmContentType = wrapper.getContentType();
    159                 if (ContentType.isTextType(drmContentType)) {
    160                     media = new TextModel(context, contentType, src,
    161                             part.getCharset(), wrapper, regionModel);
    162                 } else if (ContentType.isImageType(drmContentType)) {
    163                     media = new ImageModel(context, contentType, src,
    164                             wrapper, regionModel);
    165                 } else if (ContentType.isVideoType(drmContentType)) {
    166                     media = new VideoModel(context, contentType, src,
    167                             wrapper, regionModel);
    168                 } else if (ContentType.isAudioType(drmContentType)) {
    169                     media = new AudioModel(context, contentType, src,
    170                             wrapper);
    171                 } else {
    172                     Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: "
    173                             + contentType);
    174                     media = createEmptyTextModel(context, wrapper, regionModel);
    175                 }
    176             } else {
    177                 throw new IllegalArgumentException("Unsupported TAG: " + tag);
    178             }
    179         } else {
    180             if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
    181                 media = new TextModel(context, contentType, src,
    182                         part.getCharset(), part.getData(), regionModel);
    183             } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) {
    184                 media = new ImageModel(context, contentType, src,
    185                         part.getDataUri(), regionModel);
    186             } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) {
    187                 media = new VideoModel(context, contentType, src,
    188                         part.getDataUri(), regionModel);
    189             } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
    190                 media = new AudioModel(context, contentType, src,
    191                         part.getDataUri());
    192             } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) {
    193                 if (ContentType.isTextType(contentType)) {
    194                     media = new TextModel(context, contentType, src,
    195                             part.getCharset(), part.getData(), regionModel);
    196                 } else if (ContentType.isImageType(contentType)) {
    197                     media = new ImageModel(context, contentType, src,
    198                             part.getDataUri(), regionModel);
    199                 } else if (ContentType.isVideoType(contentType)) {
    200                     media = new VideoModel(context, contentType, src,
    201                             part.getDataUri(), regionModel);
    202                 } else if (ContentType.isAudioType(contentType)) {
    203                     media = new AudioModel(context, contentType, src,
    204                             part.getDataUri());
    205                 } else {
    206                     Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: "
    207                             + contentType);
    208                     media = createEmptyTextModel(context, null, regionModel);
    209                 }
    210             } else {
    211                 throw new IllegalArgumentException("Unsupported TAG: " + tag);
    212             }
    213         }
    214 
    215         // Set 'begin' property.
    216         int begin = 0;
    217         TimeList tl = sme.getBegin();
    218         if ((tl != null) && (tl.getLength() > 0)) {
    219             // We only support a single begin value.
    220             Time t = tl.item(0);
    221             begin = (int) (t.getResolvedOffset() * 1000);
    222         }
    223         media.setBegin(begin);
    224 
    225         // Set 'duration' property.
    226         int duration = (int) (sme.getDur() * 1000);
    227         if (duration <= 0) {
    228             tl = sme.getEnd();
    229             if ((tl != null) && (tl.getLength() > 0)) {
    230                 // We only support a single end value.
    231                 Time t = tl.item(0);
    232                 if (t.getTimeType() != Time.SMIL_TIME_INDEFINITE) {
    233                     duration = (int) (t.getResolvedOffset() * 1000) - begin;
    234 
    235                     if (duration == 0 &&
    236                             (media instanceof AudioModel || media instanceof VideoModel)) {
    237                         duration = MmsConfig.getMinimumSlideElementDuration();
    238                         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
    239                             Log.d(TAG, "[MediaModelFactory] compute new duration for " + tag +
    240                                     ", duration=" + duration);
    241                         }
    242                     }
    243                 }
    244             }
    245         }
    246 
    247         media.setDuration(duration);
    248 
    249         if (!MmsConfig.getSlideDurationEnabled()) {
    250             /**
    251              * Because The slide duration is not supported by mmsc,
    252              * the device has to set fill type as FILL_FREEZE.
    253              * If not, the media will disappear while rotating the screen
    254              * in the slide show play view.
    255              */
    256             media.setFill(sme.FILL_FREEZE);
    257         } else {
    258             // Set 'fill' property.
    259             media.setFill(sme.getFill());
    260         }
    261         return media;
    262     }
    263 }
    264