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