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