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 com.google.android.mms.ContentType;
     24 import com.google.android.mms.MmsException;
     25 import com.google.android.mms.pdu.CharacterSets;
     26 import com.google.android.mms.pdu.PduBody;
     27 import com.google.android.mms.pdu.PduPart;
     28 
     29 import org.w3c.dom.smil.SMILMediaElement;
     30 import org.w3c.dom.smil.SMILRegionElement;
     31 import org.w3c.dom.smil.SMILRegionMediaElement;
     32 import org.w3c.dom.smil.Time;
     33 import org.w3c.dom.smil.TimeList;
     34 
     35 import android.content.Context;
     36 import android.util.Log;
     37 
     38 import java.io.IOException;
     39 
     40 public class MediaModelFactory {
     41     private static final String TAG = "Mms:media";
     42 
     43     public static MediaModel getMediaModel(Context context,
     44             SMILMediaElement sme, LayoutModel layouts, PduBody pb)
     45             throws IOException, IllegalArgumentException, MmsException {
     46         String tag = sme.getTagName();
     47         String src = sme.getSrc();
     48         PduPart part = findPart(pb, src);
     49 
     50         if (sme instanceof SMILRegionMediaElement) {
     51             return getRegionMediaModel(
     52                     context, tag, src, (SMILRegionMediaElement) sme, layouts, part);
     53         } else {
     54             return getGenericMediaModel(
     55                     context, tag, src, sme, part, null);
     56         }
     57     }
     58 
     59     private static PduPart findPart(PduBody pb, String src) {
     60         PduPart part = null;
     61 
     62         if (src != null) {
     63             src = unescapeXML(src);
     64             if (src.startsWith("cid:")) {
     65                 part = pb.getPartByContentId("<" + src.substring("cid:".length()) + ">");
     66             } else {
     67                 part = pb.getPartByName(src);
     68                 if (part == null) {
     69                     part = pb.getPartByFileName(src);
     70                     if (part == null) {
     71                         part = pb.getPartByContentLocation(src);
     72                     }
     73                 }
     74             }
     75         }
     76 
     77         if (part != null) {
     78             return part;
     79         }
     80 
     81         throw new IllegalArgumentException("No part found for the model.");
     82     }
     83 
     84     private static String unescapeXML(String str) {
     85         return str.replaceAll("&lt;","<")
     86             .replaceAll("&gt;", ">")
     87             .replaceAll("&quot;","\"")
     88             .replaceAll("&apos;","'")
     89             .replaceAll("&amp;", "&");
     90     }
     91 
     92     private static MediaModel getRegionMediaModel(Context context,
     93             String tag, String src, SMILRegionMediaElement srme,
     94             LayoutModel layouts, PduPart part) throws IOException, MmsException {
     95         SMILRegionElement sre = srme.getRegion();
     96         if (sre != null) {
     97             RegionModel region = layouts.findRegionById(sre.getId());
     98             if (region != null) {
     99                 return getGenericMediaModel(context, tag, src, srme, part, region);
    100             }
    101         } else {
    102             String rId = null;
    103 
    104             if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
    105                 rId = LayoutModel.TEXT_REGION_ID;
    106             } else {
    107                 rId = LayoutModel.IMAGE_REGION_ID;
    108             }
    109 
    110             RegionModel region = layouts.findRegionById(rId);
    111             if (region != null) {
    112                 return getGenericMediaModel(context, tag, src, srme, part, region);
    113             }
    114         }
    115 
    116         throw new IllegalArgumentException("Region not found or bad region ID.");
    117     }
    118 
    119     // When we encounter a content type we can't handle, such as "application/vnd.smaf", instead
    120     // of throwing an exception and crashing, insert an empty TextModel in its place.
    121     private static MediaModel createEmptyTextModel(Context context,  RegionModel regionModel)
    122             throws IOException {
    123         return new TextModel(context, ContentType.TEXT_PLAIN, null, regionModel);
    124     }
    125 
    126     private static MediaModel getGenericMediaModel(Context context,
    127             String tag, String src, SMILMediaElement sme, PduPart part,
    128             RegionModel regionModel) throws IOException, MmsException {
    129         byte[] bytes = part.getContentType();
    130         if (bytes == null) {
    131             throw new IllegalArgumentException(
    132                     "Content-Type of the part may not be null.");
    133         }
    134 
    135         String contentType = new String(bytes);
    136         MediaModel media = null;
    137         if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) {
    138             media = new TextModel(context, contentType, src,
    139                     part.getCharset(), part.getData(), regionModel);
    140         } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) {
    141             media = new ImageModel(context, contentType, src,
    142                     part.getDataUri(), regionModel);
    143         } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) {
    144             media = new VideoModel(context, contentType, src,
    145                     part.getDataUri(), regionModel);
    146         } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
    147             media = new AudioModel(context, contentType, src,
    148                     part.getDataUri());
    149         } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) {
    150             if (ContentType.isTextType(contentType)) {
    151                 media = new TextModel(context, contentType, src,
    152                         part.getCharset(), part.getData(), regionModel);
    153             } else if (ContentType.isImageType(contentType)) {
    154                 media = new ImageModel(context, contentType, src,
    155                         part.getDataUri(), regionModel);
    156             } else if (ContentType.isVideoType(contentType)) {
    157                 media = new VideoModel(context, contentType, src,
    158                         part.getDataUri(), regionModel);
    159             } else if (ContentType.isAudioType(contentType)) {
    160                 media = new AudioModel(context, contentType, src,
    161                         part.getDataUri());
    162             } else {
    163                 Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: "
    164                         + contentType);
    165                 media = createEmptyTextModel(context, regionModel);
    166             }
    167         } else {
    168             throw new IllegalArgumentException("Unsupported TAG: " + tag);
    169         }
    170 
    171         // Set 'begin' property.
    172         int begin = 0;
    173         TimeList tl = sme.getBegin();
    174         if ((tl != null) && (tl.getLength() > 0)) {
    175             // We only support a single begin value.
    176             Time t = tl.item(0);
    177             begin = (int) (t.getResolvedOffset() * 1000);
    178         }
    179         media.setBegin(begin);
    180 
    181         // Set 'duration' property.
    182         int duration = (int) (sme.getDur() * 1000);
    183         if (duration <= 0) {
    184             tl = sme.getEnd();
    185             if ((tl != null) && (tl.getLength() > 0)) {
    186                 // We only support a single end value.
    187                 Time t = tl.item(0);
    188                 if (t.getTimeType() != Time.SMIL_TIME_INDEFINITE) {
    189                     duration = (int) (t.getResolvedOffset() * 1000) - begin;
    190 
    191                     if (duration == 0 &&
    192                             (media instanceof AudioModel || media instanceof VideoModel)) {
    193                         duration = MmsConfig.getMinimumSlideElementDuration();
    194                         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
    195                             Log.d(TAG, "[MediaModelFactory] compute new duration for " + tag +
    196                                     ", duration=" + duration);
    197                         }
    198                     }
    199                 }
    200             }
    201         }
    202 
    203         media.setDuration(duration);
    204 
    205         if (!MmsConfig.getSlideDurationEnabled()) {
    206             /**
    207              * Because The slide duration is not supported by mmsc,
    208              * the device has to set fill type as FILL_FREEZE.
    209              * If not, the media will disappear while rotating the screen
    210              * in the slide show play view.
    211              */
    212             media.setFill(sme.FILL_FREEZE);
    213         } else {
    214             // Set 'fill' property.
    215             media.setFill(sme.getFill());
    216         }
    217         return media;
    218     }
    219 }
    220