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 功能。

相关推荐
道之所在1 小时前
UE5.6源码安卓打包报错
android·ue5
用户2018792831671 小时前
贪心算法故事:拖延症小明的作业危机
android
人帅是非多1 小时前
Spanny-使用DSL优雅构建Android富文本库
android·github
liang_jy1 小时前
Activity 启动流程(六)—— Activity 窗口显示
android·面试·源码
RichardLai883 小时前
[Flutter 进阶] - 掌握StatefulWidget的艺术
android·前端·flutter
harry235day3 小时前
Flutter InheritedWidget 详解
flutter
墨狂之逸才3 小时前
为什么Thread要接受一个Runnable对象
android
倚楼听雨23 小时前
kotlin协程
android
倚楼听雨23 小时前
kotlin设计模式-创造型
android
粤M温同学3 小时前
Android OkHttp 框架超时设置详解
android·okhttp