| /* |
| * Copyright (C) 2008 Esmertec AG. |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.mms.model; |
| |
| import java.io.IOException; |
| |
| import org.w3c.dom.smil.SMILMediaElement; |
| import org.w3c.dom.smil.SMILRegionElement; |
| import org.w3c.dom.smil.SMILRegionMediaElement; |
| import org.w3c.dom.smil.Time; |
| import org.w3c.dom.smil.TimeList; |
| |
| import android.content.Context; |
| import android.util.Log; |
| |
| import com.android.mms.LogTag; |
| import com.android.mms.MmsConfig; |
| import com.google.android.mms.ContentType; |
| import com.google.android.mms.MmsException; |
| import com.google.android.mms.pdu.PduBody; |
| import com.google.android.mms.pdu.PduPart; |
| |
| public class MediaModelFactory { |
| private static final String TAG = "Mms:media"; |
| |
| public static MediaModel getMediaModel(Context context, |
| SMILMediaElement sme, LayoutModel layouts, PduBody pb) |
| throws IOException, IllegalArgumentException, MmsException { |
| String tag = sme.getTagName(); |
| String src = sme.getSrc(); |
| PduPart part = findPart(pb, src); |
| |
| if (sme instanceof SMILRegionMediaElement) { |
| return getRegionMediaModel( |
| context, tag, src, (SMILRegionMediaElement) sme, layouts, part); |
| } else { |
| return getGenericMediaModel( |
| context, tag, src, sme, part, null); |
| } |
| } |
| |
| private static PduPart findPart(PduBody pb, String src) { |
| PduPart part = null; |
| |
| if (src != null) { |
| src = unescapeXML(src); |
| if (src.startsWith("cid:")) { |
| part = pb.getPartByContentId("<" + src.substring("cid:".length()) + ">"); |
| } else { |
| part = pb.getPartByName(src); |
| if (part == null) { |
| part = pb.getPartByFileName(src); |
| if (part == null) { |
| part = pb.getPartByContentLocation(src); |
| } |
| } |
| } |
| } |
| |
| if (part != null) { |
| return part; |
| } |
| |
| throw new IllegalArgumentException("No part found for the model."); |
| } |
| |
| private static String unescapeXML(String str) { |
| return str.replaceAll("<","<") |
| .replaceAll(">", ">") |
| .replaceAll(""","\"") |
| .replaceAll("'","'") |
| .replaceAll("&", "&"); |
| } |
| |
| private static MediaModel getRegionMediaModel(Context context, |
| String tag, String src, SMILRegionMediaElement srme, |
| LayoutModel layouts, PduPart part) throws IOException, MmsException { |
| SMILRegionElement sre = srme.getRegion(); |
| if (sre != null) { |
| RegionModel region = layouts.findRegionById(sre.getId()); |
| if (region != null) { |
| return getGenericMediaModel(context, tag, src, srme, part, region); |
| } |
| } else { |
| String rId = null; |
| |
| if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) { |
| rId = LayoutModel.TEXT_REGION_ID; |
| } else { |
| rId = LayoutModel.IMAGE_REGION_ID; |
| } |
| |
| RegionModel region = layouts.findRegionById(rId); |
| if (region != null) { |
| return getGenericMediaModel(context, tag, src, srme, part, region); |
| } |
| } |
| |
| throw new IllegalArgumentException("Region not found or bad region ID."); |
| } |
| |
| // When we encounter a content type we can't handle, such as "application/vnd.smaf", instead |
| // of throwing an exception and crashing, insert an empty TextModel in its place. |
| private static MediaModel createEmptyTextModel(Context context, RegionModel regionModel) |
| throws IOException { |
| return new TextModel(context, ContentType.TEXT_PLAIN, null, regionModel); |
| } |
| |
| private static MediaModel getGenericMediaModel(Context context, |
| String tag, String src, SMILMediaElement sme, PduPart part, |
| RegionModel regionModel) throws IOException, MmsException { |
| byte[] bytes = part.getContentType(); |
| if (bytes == null) { |
| throw new IllegalArgumentException( |
| "Content-Type of the part may not be null."); |
| } |
| |
| String contentType = new String(bytes); |
| MediaModel media = null; |
| if (tag.equals(SmilHelper.ELEMENT_TAG_TEXT)) { |
| media = new TextModel(context, contentType, src, |
| part.getCharset(), part.getData(), regionModel); |
| } else if (tag.equals(SmilHelper.ELEMENT_TAG_IMAGE)) { |
| media = new ImageModel(context, contentType, src, |
| part.getDataUri(), regionModel); |
| } else if (tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)) { |
| media = new VideoModel(context, contentType, src, |
| part.getDataUri(), regionModel); |
| } else if (tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) { |
| media = new AudioModel(context, contentType, src, |
| part.getDataUri()); |
| } else if (tag.equals(SmilHelper.ELEMENT_TAG_REF)) { |
| if (ContentType.isTextType(contentType)) { |
| media = new TextModel(context, contentType, src, |
| part.getCharset(), part.getData(), regionModel); |
| } else if (ContentType.isImageType(contentType)) { |
| media = new ImageModel(context, contentType, src, |
| part.getDataUri(), regionModel); |
| } else if (ContentType.isVideoType(contentType)) { |
| media = new VideoModel(context, contentType, src, |
| part.getDataUri(), regionModel); |
| } else if (ContentType.isAudioType(contentType)) { |
| media = new AudioModel(context, contentType, src, |
| part.getDataUri()); |
| } else { |
| Log.d(TAG, "[MediaModelFactory] getGenericMediaModel Unsupported Content-Type: " |
| + contentType); |
| media = createEmptyTextModel(context, regionModel); |
| } |
| } else { |
| throw new IllegalArgumentException("Unsupported TAG: " + tag); |
| } |
| |
| // Set 'begin' property. |
| int begin = 0; |
| TimeList tl = sme.getBegin(); |
| if ((tl != null) && (tl.getLength() > 0)) { |
| // We only support a single begin value. |
| Time t = tl.item(0); |
| begin = (int) (t.getResolvedOffset() * 1000); |
| } |
| media.setBegin(begin); |
| |
| // Set 'duration' property. |
| int duration = (int) (sme.getDur() * 1000); |
| if (duration <= 0) { |
| tl = sme.getEnd(); |
| if ((tl != null) && (tl.getLength() > 0)) { |
| // We only support a single end value. |
| Time t = tl.item(0); |
| if (t.getTimeType() != Time.SMIL_TIME_INDEFINITE) { |
| duration = (int) (t.getResolvedOffset() * 1000) - begin; |
| |
| if (duration == 0 && |
| (media instanceof AudioModel || media instanceof VideoModel)) { |
| duration = MmsConfig.getMinimumSlideElementDuration(); |
| if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) { |
| Log.d(TAG, "[MediaModelFactory] compute new duration for " + tag + |
| ", duration=" + duration); |
| } |
| } |
| } |
| } |
| } |
| |
| media.setDuration(duration); |
| |
| if (!MmsConfig.getSlideDurationEnabled()) { |
| /** |
| * Because The slide duration is not supported by mmsc, |
| * the device has to set fill type as FILL_FREEZE. |
| * If not, the media will disappear while rotating the screen |
| * in the slide show play view. |
| */ |
| media.setFill(sme.FILL_FREEZE); |
| } else { |
| // Set 'fill' property. |
| media.setFill(sme.getFill()); |
| } |
| return media; |
| } |
| } |