Download File
Download Project
Settings
Line Wrap
Themes
default
ambiance
bespin
dracula
eclipse
material
mbo
mdn-like
neat
solarized dark
ttcn
zenburn
MediaSessionPlaybackActivity.java
/* * Copyright (C) 2017 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.pictureinpicture; import android.app.PictureInPictureParams; import android.content.Intent; import android.content.res.Configuration; import android.os.Bundle; import android.support.v4.media.session.MediaControllerCompat; import android.support.v4.media.session.MediaSessionCompat; import android.support.v4.media.session.PlaybackStateCompat; import android.support.v7.app.AppCompatActivity; import android.util.Rational; import android.view.View; import android.widget.Button; import android.widget.ScrollView; import com.example.android.pictureinpicture.widget.MovieView; /** * Demonstrates usage of Picture-in-Picture when using {@link * android.support.v4.media.session.MediaSessionCompat}. */ public class MediaSessionPlaybackActivity extends AppCompatActivity { private static final String TAG = "MediaSessionPlaybackActivity"; public static final long MEDIA_ACTIONS_PLAY_PAUSE = PlaybackStateCompat.ACTION_PLAY | PlaybackStateCompat.ACTION_PAUSE | PlaybackStateCompat.ACTION_PLAY_PAUSE; public static final long MEDIA_ACTIONS_ALL = MEDIA_ACTIONS_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_NEXT | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS; private MediaSessionCompat mSession; /** The arguments to be used for Picture-in-Picture mode. */ private final PictureInPictureParams.Builder mPictureInPictureParamsBuilder = new PictureInPictureParams.Builder(); /** This shows the video. */ private MovieView mMovieView; /** The bottom half of the screen; hidden on landscape */ private ScrollView mScrollView; private final View.OnClickListener mOnClickListener = new View.OnClickListener() { @Override public void onClick(View view) { switch (view.getId()) { case R.id.pip: minimize(); break; } } }; /** Callbacks from the {@link MovieView} showing the video playback. */ private MovieView.MovieListener mMovieListener = new MovieView.MovieListener() { @Override public void onMovieStarted() { // We are playing the video now. Update the media session state and the PiP // window will // update the actions. updatePlaybackState( PlaybackStateCompat.STATE_PLAYING, mMovieView.getCurrentPosition(), mMovieView.getVideoResourceId()); } @Override public void onMovieStopped() { // The video stopped or reached its end. Update the media session state and the // PiP window will // update the actions. updatePlaybackState( PlaybackStateCompat.STATE_PAUSED, mMovieView.getCurrentPosition(), mMovieView.getVideoResourceId()); } @Override public void onMovieMinimized() { // The MovieView wants us to minimize it. We enter Picture-in-Picture mode now. minimize(); } }; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // View references mMovieView = findViewById(R.id.movie); mScrollView = findViewById(R.id.scroll); Button switchExampleButton = findViewById(R.id.switch_example); switchExampleButton.setText(getString(R.string.switch_custom)); switchExampleButton.setOnClickListener(new SwitchActivityOnClick()); // Set up the video; it automatically starts. mMovieView.setMovieListener(mMovieListener); findViewById(R.id.pip).setOnClickListener(mOnClickListener); } @Override protected void onStart() { super.onStart(); initializeMediaSession(); } private void initializeMediaSession() { mSession = new MediaSessionCompat(this, TAG); mSession.setFlags( MediaSessionCompat.FLAG_HANDLES_MEDIA_BUTTONS | MediaSessionCompat.FLAG_HANDLES_TRANSPORT_CONTROLS); mSession.setActive(true); MediaControllerCompat.setMediaController(this, mSession.getController()); MediaSessionCallback mMediaSessionCallback = new MediaSessionCallback(mMovieView); mSession.setCallback(mMediaSessionCallback); int state = mMovieView.isPlaying() ? PlaybackStateCompat.STATE_PLAYING : PlaybackStateCompat.STATE_PAUSED; updatePlaybackState( state, MEDIA_ACTIONS_ALL, mMovieView.getCurrentPosition(), mMovieView.getVideoResourceId()); } @Override protected void onStop() { super.onStop(); // On entering Picture-in-Picture mode, onPause is called, but not onStop. // For this reason, this is the place where we should pause the video playback. mMovieView.pause(); mSession.release(); mSession = null; } @Override protected void onRestart() { super.onRestart(); if (!isInPictureInPictureMode()) { // Show the video controls so the video can be easily resumed. mMovieView.showControls(); } } @Override public void onConfigurationChanged(Configuration newConfig) { super.onConfigurationChanged(newConfig); adjustFullScreen(newConfig); } @Override public void onWindowFocusChanged(boolean hasFocus) { super.onWindowFocusChanged(hasFocus); if (hasFocus) { adjustFullScreen(getResources().getConfiguration()); } } @Override public void onPictureInPictureModeChanged( boolean isInPictureInPictureMode, Configuration configuration) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, configuration); if (!isInPictureInPictureMode) { // Show the video controls if the video is not playing if (mMovieView != null && !mMovieView.isPlaying()) { mMovieView.showControls(); } } } /** Enters Picture-in-Picture mode. */ void minimize() { if (mMovieView == null) { return; } // Hide the controls in picture-in-picture mode. mMovieView.hideControls(); // Calculate the aspect ratio of the PiP screen. Rational aspectRatio = new Rational(mMovieView.getWidth(), mMovieView.getHeight()); mPictureInPictureParamsBuilder.setAspectRatio(aspectRatio).build(); enterPictureInPictureMode(mPictureInPictureParamsBuilder.build()); } /** * Adjusts immersive full-screen flags depending on the screen orientation. * * @param config The current {@link Configuration}. */ private void adjustFullScreen(Configuration config) { final View decorView = getWindow().getDecorView(); if (config.orientation == Configuration.ORIENTATION_LANDSCAPE) { decorView.setSystemUiVisibility( View.SYSTEM_UI_FLAG_LAYOUT_STABLE | View.SYSTEM_UI_FLAG_LAYOUT_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_LAYOUT_FULLSCREEN | View.SYSTEM_UI_FLAG_HIDE_NAVIGATION | View.SYSTEM_UI_FLAG_FULLSCREEN | View.SYSTEM_UI_FLAG_IMMERSIVE_STICKY); mScrollView.setVisibility(View.GONE); mMovieView.setAdjustViewBounds(false); } else { decorView.setSystemUiVisibility(View.SYSTEM_UI_FLAG_LAYOUT_STABLE); mScrollView.setVisibility(View.VISIBLE); mMovieView.setAdjustViewBounds(true); } } /** * Overloaded method that persists previously set media actions. * * @param state The state of the video, e.g. playing, paused, etc. * @param position The position of playback in the video. * @param mediaId The media id related to the video in the media session. */ private void updatePlaybackState( @PlaybackStateCompat.State int state, int position, int mediaId) { long actions = mSession.getController().getPlaybackState().getActions(); updatePlaybackState(state, actions, position, mediaId); } private void updatePlaybackState( @PlaybackStateCompat.State int state, long playbackActions, int position, int mediaId) { PlaybackStateCompat.Builder builder = new PlaybackStateCompat.Builder() .setActions(playbackActions) .setActiveQueueItemId(mediaId) .setState(state, position, 1.0f); mSession.setPlaybackState(builder.build()); } /** * Updates the {@link MovieView} based on the callback actions.
* Simulates a playlist that will disable actions when you cannot skip through the playlist in a * certain direction. */ private class MediaSessionCallback extends MediaSessionCompat.Callback { private static final int PLAYLIST_SIZE = 2; private MovieView movieView; private int indexInPlaylist; public MediaSessionCallback(MovieView movieView) { this.movieView = movieView; indexInPlaylist = 1; } @Override public void onPlay() { super.onPlay(); movieView.play(); } @Override public void onPause() { super.onPause(); movieView.pause(); } @Override public void onSkipToNext() { super.onSkipToNext(); movieView.startVideo(); if (indexInPlaylist < PLAYLIST_SIZE) { indexInPlaylist++; if (indexInPlaylist >= PLAYLIST_SIZE) { updatePlaybackState( PlaybackStateCompat.STATE_PLAYING, MEDIA_ACTIONS_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_PREVIOUS, movieView.getCurrentPosition(), movieView.getVideoResourceId()); } else { updatePlaybackState( PlaybackStateCompat.STATE_PLAYING, MEDIA_ACTIONS_ALL, movieView.getCurrentPosition(), movieView.getVideoResourceId()); } } } @Override public void onSkipToPrevious() { super.onSkipToPrevious(); movieView.startVideo(); if (indexInPlaylist > 0) { indexInPlaylist--; if (indexInPlaylist <= 0) { updatePlaybackState( PlaybackStateCompat.STATE_PLAYING, MEDIA_ACTIONS_PLAY_PAUSE | PlaybackStateCompat.ACTION_SKIP_TO_NEXT, movieView.getCurrentPosition(), movieView.getVideoResourceId()); } else { updatePlaybackState( PlaybackStateCompat.STATE_PLAYING, MEDIA_ACTIONS_ALL, movieView.getCurrentPosition(), movieView.getVideoResourceId()); } } } } private class SwitchActivityOnClick implements View.OnClickListener { @Override public void onClick(View view) { startActivity(new Intent(view.getContext(), MainActivity.class)); finish(); } } }