/* * Copyright (C) 2013 The Android Open Source Project * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.example.android.supportv4.media; import android.support.v4.media.TransportMediator; import android.support.v4.media.TransportPerformer; import com.example.android.supportv4.R; import android.app.ActionBar; import android.content.Context; import android.media.MediaPlayer; import android.os.Handler; import android.util.AttributeSet; import android.view.KeyEvent; import android.view.View; import android.app.Activity; import android.net.Uri; import android.os.Bundle; import android.widget.VideoView; public class TransportControllerActivity extends Activity { /** * TODO: Set the path variable to a streaming video URL or a local media * file path. */ private Content mContent; private TransportMediator mTransportMediator; private MediaController mMediaController; /** * Handle actions from on-screen media controls. Most of these are simple re-directs * to the VideoView; some we need to capture to update our state. */ TransportPerformer mTransportPerformer = new TransportPerformer() { @Override public void onStart() { mContent.start(); } @Override public void onStop() { mContent.pause(); } @Override public void onPause() { mContent.pause(); } @Override public long onGetDuration() { return mContent.getDuration(); } @Override public long onGetCurrentPosition() { return mContent.getCurrentPosition(); } @Override public void onSeekTo(long pos) { mContent.seekTo((int)pos); } @Override public boolean onIsPlaying() { return mContent.isPlaying(); } @Override public int onGetBufferPercentage() { return mContent.getBufferPercentage(); } @Override public int onGetTransportControlFlags() { int flags = TransportMediator.FLAG_KEY_MEDIA_PLAY | TransportMediator.FLAG_KEY_MEDIA_PLAY_PAUSE | TransportMediator.FLAG_KEY_MEDIA_STOP; if (mContent.canPause()) { flags |= TransportMediator.FLAG_KEY_MEDIA_PAUSE; } if (mContent.canSeekBackward()) { flags |= TransportMediator.FLAG_KEY_MEDIA_REWIND; } if (mContent.canSeekForward()) { flags |= TransportMediator.FLAG_KEY_MEDIA_FAST_FORWARD; } return flags; } }; /** * This is the actual video player. It is the top-level content of * the activity's view hierarchy, going under the status bar and nav * bar areas. */ public static class Content extends VideoView implements View.OnSystemUiVisibilityChangeListener, View.OnClickListener, ActionBar.OnMenuVisibilityListener, MediaPlayer.OnPreparedListener, MediaPlayer.OnCompletionListener, MediaPlayer.OnErrorListener { Activity mActivity; TransportMediator mTransportMediator; MediaController mMediaController; boolean mAddedMenuListener; boolean mMenusOpen; boolean mPaused; boolean mNavVisible; int mLastSystemUiVis; Runnable mNavHider = new Runnable() { @Override public void run() { setNavVisibility(false); } }; Runnable mProgressUpdater = new Runnable() { @Override public void run() { mMediaController.updateProgress(); getHandler().postDelayed(this, 1000); } }; public Content(Context context, AttributeSet attrs) { super(context, attrs); setOnSystemUiVisibilityChangeListener(this); setOnClickListener(this); setOnPreparedListener(this); setOnCompletionListener(this); setOnErrorListener(this); } public void init(Activity activity, TransportMediator transportMediator, MediaController mediaController) { // This called by the containing activity to supply the surrounding // state of the video player that it will interact with. mActivity = activity; mTransportMediator = transportMediator; mMediaController = mediaController; pause(); } @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (mActivity != null) { mAddedMenuListener = true; mActivity.getActionBar().addOnMenuVisibilityListener(this); } } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAddedMenuListener) { mActivity.getActionBar().removeOnMenuVisibilityListener(this); } mNavVisible = false; } @Override public void onSystemUiVisibilityChange(int visibility) { // Detect when we go out of nav-hidden mode, to clear our state // back to having the full UI chrome up. Only do this when // the state is changing and nav is no longer hidden. int diff = mLastSystemUiVis ^ visibility; mLastSystemUiVis = visibility; if ((diff&SYSTEM_UI_FLAG_HIDE_NAVIGATION) != 0 && (visibility&SYSTEM_UI_FLAG_HIDE_NAVIGATION) == 0) { setNavVisibility(true); } } @Override protected void onWindowVisibilityChanged(int visibility) { super.onWindowVisibilityChanged(visibility); // When we become visible or invisible, play is paused. pause(); } @Override public void onClick(View v) { // Clicking anywhere makes the navigation visible. setNavVisibility(true); } @Override public void onMenuVisibilityChanged(boolean isVisible) { mMenusOpen = isVisible; setNavVisibility(true); } @Override public void onPrepared(MediaPlayer mp) { mMediaController.setEnabled(true); } @Override public void onCompletion(MediaPlayer mp) { mTransportMediator.pausePlaying(); pause(); } @Override public boolean onError(MediaPlayer mp, int what, int extra) { mTransportMediator.pausePlaying(); pause(); return false; } @Override public void start() { super.start(); mPaused = false; setKeepScreenOn(true); setNavVisibility(true); mMediaController.refresh(); scheduleProgressUpdater(); } @Override public void pause() { super.pause(); mPaused = true; setKeepScreenOn(false); setNavVisibility(true); mMediaController.refresh(); scheduleProgressUpdater(); } void scheduleProgressUpdater() { Handler h = getHandler(); if (h != null) { if (mNavVisible && !mPaused) { h.removeCallbacks(mProgressUpdater); h.post(mProgressUpdater); } else { h.removeCallbacks(mProgressUpdater); } } } void setNavVisibility(boolean visible) { int newVis = SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | SYSTEM_UI_FLAG_LAYOUT_STABLE; if (!visible) { newVis |= SYSTEM_UI_FLAG_LOW_PROFILE | SYSTEM_UI_FLAG_FULLSCREEN | SYSTEM_UI_FLAG_HIDE_NAVIGATION; } // If we are now visible, schedule a timer for us to go invisible. if (visible) { Handler h = getHandler(); if (h != null) { h.removeCallbacks(mNavHider); if (!mMenusOpen && !mPaused) { // If the menus are open or play is paused, we will not auto-hide. h.postDelayed(mNavHider, 3000); } } } // Set the new desired visibility. setSystemUiVisibility(newVis); mNavVisible = visible; mMediaController.setVisibility(visible ? VISIBLE : INVISIBLE); scheduleProgressUpdater(); } } @Override public void onCreate(Bundle icicle) { super.onCreate(icicle); setContentView(R.layout.videoview); // Find the video player in our UI. mContent = (Content) findViewById(R.id.content); // Create transport controller to control video, giving the callback // interface to receive actions from. mTransportMediator = new TransportMediator(this, mTransportPerformer); // Create and initialize the media control UI. mMediaController = (MediaController) findViewById(R.id.media_controller); mMediaController.setMediaPlayer(mTransportMediator); // We're just playing a built-in demo video. mContent.init(this, mTransportMediator, mMediaController); mContent.setVideoURI(Uri.parse("android.resource://" + getPackageName() + "/" + R.raw.videoviewdemo)); } @Override public boolean dispatchKeyEvent(KeyEvent event) { // We first dispatch keys to the transport controller -- we want it // to get to consume any media keys rather than letting whoever has focus // in the view hierarchy to potentially eat it. if (mTransportMediator.dispatchKeyEvent(event)) { return true; } return super.dispatchKeyEvent(event); } }