How to not separate task when entering picture in picture mode

Viewed 436

I am creating a media player application and I would like to support picture in picture. My problem is whenever I enter PIP, the player activity separates itself from the previous activity and such.

Screenshot: multiple tasks

Here is my activity declaration:

<activity
            android:name=".ui.player.PlayerActivity"
            android:allowTaskReparenting="true"
            android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation"
            android:exported="true"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/player"
            android:launchMode="singleTask"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsPictureInPicture="true">

Here is the code that I use to enter PIP:

    override fun onUserLeaveHint() {
        enterPictureInPicture()
    }

    private fun enterPictureInPicture() {
        val player = manager.currentPlayer
        if (player is SimpleExoPlayer) {
            val format = player.videoFormat
            val params = PictureInPictureParams.Builder()
                .setAspectRatio(format?.let { Rational(it.width, it.height) } ?: Rational(16, 9))
                .build()
            enterPictureInPictureMode(params)
        }
    }
2 Answers

I was having issue having multiple task running after expanding the PIP back into the app. We use multiple activities because we want PIP running while in the app. So when user trigger expanding/restoring the pip I call this method:


    public static boolean removeLauncherTask(Context appContext) {
        ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
        // iterate app tasks available and navigate to launcher task (browse task)
        assert activityManager != null;
        final List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
        for (ActivityManager.AppTask task : appTasks) {
            final Intent baseIntent = task.getTaskInfo().baseIntent;
            final Set<String> categories = baseIntent.getCategories();
            if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
                PictureInPictureActivity.mBackstackLost = true; // to keep track
                task.setExcludeFromRecents(true);
                return true;
            }
        }
        return false;
    }

You still need to handle your backstack after coming from restoring pip but many post have addressed this. Hint you need to call this method after navigating from the pip activity if you lost your backstack

    public static boolean navToLauncherTask(Context appContext) {
        ActivityManager activityManager = (ActivityManager) appContext.getSystemService(Context.ACTIVITY_SERVICE);
        // iterate app tasks available and navigate to launcher task (browse task)
        assert activityManager != null;
        final List<ActivityManager.AppTask> appTasks = activityManager.getAppTasks();
        for (ActivityManager.AppTask task : appTasks) {
            final Intent baseIntent = task.getTaskInfo().baseIntent;
            final Set<String> categories = baseIntent.getCategories();
            if (categories != null && categories.contains(Intent.CATEGORY_LAUNCHER)) {
                task.moveToFront();
                return true;
            }
        }
        return false;
    }
''''

Which looks very similar as the removing of the main task. 

The best way to avoid this would be to use one activity and have stuff as fragments

Related