2 * Copyright (C) 2008 Esmertec AG.
3 * Copyright (C) 2008 The Android Open Source Project
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
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 package com.android.mms.ui;
20 import com.android.mms.R;
21 import com.android.mms.dom.AttrImpl;
22 import com.android.mms.dom.smil.SmilDocumentImpl;
23 import com.android.mms.dom.smil.SmilPlayer;
24 import com.android.mms.dom.smil.parser.SmilXmlSerializer;
25 import com.android.mms.model.LayoutModel;
26 import com.android.mms.model.RegionModel;
27 import com.android.mms.model.SlideshowModel;
28 import com.android.mms.model.SmilHelper;
29 import com.google.android.mms.MmsException;
31 import org.w3c.dom.NamedNodeMap;
32 import org.w3c.dom.Node;
33 import org.w3c.dom.NodeList;
34 import org.w3c.dom.events.Event;
35 import org.w3c.dom.events.EventListener;
36 import org.w3c.dom.events.EventTarget;
37 import org.w3c.dom.smil.SMILDocument;
38 import org.w3c.dom.smil.SMILElement;
40 import android.app.Activity;
41 import android.content.Intent;
42 import android.graphics.PixelFormat;
43 import android.net.Uri;
44 import android.os.Bundle;
45 import android.os.Handler;
46 import android.util.Config;
47 import android.util.Log;
48 import android.view.KeyEvent;
49 import android.view.MotionEvent;
50 import android.view.View;
51 import android.view.Window;
52 import android.view.View.OnClickListener;
53 import android.widget.MediaController;
54 import android.widget.MediaController.MediaPlayerControl;
56 import java.io.ByteArrayOutputStream;
59 * Plays the given slideshow in full-screen mode with a common controller.
61 public class SlideshowActivity extends Activity implements EventListener {
62 private static final String TAG = "SlideshowActivity";
63 private static final boolean DEBUG = false;
64 private static final boolean LOCAL_LOGV = DEBUG ? Config.LOGD : Config.LOGV;
66 private MediaController mMediaController;
67 private SmilPlayer mSmilPlayer;
69 private Handler mHandler;
71 private SMILDocument mSmilDoc;
73 private SlideView mSlideView;
76 * @return whether the Smil has MMS conformance layout.
77 * Refer to MMS Conformance Document OMA-MMS-CONF-v1_2-20050301-A
79 private static final boolean isMMSConformance(SMILDocument smilDoc) {
80 SMILElement head = smilDoc.getHead();
85 NodeList children = head.getChildNodes();
86 if (children == null || children.getLength() != 1) {
87 // The 'head' element should have only one child.
90 Node layout = children.item(0);
91 if (layout == null || !"layout".equals(layout.getNodeName())) {
92 // The child is not layout element
95 NodeList layoutChildren = layout.getChildNodes();
96 if (layoutChildren == null) {
97 // The 'layout' element has no child.
100 int num = layoutChildren.getLength();
102 // The 'layout' element has no child.
105 for (int i = 0; i < num; i++) {
106 Node layoutChild = layoutChildren.item(i);
107 if (layoutChild == null) {
108 // The 'layout' child is null.
111 String name = layoutChild.getNodeName();
112 if ("root-layout".equals(name)) {
114 } else if ("region".equals(name)) {
115 NamedNodeMap map = layoutChild.getAttributes();
116 for (int j = 0; j < map.getLength(); j++) {
117 Node node = map.item(j);
121 String attrName = node.getNodeName();
122 // The attr should be one of left, top, height, width, fit and id
123 if ("left".equals(attrName) || "top".equals(attrName) ||
124 "height".equals(attrName) || "width".equals(attrName) ||
125 "fit".equals(attrName)) {
127 } else if ("id".equals(attrName)) {
129 if (node instanceof AttrImpl) {
130 value = ((AttrImpl)node).getValue();
134 if ("Text".equals(value) || "Image".equals(value)) {
137 // The id attr is not 'Text' or 'Image'
145 // The 'layout' element has the child other than 'root-layout' or 'region'
153 public void onCreate(Bundle icicle) {
154 super.onCreate(icicle);
155 mHandler = new Handler();
157 // Play slide-show in full-screen mode.
158 requestWindowFeature(Window.FEATURE_NO_TITLE);
159 getWindow().setFormat(PixelFormat.TRANSLUCENT);
160 setContentView(R.layout.slideshow);
162 Intent intent = getIntent();
163 Uri msg = intent.getData();
164 final SlideshowModel model;
167 model = SlideshowModel.createFromMessageUri(this, msg);
168 } catch (MmsException e) {
169 Log.e(TAG, "Cannot present the slide show.", e);
174 mSlideView = (SlideView) findViewById(R.id.slide_view);
175 PresenterFactory.getPresenter("SlideshowPresenter", this, mSlideView, model);
177 mHandler.post(new Runnable() {
178 private boolean isRotating() {
179 return mSmilPlayer.isPausedState()
180 || mSmilPlayer.isPlayingState()
181 || mSmilPlayer.isPlayedState();
185 mSmilPlayer = SmilPlayer.getPlayer();
186 initMediaController();
187 mSlideView.setMediaController(mMediaController);
188 // Use SmilHelper.getDocument() to ensure rebuilding the
189 // entire SMIL document.
190 mSmilDoc = SmilHelper.getDocument(model);
191 if (isMMSConformance(mSmilDoc)) {
196 LayoutModel layout = model.getLayout();
197 if (layout != null) {
198 RegionModel imageRegion = layout.getImageRegion();
199 if (imageRegion != null) {
200 imageLeft = imageRegion.getLeft();
201 imageTop = imageRegion.getTop();
203 RegionModel textRegion = layout.getTextRegion();
204 if (textRegion != null) {
205 textLeft = textRegion.getLeft();
206 textTop = textRegion.getTop();
209 mSlideView.enableMMSConformanceMode(textLeft, textTop, imageLeft, imageTop);
212 ByteArrayOutputStream ostream = new ByteArrayOutputStream();
213 SmilXmlSerializer.serialize(mSmilDoc, ostream);
215 Log.v(TAG, ostream.toString());
219 // Add event listener.
220 ((EventTarget) mSmilDoc).addEventListener(
221 SmilDocumentImpl.SMIL_DOCUMENT_END_EVENT,
222 SlideshowActivity.this, false);
224 mSmilPlayer.init(mSmilDoc);
226 mSmilPlayer.reload();
234 private void initMediaController() {
235 mMediaController = new MediaController(SlideshowActivity.this, false);
236 mMediaController.setMediaPlayer(new SmilPlayerController(mSmilPlayer));
237 mMediaController.setAnchorView(findViewById(R.id.slide_view));
238 mMediaController.setPrevNextListeners(
239 new OnClickListener() {
240 public void onClick(View v) {
244 new OnClickListener() {
245 public void onClick(View v) {
252 public boolean onTouchEvent(MotionEvent ev) {
253 if ((mSmilPlayer != null) && (mMediaController != null)) {
254 mMediaController.show();
260 protected void onPause() {
262 if (mSmilDoc != null) {
263 ((EventTarget) mSmilDoc).removeEventListener(
264 SmilDocumentImpl.SMIL_DOCUMENT_END_EVENT, this, false);
269 protected void onStop() {
271 if ((null != mSmilPlayer)) {
275 mSmilPlayer.stopWhenReload();
277 if (mMediaController != null) {
278 // Must do this so we don't leak a window.
279 mMediaController.hide();
285 public boolean onKeyDown(int keyCode, KeyEvent event) {
287 case KeyEvent.KEYCODE_VOLUME_DOWN:
288 case KeyEvent.KEYCODE_VOLUME_UP:
289 case KeyEvent.KEYCODE_DPAD_UP:
290 case KeyEvent.KEYCODE_DPAD_DOWN:
291 case KeyEvent.KEYCODE_DPAD_LEFT:
292 case KeyEvent.KEYCODE_DPAD_RIGHT:
294 case KeyEvent.KEYCODE_BACK:
295 case KeyEvent.KEYCODE_MENU:
296 if ((mSmilPlayer != null) &&
297 (mSmilPlayer.isPausedState()
298 || mSmilPlayer.isPlayingState()
299 || mSmilPlayer.isPlayedState())) {
304 if ((mSmilPlayer != null) && (mMediaController != null)) {
305 mMediaController.show();
308 return super.onKeyDown(keyCode, event);
311 private class SmilPlayerController implements MediaPlayerControl {
312 private final SmilPlayer mPlayer;
314 public SmilPlayerController(SmilPlayer player) {
318 public int getBufferPercentage() {
319 // We don't need to buffer data, always return 100%.
323 public int getCurrentPosition() {
324 return mPlayer.getCurrentPosition();
327 public int getDuration() {
328 return mPlayer.getDuration();
331 public boolean isPlaying() {
332 return mPlayer != null ? mPlayer.isPlayingState() : false;
335 public void pause() {
336 if (mPlayer != null) {
341 public void seekTo(int pos) {
342 // Don't need to support.
345 public void start() {
346 if (mPlayer != null) {
351 public boolean canPause() {
355 public boolean canSeekBackward() {
359 public boolean canSeekForward() {
364 public void handleEvent(Event evt) {
365 final Event event = evt;
366 mHandler.post(new Runnable() {
368 String type = event.getType();
369 if(type.equals(SmilDocumentImpl.SMIL_DOCUMENT_END_EVENT)) {