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