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