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 getMediaModel(Context context, SMILMediaElement sme, LayoutModel layouts, PduBody pb)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 findPart(PduBody pb, String src)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 unescapeXML(String str)86 private static String unescapeXML(String str) { 87 return str.replaceAll("<","<") 88 .replaceAll(">", ">") 89 .replaceAll(""","\"") 90 .replaceAll("'","'") 91 .replaceAll("&", "&"); 92 } 93 getRegionMediaModel(Context context, String tag, String src, SMILRegionMediaElement srme, LayoutModel layouts, PduPart part)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. createEmptyTextModel(Context context, DrmWrapper wrapper, RegionModel regionModel)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 getGenericMediaModel(Context context, String tag, String src, SMILMediaElement sme, PduPart part, RegionModel regionModel)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