'How Do We Leave Picture-In-Picture Mode?

We have enterPictureInPictureMode() to move an activity from its current form into a picture-in-picture representation.

What is the means by which we revert that, returning the activity to its normal state, besides destroying the activity? There is no exitPictureInPictureMode(), leavePictureInPictureMode(), or janeGetMeOffThisCrazyPictureInPictureModeThing() method on Activity, and the documentation does not seem to cover an alternative.

I am interested in a solution for Android O, for picture-in-picture mode on mobile devices, though if that works for Android TV too, wonderful!

UPDATE 2017-04-08: If what you want is to return to normal mode when the user clicks the X button to exit picture-in-picture mode, you can do something like this:

  @Override
  public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    super.onPictureInPictureModeChanged(isInPictureInPictureMode);

    if (!isInPictureInPictureMode) {
      getApplication().startActivity(new Intent(this, getClass())
        .addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT));
    }
  }

The key bits are to call startActivity() to start the current activity again with FLAG_ACTIVITY_REORDER_TO_FRONT. With a singleTask activity, you need to call that on some non-Activity context, such as the Application singleton. This does not appear to trigger onStop() or onStart(), but it does trigger onNewIntent() (with whatever Intent you pass to startActivity()).



Solution 1:[1]

  1. Move the activity to the back

    activity.moveTaskToBack(false /* nonRoot */);
    
  2. restore the activity to the front

    Intent startIntent = new Intent(PipActivity.this, PipActivity.class);
    startIntent.setFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT);
    activity.startActivity(startIntent);
    

Solution 2:[2]

I had the same problem:

  • MainActivity opens VideoPlayerActivity which has PIP mode enabled.
  • Press the back button to go to the PIP mode.
  • Press back button again until I exit from MainActivity.
  • Press close (X) button on the PIP window.
  • Open application, It will open VideoPlayerActivity.

While none of the above solutions work for me, I found out that the only way to listen to X button is to override onStop.

When the activity is restored from PIP, onResume and onPictureInPictureModeChanged are called, when the X button is clicked, the onStop and onPictureInPictureModeChanged are called.

So I tried to call finish() inside onPictureInPictureModeChanged when the onStop is alreay called.

override fun onStop() {
    super.onStop()
    onStopCalled = true
}

override fun onResume() {
    super.onResume()
    onStopCalled = false
}

override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean, newConfig: Configuration) {
        if (isInPictureInPictureMode) {
            // ...
        } else {
            if (onStopCalled) {
                finish()
            }
        }
    }

Solution 3:[3]

I don't think the activity can decide to leave Picture-in-picture mode.

From the Android O API preview doc:

The activity entering PIP mode goes into the paused state, but remains started. If the user taps the PIP activity, the system shows a menu for the user to interact with; no touch events reach the activity while it is in the PIP state.

The activity will be notified by onPictureInPictureModeChanged().

Solution 4:[4]

I've found a 100% reliable way to do this.

  1. Set the taskAffinity attribute for your PIP activity in the manifest to something like "com.package.pip". Doesn't matter what, it just has to be different from your package name which is the default task affinity. This will cause it to launch in a completely separate stack as if it were another app altogether.
  2. Whenever you want to exit PIP, launch it with startActivity(new Intent(this, PipActivity.class).addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)) from within another activity.

I just looked at what happens when the app's main activity is currently in PIP mode and you launch it from the launcher and thought that I could replicate this, and I indeed could.

Solution 5:[5]

Official documentation says PIP window comes up with menu which let you toggle to full screen.

The PIP window is 240x135 dp and is shown at the top-most layer in one of the four corners of the screen, chosen by the system. The user can bring up a PIP menu that lets them toggle the PIP window to full-screen, or close the PIP window, by holding down the Home button on the remote. If another video starts playing on the main screen, the PIP window is automatically closed.

And you can override PIP changed event to handle UI elements whenever the user toggles PIP mode.

link to onPictureInPictureModeChanged

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode) {
    if (isInPictureInPictureMode) {
        // Hide the controls in picture-in-picture mode.
        ...
    } else {
        // Restore the playback UI based on the playback status.
        ...
    }
}

Solution 6:[6]

According to latest answers from another stackoverflow blog https://stackoverflow.com/a/71797433/3842263 , it should be this way. It works good for me.

@Override
public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) {

    if (getLifecycle().getCurrentState() == Lifecycle.State.CREATED) {
        //when user click on Close button of PIP this will trigger.
        finishAndRemoveTask();

    }
    else if (getLifecycle().getCurrentState() == Lifecycle.State.STARTED){
        //when PIP maximize this will trigger
    }
    super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig);
}

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 rds
Solution 2 TBG
Solution 3 rds
Solution 4 Grishka
Solution 5 ugur
Solution 6