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