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 17 package com.example.android.supportv4.media; 18 19 //BEGIN_INCLUDE(complete) 20 import android.support.v4.media.TransportMediator; 21 import android.support.v4.media.TransportPerformer; 22 import com.example.android.supportv4.R; 23 24 import android.app.ActionBar; 25 import android.content.Context; 26 import android.media.MediaPlayer; 27 import android.os.Handler; 28 import android.util.AttributeSet; 29 import android.view.KeyEvent; 30 import android.view.View; 31 32 import android.app.Activity; 33 import android.net.Uri; 34 import android.os.Bundle; 35 import android.widget.VideoView; 36 37 public 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