Flutter PIP 插件 ---- 新增PipActivity,Android 11以下支持自动进入PIP Mode

接上文 Flutter PIP 插件 ---- Android
项目地址 PIP, pub.dev也已经同步发布 pip 0.0.3,你的加星和点赞,将是我继续改进最大的动力

开发文档 Add videos using picture-in-picture (PiP)介绍PIP 功能从 Android 8.0 (API level 26) 引入,但是autoEnter 功能从 Android 12 才开始支持,那么不支持的版本呢就需要通过监听 onUserLeaveHint 主动调用 enterPictureInPictureMode 才能进入 PIP Mode ,在之前的版本中因为 FlutterActivity 没有转发 onUserLeaveHint ,导致我们只能在 dart 中通过 flutterdidChangeAppLifecycleState 事件,在应用进入后台是主动调用的方式进入PIP Mode ,但实际测下来,似乎无法区分通知栏下滑的通知,这导致即使应用在前台,当用户下滑通知栏的时候依然会自动进入PIP Mode, 这显然不是我们想要的,优化后的效果如下:

修改PIP插件

  • 新增PipActivity

    java 复制代码
    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 来决定是否启用相关的功能。

  • 绑定 ActivityPipController
    PipPluginonAttachedToActivityonReattachedToActivityForConfigChanges 的时候去初始化 PipController

    java 复制代码
    private 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

    java 复制代码
    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

    java 复制代码
    package org.opentraa.pip_example;
    
    import io.flutter.embedding.android.FlutterActivity;
    import org.opentraa.pip.PipActivity;
    
    public class MainActivity extends PipActivity {
    }

如上,至此我们已经支持了全部版本的 PIP Mode autoEnter 功能。

相关推荐
张拭心2 分钟前
Android 17 来了!新特性介绍与适配建议
android·前端
shankss1 小时前
Flutter 下拉刷新库 pull_to_refresh_plus 设计与实现分析
flutter
Kapaseker2 小时前
Compose 进阶—巧用 GraphicsLayer
android·kotlin
黄林晴3 小时前
Android17 为什么重写 MessageQueue
android
忆江南17 小时前
iOS 深度解析
flutter·ios
明君8799718 小时前
Flutter 实现 AI 聊天页面 —— 记一次 Markdown 数学公式显示的踩坑之旅
前端·flutter
恋猫de小郭19 小时前
移动端开发稳了?AI 目前还无法取代客户端开发,小红书的论文告诉你数据
前端·flutter·ai编程
MakeZero21 小时前
Flutter那些事-交互式组件
flutter
shankss21 小时前
pull_to_refresh_simple
flutter
shankss21 小时前
Flutter 下拉刷新库新特性:智能预加载 (enableSmartPreload) 详解
flutter