Open someq opened 3 years ago
After digging some code found that PluginRegistry.Registrar which is used to register flutter_android_pip is deprecated (which causes deprecation warning).
Its method activity may return null, if application has no foreground activity (e.g., when it's paused).
Now seems it's an issue with async receiving of native state events in flutter. As I am trying to enter pip mode when app is minified (home button pressed, etc.) it should be called in onPause()
callback. But Flutter version of it is called too late to handle the pause. The app is paused, acitivity is no longer visible, thus the error.
It's similar to this case.
Seems Firebase just adds some asynchrounous communication on pause, thats why it does not work with it (firebase takes some time) and works without (firebase does not take any time).
Interesting. I have to read myself into it but it seems Flutter's Pigeon is the way to go for synchronous messages.
EDIT: pre-release here
Indeed Pigeon may work, but right now I made a workaround. It's still asynchronous, but fails less in my case:
added methods to MainActivity to detect if current screen may enter pip-mode when app is minimized:
class MainActivity: FlutterActivity() {
// ...
private var pipAllowed: Boolean = false
private var pipWidth: Int = 4
private var pipHeight: Int = 3
private fun allowPip(width: Int?, height: Int?) {
pipAllowed = true
if(width != null && height != null) {
pipWidth = width
pipHeight = height
}
}
private fun blockPip() {
pipAllowed = false
}
// ...
onUserLeaveHint()
to enter pip mode when user presses home button:
// ...
override fun onUserLeaveHint() {
super.onUserLeaveHint()
if(pipAllowed && android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
val pipParamsBuilder = PictureInPictureParams.Builder();
pipParamsBuilder.setAspectRatio(Rational(pipWidth, pipHeight))
enterPictureInPictureMode(pipParamsBuilder.build())
}
}
// ...
added native channel:
class MainActivity: FlutterActivity() {
private val channel = "my_app/pip_channel"
// ...
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, pipChannel).setMethodCallHandler {
call, result ->
when (call.method) {
"allowPip" -> {
val width = call.argument<Int?>("width")
val height = call.argument<Int?>("height")
allowPip(width, height)
result.success(null)
}
"blockPip" -> {
blockPip()
result.success(null)
}
else -> {
result.notImplemented()
}
}
}
}
// ...
Now i can access it from my video screen in flutter:
allow pip mode, when initializing:
class _MyScreenState extends State<MyScreen> with WidgetsBindingObserver {
// ...
static const platform = const MethodChannel('PIP_CHANNEL'); // same as in native code
@override
void initState() {
super.initState();
platform.invokeMethod('allowPip');
// ...
}
// ...
block pip mode when disposing:
// ...
@override
void dispose() {
// ...
platform.invokeMethod('blockPip');
super.dispose();
}
// ...
still need to handle local state to hide unnecessary controls, etc. in pip mode:
// ...
bool _pipMode = false;
void didChangeAppLifecycleState(AppLifecycleState state) {
// may also check for android sdk level >= 26 here
if (state == AppLifecycleState.inactive) {
setState(() { _pipMode = true; });
}
else if (state == AppLifecycleState.resumed) {
setState(() { _pipMode = false; });
}
}
// ...
Downsides of this approach are:
I am using flutter_android_pip in my Flutter app to enter PiP mode instead of minimizing the app (when user presses home). It worked fine with code like this:
After I have installed Firebase it stopped working with following error:
Note, it still works if Firebase is not initialized in the code.
Also noted deprecation warning on both plugins:
Are these plugins incompatible in some way?