blob: abb3c97b8a5810f7ebececc34373f6976b5c29db [file] [log] [blame]
/*
* 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;
//BEGIN_INCLUDE(complete)
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);
}
}
//END_INCLUDE(complete)