- 안드로이드에서 Picture-In-Picture 모드로 현재 화면과 독립적으로 움직일 수 있는 Activity 를 띄울 수 있습니다.
- 코드 중심으로 설명을 하겠습니다.
1. PIP 모드를 사용할 Activity 클래스 생성
package im.metrex.oa.features.sendbird
import android.app.PictureInPictureParams
import android.content.res.Configuration
import android.net.Uri
import android.os.Bundle
import android.util.Rational
import androidx.activity.ComponentActivity
import androidx.activity.OnBackPressedCallback
import androidx.activity.compose.setContent
import androidx.annotation.OptIn
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.viewinterop.AndroidView
import androidx.lifecycle.compose.LocalLifecycleOwner
import androidx.media3.common.MediaItem
import androidx.media3.common.Player
import androidx.media3.common.util.UnstableApi
import androidx.media3.exoplayer.ExoPlayer
import androidx.media3.ui.AspectRatioFrameLayout
import androidx.media3.ui.PlayerView
import dagger.hilt.android.AndroidEntryPoint
import im.metrex.oa.core.ui.PlayerSurface
import im.metrex.oa.theme.MetrexTheme
@AndroidEntryPoint
class SendbirdPipActivity : ComponentActivity() {
private lateinit var pipState: PipState
private val onBackPressedCallback by lazy {
object : OnBackPressedCallback(true) {
override fun handleOnBackPressed() {
if(::pipState.isInitialized && pipState == PipState.Expand) {
enterPipMode()
}
}
}
}
@OptIn(UnstableApi::class)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
enterPipMode()
initBackCallback()
setContent {
MetrexTheme {
val context = LocalContext.current
val lifecycleOwner = LocalLifecycleOwner.current
val exoPlayer = remember {
ExoPlayer
.Builder(context)
.build()
.apply {
addListener(object: Player.Listener {
override fun onPlaybackStateChanged(playbackState: Int) {
if (playbackState == Player.STATE_ENDED) {
finish()
}
}
})
}
}
DisposableEffect(lifecycleOwner) {
val mediaItem = MediaItem.Builder()
.setUri(
Uri.parse("android.resource://${context?.packageName}/raw/caption")
)
.build()
exoPlayer.setMediaItem(mediaItem)
exoPlayer.prepare()
exoPlayer.playWhenReady = true
onDispose {
exoPlayer.release()
}
}
PlayerSurface(
modifier = Modifier,
player = exoPlayer
)
}
}
}
private fun enterPipMode() {
// PIP 모드 파라미터 생성
val aspectRatio = Rational(9, 16) // 가로 세로 비율 설정
val pipParams = PictureInPictureParams.Builder()
.setAspectRatio(aspectRatio)
.build()
// PIP 모드로 전환
enterPictureInPictureMode(pipParams)
}
override fun onPictureInPictureModeChanged(
isInPictureInPictureMode: Boolean,
newConfig: Configuration
) {
super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
// PIP 모드 진입
if(isInPictureInPictureMode) {
pipState = PipState.Active
}
}
override fun onUserLeaveHint() {
// 사용자가 앱을 최소화하거나 홈 버튼을 누를 때 자동으로 PIP 모드로 전환하려면 이 메서드를 사용할 수 있습니다.
super.onUserLeaveHint()
enterPipMode()
}
private fun initBackCallback() {
onBackPressedDispatcher.addCallback(this, onBackPressedCallback)
}
// PIP 모드에서 확대 클릭 시 호출
override fun onResume() {
super.onResume()
if(::pipState.isInitialized && isInPictureInPictureMode.not()) {
pipState = PipState.Expand
}
}
// PIP 모드에서 x 클릭 시 호출
override fun onStop() {
super.onStop()
if(::pipState.isInitialized && isInPictureInPictureMode) {
finish()
}
}
override fun onDestroy() {
super.onDestroy()
onBackPressedCallback.remove()
}
}
- PictureInPictureParams 클래스를 생성해서 가로 세로 비율을 넣어줍니다.
- enterPictureInPictureMode 메서드에 Params 를 넘겨주면 자동으로 pip 모드로 변경됩니다.
- OnPictureInPictureModeChanged
- pip 모드의 config 가 변경될 때 마다 호출되는 함수입니다. (ex. pip 모드 진입)
- OnUserLeaveHint
- 사용자가 앱을 최소화하거나 홈 버튼을 누를 때 호출되는 함수입니다.
- 홈 버튼을 누를 때 pip모드로 진입하게 할 때 사용할 수 있는 함수입니다.
- 사용자가 앱을 최소화하거나 홈 버튼을 누를 때 호출되는 함수입니다.
2. PIP 모드 제어를 위한 상태 enum 클래스 생성
enum class PipState {
Active,
Expand,
}
- PIP 모드에서 전체화면으로 확대 됐을 때 Back키에 대해 제어를 위해서 상태 클래스를 생성했습니다.
- 또한 PIP 모드일 때 닫기 클릭 시 exoplayer 의 영상이 제대로 종료가 안되서 Activity Lifecycle 에 대해 제어하기 위해서도 사용했습니다.
3. AndroidManifast.xml 설정
<activity
android:name=".features.sendbird.SendbirdPipActivity"
android:supportsPictureInPicture="true"
android:launchMode="singleTask"
android:configChanges="screenSize|smallestScreenSize|screenLayout|orientation">
</activity>
'안드로이드 > 개발중 알게된점' 카테고리의 다른 글
안드로이드 PIP 모드 커스텀 버튼 추가 (2) | 2024.11.21 |
---|---|
Closure(클로저) (0) | 2024.07.20 |
삐져나오는 이미지 영역을 감싸는 방법 (0) | 2024.06.24 |
AppBarLayout 과 CollapsingToolBarLayout 의 상속 구조 (0) | 2024.04.27 |
build-logic rebuild project 시 에러 관련 (0) | 2024.04.21 |