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