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.ui; 19 20 import com.android.mms.R; 21 import android.drm.mobile1.DrmException; 22 import com.android.mms.model.AudioModel; 23 import com.android.mms.model.ImageModel; 24 import com.android.mms.model.LayoutModel; 25 import com.android.mms.model.MediaModel; 26 import com.android.mms.model.Model; 27 import com.android.mms.model.RegionMediaModel; 28 import com.android.mms.model.RegionModel; 29 import com.android.mms.model.SlideModel; 30 import com.android.mms.model.SlideshowModel; 31 import com.android.mms.model.TextModel; 32 import com.android.mms.model.VideoModel; 33 import com.android.mms.model.MediaModel.MediaAction; 34 import com.android.mms.ui.AdaptableSlideViewInterface.OnSizeChangedListener; 35 import com.android.mms.util.ItemLoadedCallback; 36 37 import android.content.Context; 38 import android.os.Handler; 39 import android.util.Log; 40 import android.widget.Toast; 41 42 /** 43 * A basic presenter of slides. 44 */ 45 public class SlideshowPresenter extends Presenter { 46 private static final String TAG = "SlideshowPresenter"; 47 private static final boolean DEBUG = false; 48 private static final boolean LOCAL_LOGV = false; 49 50 protected int mLocation; 51 protected final int mSlideNumber; 52 53 protected float mWidthTransformRatio = 1.0f; 54 protected float mHeightTransformRatio = 1.0f; 55 56 // Since only the original thread that created a view hierarchy can touch 57 // its views, we have to use Handler to manage the views in the some 58 // callbacks such as onModelChanged(). 59 protected final Handler mHandler = new Handler(); 60 61 public SlideshowPresenter(Context context, ViewInterface view, Model model) { 62 super(context, view, model); 63 mLocation = 0; 64 mSlideNumber = ((SlideshowModel) mModel).size(); 65 66 if (view instanceof AdaptableSlideViewInterface) { 67 ((AdaptableSlideViewInterface) view).setOnSizeChangedListener( 68 mViewSizeChangedListener); 69 } 70 } 71 72 private final OnSizeChangedListener mViewSizeChangedListener = 73 new OnSizeChangedListener() { 74 public void onSizeChanged(int width, int height) { 75 LayoutModel layout = ((SlideshowModel) mModel).getLayout(); 76 mWidthTransformRatio = getWidthTransformRatio( 77 width, layout.getLayoutWidth()); 78 mHeightTransformRatio = getHeightTransformRatio( 79 height, layout.getLayoutHeight()); 80 // The ratio indicates how to reduce the source to match the View, 81 // so the larger one should be used. 82 float ratio = mWidthTransformRatio > mHeightTransformRatio ? 83 mWidthTransformRatio : mHeightTransformRatio; 84 mWidthTransformRatio = ratio; 85 mHeightTransformRatio = ratio; 86 if (LOCAL_LOGV) { 87 Log.v(TAG, "ratio_w = " + mWidthTransformRatio 88 + ", ratio_h = " + mHeightTransformRatio); 89 } 90 } 91 }; 92 93 private float getWidthTransformRatio(int width, int layoutWidth) { 94 if (width > 0) { 95 return (float) layoutWidth / (float) width; 96 } 97 return 1.0f; 98 } 99 100 private float getHeightTransformRatio(int height, int layoutHeight) { 101 if (height > 0) { 102 return (float) layoutHeight / (float) height; 103 } 104 return 1.0f; 105 } 106 107 private int transformWidth(int width) { 108 return (int) (width / mWidthTransformRatio); 109 } 110 111 private int transformHeight(int height) { 112 return (int) (height / mHeightTransformRatio); 113 } 114 115 @Override 116 public void present(ItemLoadedCallback callback) { 117 // This is called to show a full-screen slideshow. Presently, all parts of 118 // a slideshow (images, sounds, etc.) are loaded and displayed on the UI thread. 119 presentSlide((SlideViewInterface) mView, ((SlideshowModel) mModel).get(mLocation)); 120 } 121 122 /** 123 * @param view 124 * @param model 125 */ 126 protected void presentSlide(SlideViewInterface view, SlideModel model) { 127 view.reset(); 128 129 for (MediaModel media : model) { 130 if (media instanceof RegionMediaModel) { 131 presentRegionMedia(view, (RegionMediaModel) media, true); 132 } else if (media.isAudio()) { 133 presentAudio(view, (AudioModel) media, true); 134 } 135 } 136 } 137 138 /** 139 * @param view 140 */ 141 protected void presentRegionMedia(SlideViewInterface view, 142 RegionMediaModel rMedia, boolean dataChanged) { 143 RegionModel r = (rMedia).getRegion(); 144 if (rMedia.isText()) { 145 presentText(view, (TextModel) rMedia, r, dataChanged); 146 } else if (rMedia.isImage()) { 147 presentImage(view, (ImageModel) rMedia, r, dataChanged); 148 } else if (rMedia.isVideo()) { 149 presentVideo(view, (VideoModel) rMedia, r, dataChanged); 150 } 151 } 152 153 protected void presentAudio(SlideViewInterface view, AudioModel audio, 154 boolean dataChanged) { 155 // Set audio only when data changed. 156 if (dataChanged) { 157 view.setAudio(audio.getUri(), audio.getSrc(), audio.getExtras()); 158 } 159 160 MediaAction action = audio.getCurrentAction(); 161 if (action == MediaAction.START) { 162 view.startAudio(); 163 } else if (action == MediaAction.PAUSE) { 164 view.pauseAudio(); 165 } else if (action == MediaAction.STOP) { 166 view.stopAudio(); 167 } else if (action == MediaAction.SEEK) { 168 view.seekAudio(audio.getSeekTo()); 169 } 170 } 171 172 protected void presentText(SlideViewInterface view, TextModel text, 173 RegionModel r, boolean dataChanged) { 174 if (dataChanged) { 175 view.setText(text.getSrc(), text.getText()); 176 } 177 178 if (view instanceof AdaptableSlideViewInterface) { 179 ((AdaptableSlideViewInterface) view).setTextRegion( 180 transformWidth(r.getLeft()), 181 transformHeight(r.getTop()), 182 transformWidth(r.getWidth()), 183 transformHeight(r.getHeight())); 184 } 185 view.setTextVisibility(text.isVisible()); 186 } 187 188 /** 189 * @param view 190 * @param image 191 * @param r 192 */ 193 protected void presentImage(SlideViewInterface view, ImageModel image, 194 RegionModel r, boolean dataChanged) { 195 int transformedWidth = transformWidth(r.getWidth()); 196 int transformedHeight = transformWidth(r.getHeight()); 197 198 if (LOCAL_LOGV) { 199 Log.v(TAG, "presentImage r.getWidth: " + r.getWidth() 200 + ", r.getHeight: " + r.getHeight() + 201 " transformedWidth: " + transformedWidth + 202 " transformedHeight: " + transformedHeight); 203 } 204 205 if (dataChanged) { 206 view.setImage(image.getSrc(), image.getBitmap(r.getWidth(), r.getHeight())); 207 } 208 209 if (view instanceof AdaptableSlideViewInterface) { 210 ((AdaptableSlideViewInterface) view).setImageRegion( 211 transformWidth(r.getLeft()), 212 transformHeight(r.getTop()), 213 transformedWidth, 214 transformedHeight); 215 } 216 view.setImageRegionFit(r.getFit()); 217 view.setImageVisibility(image.isVisible()); 218 } 219 220 /** 221 * @param view 222 * @param video 223 * @param r 224 */ 225 protected void presentVideo(SlideViewInterface view, VideoModel video, 226 RegionModel r, boolean dataChanged) { 227 if (dataChanged) { 228 view.setVideo(video.getSrc(), video.getUri()); 229 } 230 231 if (view instanceof AdaptableSlideViewInterface) { 232 ((AdaptableSlideViewInterface) view).setVideoRegion( 233 transformWidth(r.getLeft()), 234 transformHeight(r.getTop()), 235 transformWidth(r.getWidth()), 236 transformHeight(r.getHeight())); 237 } 238 view.setVideoVisibility(video.isVisible()); 239 240 MediaAction action = video.getCurrentAction(); 241 if (action == MediaAction.START) { 242 view.startVideo(); 243 } else if (action == MediaAction.PAUSE) { 244 view.pauseVideo(); 245 } else if (action == MediaAction.STOP) { 246 view.stopVideo(); 247 } else if (action == MediaAction.SEEK) { 248 view.seekVideo(video.getSeekTo()); 249 } 250 } 251 252 public void setLocation(int location) { 253 mLocation = location; 254 } 255 256 public int getLocation() { 257 return mLocation; 258 } 259 260 public void goBackward() { 261 if (mLocation > 0) { 262 mLocation--; 263 } 264 } 265 266 public void goForward() { 267 if (mLocation < (mSlideNumber - 1)) { 268 mLocation++; 269 } 270 } 271 272 public void onModelChanged(final Model model, final boolean dataChanged) { 273 final SlideViewInterface view = (SlideViewInterface) mView; 274 275 // FIXME: Should be optimized. 276 if (model instanceof SlideshowModel) { 277 // TODO: 278 } else if (model instanceof SlideModel) { 279 if (((SlideModel) model).isVisible()) { 280 mHandler.post(new Runnable() { 281 public void run() { 282 presentSlide(view, (SlideModel) model); 283 } 284 }); 285 } else { 286 mHandler.post(new Runnable() { 287 public void run() { 288 goForward(); 289 } 290 }); 291 } 292 } else if (model instanceof MediaModel) { 293 if (model instanceof RegionMediaModel) { 294 mHandler.post(new Runnable() { 295 public void run() { 296 presentRegionMedia(view, (RegionMediaModel) model, dataChanged); 297 } 298 }); 299 } else if (((MediaModel) model).isAudio()) { 300 mHandler.post(new Runnable() { 301 public void run() { 302 presentAudio(view, (AudioModel) model, dataChanged); 303 } 304 }); 305 } 306 } else if (model instanceof RegionModel) { 307 // TODO: 308 } 309 } 310 311 @Override 312 public void cancelBackgroundLoading() { 313 // For now, the SlideshowPresenter does no background loading so there is nothing to cancel. 314 } 315 } 316