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

相关推荐
行者967 分钟前
Flutter适配鸿蒙:SnackBar组件实践与优化策略
flutter·harmonyos·鸿蒙
2501_915918419 分钟前
介绍如何在电脑上查看 iPhone 和 iPad 的完整设备信息
android·ios·小程序·uni-app·电脑·iphone·ipad
TheNextByte112 分钟前
如何通过蓝牙将照片从 iPhone 分享到Android ?
android·gitee·iphone
kirk_wang19 分钟前
Flutter艺术探索-ListView与GridView列表组件完全指南
flutter·移动开发·flutter教程·移动开发教程
2501_9160088919 分钟前
没有 Mac 如何在 Windows 上创建 iOS 应用描述文件
android·macos·ios·小程序·uni-app·iphone·webview
Android系统攻城狮2 小时前
Android ALSA进阶之处理PCM的ioctl命令snd_pcm_lib_ioctl:用法实例(一百)
android·pcm·alsa·音频进阶
诸神黄昏EX10 小时前
Android Build系列专题【篇六:VINTF机制】
android
浪客川11 小时前
安卓日志工具类
android
消失的旧时光-194311 小时前
Flutter 插件通信架构设计:从 Channel 到 FFI 的完整边界
flutter·ffi
csj5011 小时前
安卓基础之《(14)—数据存储(4)应用组件Application》
android