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 = LogTag.TAG; 40 getMediaModel(Context context, SMILMediaElement sme, LayoutModel layouts, PduBody pb)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 findPart(PduBody pb, String src)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 unescapeXML(String str)82 private static String unescapeXML(String str) { 83 return str.replaceAll("<","<") 84 .replaceAll(">", ">") 85 .replaceAll(""","\"") 86 .replaceAll("'","'") 87 .replaceAll("&", "&"); 88 } 89 getRegionMediaModel(Context context, String tag, String src, SMILRegionMediaElement srme, LayoutModel layouts, PduPart part)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. createEmptyTextModel(Context context, RegionModel regionModel)119 private static MediaModel createEmptyTextModel(Context context, RegionModel regionModel) 120 throws IOException { 121 return new TextModel(context, ContentType.TEXT_PLAIN, null, regionModel); 122 } 123 getGenericMediaModel(Context context, String tag, String src, SMILMediaElement sme, PduPart part, RegionModel regionModel)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