• 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.ContentRestrictionException;
21 import com.android.mms.dom.smil.SmilParElementImpl;
22 import com.google.android.mms.ContentType;
23 
24 import org.w3c.dom.events.Event;
25 import org.w3c.dom.events.EventListener;
26 import org.w3c.dom.smil.ElementTime;
27 
28 import android.util.Config;
29 import android.util.Log;
30 import android.text.TextUtils;
31 
32 import java.util.ArrayList;
33 import java.util.Collection;
34 import java.util.Iterator;
35 import java.util.List;
36 import java.util.ListIterator;
37 
38 public class SlideModel extends Model implements List<MediaModel>, EventListener {
39     public static final String TAG = "Mms/slideshow";
40     private static final boolean DEBUG = false;
41     private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
42     private static final int DEFAULT_SLIDE_DURATION = 5000;
43 
44     private final ArrayList<MediaModel> mMedia = new ArrayList<MediaModel>();
45 
46     private MediaModel mText;
47     private MediaModel mImage;
48     private MediaModel mAudio;
49     private MediaModel mVideo;
50 
51     private boolean mCanAddImage = true;
52     private boolean mCanAddAudio = true;
53     private boolean mCanAddVideo = true;
54 
55     private int mDuration;
56     private boolean mVisible = true;
57     private short mFill;
58     private int mSlideSize;
59     private SlideshowModel mParent;
60 
SlideModel(SlideshowModel slideshow)61     public SlideModel(SlideshowModel slideshow) {
62         this(DEFAULT_SLIDE_DURATION, slideshow);
63     }
64 
SlideModel(int duration, SlideshowModel slideshow)65     public SlideModel(int duration, SlideshowModel slideshow) {
66         mDuration = duration;
67         mParent = slideshow;
68     }
69 
70     /**
71      * Create a SlideModel with exist media collection.
72      *
73      * @param duration The duration of the slide.
74      * @param mediaList The exist media collection.
75      *
76      * @throws IllegalStateException One or more media in the mediaList cannot
77      *         be added into the slide due to a slide cannot contain image
78      *         and video or audio and video at the same time.
79      */
SlideModel(int duration, ArrayList<MediaModel> mediaList)80     public SlideModel(int duration, ArrayList<MediaModel> mediaList) {
81         mDuration = duration;
82 
83         int maxDur = 0;
84         for (MediaModel media : mediaList) {
85             internalAdd(media);
86 
87             int mediaDur = media.getDuration();
88             if (mediaDur > maxDur) {
89                 maxDur = mediaDur;
90             }
91         }
92 
93         updateDuration(maxDur);
94     }
95 
internalAdd(MediaModel media)96     private void internalAdd(MediaModel media) throws IllegalStateException {
97         if (media == null) {
98             // Don't add null value into the list.
99             return;
100         }
101 
102         if (media.isText()) {
103             String contentType = media.getContentType();
104             if (TextUtils.isEmpty(contentType) || ContentType.TEXT_PLAIN.equals(contentType)
105                     || ContentType.TEXT_HTML.equals(contentType)) {
106                 internalAddOrReplace(mText, media);
107                 mText = media;
108             } else {
109                 Log.w(TAG, "[SlideModel] content type " + media.getContentType() +
110                         " isn't supported (as text)");
111             }
112         } else if (media.isImage()) {
113             if (mCanAddImage) {
114                 internalAddOrReplace(mImage, media);
115                 mImage = media;
116                 mCanAddVideo = false;
117             } else {
118                 throw new IllegalStateException();
119             }
120         } else if (media.isAudio()) {
121             if (mCanAddAudio) {
122                 internalAddOrReplace(mAudio, media);
123                 mAudio = media;
124                 mCanAddVideo = false;
125             } else {
126                 throw new IllegalStateException();
127             }
128         } else if (media.isVideo()) {
129             if (mCanAddVideo) {
130                 internalAddOrReplace(mVideo, media);
131                 mVideo = media;
132                 mCanAddImage = false;
133                 mCanAddAudio = false;
134             } else {
135                 throw new IllegalStateException();
136             }
137         }
138     }
139 
internalAddOrReplace(MediaModel old, MediaModel media)140     private void internalAddOrReplace(MediaModel old, MediaModel media) {
141         // If the media is resizable, at this point consider it to be zero length.
142         // Just before we send the slideshow, we take the remaining space in the
143         // slideshow and equally allocate it to all the resizeable media items and resize them.
144         int addSize = media.getMediaResizable() ? 0 : media.getMediaSize();
145         int removeSize;
146         if (old == null) {
147             if (null != mParent) {
148                 mParent.checkMessageSize(addSize);
149             }
150             mMedia.add(media);
151             increaseSlideSize(addSize);
152             increaseMessageSize(addSize);
153         } else {
154             removeSize = old.getMediaSize();
155             if (addSize > removeSize) {
156                 if (null != mParent) {
157                     mParent.checkMessageSize(addSize - removeSize);
158                 }
159                 increaseSlideSize(addSize - removeSize);
160                 increaseMessageSize(addSize - removeSize);
161             } else {
162                 decreaseSlideSize(removeSize - addSize);
163                 decreaseMessageSize(removeSize - addSize);
164             }
165             mMedia.set(mMedia.indexOf(old), media);
166             old.unregisterAllModelChangedObservers();
167         }
168 
169         for (IModelChangedObserver observer : mModelChangedObservers) {
170             media.registerModelChangedObserver(observer);
171         }
172     }
173 
internalRemove(Object object)174     private boolean internalRemove(Object object) {
175         if (mMedia.remove(object)) {
176             if (object instanceof TextModel) {
177                 mText = null;
178             } else if (object instanceof ImageModel) {
179                 mImage = null;
180                 mCanAddVideo = true;
181             } else if (object instanceof AudioModel) {
182                 mAudio = null;
183                 mCanAddVideo = true;
184             } else if (object instanceof VideoModel) {
185                 mVideo = null;
186                 mCanAddImage = true;
187                 mCanAddAudio = true;
188             }
189             // If the media is resizable, at this point consider it to be zero length.
190             // Just before we send the slideshow, we take the remaining space in the
191             // slideshow and equally allocate it to all the resizeable media items and resize them.
192             int decreaseSize = ((MediaModel) object).getMediaResizable() ? 0
193                                         : ((MediaModel) object).getMediaSize();
194             decreaseSlideSize(decreaseSize);
195             decreaseMessageSize(decreaseSize);
196 
197             ((Model) object).unregisterAllModelChangedObservers();
198 
199             return true;
200         }
201 
202         return false;
203     }
204 
205     /**
206      * @return the mDuration
207      */
getDuration()208     public int getDuration() {
209         return mDuration;
210     }
211 
212     /**
213      * @param duration the mDuration to set
214      */
setDuration(int duration)215     public void setDuration(int duration) {
216         mDuration = duration;
217         notifyModelChanged(true);
218     }
219 
getSlideSize()220     public int getSlideSize() {
221         return mSlideSize;
222     }
223 
increaseSlideSize(int increaseSize)224     public void increaseSlideSize(int increaseSize) {
225         if (increaseSize > 0) {
226             mSlideSize += increaseSize;
227         }
228     }
229 
decreaseSlideSize(int decreaseSize)230     public void decreaseSlideSize(int decreaseSize) {
231         if (decreaseSize > 0) {
232             mSlideSize -= decreaseSize;
233         }
234     }
235 
setParent(SlideshowModel parent)236     public void setParent(SlideshowModel parent) {
237         mParent = parent;
238     }
239 
increaseMessageSize(int increaseSize)240     public void increaseMessageSize(int increaseSize) {
241         if ((increaseSize > 0) && (null != mParent)) {
242             int size = mParent.getCurrentMessageSize();
243             size += increaseSize;
244             mParent.setCurrentMessageSize(size);
245         }
246     }
247 
decreaseMessageSize(int decreaseSize)248     public void decreaseMessageSize(int decreaseSize) {
249         if ((decreaseSize > 0) && (null != mParent)) {
250             int size = mParent.getCurrentMessageSize();
251             size -= decreaseSize;
252             mParent.setCurrentMessageSize(size);
253         }
254     }
255 
256     //
257     // Implement List<E> interface.
258     //
259 
260     /**
261      * Add a MediaModel to the slide. If the slide has already contained
262      * a media object in the same type, the media object will be replaced by
263      * the new one.
264      *
265      * @param object A media object to be added into the slide.
266      * @return true
267      * @throws IllegalStateException One or more media in the mediaList cannot
268      *         be added into the slide due to a slide cannot contain image
269      *         and video or audio and video at the same time.
270      * @throws ContentRestrictionException when can not add this object.
271      *
272      */
add(MediaModel object)273     public boolean add(MediaModel object) {
274         internalAdd(object);
275         notifyModelChanged(true);
276         return true;
277     }
278 
addAll(Collection<? extends MediaModel> collection)279     public boolean addAll(Collection<? extends MediaModel> collection) {
280         throw new UnsupportedOperationException("Operation not supported.");
281     }
282 
clear()283     public void clear() {
284         if (mMedia.size() > 0) {
285             for (MediaModel media : mMedia) {
286                 media.unregisterAllModelChangedObservers();
287                 int decreaseSize = media.getMediaSize();
288                 decreaseSlideSize(decreaseSize);
289                 decreaseMessageSize(decreaseSize);
290             }
291             mMedia.clear();
292 
293             mText = null;
294             mImage = null;
295             mAudio = null;
296             mVideo = null;
297 
298             mCanAddImage = true;
299             mCanAddAudio = true;
300             mCanAddVideo = true;
301 
302             notifyModelChanged(true);
303         }
304     }
305 
contains(Object object)306     public boolean contains(Object object) {
307         return mMedia.contains(object);
308     }
309 
containsAll(Collection<?> collection)310     public boolean containsAll(Collection<?> collection) {
311         return mMedia.containsAll(collection);
312     }
313 
isEmpty()314     public boolean isEmpty() {
315         return mMedia.isEmpty();
316     }
317 
iterator()318     public Iterator<MediaModel> iterator() {
319         return mMedia.iterator();
320     }
321 
remove(Object object)322     public boolean remove(Object object) {
323         if ((object != null) && (object instanceof MediaModel)
324                 && internalRemove(object)) {
325             notifyModelChanged(true);
326             return true;
327         }
328         return false;
329     }
330 
removeAll(Collection<?> collection)331     public boolean removeAll(Collection<?> collection) {
332         throw new UnsupportedOperationException("Operation not supported.");
333     }
334 
retainAll(Collection<?> collection)335     public boolean retainAll(Collection<?> collection) {
336         throw new UnsupportedOperationException("Operation not supported.");
337     }
338 
size()339     public int size() {
340         return mMedia.size();
341     }
342 
toArray()343     public Object[] toArray() {
344         return mMedia.toArray();
345     }
346 
toArray(T[] array)347     public <T> T[] toArray(T[] array) {
348         return mMedia.toArray(array);
349     }
350 
add(int location, MediaModel object)351     public void add(int location, MediaModel object) {
352         throw new UnsupportedOperationException("Operation not supported.");
353     }
354 
addAll(int location, Collection<? extends MediaModel> collection)355     public boolean addAll(int location,
356             Collection<? extends MediaModel> collection) {
357         throw new UnsupportedOperationException("Operation not supported.");
358     }
359 
get(int location)360     public MediaModel get(int location) {
361         if (mMedia.size() == 0) {
362             return null;
363         }
364 
365         return mMedia.get(location);
366     }
367 
indexOf(Object object)368     public int indexOf(Object object) {
369         return mMedia.indexOf(object);
370     }
371 
lastIndexOf(Object object)372     public int lastIndexOf(Object object) {
373         return mMedia.lastIndexOf(object);
374     }
375 
listIterator()376     public ListIterator<MediaModel> listIterator() {
377         return mMedia.listIterator();
378     }
379 
listIterator(int location)380     public ListIterator<MediaModel> listIterator(int location) {
381         return mMedia.listIterator(location);
382     }
383 
remove(int location)384     public MediaModel remove(int location) {
385         MediaModel media = mMedia.get(location);
386         if ((media != null) && internalRemove(media)) {
387             notifyModelChanged(true);
388         }
389         return media;
390     }
391 
set(int location, MediaModel object)392     public MediaModel set(int location, MediaModel object) {
393         throw new UnsupportedOperationException("Operation not supported.");
394     }
395 
subList(int start, int end)396     public List<MediaModel> subList(int start, int end) {
397         return mMedia.subList(start, end);
398     }
399 
400     /**
401      * @return the mVisible
402      */
isVisible()403     public boolean isVisible() {
404         return mVisible;
405     }
406 
407     /**
408      * @param visible the mVisible to set
409      */
setVisible(boolean visible)410     public void setVisible(boolean visible) {
411         mVisible = visible;
412         notifyModelChanged(true);
413     }
414 
415     /**
416      * @return the mFill
417      */
getFill()418     public short getFill() {
419         return mFill;
420     }
421 
422     /**
423      * @param fill the mFill to set
424      */
setFill(short fill)425     public void setFill(short fill) {
426         mFill = fill;
427         notifyModelChanged(true);
428     }
429 
430     @Override
registerModelChangedObserverInDescendants( IModelChangedObserver observer)431     protected void registerModelChangedObserverInDescendants(
432             IModelChangedObserver observer) {
433         for (MediaModel media : mMedia) {
434             media.registerModelChangedObserver(observer);
435         }
436     }
437 
438     @Override
unregisterModelChangedObserverInDescendants( IModelChangedObserver observer)439     protected void unregisterModelChangedObserverInDescendants(
440             IModelChangedObserver observer) {
441         for (MediaModel media : mMedia) {
442             media.unregisterModelChangedObserver(observer);
443         }
444     }
445 
446     @Override
unregisterAllModelChangedObserversInDescendants()447     protected void unregisterAllModelChangedObserversInDescendants() {
448         for (MediaModel media : mMedia) {
449             media.unregisterAllModelChangedObservers();
450         }
451     }
452 
453     // EventListener Interface
handleEvent(Event evt)454     public void handleEvent(Event evt) {
455         if (evt.getType().equals(SmilParElementImpl.SMIL_SLIDE_START_EVENT)) {
456             if (LOCAL_LOGV) {
457                 Log.v(TAG, "Start to play slide: " + this);
458             }
459             mVisible = true;
460         } else if (mFill != ElementTime.FILL_FREEZE) {
461             if (LOCAL_LOGV) {
462                 Log.v(TAG, "Stop playing slide: " + this);
463             }
464             mVisible = false;
465         }
466 
467         notifyModelChanged(false);
468     }
469 
hasText()470     public boolean hasText() {
471         return mText != null;
472     }
473 
hasImage()474     public boolean hasImage() {
475         return mImage != null;
476     }
477 
hasAudio()478     public boolean hasAudio() {
479         return mAudio != null;
480     }
481 
hasVideo()482     public boolean hasVideo() {
483         return mVideo != null;
484     }
485 
removeText()486     public boolean removeText() {
487         return remove(mText);
488     }
489 
removeImage()490     public boolean removeImage() {
491         return remove(mImage);
492     }
493 
removeAudio()494     public boolean removeAudio() {
495         return remove(mAudio);
496     }
497 
removeVideo()498     public boolean removeVideo() {
499         return remove(mVideo);
500     }
501 
getText()502     public TextModel getText() {
503         return (TextModel) mText;
504     }
505 
getImage()506     public ImageModel getImage() {
507         return (ImageModel) mImage;
508     }
509 
getAudio()510     public AudioModel getAudio() {
511         return (AudioModel) mAudio;
512     }
513 
getVideo()514     public VideoModel getVideo() {
515         return (VideoModel) mVideo;
516     }
517 
updateDuration(int duration)518     public void updateDuration(int duration) {
519         if (duration <= 0) {
520             return;
521         }
522 
523         if ((duration > mDuration)
524                 || (mDuration == DEFAULT_SLIDE_DURATION)) {
525             mDuration = duration;
526         }
527     }
528 }
529