• 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 
21 import com.android.mms.ContentRestrictionException;
22 import com.android.mms.ExceedMessageSizeException;
23 import com.android.mms.LogTag;
24 import com.android.mms.MmsConfig;
25 import com.android.mms.R;
26 import com.android.mms.dom.smil.parser.SmilXmlSerializer;
27 import com.android.mms.layout.LayoutManager;
28 import com.google.android.mms.ContentType;
29 import com.google.android.mms.MmsException;
30 import com.google.android.mms.pdu.GenericPdu;
31 import com.google.android.mms.pdu.MultimediaMessagePdu;
32 import com.google.android.mms.pdu.PduBody;
33 import com.google.android.mms.pdu.PduHeaders;
34 import com.google.android.mms.pdu.PduPart;
35 import com.google.android.mms.pdu.PduPersister;
36 
37 import org.w3c.dom.NodeList;
38 import org.w3c.dom.events.EventTarget;
39 import org.w3c.dom.smil.SMILDocument;
40 import org.w3c.dom.smil.SMILElement;
41 import org.w3c.dom.smil.SMILLayoutElement;
42 import org.w3c.dom.smil.SMILMediaElement;
43 import org.w3c.dom.smil.SMILParElement;
44 import org.w3c.dom.smil.SMILRegionElement;
45 import org.w3c.dom.smil.SMILRootLayoutElement;
46 
47 import android.content.ContentUris;
48 import android.content.Context;
49 import android.net.Uri;
50 import android.text.TextUtils;
51 import android.util.Log;
52 import android.widget.Toast;
53 
54 import java.io.ByteArrayOutputStream;
55 import java.io.IOException;
56 import java.util.ArrayList;
57 import java.util.Collection;
58 import java.util.Iterator;
59 import java.util.List;
60 import java.util.ListIterator;
61 
62 public class SlideshowModel extends Model
63         implements List<SlideModel>, IModelChangedObserver {
64     private static final String TAG = "Mms/slideshow";
65 
66     private final LayoutModel mLayout;
67     private final ArrayList<SlideModel> mSlides;
68     private SMILDocument mDocumentCache;
69     private PduBody mPduBodyCache;
70     private int mCurrentMessageSize;    // This is the current message size, not including
71                                         // attachments that can be resized (such as photos)
72     private int mTotalMessageSize;      // This is the computed total message size
73     private Context mContext;
74 
75     // amount of space to leave in a slideshow for text and overhead.
76     public static final int SLIDESHOW_SLOP = 1024;
77 
SlideshowModel(Context context)78     private SlideshowModel(Context context) {
79         mLayout = new LayoutModel();
80         mSlides = new ArrayList<SlideModel>();
81         mContext = context;
82     }
83 
SlideshowModel( LayoutModel layouts, ArrayList<SlideModel> slides, SMILDocument documentCache, PduBody pbCache, Context context)84     private SlideshowModel (
85             LayoutModel layouts, ArrayList<SlideModel> slides,
86             SMILDocument documentCache, PduBody pbCache,
87             Context context) {
88         mLayout = layouts;
89         mSlides = slides;
90         mContext = context;
91 
92         mDocumentCache = documentCache;
93         mPduBodyCache = pbCache;
94         for (SlideModel slide : mSlides) {
95             increaseMessageSize(slide.getSlideSize());
96             slide.setParent(this);
97         }
98     }
99 
createNew(Context context)100     public static SlideshowModel createNew(Context context) {
101         return new SlideshowModel(context);
102     }
103 
createFromMessageUri( Context context, Uri uri)104     public static SlideshowModel createFromMessageUri(
105             Context context, Uri uri) throws MmsException {
106         return createFromPduBody(context, getPduBody(context, uri));
107     }
108 
createFromPduBody(Context context, PduBody pb)109     public static SlideshowModel createFromPduBody(Context context, PduBody pb) throws MmsException {
110         SMILDocument document = SmilHelper.getDocument(pb);
111 
112         // Create root-layout model.
113         SMILLayoutElement sle = document.getLayout();
114         SMILRootLayoutElement srle = sle.getRootLayout();
115         int w = srle.getWidth();
116         int h = srle.getHeight();
117         if ((w == 0) || (h == 0)) {
118             w = LayoutManager.getInstance().getLayoutParameters().getWidth();
119             h = LayoutManager.getInstance().getLayoutParameters().getHeight();
120             srle.setWidth(w);
121             srle.setHeight(h);
122         }
123         RegionModel rootLayout = new RegionModel(
124                 null, 0, 0, w, h);
125 
126         // Create region models.
127         ArrayList<RegionModel> regions = new ArrayList<RegionModel>();
128         NodeList nlRegions = sle.getRegions();
129         int regionsNum = nlRegions.getLength();
130 
131         for (int i = 0; i < regionsNum; i++) {
132             SMILRegionElement sre = (SMILRegionElement) nlRegions.item(i);
133             RegionModel r = new RegionModel(sre.getId(), sre.getFit(),
134                     sre.getLeft(), sre.getTop(), sre.getWidth(), sre.getHeight(),
135                     sre.getBackgroundColor());
136             regions.add(r);
137         }
138         LayoutModel layouts = new LayoutModel(rootLayout, regions);
139 
140         // Create slide models.
141         SMILElement docBody = document.getBody();
142         NodeList slideNodes = docBody.getChildNodes();
143         int slidesNum = slideNodes.getLength();
144         ArrayList<SlideModel> slides = new ArrayList<SlideModel>(slidesNum);
145         int totalMessageSize = 0;
146 
147         for (int i = 0; i < slidesNum; i++) {
148             // FIXME: This is NOT compatible with the SMILDocument which is
149             // generated by some other mobile phones.
150             SMILParElement par = (SMILParElement) slideNodes.item(i);
151 
152             // Create media models for each slide.
153             NodeList mediaNodes = par.getChildNodes();
154             int mediaNum = mediaNodes.getLength();
155             ArrayList<MediaModel> mediaSet = new ArrayList<MediaModel>(mediaNum);
156 
157             for (int j = 0; j < mediaNum; j++) {
158                 SMILMediaElement sme = (SMILMediaElement) mediaNodes.item(j);
159                 try {
160                     MediaModel media = MediaModelFactory.getMediaModel(
161                             context, sme, layouts, pb);
162 
163                     /*
164                     * This is for slide duration value set.
165                     * If mms server does not support slide duration.
166                     */
167                     if (!MmsConfig.getSlideDurationEnabled()) {
168                         int mediadur = media.getDuration();
169                         float dur = par.getDur();
170                         if (dur == 0) {
171                             mediadur = MmsConfig.getMinimumSlideElementDuration() * 1000;
172                             media.setDuration(mediadur);
173                         }
174 
175                         if ((int)mediadur / 1000 != dur) {
176                             String tag = sme.getTagName();
177 
178                             if (ContentType.isVideoType(media.mContentType)
179                               || tag.equals(SmilHelper.ELEMENT_TAG_VIDEO)
180                               || ContentType.isAudioType(media.mContentType)
181                               || tag.equals(SmilHelper.ELEMENT_TAG_AUDIO)) {
182                                 /*
183                                 * add 1 sec to release and close audio/video
184                                 * for guaranteeing the audio/video playing.
185                                 * because the mmsc does not support the slide duration.
186                                 */
187                                 par.setDur((float)mediadur / 1000 + 1);
188                             } else {
189                                 /*
190                                 * If a slide has an image and an audio/video element
191                                 * and the audio/video element has longer duration than the image,
192                                 * The Image disappear before the slide play done. so have to match
193                                 * an image duration to the slide duration.
194                                 */
195                                 if ((int)mediadur / 1000 < dur) {
196                                     media.setDuration((int)dur * 1000);
197                                 } else {
198                                     if ((int)dur != 0) {
199                                         media.setDuration((int)dur * 1000);
200                                     } else {
201                                         par.setDur((float)mediadur / 1000);
202                                     }
203                                 }
204                             }
205                         }
206                     }
207                     SmilHelper.addMediaElementEventListeners(
208                             (EventTarget) sme, media);
209                     mediaSet.add(media);
210                     totalMessageSize += media.getMediaSize();
211                 } catch (IOException e) {
212                     Log.e(TAG, e.getMessage(), e);
213                 } catch (IllegalArgumentException e) {
214                     Log.e(TAG, e.getMessage(), e);
215                 }
216             }
217 
218             SlideModel slide = new SlideModel((int) (par.getDur() * 1000), mediaSet);
219             slide.setFill(par.getFill());
220             SmilHelper.addParElementEventListeners((EventTarget) par, slide);
221             slides.add(slide);
222         }
223 
224         SlideshowModel slideshow = new SlideshowModel(layouts, slides, document, pb, context);
225         slideshow.mTotalMessageSize = totalMessageSize;
226         slideshow.registerModelChangedObserver(slideshow);
227         return slideshow;
228     }
229 
toPduBody()230     public PduBody toPduBody() {
231         if (mPduBodyCache == null) {
232             mDocumentCache = SmilHelper.getDocument(this);
233             mPduBodyCache = makePduBody(mDocumentCache);
234         }
235         return mPduBodyCache;
236     }
237 
makePduBody(SMILDocument document)238     private PduBody makePduBody(SMILDocument document) {
239         PduBody pb = new PduBody();
240 
241         boolean hasForwardLock = false;
242         for (SlideModel slide : mSlides) {
243             for (MediaModel media : slide) {
244                 PduPart part = new PduPart();
245 
246                 if (media.isText()) {
247                     TextModel text = (TextModel) media;
248                     // Don't create empty text part.
249                     if (TextUtils.isEmpty(text.getText())) {
250                         continue;
251                     }
252                     // Set Charset if it's a text media.
253                     part.setCharset(text.getCharset());
254                 }
255 
256                 // Set Content-Type.
257                 part.setContentType(media.getContentType().getBytes());
258 
259                 String src = media.getSrc();
260                 String location;
261                 boolean startWithContentId = src.startsWith("cid:");
262                 if (startWithContentId) {
263                     location = src.substring("cid:".length());
264                 } else {
265                     location = src;
266                 }
267 
268                 // Set Content-Location.
269                 part.setContentLocation(location.getBytes());
270 
271                 // Set Content-Id.
272                 if (startWithContentId) {
273                     //Keep the original Content-Id.
274                     part.setContentId(location.getBytes());
275                 }
276                 else {
277                     int index = location.lastIndexOf(".");
278                     String contentId = (index == -1) ? location
279                             : location.substring(0, index);
280                     part.setContentId(contentId.getBytes());
281                 }
282 
283                 if (media.isText()) {
284                     part.setData(((TextModel) media).getText().getBytes());
285                 } else if (media.isImage() || media.isVideo() || media.isAudio()) {
286                     part.setDataUri(media.getUri());
287                 } else {
288                     Log.w(TAG, "Unsupport media: " + media);
289                 }
290 
291                 pb.addPart(part);
292             }
293         }
294 
295         // Create and insert SMIL part(as the first part) into the PduBody.
296         ByteArrayOutputStream out = new ByteArrayOutputStream();
297         SmilXmlSerializer.serialize(document, out);
298         PduPart smilPart = new PduPart();
299         smilPart.setContentId("smil".getBytes());
300         smilPart.setContentLocation("smil.xml".getBytes());
301         smilPart.setContentType(ContentType.APP_SMIL.getBytes());
302         smilPart.setData(out.toByteArray());
303         pb.addPart(0, smilPart);
304 
305         return pb;
306     }
307 
makeCopy()308     public PduBody makeCopy() {
309         return makePduBody(SmilHelper.getDocument(this));
310     }
311 
toSmilDocument()312     public SMILDocument toSmilDocument() {
313         if (mDocumentCache == null) {
314             mDocumentCache = SmilHelper.getDocument(this);
315         }
316         return mDocumentCache;
317     }
318 
getPduBody(Context context, Uri msg)319     public static PduBody getPduBody(Context context, Uri msg) throws MmsException {
320         PduPersister p = PduPersister.getPduPersister(context);
321         GenericPdu pdu = p.load(msg);
322 
323         int msgType = pdu.getMessageType();
324         if ((msgType == PduHeaders.MESSAGE_TYPE_SEND_REQ)
325                 || (msgType == PduHeaders.MESSAGE_TYPE_RETRIEVE_CONF)) {
326             return ((MultimediaMessagePdu) pdu).getBody();
327         } else {
328             throw new MmsException();
329         }
330     }
331 
setCurrentMessageSize(int size)332     public void setCurrentMessageSize(int size) {
333         mCurrentMessageSize = size;
334     }
335 
336     // getCurrentMessageSize returns the size of the message, not including resizable attachments
337     // such as photos. mCurrentMessageSize is used when adding/deleting/replacing non-resizable
338     // attachments (movies, sounds, etc) in order to compute how much size is left in the message.
339     // The difference between mCurrentMessageSize and the maxSize allowed for a message is then
340     // divided up between the remaining resizable attachments. While this function is public,
341     // it is only used internally between various MMS classes. If the UI wants to know the
342     // size of a MMS message, it should call getTotalMessageSize() instead.
getCurrentMessageSize()343     public int getCurrentMessageSize() {
344         return mCurrentMessageSize;
345     }
346 
347     // getTotalMessageSize returns the total size of the message, including resizable attachments
348     // such as photos. This function is intended to be used by the UI for displaying the size of the
349     // MMS message.
getTotalMessageSize()350     public int getTotalMessageSize() {
351         return mTotalMessageSize;
352     }
353 
increaseMessageSize(int increaseSize)354     public void increaseMessageSize(int increaseSize) {
355         if (increaseSize > 0) {
356             mCurrentMessageSize += increaseSize;
357         }
358     }
359 
decreaseMessageSize(int decreaseSize)360     public void decreaseMessageSize(int decreaseSize) {
361         if (decreaseSize > 0) {
362             mCurrentMessageSize -= decreaseSize;
363         }
364     }
365 
getLayout()366     public LayoutModel getLayout() {
367         return mLayout;
368     }
369 
370     //
371     // Implement List<E> interface.
372     //
add(SlideModel object)373     public boolean add(SlideModel object) {
374         int increaseSize = object.getSlideSize();
375         checkMessageSize(increaseSize);
376 
377         if ((object != null) && mSlides.add(object)) {
378             increaseMessageSize(increaseSize);
379             object.registerModelChangedObserver(this);
380             for (IModelChangedObserver observer : mModelChangedObservers) {
381                 object.registerModelChangedObserver(observer);
382             }
383             notifyModelChanged(true);
384             return true;
385         }
386         return false;
387     }
388 
addAll(Collection<? extends SlideModel> collection)389     public boolean addAll(Collection<? extends SlideModel> collection) {
390         throw new UnsupportedOperationException("Operation not supported.");
391     }
392 
clear()393     public void clear() {
394         if (mSlides.size() > 0) {
395             for (SlideModel slide : mSlides) {
396                 slide.unregisterModelChangedObserver(this);
397                 for (IModelChangedObserver observer : mModelChangedObservers) {
398                     slide.unregisterModelChangedObserver(observer);
399                 }
400             }
401             mCurrentMessageSize = 0;
402             mSlides.clear();
403             notifyModelChanged(true);
404         }
405     }
406 
contains(Object object)407     public boolean contains(Object object) {
408         return mSlides.contains(object);
409     }
410 
containsAll(Collection<?> collection)411     public boolean containsAll(Collection<?> collection) {
412         return mSlides.containsAll(collection);
413     }
414 
isEmpty()415     public boolean isEmpty() {
416         return mSlides.isEmpty();
417     }
418 
iterator()419     public Iterator<SlideModel> iterator() {
420         return mSlides.iterator();
421     }
422 
remove(Object object)423     public boolean remove(Object object) {
424         if ((object != null) && mSlides.remove(object)) {
425             SlideModel slide = (SlideModel) object;
426             decreaseMessageSize(slide.getSlideSize());
427             slide.unregisterAllModelChangedObservers();
428             notifyModelChanged(true);
429             return true;
430         }
431         return false;
432     }
433 
removeAll(Collection<?> collection)434     public boolean removeAll(Collection<?> collection) {
435         throw new UnsupportedOperationException("Operation not supported.");
436     }
437 
retainAll(Collection<?> collection)438     public boolean retainAll(Collection<?> collection) {
439         throw new UnsupportedOperationException("Operation not supported.");
440     }
441 
size()442     public int size() {
443         return mSlides.size();
444     }
445 
toArray()446     public Object[] toArray() {
447         return mSlides.toArray();
448     }
449 
toArray(T[] array)450     public <T> T[] toArray(T[] array) {
451         return mSlides.toArray(array);
452     }
453 
add(int location, SlideModel object)454     public void add(int location, SlideModel object) {
455         if (object != null) {
456             int increaseSize = object.getSlideSize();
457             checkMessageSize(increaseSize);
458 
459             mSlides.add(location, object);
460             increaseMessageSize(increaseSize);
461             object.registerModelChangedObserver(this);
462             for (IModelChangedObserver observer : mModelChangedObservers) {
463                 object.registerModelChangedObserver(observer);
464             }
465             notifyModelChanged(true);
466         }
467     }
468 
addAll(int location, Collection<? extends SlideModel> collection)469     public boolean addAll(int location,
470             Collection<? extends SlideModel> collection) {
471         throw new UnsupportedOperationException("Operation not supported.");
472     }
473 
get(int location)474     public SlideModel get(int location) {
475         return (location >= 0 && location < mSlides.size()) ? mSlides.get(location) : null;
476     }
477 
indexOf(Object object)478     public int indexOf(Object object) {
479         return mSlides.indexOf(object);
480     }
481 
lastIndexOf(Object object)482     public int lastIndexOf(Object object) {
483         return mSlides.lastIndexOf(object);
484     }
485 
listIterator()486     public ListIterator<SlideModel> listIterator() {
487         return mSlides.listIterator();
488     }
489 
listIterator(int location)490     public ListIterator<SlideModel> listIterator(int location) {
491         return mSlides.listIterator(location);
492     }
493 
remove(int location)494     public SlideModel remove(int location) {
495         SlideModel slide = mSlides.remove(location);
496         if (slide != null) {
497             decreaseMessageSize(slide.getSlideSize());
498             slide.unregisterAllModelChangedObservers();
499             notifyModelChanged(true);
500         }
501         return slide;
502     }
503 
set(int location, SlideModel object)504     public SlideModel set(int location, SlideModel object) {
505         SlideModel slide = mSlides.get(location);
506         if (null != object) {
507             int removeSize = 0;
508             int addSize = object.getSlideSize();
509             if (null != slide) {
510                 removeSize = slide.getSlideSize();
511             }
512             if (addSize > removeSize) {
513                 checkMessageSize(addSize - removeSize);
514                 increaseMessageSize(addSize - removeSize);
515             } else {
516                 decreaseMessageSize(removeSize - addSize);
517             }
518         }
519 
520         slide =  mSlides.set(location, object);
521         if (slide != null) {
522             slide.unregisterAllModelChangedObservers();
523         }
524 
525         if (object != null) {
526             object.registerModelChangedObserver(this);
527             for (IModelChangedObserver observer : mModelChangedObservers) {
528                 object.registerModelChangedObserver(observer);
529             }
530         }
531 
532         notifyModelChanged(true);
533         return slide;
534     }
535 
subList(int start, int end)536     public List<SlideModel> subList(int start, int end) {
537         return mSlides.subList(start, end);
538     }
539 
540     @Override
registerModelChangedObserverInDescendants( IModelChangedObserver observer)541     protected void registerModelChangedObserverInDescendants(
542             IModelChangedObserver observer) {
543         mLayout.registerModelChangedObserver(observer);
544 
545         for (SlideModel slide : mSlides) {
546             slide.registerModelChangedObserver(observer);
547         }
548     }
549 
550     @Override
unregisterModelChangedObserverInDescendants( IModelChangedObserver observer)551     protected void unregisterModelChangedObserverInDescendants(
552             IModelChangedObserver observer) {
553         mLayout.unregisterModelChangedObserver(observer);
554 
555         for (SlideModel slide : mSlides) {
556             slide.unregisterModelChangedObserver(observer);
557         }
558     }
559 
560     @Override
unregisterAllModelChangedObserversInDescendants()561     protected void unregisterAllModelChangedObserversInDescendants() {
562         mLayout.unregisterAllModelChangedObservers();
563 
564         for (SlideModel slide : mSlides) {
565             slide.unregisterAllModelChangedObservers();
566         }
567     }
568 
onModelChanged(Model model, boolean dataChanged)569     public void onModelChanged(Model model, boolean dataChanged) {
570         if (dataChanged) {
571             mDocumentCache = null;
572             mPduBodyCache = null;
573         }
574     }
575 
sync(PduBody pb)576     public void sync(PduBody pb) {
577         for (SlideModel slide : mSlides) {
578             for (MediaModel media : slide) {
579                 PduPart part = pb.getPartByContentLocation(media.getSrc());
580                 if (part != null) {
581                     media.setUri(part.getDataUri());
582                 }
583             }
584         }
585     }
586 
checkMessageSize(int increaseSize)587     public void checkMessageSize(int increaseSize) throws ContentRestrictionException {
588         ContentRestriction cr = ContentRestrictionFactory.getContentRestriction();
589         cr.checkMessageSize(mCurrentMessageSize, increaseSize, mContext.getContentResolver());
590     }
591 
592     /**
593      * Determines whether this is a "simple" slideshow.
594      * Criteria:
595      * - Exactly one slide
596      * - Exactly one multimedia attachment, but no audio
597      * - It can optionally have a caption
598     */
isSimple()599     public boolean isSimple() {
600         // There must be one (and only one) slide.
601         if (size() != 1)
602             return false;
603 
604         SlideModel slide = get(0);
605         // The slide must have either an image or video, but not both.
606         if (!(slide.hasImage() ^ slide.hasVideo()))
607             return false;
608 
609         // No audio allowed.
610         if (slide.hasAudio())
611             return false;
612 
613         return true;
614     }
615 
616     /**
617      * Make sure the text in slide 0 is no longer holding onto a reference to the text
618      * in the message text box.
619      */
prepareForSend()620     public void prepareForSend() {
621         if (size() == 1) {
622             TextModel text = get(0).getText();
623             if (text != null) {
624                 text.cloneText();
625             }
626         }
627     }
628 
629     /**
630      * Resize all the resizeable media objects to fit in the remaining size of the slideshow.
631      * This should be called off of the UI thread.
632      *
633      * @throws MmsException, ExceedMessageSizeException
634      */
finalResize(Uri messageUri)635     public void finalResize(Uri messageUri) throws MmsException, ExceedMessageSizeException {
636 
637         // Figure out if we have any media items that need to be resized and total up the
638         // sizes of the items that can't be resized.
639         int resizableCnt = 0;
640         int fixedSizeTotal = 0;
641         for (SlideModel slide : mSlides) {
642             for (MediaModel media : slide) {
643                 if (media.getMediaResizable()) {
644                     ++resizableCnt;
645                 } else {
646                     fixedSizeTotal += media.getMediaSize();
647                 }
648             }
649         }
650         if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
651             Log.v(TAG, "finalResize: original message size: " + getCurrentMessageSize() +
652                     " getMaxMessageSize: " + MmsConfig.getMaxMessageSize() +
653                     " fixedSizeTotal: " + fixedSizeTotal);
654         }
655         if (resizableCnt > 0) {
656             int remainingSize = MmsConfig.getMaxMessageSize() - fixedSizeTotal - SLIDESHOW_SLOP;
657             if (remainingSize <= 0) {
658                 throw new ExceedMessageSizeException("No room for pictures");
659             }
660             long messageId = ContentUris.parseId(messageUri);
661             int bytesPerMediaItem = remainingSize / resizableCnt;
662             // Resize the resizable media items to fit within their byte limit.
663             for (SlideModel slide : mSlides) {
664                 for (MediaModel media : slide) {
665                     if (media.getMediaResizable()) {
666                         media.resizeMedia(bytesPerMediaItem, messageId);
667                     }
668                 }
669             }
670             // One last time through to calc the real message size.
671             int totalSize = 0;
672             for (SlideModel slide : mSlides) {
673                 for (MediaModel media : slide) {
674                     totalSize += media.getMediaSize();
675                 }
676             }
677             if (Log.isLoggable(LogTag.APP, Log.VERBOSE)) {
678                 Log.v(TAG, "finalResize: new message size: " + totalSize);
679             }
680 
681             if (totalSize > MmsConfig.getMaxMessageSize()) {
682                 throw new ExceedMessageSizeException("After compressing pictures, message too big");
683             }
684             setCurrentMessageSize(totalSize);
685 
686             onModelChanged(this, true);     // clear the cached pdu body
687             PduBody pb = toPduBody();
688             // This will write out all the new parts to:
689             //      /data/data/com.android.providers.telephony/app_parts
690             // and at the same time delete the old parts.
691             PduPersister.getPduPersister(mContext).updateParts(messageUri, pb);
692         }
693     }
694 
695 }
696