fix(android): fix bugs related Android PIP listeners (#4441)

* fix(android): fixed bug where listeners were not removed properly

* fix(android): fixes a bug that causes PIP to work when player is null

* refactor(android): call pipUnsubscriber without handler

* chore(android): apply lint
This commit is contained in:
YangJH
2025-03-06 20:24:59 +09:00
committed by GitHub
parent 13a5da8955
commit 82f5f3d21c
2 changed files with 23 additions and 19 deletions
@@ -17,6 +17,7 @@ import androidx.annotation.ChecksSdkIntAtLeast
import androidx.annotation.RequiresApi
import androidx.core.app.AppOpsManagerCompat
import androidx.core.app.PictureInPictureModeChangedInfo
import androidx.core.util.Consumer
import androidx.lifecycle.Lifecycle
import androidx.media3.exoplayer.ExoPlayer
import com.brentvatne.common.toolbox.DebugLog
@@ -40,7 +41,7 @@ object PictureInPictureUtil {
fun addLifecycleEventListener(context: ThemedReactContext, view: ReactExoplayerView): Runnable {
val activity = context.findActivity()
val onPictureInPictureModeChanged: (info: PictureInPictureModeChangedInfo) -> Unit = { info: PictureInPictureModeChangedInfo ->
val onPictureInPictureModeChanged = Consumer<PictureInPictureModeChangedInfo> { info ->
view.setIsInPictureInPicture(info.isInPictureInPictureMode)
if (!info.isInPictureInPictureMode && activity.lifecycle.currentState == Lifecycle.State.CREATED) {
// when user click close button of PIP
@@ -48,7 +49,7 @@ object PictureInPictureUtil {
}
}
val onUserLeaveHintCallback = {
val onUserLeaveHintCallback = Runnable {
if (view.enterPictureInPictureOnLeave) {
view.enterPictureInPictureMode()
}
@@ -61,10 +62,10 @@ object PictureInPictureUtil {
}
// @TODO convert to lambda when ReactExoplayerView migrated
return object : Runnable {
override fun run() {
context.findActivity().removeOnPictureInPictureModeChangedListener(onPictureInPictureModeChanged)
context.findActivity().removeOnUserLeaveHintListener(onUserLeaveHintCallback)
return Runnable {
with(activity) {
removeOnPictureInPictureModeChangedListener(onPictureInPictureModeChanged)
removeOnUserLeaveHintListener(onUserLeaveHintCallback)
}
}
}
@@ -224,9 +224,9 @@ public class ReactExoplayerView extends FrameLayout implements
private ArrayList<Integer> rootViewChildrenOriginalVisibility = new ArrayList<Integer>();
/*
* When user is seeking first called is on onPositionDiscontinuity -> DISCONTINUITY_REASON_SEEK
* Then we set if to false when playback is back in onIsPlayingChanged -> true
*/
* When user is seeking first called is on onPositionDiscontinuity -> DISCONTINUITY_REASON_SEEK
* Then we set if to false when playback is back in onIsPlayingChanged -> true
*/
private boolean isSeeking = false;
private long seekPosition = -1;
@@ -332,7 +332,6 @@ public class ReactExoplayerView extends FrameLayout implements
audioManager = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE);
themedReactContext.addLifecycleEventListener(this);
pipListenerUnsubscribe = PictureInPictureUtil.addLifecycleEventListener(context, this);
audioBecomingNoisyReceiver = new AudioBecomingNoisyReceiver(themedReactContext);
audioFocusChangeListener = new OnAudioFocusChangedListener(this, themedReactContext);
pictureInPictureReceiver = new PictureInPictureReceiver(this, themedReactContext);
@@ -767,6 +766,8 @@ public class ReactExoplayerView extends FrameLayout implements
if (player == null) {
// Initialize core configuration and listeners
initializePlayerCore(self);
pipListenerUnsubscribe = PictureInPictureUtil.addLifecycleEventListener(themedReactContext, this);
PictureInPictureUtil.applyAutoEnterEnabled(themedReactContext, pictureInPictureParamsBuilder, this.enterPictureInPictureOnLeave);
}
if (!source.isLocalAssetFile() && !source.isAsset() && source.getBufferConfig().getCacheSize() > 0) {
RNVSimpleCache.INSTANCE.setSimpleCache(
@@ -935,7 +936,7 @@ public class ReactExoplayerView extends FrameLayout implements
: (e.reason == UnsupportedDrmException.REASON_UNSUPPORTED_SCHEME
? R.string.error_drm_unsupported_scheme : R.string.error_drm_unknown);
eventEmitter.onVideoError.invoke(getResources().getString(errorStringId), e, "3003");
}
}
}
}
return drmSessionManager;
@@ -1270,12 +1271,12 @@ public class ReactExoplayerView extends FrameLayout implements
for (SideLoadedTextTrack track : source.getSideLoadedTextTracks().getTracks()) {
MediaItem.SubtitleConfiguration subtitleConfiguration = new MediaItem.SubtitleConfiguration.Builder(track.getUri())
.setMimeType(track.getType())
.setLanguage(track.getLanguage())
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.setRoleFlags(C.ROLE_FLAG_SUBTITLE)
.setLabel(track.getTitle())
.build();
.setMimeType(track.getType())
.setLanguage(track.getLanguage())
.setSelectionFlags(C.SELECTION_FLAG_DEFAULT)
.setRoleFlags(C.ROLE_FLAG_SUBTITLE)
.setLabel(track.getTitle())
.build();
subtitleConfigurations.add(subtitleConfiguration);
}
@@ -1298,7 +1299,7 @@ public class ReactExoplayerView extends FrameLayout implements
player.removeListener(this);
PictureInPictureUtil.applyAutoEnterEnabled(themedReactContext, pictureInPictureParamsBuilder, false);
if (pipListenerUnsubscribe != null) {
new Handler().post(pipListenerUnsubscribe);
pipListenerUnsubscribe.run();
}
trackSelector = null;
@@ -2245,7 +2246,9 @@ public class ReactExoplayerView extends FrameLayout implements
public void setEnterPictureInPictureOnLeave(boolean enterPictureInPictureOnLeave) {
this.enterPictureInPictureOnLeave = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N && enterPictureInPictureOnLeave;
PictureInPictureUtil.applyAutoEnterEnabled(themedReactContext, pictureInPictureParamsBuilder, this.enterPictureInPictureOnLeave);
if (player != null) {
PictureInPictureUtil.applyAutoEnterEnabled(themedReactContext, pictureInPictureParamsBuilder, this.enterPictureInPictureOnLeave);
}
}
protected void setIsInPictureInPicture(boolean isInPictureInPicture) {