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