Picture In Picture | Android Studio | Java
How to add Picture In Picture Mode in the android app?
The Android 8.0 (API level 26) allows activities to launch in the picture-in-picture (PIP) mode. PIP is a special type of multi-window mode mostly used for video playback. It lets the user watch a video in a small window pinned to a corner of the screen while navigating between apps or browsing content on the main screen. The PIP window appears in the top layer of the screen in a corner chosen by the system.
Video:
Step 1: Create a new project OR Open your project
Step 2: Create another activity named PIPActivity
Step 3: Add the following properties to the PIPActivity in AndroidManifest
<activity android:name=".PIPActivity" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:launchMode="singleTask" android:resizeableActivity="true" android:supportsPictureInPicture="true"/>
Step 3: Code
AndroidMenifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.blogspot.atifsoftwares.pictureinpicture"> <!-- internet permission --> <uses-permission android:name="android.permission.INTERNET" /> <application android:allowBackup="true" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.PictureInPicture"> <activity android:name=".PIPActivity" android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation" android:launchMode="singleTask" android:resizeableActivity="true" android:supportsPictureInPicture="true"/> <activity android:name=".MainActivity"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
actiivty_main.xml
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:padding="20dp" android:orientation="vertical" android:gravity="center" tools:context=".MainActivity"> <!--Button click, play 1st video--> <Button android:id="@+id/videoOneBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Video One"/> <!--Button click, play 2nd video--> <Button android:id="@+id/videoTwoBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Video Two"/> <!--Button click, play 3rd video--> <Button android:id="@+id/videoThreeBtn" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="Video Three"/> </LinearLayout>
MainActivity.java
package com.blogspot.atifsoftwares.pictureinpicture; import androidx.appcompat.app.AppCompatActivity; import android.content.Intent; import android.os.Bundle; import android.view.View; import android.widget.Button; public class MainActivity extends AppCompatActivity { //video urls/links private static final String videoUrlOne = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/BigBuckBunny.mp4"; private static final String videoUrlTwo = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/WeAreGoingOnBullrun.mp4"; private static final String videoUrlThree = "https://commondatastorage.googleapis.com/gtv-videos-bucket/sample/VolkswagenGTIReview.mp4"; private Button videoOneBtn, videoTwoBtn, videoThreeBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //init UI Views videoOneBtn = findViewById(R.id.videoOneBtn); videoTwoBtn = findViewById(R.id.videoTwoBtn); videoThreeBtn = findViewById(R.id.videoThreeBtn); //handle clicks, to play specific video in new activity videoOneBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { playVideo(videoUrlOne); } }); videoTwoBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { playVideo(videoUrlTwo); } }); videoThreeBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { playVideo(videoUrlThree); } }); } private void playVideo(String videoUrl){ //Intent to start acitivity, with video url Intent intent = new Intent(MainActivity.this, PIPActivity.class); intent.putExtra("videoURL", videoUrl); startActivity(intent); } }
activity_pip.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:background="#000" tools:context=".PIPActivity"> <!--VideoView: Play Video--> <VideoView android:id="@+id/videoView" android:layout_width="match_parent" android:layout_centerInParent="true" android:layout_height="wrap_content"/> <!--ImageButton: Click to switch to Picture In Picture Mode--> <ImageButton android:id="@+id/pipBtn" android:layout_width="wrap_content" android:layout_height="wrap_content" android:src="@drawable/ic_pip_white" android:layout_alignParentEnd="true" android:background="@android:color/transparent" android:layout_margin="10dp"/> </RelativeLayout>
PIPActivity.java
package com.blogspot.atifsoftwares.pictureinpicture; import androidx.appcompat.app.ActionBar; import androidx.appcompat.app.AppCompatActivity; import android.app.PictureInPictureParams; import android.content.Intent; import android.content.res.Configuration; import android.media.MediaPlayer; import android.net.Uri; import android.os.Build; import android.os.Bundle; import android.util.Log; import android.util.Rational; import android.view.View; import android.widget.ImageButton; import android.widget.MediaController; import android.widget.VideoView; public class PIPActivity extends AppCompatActivity { private Uri videoUri; private static final String TAG = "PIP_TAG"; private VideoView videoView; private ImageButton pipBtn; private ActionBar actionBar; private PictureInPictureParams.Builder pictureInPictureParams; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_p_i_p); //actionbar actionBar = getSupportActionBar(); //init UI Views videoView = findViewById(R.id.videoView); pipBtn = findViewById(R.id.pipBtn); setVideoView(getIntent());//get and pass intent to a method that will handle video playback, intent contains url of video //init PictureInPictureParams, requires Android O and higher if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ pictureInPictureParams = new PictureInPictureParams.Builder(); } //handle click, enter PIP mode pipBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { pictureInPictureMode(); } }); } private void setVideoView(Intent intent) { String videoURL = intent.getStringExtra("videoURL"); Log.d(TAG, "setVideoView: URL:"+ videoURL); //MediaController for play, pause, seekbar, time etc MediaController mediaController = new MediaController(this); mediaController.setAnchorView(videoView); videoUri = Uri.parse(videoURL); //set media controller to videoview videoView.setMediaController(mediaController); //set video uri to videoview videoView.setVideoURI(videoUri); //add video prepare listener videoView.setOnPreparedListener(new MediaPlayer.OnPreparedListener() { @Override public void onPrepared(MediaPlayer mp) { //when video is ready, play it Log.d(TAG, "onPrepared: Video Prepared, Playing..."); mp.start(); } }); } private void pictureInPictureMode(){ //Requires Android O and higher if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){ Log.d(TAG, "pictureInPictureMode: Supports PIP"); //setup height and width of PIP window Rational aspectRation = new Rational(videoView.getWidth(), videoView.getHeight()); pictureInPictureParams.setAspectRatio(aspectRation).build(); enterPictureInPictureMode(pictureInPictureParams.build()); } else { Log.d(TAG, "pictureInPictureMode: Doesn't supports PIP"); } } @Override protected void onUserLeaveHint() { super.onUserLeaveHint(); //called when user presses Home button, enter in PIP mode, requires Android N if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){ if (!isInPictureInPictureMode()){ Log.d(TAG, "onUserLeaveHint: was not in PIP"); pictureInPictureMode(); } else { Log.d(TAG, "onUserLeaveHint: Already in PIP"); } } } @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); if (isInPictureInPictureMode){ Log.d(TAG, "onPictureInPictureModeChanged: Entered PIP"); //hide Pip button and actionbar pipBtn.setVisibility(View.GONE); actionBar.hide(); } else { Log.d(TAG, "onPictureInPictureModeChanged: Exited PIP"); //show pip button and actionbar pipBtn.setVisibility(View.VISIBLE); actionBar.show(); } } @Override protected void onNewIntent(Intent intent) { super.onNewIntent(intent); //when video 1 is playing in PIP mode, and user clicks video 2: handle/play new video Log.d(TAG, "onNewIntent: Play new Video"); setVideoView(intent); } @Override protected void onStop() { super.onStop(); if (videoView.isPlaying()){ videoView.stopPlayback(); } } }
Thanks
ReplyDelete