• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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("&lt;","<")
88             .replaceAll("&gt;", ">")
89             .replaceAll("&quot;","\"")
90             .replaceAll("&apos;","'")
91             .replaceAll("&amp;", "&");
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