• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 java.io.IOException;
21 import java.util.Comparator;
22 import java.util.Map;
23 import java.util.TreeMap;
24 
25 import android.content.Context;
26 import android.graphics.Bitmap;
27 import android.graphics.BitmapFactory;
28 import android.media.MediaPlayer;
29 import android.net.Uri;
30 import android.text.method.HideReturnsTransformationMethod;
31 import android.util.AttributeSet;
32 import android.util.Log;
33 import android.view.Gravity;
34 import android.view.LayoutInflater;
35 import android.view.View;
36 import android.widget.AbsoluteLayout;
37 import android.widget.FrameLayout;
38 import android.widget.ImageView;
39 import android.widget.LinearLayout;
40 import android.widget.MediaController;
41 import android.widget.ScrollView;
42 import android.widget.TextView;
43 import android.widget.VideoView;
44 
45 import com.android.mms.R;
46 import com.android.mms.layout.LayoutManager;
47 
48 /**
49  * A basic view to show the contents of a slide.
50  */
51 public class SlideView extends AbsoluteLayout implements
52         AdaptableSlideViewInterface {
53     private static final String TAG = "SlideView";
54     private static final boolean DEBUG = false;
55     private static final boolean LOCAL_LOGV = false;
56     // FIXME: Need getHeight from mAudioInfoView instead of constant AUDIO_INFO_HEIGHT.
57     private static final int AUDIO_INFO_HEIGHT = 82;
58 
59     private View mAudioInfoView;
60     private ImageView mImageView;
61     private VideoView mVideoView;
62     private ScrollView mScrollText;
63     private TextView mTextView;
64     private OnSizeChangedListener mSizeChangedListener;
65     private MediaPlayer mAudioPlayer;
66     private boolean mIsPrepared;
67     private boolean mStartWhenPrepared;
68     private int     mSeekWhenPrepared;
69     private boolean mStopWhenPrepared;
70     private ScrollView mScrollViewPort;
71     private LinearLayout mViewPort;
72     // Indicates whether the view is in MMS conformance mode.
73     private boolean mConformanceMode;
74     private MediaController mMediaController;
75 
76     MediaPlayer.OnPreparedListener mPreparedListener = new MediaPlayer.OnPreparedListener() {
77         public void onPrepared(MediaPlayer mp) {
78             mIsPrepared = true;
79             if (mSeekWhenPrepared > 0) {
80                 mAudioPlayer.seekTo(mSeekWhenPrepared);
81                 mSeekWhenPrepared = 0;
82             }
83             if (mStartWhenPrepared) {
84                 mAudioPlayer.start();
85                 mStartWhenPrepared = false;
86                 displayAudioInfo();
87             }
88             if (mStopWhenPrepared) {
89                 mAudioPlayer.stop();
90                 mAudioPlayer.release();
91                 mAudioPlayer = null;
92                 mStopWhenPrepared = false;
93                 hideAudioInfo();
94             }
95         }
96     };
97 
SlideView(Context context)98     public SlideView(Context context) {
99         super(context);
100     }
101 
SlideView(Context context, AttributeSet attrs)102     public SlideView(Context context, AttributeSet attrs) {
103         super(context, attrs);
104     }
105 
setImage(String name, Bitmap bitmap)106     public void setImage(String name, Bitmap bitmap) {
107         if (mImageView == null) {
108             mImageView = new ImageView(mContext);
109             mImageView.setPadding(0, 5, 0, 5);
110             addView(mImageView, new LayoutParams(
111                     LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 0, 0));
112             if (DEBUG) {
113                 mImageView.setBackgroundColor(0xFFFF0000);
114             }
115         }
116         try {
117             if (null == bitmap) {
118                 bitmap = BitmapFactory.decodeResource(getResources(),
119                         R.drawable.ic_missing_thumbnail_picture);
120             }
121             mImageView.setVisibility(View.VISIBLE);
122             mImageView.setImageBitmap(bitmap);
123         } catch (java.lang.OutOfMemoryError e) {
124             Log.e(TAG, "setImage: out of memory: ", e);
125         }
126     }
127 
setImageRegion(int left, int top, int width, int height)128     public void setImageRegion(int left, int top, int width, int height) {
129         // Ignore any requirement of layout change once we are in MMS conformance mode.
130         if (mImageView != null && !mConformanceMode) {
131             mImageView.setLayoutParams(new LayoutParams(width, height, left, top));
132         }
133     }
134 
setImageRegionFit(String fit)135     public void setImageRegionFit(String fit) {
136         // TODO Auto-generated method stub
137     }
138 
setVideo(String name, Uri video)139     public void setVideo(String name, Uri video) {
140         if (mVideoView == null) {
141             mVideoView = new VideoView(mContext);
142             addView(mVideoView, new LayoutParams(
143                     LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0));
144             if (DEBUG) {
145                 mVideoView.setBackgroundColor(0xFFFF0000);
146             }
147         }
148 
149         if (LOCAL_LOGV) {
150             Log.v(TAG, "Changing video source to " + video);
151         }
152         mVideoView.setVisibility(View.VISIBLE);
153         mVideoView.setVideoURI(video);
154     }
155 
setMediaController(MediaController mediaController)156     public void setMediaController(MediaController mediaController) {
157         mMediaController = mediaController;
158     }
159 
initAudioInfoView(String name)160     private void initAudioInfoView(String name) {
161         if (null == mAudioInfoView) {
162             LayoutInflater factory = LayoutInflater.from(getContext());
163             mAudioInfoView = factory.inflate(R.layout.playing_audio_info, null);
164             int height = mAudioInfoView.getHeight();
165             if (mConformanceMode) {
166                 mViewPort.addView(mAudioInfoView, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
167                         AUDIO_INFO_HEIGHT));
168             } else {
169                 addView(mAudioInfoView, new LayoutParams(
170                         LayoutParams.MATCH_PARENT, AUDIO_INFO_HEIGHT,
171                         0, getHeight() - AUDIO_INFO_HEIGHT));
172                 if (DEBUG) {
173                     mAudioInfoView.setBackgroundColor(0xFFFF0000);
174                 }
175             }
176         }
177         TextView audioName = (TextView) mAudioInfoView.findViewById(R.id.name);
178         audioName.setText(name);
179         mAudioInfoView.setVisibility(View.GONE);
180     }
181 
displayAudioInfo()182     private void displayAudioInfo() {
183         if (null != mAudioInfoView) {
184             mAudioInfoView.setVisibility(View.VISIBLE);
185         }
186     }
187 
hideAudioInfo()188     private void hideAudioInfo() {
189         if (null != mAudioInfoView) {
190             mAudioInfoView.setVisibility(View.GONE);
191         }
192     }
193 
setAudio(Uri audio, String name, Map<String, ?> extras)194     public void setAudio(Uri audio, String name, Map<String, ?> extras) {
195         if (audio == null) {
196             throw new IllegalArgumentException("Audio URI may not be null.");
197         }
198 
199         if (LOCAL_LOGV) {
200             Log.v(TAG, "Changing audio source to " + audio);
201         }
202 
203         if (mAudioPlayer != null) {
204             mAudioPlayer.reset();
205             mAudioPlayer.release();
206             mAudioPlayer = null;
207         }
208 
209         // Reset state variables
210         mIsPrepared = false;
211         mStartWhenPrepared = false;
212         mSeekWhenPrepared = 0;
213         mStopWhenPrepared = false;
214 
215         try {
216             mAudioPlayer = new MediaPlayer();
217             mAudioPlayer.setOnPreparedListener(mPreparedListener);
218             mAudioPlayer.setDataSource(mContext, audio);
219             mAudioPlayer.prepareAsync();
220         } catch (IOException e) {
221             Log.e(TAG, "Unexpected IOException.", e);
222             mAudioPlayer.release();
223             mAudioPlayer = null;
224         }
225         initAudioInfoView(name);
226     }
227 
setText(String name, String text)228     public void setText(String name, String text) {
229         if (!mConformanceMode) {
230             if (null == mScrollText) {
231                 mScrollText = new ScrollView(mContext);
232                 mScrollText.setScrollBarStyle(SCROLLBARS_OUTSIDE_INSET);
233                 addView(mScrollText, new LayoutParams(
234                         LayoutParams.WRAP_CONTENT, LayoutParams.WRAP_CONTENT, 0, 0));
235                 if (DEBUG) {
236                     mScrollText.setBackgroundColor(0xFF00FF00);
237                 }
238             }
239             if (null == mTextView) {
240                 mTextView = new TextView(mContext);
241                 mTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
242                 mScrollText.addView(mTextView);
243             }
244             mScrollText.requestFocus();
245         }
246         mTextView.setVisibility(View.VISIBLE);
247         mTextView.setText(text);
248         // Let the text in Mms can be selected.
249         mTextView.setTextIsSelectable(true);
250     }
251 
setTextRegion(int left, int top, int width, int height)252     public void setTextRegion(int left, int top, int width, int height) {
253         // Ignore any requirement of layout change once we are in MMS conformance mode.
254         if (mScrollText != null && !mConformanceMode) {
255             mScrollText.setLayoutParams(new LayoutParams(width, height, left, top));
256         }
257     }
258 
setVideoRegion(int left, int top, int width, int height)259     public void setVideoRegion(int left, int top, int width, int height) {
260         if (mVideoView != null && !mConformanceMode) {
261             mVideoView.setLayoutParams(new LayoutParams(width, height, left, top));
262         }
263     }
264 
setImageVisibility(boolean visible)265     public void setImageVisibility(boolean visible) {
266         if (mImageView != null) {
267             if (mConformanceMode) {
268                 mImageView.setVisibility(visible ? View.VISIBLE : View.GONE);
269             } else {
270                 mImageView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
271             }
272         }
273     }
274 
setTextVisibility(boolean visible)275     public void setTextVisibility(boolean visible) {
276         if (mConformanceMode) {
277             if (mTextView != null) {
278                 mTextView.setVisibility(visible ? View.VISIBLE : View.GONE);
279             }
280         } else if (mScrollText != null) {
281             mScrollText.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
282         }
283     }
284 
setVideoVisibility(boolean visible)285     public void setVideoVisibility(boolean visible) {
286         if (mVideoView != null) {
287             if (mConformanceMode) {
288                 mVideoView.setVisibility(visible ? View.VISIBLE : View.GONE);
289             } else {
290                 mVideoView.setVisibility(visible ? View.VISIBLE : View.INVISIBLE);
291             }
292         }
293     }
294 
startAudio()295     public void startAudio() {
296         if ((mAudioPlayer != null) && mIsPrepared) {
297             mAudioPlayer.start();
298             mStartWhenPrepared = false;
299             displayAudioInfo();
300         } else {
301             mStartWhenPrepared = true;
302         }
303     }
304 
stopAudio()305     public void stopAudio() {
306         if ((mAudioPlayer != null) && mIsPrepared) {
307             mAudioPlayer.stop();
308             mAudioPlayer.release();
309             mAudioPlayer = null;
310             hideAudioInfo();
311         } else {
312             mStopWhenPrepared = true;
313         }
314     }
315 
pauseAudio()316     public void pauseAudio() {
317         if ((mAudioPlayer != null) && mIsPrepared) {
318             if (mAudioPlayer.isPlaying()) {
319                 mAudioPlayer.pause();
320             }
321         }
322         mStartWhenPrepared = false;
323     }
324 
seekAudio(int seekTo)325     public void seekAudio(int seekTo) {
326         if ((mAudioPlayer != null) && mIsPrepared) {
327             mAudioPlayer.seekTo(seekTo);
328         } else {
329             mSeekWhenPrepared = seekTo;
330         }
331     }
332 
startVideo()333     public void startVideo() {
334         if (mVideoView != null) {
335             if (LOCAL_LOGV) {
336                 Log.v(TAG, "Starting video playback.");
337             }
338             mVideoView.start();
339         }
340     }
341 
stopVideo()342     public void stopVideo() {
343         if ((mVideoView != null)) {
344             if (LOCAL_LOGV) {
345                 Log.v(TAG, "Stopping video playback.");
346             }
347             mVideoView.stopPlayback();
348         }
349     }
350 
pauseVideo()351     public void pauseVideo() {
352         if (mVideoView != null) {
353             if (LOCAL_LOGV) {
354                 Log.v(TAG, "Pausing video playback.");
355             }
356             mVideoView.pause();
357         }
358     }
359 
seekVideo(int seekTo)360     public void seekVideo(int seekTo) {
361         if (mVideoView != null) {
362             if (seekTo > 0) {
363                 if (LOCAL_LOGV) {
364                     Log.v(TAG, "Seeking video playback to " + seekTo);
365                 }
366                 mVideoView.seekTo(seekTo);
367             }
368         }
369     }
370 
reset()371     public void reset() {
372         if (null != mScrollText) {
373             mScrollText.setVisibility(View.GONE);
374         }
375 
376         if (null != mImageView) {
377             mImageView.setVisibility(View.GONE);
378         }
379 
380         if (null != mAudioPlayer) {
381             stopAudio();
382         }
383 
384         if (null != mVideoView) {
385             stopVideo();
386             mVideoView.setVisibility(View.GONE);
387         }
388 
389         if (null != mTextView) {
390             mTextView.setVisibility(View.GONE);
391         }
392 
393         if (mScrollViewPort != null) {
394             mScrollViewPort.scrollTo(0, 0);
395             mScrollViewPort.setLayoutParams(
396                     new LayoutParams(LayoutParams.MATCH_PARENT, LayoutParams.MATCH_PARENT, 0, 0));
397         }
398 
399     }
400 
setVisibility(boolean visible)401     public void setVisibility(boolean visible) {
402         // TODO Auto-generated method stub
403     }
404 
405     @Override
onSizeChanged(int w, int h, int oldw, int oldh)406     protected void onSizeChanged(int w, int h, int oldw, int oldh) {
407         super.onSizeChanged(w, h, oldw, oldh);
408 
409         if (mSizeChangedListener != null) {
410             if (LOCAL_LOGV) {
411                 Log.v(TAG, "new size=" + w + "x" + h);
412             }
413             mSizeChangedListener.onSizeChanged(w, h - AUDIO_INFO_HEIGHT);
414         }
415     }
416 
setOnSizeChangedListener(OnSizeChangedListener l)417     public void setOnSizeChangedListener(OnSizeChangedListener l) {
418         mSizeChangedListener = l;
419     }
420 
421     private class Position {
Position(int left, int top)422         public Position(int left, int top) {
423             mTop = top;
424             mLeft = left;
425         }
426         public int mTop;
427         public int mLeft;
428     }
429 
430     /**
431      * Makes the SlideView working on  MMSConformance Mode. The view will be
432      * re-layout to the linear view.
433      * <p>
434      * This is Chinese requirement about mms conformance.
435      * The most popular Mms service in China is newspaper which is MMS conformance,
436      * normally it mixes the image and text and has a number of slides. The
437      * AbsoluteLayout doesn't have good user experience for this kind of message,
438      * for example,
439      *
440      * 1. AbsoluteLayout exactly follows the smil's layout which is not optimized,
441      * and actually, no other MMS applications follow the smil's layout, they adjust
442      * the layout according their screen size. MMS conformance doc also allows the
443      * implementation to adjust the layout.
444      *
445      * 2. The TextView is fixed in the small area of screen, and other part of screen
446      * is empty once there is no image in the current slide.
447      *
448      * 3. The TextView is scrollable in a small area of screen and the font size is
449      * small which make the user experience bad.
450      *
451      * The better UI for the MMS conformance message could be putting the image/video
452      * and text in a linear layout view and making them scrollable together.
453      *
454      * Another reason for only applying the LinearLayout to the MMS conformance message
455      * is that the AbsoluteLayout has ability to play image and video in a same screen.
456      * which shouldn't be broken.
457      */
enableMMSConformanceMode(int textLeft, int textTop, int imageLeft, int imageTop)458     public void enableMMSConformanceMode(int textLeft, int textTop,
459             int imageLeft, int imageTop) {
460         mConformanceMode = true;
461         if (mScrollViewPort == null) {
462             mScrollViewPort = new ScrollView(mContext) {
463                 private int mBottomY;
464                 @Override
465                 protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
466                     super.onLayout(changed, left, top, right, bottom);
467                     if (getChildCount() > 0) {
468                         int childHeight = getChildAt(0).getHeight();
469                         int height = getHeight();
470                         mBottomY = height < childHeight ? childHeight - height : 0;
471                     }
472                 }
473                 @Override
474                 protected void onScrollChanged(int l, int t, int oldl, int oldt) {
475                     // Shows MediaController when the view is scrolled to the top/bottom of itself.
476                     if (t == 0 || t >= mBottomY){
477                         if (mMediaController != null
478                                 && !((SlideshowActivity) mContext).isFinishing()) {
479                             mMediaController.show();
480                         }
481                     }
482                 }
483             };
484             mScrollViewPort.setScrollBarStyle(SCROLLBARS_INSIDE_OVERLAY);
485             mViewPort = new LinearLayout(mContext);
486             mViewPort.setOrientation(LinearLayout.VERTICAL);
487             mViewPort.setGravity(Gravity.CENTER);
488             mViewPort.setOnClickListener(new OnClickListener() {
489                 public void onClick(View v) {
490                     if (mMediaController != null) {
491                         mMediaController.show();
492                     }
493                 }
494             });
495             mScrollViewPort.addView(mViewPort, new FrameLayout.LayoutParams(LayoutParams.MATCH_PARENT,
496                     LayoutParams.WRAP_CONTENT));
497             addView(mScrollViewPort);
498         }
499         // Layout views to fit the LinearLayout from left to right, then top to
500         // bottom.
501         TreeMap<Position, View> viewsByPosition = new TreeMap<Position, View>(new Comparator<Position>() {
502             public int compare(Position p1, Position p2) {
503                 int l1 = p1.mLeft;
504                 int t1 = p1.mTop;
505                 int l2 = p2.mLeft;
506                 int t2 = p2.mTop;
507                 int res = t1 - t2;
508                 if (res == 0) {
509                     res = l1 - l2;
510                 }
511                 if (res == 0) {
512                     // A view will be lost if return 0.
513                     return -1;
514                 }
515                 return res;
516             }
517         });
518         if (textLeft >=0 && textTop >=0) {
519             mTextView = new TextView(mContext);
520             mTextView.setTransformationMethod(HideReturnsTransformationMethod.getInstance());
521             mTextView.setTextSize(18);
522             mTextView.setPadding(5, 5, 5, 5);
523             viewsByPosition.put(new Position(textLeft, textTop), mTextView);
524         }
525 
526         if (imageLeft >=0 && imageTop >=0) {
527             mImageView = new ImageView(mContext);
528             mImageView.setPadding(0, 5, 0, 5);
529             viewsByPosition.put(new Position(imageLeft, imageTop), mImageView);
530             // According MMS Conformance Document, the image and video should use the same
531             // region. So, put the VideoView below the ImageView.
532             mVideoView = new VideoView(mContext);
533             viewsByPosition.put(new Position(imageLeft + 1, imageTop), mVideoView);
534         }
535         for (View view : viewsByPosition.values()) {
536             if (view instanceof VideoView) {
537                 mViewPort.addView(view, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
538                         LayoutManager.getInstance().getLayoutParameters().getHeight()));
539             } else {
540                 mViewPort.addView(view, new LinearLayout.LayoutParams(LayoutParams.MATCH_PARENT,
541                         LayoutParams.WRAP_CONTENT));
542             }
543             view.setVisibility(View.GONE);
544         }
545     }
546 
setVideoThumbnail(String name, Bitmap bitmap)547     public void setVideoThumbnail(String name, Bitmap bitmap) {
548     }
549 }
550