| /* |
| * Copyright (C) 2008 Esmertec AG. |
| * Copyright (C) 2008 The Android Open Source Project |
| * |
| * Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package com.android.mms.ui; |
| |
| import android.content.Context; |
| import android.os.Handler; |
| import android.util.Log; |
| |
| import com.android.mms.model.AudioModel; |
| import com.android.mms.model.ImageModel; |
| import com.android.mms.model.LayoutModel; |
| import com.android.mms.model.MediaModel; |
| import com.android.mms.model.MediaModel.MediaAction; |
| import com.android.mms.model.Model; |
| import com.android.mms.model.RegionMediaModel; |
| import com.android.mms.model.RegionModel; |
| import com.android.mms.model.SlideModel; |
| import com.android.mms.model.SlideshowModel; |
| import com.android.mms.model.TextModel; |
| import com.android.mms.model.VideoModel; |
| import com.android.mms.ui.AdaptableSlideViewInterface.OnSizeChangedListener; |
| import com.android.mms.util.ItemLoadedCallback; |
| |
| /** |
| * A basic presenter of slides. |
| */ |
| public class SlideshowPresenter extends Presenter { |
| private static final String TAG = "SlideshowPresenter"; |
| private static final boolean DEBUG = false; |
| private static final boolean LOCAL_LOGV = false; |
| |
| protected int mLocation; |
| protected final int mSlideNumber; |
| |
| protected float mWidthTransformRatio = 1.0f; |
| protected float mHeightTransformRatio = 1.0f; |
| |
| // Since only the original thread that created a view hierarchy can touch |
| // its views, we have to use Handler to manage the views in the some |
| // callbacks such as onModelChanged(). |
| protected final Handler mHandler = new Handler(); |
| |
| public SlideshowPresenter(Context context, ViewInterface view, Model model) { |
| super(context, view, model); |
| mLocation = 0; |
| mSlideNumber = ((SlideshowModel) mModel).size(); |
| |
| if (view instanceof AdaptableSlideViewInterface) { |
| ((AdaptableSlideViewInterface) view).setOnSizeChangedListener( |
| mViewSizeChangedListener); |
| } |
| } |
| |
| private final OnSizeChangedListener mViewSizeChangedListener = |
| new OnSizeChangedListener() { |
| public void onSizeChanged(int width, int height) { |
| LayoutModel layout = ((SlideshowModel) mModel).getLayout(); |
| mWidthTransformRatio = getWidthTransformRatio( |
| width, layout.getLayoutWidth()); |
| mHeightTransformRatio = getHeightTransformRatio( |
| height, layout.getLayoutHeight()); |
| // The ratio indicates how to reduce the source to match the View, |
| // so the larger one should be used. |
| float ratio = mWidthTransformRatio > mHeightTransformRatio ? |
| mWidthTransformRatio : mHeightTransformRatio; |
| mWidthTransformRatio = ratio; |
| mHeightTransformRatio = ratio; |
| if (LOCAL_LOGV) { |
| Log.v(TAG, "ratio_w = " + mWidthTransformRatio |
| + ", ratio_h = " + mHeightTransformRatio); |
| } |
| } |
| }; |
| |
| private float getWidthTransformRatio(int width, int layoutWidth) { |
| if (width > 0) { |
| return (float) layoutWidth / (float) width; |
| } |
| return 1.0f; |
| } |
| |
| private float getHeightTransformRatio(int height, int layoutHeight) { |
| if (height > 0) { |
| return (float) layoutHeight / (float) height; |
| } |
| return 1.0f; |
| } |
| |
| private int transformWidth(int width) { |
| return (int) (width / mWidthTransformRatio); |
| } |
| |
| private int transformHeight(int height) { |
| return (int) (height / mHeightTransformRatio); |
| } |
| |
| @Override |
| public void present(ItemLoadedCallback callback) { |
| // This is called to show a full-screen slideshow. Presently, all parts of |
| // a slideshow (images, sounds, etc.) are loaded and displayed on the UI thread. |
| presentSlide((SlideViewInterface) mView, ((SlideshowModel) mModel).get(mLocation)); |
| } |
| |
| /** |
| * @param view |
| * @param model |
| */ |
| protected void presentSlide(SlideViewInterface view, SlideModel model) { |
| view.reset(); |
| |
| for (MediaModel media : model) { |
| if (media instanceof RegionMediaModel) { |
| presentRegionMedia(view, (RegionMediaModel) media, true); |
| } else if (media.isAudio()) { |
| presentAudio(view, (AudioModel) media, true); |
| } |
| } |
| } |
| |
| /** |
| * @param view |
| */ |
| protected void presentRegionMedia(SlideViewInterface view, |
| RegionMediaModel rMedia, boolean dataChanged) { |
| RegionModel r = (rMedia).getRegion(); |
| if (rMedia.isText()) { |
| presentText(view, (TextModel) rMedia, r, dataChanged); |
| } else if (rMedia.isImage()) { |
| presentImage(view, (ImageModel) rMedia, r, dataChanged); |
| } else if (rMedia.isVideo()) { |
| presentVideo(view, (VideoModel) rMedia, r, dataChanged); |
| } |
| } |
| |
| protected void presentAudio(SlideViewInterface view, AudioModel audio, |
| boolean dataChanged) { |
| // Set audio only when data changed. |
| if (dataChanged) { |
| view.setAudio(audio.getUri(), audio.getSrc(), audio.getExtras()); |
| } |
| |
| MediaAction action = audio.getCurrentAction(); |
| if (action == MediaAction.START) { |
| view.startAudio(); |
| } else if (action == MediaAction.PAUSE) { |
| view.pauseAudio(); |
| } else if (action == MediaAction.STOP) { |
| view.stopAudio(); |
| } else if (action == MediaAction.SEEK) { |
| view.seekAudio(audio.getSeekTo()); |
| } |
| } |
| |
| protected void presentText(SlideViewInterface view, TextModel text, |
| RegionModel r, boolean dataChanged) { |
| if (dataChanged) { |
| view.setText(text.getSrc(), text.getText()); |
| } |
| |
| if (view instanceof AdaptableSlideViewInterface) { |
| ((AdaptableSlideViewInterface) view).setTextRegion( |
| transformWidth(r.getLeft()), |
| transformHeight(r.getTop()), |
| transformWidth(r.getWidth()), |
| transformHeight(r.getHeight())); |
| } |
| view.setTextVisibility(text.isVisible()); |
| } |
| |
| /** |
| * @param view |
| * @param image |
| * @param r |
| */ |
| protected void presentImage(SlideViewInterface view, ImageModel image, |
| RegionModel r, boolean dataChanged) { |
| int transformedWidth = transformWidth(r.getWidth()); |
| int transformedHeight = transformWidth(r.getHeight()); |
| |
| if (LOCAL_LOGV) { |
| Log.v(TAG, "presentImage r.getWidth: " + r.getWidth() |
| + ", r.getHeight: " + r.getHeight() + |
| " transformedWidth: " + transformedWidth + |
| " transformedHeight: " + transformedHeight); |
| } |
| |
| if (dataChanged) { |
| view.setImage(image.getSrc(), image.getBitmap(transformedWidth, transformedHeight)); |
| } |
| |
| if (view instanceof AdaptableSlideViewInterface) { |
| ((AdaptableSlideViewInterface) view).setImageRegion( |
| transformWidth(r.getLeft()), |
| transformHeight(r.getTop()), |
| transformedWidth, |
| transformedHeight); |
| } |
| view.setImageRegionFit(r.getFit()); |
| view.setImageVisibility(image.isVisible()); |
| } |
| |
| /** |
| * @param view |
| * @param video |
| * @param r |
| */ |
| protected void presentVideo(SlideViewInterface view, VideoModel video, |
| RegionModel r, boolean dataChanged) { |
| if (dataChanged) { |
| view.setVideo(video.getSrc(), video.getUri()); |
| } |
| |
| if (view instanceof AdaptableSlideViewInterface) { |
| ((AdaptableSlideViewInterface) view).setVideoRegion( |
| transformWidth(r.getLeft()), |
| transformHeight(r.getTop()), |
| transformWidth(r.getWidth()), |
| transformHeight(r.getHeight())); |
| } |
| view.setVideoVisibility(video.isVisible()); |
| |
| MediaAction action = video.getCurrentAction(); |
| if (action == MediaAction.START) { |
| view.startVideo(); |
| } else if (action == MediaAction.PAUSE) { |
| view.pauseVideo(); |
| } else if (action == MediaAction.STOP) { |
| view.stopVideo(); |
| } else if (action == MediaAction.SEEK) { |
| view.seekVideo(video.getSeekTo()); |
| } |
| } |
| |
| public void setLocation(int location) { |
| mLocation = location; |
| } |
| |
| public int getLocation() { |
| return mLocation; |
| } |
| |
| public void goBackward() { |
| if (mLocation > 0) { |
| mLocation--; |
| } |
| } |
| |
| public void goForward() { |
| if (mLocation < (mSlideNumber - 1)) { |
| mLocation++; |
| } |
| } |
| |
| public void onModelChanged(final Model model, final boolean dataChanged) { |
| final SlideViewInterface view = (SlideViewInterface) mView; |
| |
| // FIXME: Should be optimized. |
| if (model instanceof SlideshowModel) { |
| // TODO: |
| } else if (model instanceof SlideModel) { |
| if (((SlideModel) model).isVisible()) { |
| mHandler.post(new Runnable() { |
| public void run() { |
| presentSlide(view, (SlideModel) model); |
| } |
| }); |
| } else { |
| mHandler.post(new Runnable() { |
| public void run() { |
| goForward(); |
| } |
| }); |
| } |
| } else if (model instanceof MediaModel) { |
| if (model instanceof RegionMediaModel) { |
| mHandler.post(new Runnable() { |
| public void run() { |
| presentRegionMedia(view, (RegionMediaModel) model, dataChanged); |
| } |
| }); |
| } else if (((MediaModel) model).isAudio()) { |
| mHandler.post(new Runnable() { |
| public void run() { |
| presentAudio(view, (AudioModel) model, dataChanged); |
| } |
| }); |
| } |
| } else if (model instanceof RegionModel) { |
| // TODO: |
| } |
| } |
| |
| @Override |
| public void cancelBackgroundLoading() { |
| // For now, the SlideshowPresenter does no background loading so there is nothing to cancel. |
| } |
| } |