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