开发文档 Add videos using picture-in-picture (PiP)介绍PIP功能从 Android 8.0 (API level 26) 引入,但是autoEnter功能从 Android 12 才开始支持,那么不支持的版本呢就需要通过监听 onUserLeaveHint 主动调用 enterPictureInPictureMode 才能进入 PIP Mode,在之前的版本中因为 FlutterActivity 没有转发 onUserLeaveHint,导致我们只能在 dart 中通过 flutter 的 didChangeAppLifecycleState 事件,在应用进入后台是主动调用的方式进入PIP Mode,但实际测下来,似乎无法区分通知栏下滑的通知,这导致即使应用在前台,当用户下滑通知栏的时候依然会自动进入PIP Mode, 这显然不是我们想要的,优化后的效果如下:
修改PIP插件
-
新增PipActivity
package org.opentraa.pip; import android.app.PictureInPictureUiState; import android.content.res.Configuration; import android.os.Build; import androidx.annotation.NonNull; import androidx.annotation.RequiresApi; import io.flutter.embedding.android.FlutterActivity; @RequiresApi(Build.VERSION_CODES.O) public class PipActivity extends FlutterActivity { public interface PipActivityListener { void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig); void onPictureInPictureUiStateChanged(PictureInPictureUiState state); boolean onPictureInPictureRequested(); void onUserLeaveHint(); } private PipActivityListener mListener; public void setPipActivityListener(PipActivityListener listener) { mListener = listener; } // only available in API level 26 and above @RequiresApi(26) @Override public void onPictureInPictureModeChanged(boolean isInPictureInPictureMode, Configuration newConfig) { super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); if (mListener != null) { mListener.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig); } } // only available in API level 30 and above @RequiresApi(30) @Override public boolean onPictureInPictureRequested() { if (mListener != null) { return mListener.onPictureInPictureRequested(); } return super.onPictureInPictureRequested(); } // only available in API level 31 and above @RequiresApi(31) @Override public void onPictureInPictureUiStateChanged(@NonNull PictureInPictureUiState state) { super.onPictureInPictureUiStateChanged(state); if (mListener != null) { mListener.onPictureInPictureUiStateChanged(state); } } @Override public void onUserLeaveHint() { super.onUserLeaveHint(); if (mListener != null) { mListener.onUserLeaveHint(); } } }
主要思路就是如果PIP 插件的用户想要在 Android 12 以下支持应用进入后台自动进入 PIP Mode 的话,可以将自己 MainActivity 的父类修改为 PipActivity ,这样在 PIP 插件被注册时,可以通过判断传入的 Activity 是否是 PipActivity 来决定是否启用相关的功能。
-
绑定 Activity 到 PipController
PipPlugin 在 onAttachedToActivity 和 onReattachedToActivityForConfigChanges 的时候去初始化 PipControllerprivate void initPipController(@NonNull ActivityPluginBinding binding) { if (pipController == null) { pipController = new PipController( binding.getActivity(), new PipController.PipStateChangedListener() { @Override public void onPipStateChangedListener( PipController.PipState state) { // put state into a json object channel.invokeMethod("stateChanged", new HashMap<String, Object>() { { put("state", state.getValue()); } }); } }); } else { pipController.attachToActivity(binding.getActivity()); } } @Override public void onAttachedToActivity(@NonNull ActivityPluginBinding binding) { initPipController(binding); } @Override public void onReattachedToActivityForConfigChanges( @NonNull ActivityPluginBinding binding) { initPipController(binding); }
-
在 PipController 构造函数和 attachToActivity 方法中去综合当前的系统版本和绑定的 Activity 进行检查是否支持 autoEnter
public PipController(@NonNull Activity activity, @Nullable PipStateChangedListener listener) { setActivity(activity); // ... Other code ... } private boolean checkAutoEnterSupport() { // Android 12 and above support to set auto enter enabled directly if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) { return true; } // For android 11 and below, we need to check if the activity is kind of // PipActivity since we can enter pip mode when the onUserLeaveHint is // called to enter pip mode as a workaround Activity activity = mActivity.get(); return activity instanceof PipActivity; } private void setActivity(Activity activity) { mActivity = new WeakReference<>(activity); if (activity instanceof PipActivity) { ((PipActivity)activity).setPipActivityListener(this); } mIsSupported = checkPipSupport(); mIsAutoEnterSupported = checkAutoEnterSupport(); } public void attachToActivity(@NonNull Activity activity) { setActivity(activity); }
修改Example项目中的MainActivity
- 孤伶伶的MainActivity
package org.opentraa.pip_example; import io.flutter.embedding.android.FlutterActivity; import org.opentraa.pip.PipActivity; public class MainActivity extends PipActivity { }
如上,至此我们已经支持了全部版本的 PIP Mode autoEnter 功能。