TransportControllerActivity.java revision c9887f62d697bcf7d2f6443c848c8b57a7bfc3bd
1/*
2 * Copyright (C) 2013 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 *      http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.example.android.supportv4.media;
18
19import android.support.v4.media.TransportMediator;
20import android.support.v4.media.TransportPerformer;
21import com.example.android.supportv4.R;
22
23import android.app.ActionBar;
24import android.content.Context;
25import android.media.MediaPlayer;
26import android.os.Handler;
27import android.util.AttributeSet;
28import android.view.KeyEvent;
29import android.view.View;
30
31import android.app.Activity;
32import android.net.Uri;
33import android.os.Bundle;
34import android.widget.VideoView;
35
36public class TransportControllerActivity extends Activity {
37
38    /**
39     * TODO: Set the path variable to a streaming video URL or a local media
40     * file path.
41     */
42    private Content mContent;
43    private TransportMediator mTransportMediator;
44    private MediaController mMediaController;
45
46    /**
47     * Handle actions from on-screen media controls.  Most of these are simple re-directs
48     * to the VideoView; some we need to capture to update our state.
49     */
50    TransportPerformer mTransportPerformer = new TransportPerformer() {
51
52        @Override
53        public void onStart() {
54            mContent.start();
55        }
56
57        @Override
58        public void onStop() {
59            mContent.pause();
60        }
61
62        @Override
63        public void onPause() {
64            mContent.pause();
65        }
66
67        @Override
68        public int onGetDuration() {
69            return mContent.getDuration();
70        }
71
72        @Override
73        public int onGetCurrentPosition() {
74            return mContent.getCurrentPosition();
75        }
76
77        @Override
78        public void onSeekTo(int pos) {
79            mContent.seekTo(pos);
80        }
81
82        @Override
83        public boolean onIsPlaying() {
84            return mContent.isPlaying();
85        }
86
87        @Override
88        public int onGetBufferPercentage() {
89            return mContent.getBufferPercentage();
90        }
91
92        @Override
93        public int onGetTransportControlFlags() {
94            int flags = TransportMediator.FLAG_KEY_MEDIA_PLAY
95                    | TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE
96                    | TransportMediator.FLAG_KEY_MEDIA_STOP;
97            if (mContent.canPause()) {
98                flags |= TransportMediator.FLAG_KEY_MEDIA_PAUSE;
99            }
100            if (mContent.canSeekBackward()) {
101                flags |= TransportMediator.FLAG_KEY_MEDIA_REWIND;
102            }
103            if (mContent.canSeekForward()) {
104                flags |= TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD;
105            }
106            return flags;
107        }
108    };
109
110    /**
111     * This is the actual video player.  It is the top-level content of
112     * the activity's view hierarchy, going under the status bar and nav
113     * bar areas.
114     */
115    public static class Content extends VideoView implements
116            View.OnSystemUiVisibilityChangeListener, View.OnClickListener,
117            ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener,
118            MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener {
119        Activity mActivity;
120        TransportMediator mTransportMediator;
121        MediaController mMediaController;
122        boolean mAddedMenuListener;
123        boolean mMenusOpen;
124        boolean mPaused;
125        boolean mNavVisible;
126        int mLastSystemUiVis;
127
128        Runnable mNavHider = new Runnable() {
129            @Override public void run() {
130                setNavVisibility(false);
131            }
132        };
133
134        Runnable mProgressUpdater = new Runnable() {
135            @Override public void run() {
136                mMediaController.updateProgress();
137                getHandler().postDelayed(this, 1000);
138            }
139        };
140
141        public Content(Context context, AttributeSet attrs) {
142            super(context, attrs);
143            setOnSystemUiVisibilityChangeListener(this);
144            setOnClickListener(this);
145            setOnPreparedListener(this);
146            setOnCompletionListener(this);
147            setOnErrorListener(this);
148        }
149
150        public void init(Activity activity, TransportMediator transportMediator,
151                MediaController mediaController) {
152            // This called by the containing activity to supply the surrounding
153            // state of the video player that it will interact with.
154            mActivity = activity;
155            mTransportMediator = transportMediator;
156            mMediaController = mediaController;
157            pause();
158        }
159
160        @Override protected void onAttachedToWindow() {
161            super.onAttachedToWindow();
162            if (mActivity != null) {
163                mAddedMenuListener = true;
164                mActivity.getActionBar().addOnMenuVisibilityListener(this);
165            }
166        }
167
168        @Override protected void onDetachedFromWindow() {
169            super.onDetachedFromWindow();
170            if (mAddedMenuListener) {
171                mActivity.getActionBar().removeOnMenuVisibilityListener(this);
172            }
173            mNavVisible = false;
174        }
175
176        @Override public void onSystemUiVisibilityChange(int visibility) {
177            // Detect when we go out of nav-hidden mode, to clear our state
178            // back to having the full UI chrome up.  Only do this when
179            // the state is changing and nav is no longer hidden.
180            int diff = mLastSystemUiVis ^ visibility;
181            mLastSystemUiVis = visibility;
182            if ((diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0
183                    && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) {
184                setNavVisibility(true);
185            }
186        }
187
188        @Override protected void onWindowVisibilityChanged(int visibility) {
189            super.onWindowVisibilityChanged(visibility);
190
191            // When we become visible or invisible, play is paused.
192            pause();
193        }
194
195        @Override public void onClick(View v) {
196            // Clicking anywhere makes the navigation visible.
197            setNavVisibility(true);
198        }
199
200        @Override public void onMenuVisibilityChanged(boolean isVisible) {
201            mMenusOpen = isVisible;
202            setNavVisibility(true);
203        }
204
205        @Override
206        public void onPrepared(MediaPlayer mp) {
207            mMediaController.setEnabled(true);
208        }
209
210        @Override
211        public void onCompletion(MediaPlayer mp) {
212            mTransportMediator.pausePlaying();
213            pause();
214        }
215
216        @Override
217        public boolean onError(MediaPlayer mp, int what, int extra) {
218            mTransportMediator.pausePlaying();
219            pause();
220            return false;
221        }
222
223        @Override public void start() {
224            super.start();
225            mPaused = false;
226            setKeepScreenOn(true);
227            setNavVisibility(true);
228            mMediaController.refresh();
229            scheduleProgressUpdater();
230        }
231
232        @Override public void pause() {
233            super.pause();
234            mPaused = true;
235            setKeepScreenOn(false);
236            setNavVisibility(true);
237            mMediaController.refresh();
238            scheduleProgressUpdater();
239        }
240
241        void scheduleProgressUpdater() {
242            Handler h = getHandler();
243            if (h != null) {
244                if (mNavVisible && !mPaused) {
245                    h.removeCallbacks(mProgressUpdater);
246                    h.post(mProgressUpdater);
247                } else {
248                    h.removeCallbacks(mProgressUpdater);
249                }
250            }
251        }
252
253        void setNavVisibility(boolean visible) {
254            int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN
255                    | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION
256                    | SYSTEM_UI_FLAG_LAYOUT_STABLE;
257            if (!visible) {
258                newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN
259                        | SYSTEM_UI_FLAG_HIDE_NAVIGATION;
260            }
261
262            // If we are now visible, schedule a timer for us to go invisible.
263            if (visible) {
264                Handler h = getHandler();
265                if (h != null) {
266                    h.removeCallbacks(mNavHider);
267                    if (!mMenusOpen && !mPaused) {
268                        // If the menus are open or play is paused, we will not auto-hide.
269                        h.postDelayed(mNavHider, 3000);
270                    }
271                }
272            }
273
274            // Set the new desired visibility.
275            setSystemUiVisibility(newVis);
276            mNavVisible = visible;
277            mMediaController.setVisibility(visible ? VISIBLE : INVISIBLE);
278            scheduleProgressUpdater();
279        }
280    }
281
282    @Override
283    public void onCreate(Bundle icicle) {
284        super.onCreate(icicle);
285        setContentView(R.layout.videoview);
286
287        // Find the video player in our UI.
288        mContent = (Content) findViewById(R.id.content);
289
290        // Create transport controller to control video, giving the callback
291        // interface to receive actions from.
292        mTransportMediator = new TransportMediator(this, mTransportPerformer);
293
294        // Create and initialize the media control UI.
295        mMediaController = (MediaController) findViewById(R.id.media_controller);
296        mMediaController.setMediaPlayer(mTransportMediator);
297
298        // We're just playing a built-in demo video.
299        mContent.init(this, mTransportMediator, mMediaController);
300        mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() +
301                "/" + R.raw.videoviewdemo));
302    }
303
304    @Override
305    public boolean dispatchKeyEvent(KeyEvent event) {
306        // We first dispatch keys to the transport controller -- we want it
307        // to get to consume any media keys rather than letting whoever has focus
308        // in the view hierarchy to potentially eat it.
309        if (mTransportMediator.dispatchKeyEvent(event)) {
310            return true;
311        }
312
313        return super.dispatchKeyEvent(event);
314    }
315}
316