Skip to content

Commit 813636b

Browse files
Fix PiP mode in gesture navigation (#758)
Co-authored-by: Jaewoong Eum <skydoves2@gmail.com>
1 parent dbf3855 commit 813636b

File tree

3 files changed

+54
-47
lines changed

3 files changed

+54
-47
lines changed

stream-video-android-compose/api/stream-video-android-compose.api

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ public final class io/getstream/video/android/compose/lifecycle/CallLifecycleKt
33
}
44

55
public final class io/getstream/video/android/compose/lifecycle/MediaPiPLifecycleKt {
6-
public static final fun MediaPiPLifecycle (Lio/getstream/video/android/core/Call;ZJLandroidx/compose/runtime/Composer;II)V
6+
public static final fun MediaPiPLifecycle (Lio/getstream/video/android/core/Call;ZLandroidx/compose/runtime/Composer;II)V
77
}
88

99
public final class io/getstream/video/android/compose/permission/CallPermissionsKt {

stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/lifecycle/MediaPiPLifecycle.kt

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -16,24 +16,21 @@
1616

1717
package io.getstream.video.android.compose.lifecycle
1818

19+
import android.app.Activity
20+
import android.app.Application
21+
import android.os.Bundle
1922
import android.os.Handler
2023
import android.os.Looper
2124
import androidx.compose.runtime.Composable
2225
import androidx.compose.runtime.DisposableEffect
23-
import androidx.compose.runtime.LaunchedEffect
24-
import androidx.compose.runtime.getValue
25-
import androidx.compose.runtime.mutableStateOf
26-
import androidx.compose.runtime.remember
27-
import androidx.compose.runtime.setValue
2826
import androidx.compose.ui.platform.LocalContext
2927
import androidx.compose.ui.platform.LocalLifecycleOwner
30-
import androidx.lifecycle.Lifecycle
31-
import androidx.lifecycle.LifecycleEventObserver
28+
import androidx.lifecycle.LifecycleOwner
3229
import io.getstream.log.StreamLog
3330
import io.getstream.video.android.compose.pip.enterPictureInPicture
31+
import io.getstream.video.android.compose.pip.findActivity
3432
import io.getstream.video.android.compose.pip.isInPictureInPictureMode
3533
import io.getstream.video.android.core.Call
36-
import kotlinx.coroutines.delay
3734

3835
/**
3936
* Register a call media lifecycle that controls camera and microphone depending on lifecycles.
@@ -43,56 +40,66 @@ import kotlinx.coroutines.delay
4340
* - camera/microphone will be enabled if the lifecycle is onResumed, and not on the PIP mode.
4441
*
4542
* @param call The call includes states and will be rendered with participants.
46-
* @param pipEnteringDuration The duration requires to be engaged in Picture-In-Picture mode.
4743
*/
4844
@Composable
4945
public fun MediaPiPLifecycle(
5046
call: Call,
5147
enableInPictureInPicture: Boolean = false,
52-
pipEnteringDuration: Long = 250,
5348
) {
5449
val context = LocalContext.current
55-
val lifecycle = LocalLifecycleOwner.current.lifecycle
56-
var latestLifecycleEvent by remember { mutableStateOf(Lifecycle.Event.ON_ANY) }
57-
DisposableEffect(lifecycle) {
58-
val observer = LifecycleEventObserver { _, event ->
59-
latestLifecycleEvent = event
60-
}
61-
lifecycle.addObserver(observer)
62-
onDispose {
63-
lifecycle.removeObserver(observer)
64-
}
65-
}
50+
val lifecycleOwner: LifecycleOwner = LocalLifecycleOwner.current
51+
val currentActivity: Activity? = LocalContext.current.findActivity()
52+
53+
DisposableEffect(key1 = lifecycleOwner) {
54+
// TODO: There's not way to onUserLeaveHint in Compose for now. The only thing
55+
// that works so far is to listen to ActivityLifecycleCallbacks and enable PiP in
56+
// onPause.
57+
// https://developer.android.com/reference/android/app/Activity#onUserLeaveHint()
58+
val application = (context.applicationContext as? Application)
59+
val callbackListener = object : Application.ActivityLifecycleCallbacks {
60+
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) { }
6661

67-
if (latestLifecycleEvent == Lifecycle.Event.ON_PAUSE) {
68-
LaunchedEffect(latestLifecycleEvent) {
69-
delay(pipEnteringDuration)
70-
val isInPictureInPicture = context.isInPictureInPictureMode
71-
if (!isInPictureInPicture && !enableInPictureInPicture) {
72-
call.camera.pause(fromUser = false)
73-
call.microphone.pause(fromUser = false)
74-
} else if (!isInPictureInPicture) {
75-
Handler(Looper.getMainLooper()).post {
76-
try {
77-
// TODO: There's not way to onUserLeaveHint in Compose for now.
78-
// https://developer.android.com/reference/android/app/Activity#onUserLeaveHint()
79-
enterPictureInPicture(context = context, call = call)
80-
} catch (e: Exception) {
81-
StreamLog.d("MediaPiPLifecycle") { e.stackTraceToString() }
62+
override fun onActivityStarted(activity: Activity) { }
63+
64+
override fun onActivityResumed(activity: Activity) {
65+
if (activity == currentActivity) {
66+
val isInPictureInPicture = context.isInPictureInPictureMode
67+
if (!isInPictureInPicture && !enableInPictureInPicture) {
68+
call.camera.resume(fromUser = false)
69+
call.microphone.resume(fromUser = false)
8270
}
8371
}
8472
}
85-
}
86-
}
8773

88-
if (latestLifecycleEvent == Lifecycle.Event.ON_RESUME) {
89-
LaunchedEffect(latestLifecycleEvent) {
90-
delay(pipEnteringDuration)
91-
val isInPictureInPicture = context.isInPictureInPictureMode
92-
if (!isInPictureInPicture && !enableInPictureInPicture) {
93-
call.camera.resume(fromUser = false)
94-
call.microphone.resume(fromUser = false)
74+
override fun onActivityPaused(activity: Activity) {
75+
if (activity == currentActivity) {
76+
val isInPictureInPicture = context.isInPictureInPictureMode
77+
if (!isInPictureInPicture && !enableInPictureInPicture) {
78+
call.camera.pause(fromUser = false)
79+
call.microphone.pause(fromUser = false)
80+
} else if (!isInPictureInPicture) {
81+
Handler(Looper.getMainLooper()).post {
82+
try {
83+
enterPictureInPicture(context = context, call = call)
84+
} catch (e: Exception) {
85+
StreamLog.d("MediaPiPLifecycle") { e.stackTraceToString() }
86+
}
87+
}
88+
}
89+
}
9590
}
91+
92+
override fun onActivityStopped(activity: Activity) { }
93+
94+
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) { }
95+
96+
override fun onActivityDestroyed(activity: Activity) { }
97+
}
98+
99+
application?.registerActivityLifecycleCallbacks(callbackListener)
100+
101+
onDispose {
102+
application?.unregisterActivityLifecycleCallbacks(callbackListener)
96103
}
97104
}
98105
}

stream-video-android-compose/src/main/kotlin/io/getstream/video/android/compose/ui/components/call/lobby/CallLobby.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -134,7 +134,7 @@ public fun CallLobby(
134134

135135
DefaultPermissionHandler(videoPermission = permissions)
136136

137-
MediaPiPLifecycle(call = call, pipEnteringDuration = 0)
137+
MediaPiPLifecycle(call = call)
138138

139139
Column(modifier = modifier) {
140140
Box(

0 commit comments

Comments
 (0)