카메라 권한이 없는 사용자가 비디오 통화 연결 되고 난 후에 앱 권한 설정 하고 돌아 올때
어떻게 로컬 카메라 비디오 세팅을 할수 있습니까?
권한 획득 후 돌아와서 DirectCall.startVideo()가 호출 됐는데 나오지 않습니다… 어떻게 해야 할까요??
아래는 제 코드입니다
class VideoCallActivity : CallActivity() {
private var mIsVideoEnabled = false
private var permissionToRecordAccepted = false
private var requiredPermissions = arrayListOf(Manifest.permission.RECORD_AUDIO, Manifest.permission.CAMERA)
private val PERMISSION_REQUEST_CODE = 100
private val requestPermissionLauncher: ActivityResultLauncher<String> =
registerForActivityResult(ActivityResultContracts.RequestPermission()) { permission ->
Log.d(TAG, ":: registerForActivityResult ")
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) == PackageManager.PERMISSION_GRANTED &&
ContextCompat.checkSelfPermission(this, Manifest.permission.RECORD_AUDIO) == PackageManager.PERMISSION_GRANTED) {
Log.d(TAG, ":: registerForActivityResult granted permission=$permission mDoLocalVideoStart=$mDoLocalVideoStart mDirectCall=$mDirectCall")
if(permission) {
if (mDoLocalVideoStart == false) {
mDoLocalVideoStart = true
return@registerForActivityResult
}
mDoLocalVideoStart = false
if (mDirectCall != null) {
Log.d(TAG, ":: registerForActivityResult permission = $permission")
// mDoLocalVideoStart = false
// updateCallService()
mDirectCall?.let {
// setLocalVideoSettings(it)
// mIsVideoEnabled = true
// mImageViewVideoOff.isSelected = !mIsVideoEnabled
}
// initViews()
// setViews()
setAudioDevice()
}
}
}
}
private fun checkCameraAndAudioPermission() {
Log.d(TAG, "checkCameraAndAudioPermission:: 1111 ")
var rejectedPermissionList = ArrayList<String>()
for (permission in requiredPermissions) {
when {
ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED -> {
Log.d(TAG, "checkCameraAndAudioPermission:: checkSelfPermission ")
rejectedPermissionList.add(permission)
}
shouldShowRequestPermissionRationale(permission) -> {
Log.d(TAG, "checkCameraAndAudioPermission:: shouldShowRequestPermissionRationale ")
showPermissionDialog()
}
else -> {
Log.d(TAG, "checkCameraAndAudioPermission:: else ")
requestPermissionLauncher.launch(
permission
)
}
}
}
if (rejectedPermissionList.isNotEmpty()) {
val array = arrayOfNulls<String>(rejectedPermissionList.size)
Log.d(TAG, "checkCameraAndAudioPermission:: 권한 없음 ")
ActivityCompat.requestPermissions(this, rejectedPermissionList.toArray(array), PERMISSION_REQUEST_CODE)
} else {
Log.d(TAG, "checkCameraAndAudioPermission:: 권한 있음 ")
mDirectCall?.let {
// setLocalVideoSettings(it)
it.startVideo()
}
}
}
var isShowDialog = false
private fun showPermissionDialog() {
if (isShowDialog) {
isShowDialog = false
return
}
MaterialAlertDialogBuilder(this)
.setTitle(R.string.perm__lab_audio_camera)
.setMessage(R.string.perm__desc_audio_camera)
.setPositiveButton(R.string.request_permission) { dialogInterface, _ ->
dialogInterface.dismiss()
UIUtil.startInstalledAppDetailSetting(this)
}
.setOnDismissListener {
isShowDialog = false
}
.setNegativeButton(R.string.cancel, null)
.create()
.show()
isShowDialog = true
}
override fun onRequestPermissionsResult(
requestCode: Int,
permissions: Array<out String>,
grantResults: IntArray
) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
when (requestCode) {
PERMISSION_REQUEST_CODE -> {
if (grantResults.isNotEmpty()) {
for ((i, permission) in permissions.withIndex()) {
if(grantResults[i] != PackageManager.PERMISSION_GRANTED) {
// 권한 획득 실패
Log.d(TAG, "onRequestPermissionsResult:: 권한 획득 실패 $permission")
showPermissionDialog()
}
}
}
}
}
}
//+ Views
private lateinit var mVideoViewFullScreen: SendBirdVideoView
private lateinit var mViewConnectingVideoViewFullScreenFg: View
private lateinit var mRelativeLayoutVideoViewSmall: RelativeLayout
private lateinit var mVideoViewSmall: SendBirdVideoView
private lateinit var mImageViewCameraSwitch: ImageView
private lateinit var mImageViewVideoOff: ImageView
//- Views
override val layoutResourceId: Int
get() = R.layout.activity_video_call
override fun initViews() {
super.initViews()
Log.d(TAG, "[VideoCallActivity] :: initViews()")
mVideoViewFullScreen = findViewById(R.id.video_view_fullscreen)
mViewConnectingVideoViewFullScreenFg =
findViewById(R.id.view_connecting_video_view_fullscreen_fg)
mRelativeLayoutVideoViewSmall = findViewById(R.id.relative_layout_video_view_small)
mVideoViewSmall = findViewById(R.id.video_view_small)
mImageViewCameraSwitch = findViewById(R.id.image_view_camera_switch)
mImageViewVideoOff = findViewById(R.id.image_view_video_off)
}
override fun setViews() {
super.setViews()
Log.d(TAG, "[VideoCallActivity] :: setViews() ")
mVideoViewFullScreen.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
mVideoViewFullScreen.setZOrderMediaOverlay(false)
mVideoViewFullScreen.setEnableHardwareScaler(true)
mVideoViewSmall.setScalingType(RendererCommon.ScalingType.SCALE_ASPECT_FIT)
mVideoViewSmall.setZOrderMediaOverlay(true)
mVideoViewSmall.setEnableHardwareScaler(true)
val directCall = mDirectCall
if (directCall != null) {
if (directCall.myRole == DirectCallUserRole.CALLER && mState == STATE.STATE_OUTGOING) {
directCall.setLocalVideoView(mVideoViewFullScreen)
directCall.setRemoteVideoView(mVideoViewSmall)
} else {
directCall.setLocalVideoView(mVideoViewSmall)
directCall.setRemoteVideoView(mVideoViewFullScreen)
}
}
mImageViewCameraSwitch.setOnClickListener { view: View? ->
directCall?.switchCamera(object : CompletionHandler {
override fun onResult(e: SendBirdException?) {
if (e != null) {
Log.d(TAG, "[VideoCallActivity] switchCamera(e: " + e.message + ")")
}
}
})
}
mIsVideoEnabled = if (mDirectCall != null && !mDoLocalVideoStart) {
directCall?.isLocalVideoEnabled ?: false
} else {
true
}
Log.d(TAG, "[VideoCallActivity] :: setViews() mIsVideoEnabled=$mIsVideoEnabled ")
mImageViewVideoOff.isSelected = !mIsVideoEnabled
mImageViewVideoOff.setOnClickListener { view: View? ->
if (ContextCompat.checkSelfPermission(this, Manifest.permission.CAMERA) != PackageManager.PERMISSION_GRANTED) {
ToastUtils.showToast(this, "카메라 권한 설정이 필요 합니다.")
return@setOnClickListener
}
val call = mDirectCall
Log.d(TAG, "setViews:: call=$call mIsVideoEnabled=$mIsVideoEnabled")
if (call != null) {
if (mIsVideoEnabled) {
Log.d(TAG, "[VideoCallActivity] :: stopVideo()")
call.stopVideo()
mIsVideoEnabled = false
mImageViewVideoOff.isSelected = true
} else {
Log.d(TAG, "[VideoCallActivity] :: startVideo()")
call.startVideo()
mIsVideoEnabled = true
mImageViewVideoOff.isSelected = false
}
}
}
mImageViewBluetooth.isEnabled = false
mImageViewBluetooth.setOnClickListener { view: View? ->
mImageViewBluetooth.isSelected = !mImageViewBluetooth.isSelected
val call = mDirectCall
if (call != null) {
if (mImageViewBluetooth.isSelected) {
call.selectAudioDevice(
AudioDevice.BLUETOOTH,
object : CompletionHandler {
override fun onResult(e: SendBirdException?) {
if (e != null) {
mImageViewBluetooth.isSelected = false
}
}
})
} else {
call.selectAudioDevice(
AudioDevice.WIRED_HEADSET,
object : CompletionHandler {
override fun onResult(e: SendBirdException?) {
if (e != null) {
call.selectAudioDevice(AudioDevice.SPEAKERPHONE, null)
}
}
})
}
}
}
}
fun setLocalVideoSettings(call: DirectCall) {
mIsVideoEnabled = call.isLocalVideoEnabled
Log.d(
TAG,
"[VideoCallActivity] :: setLocalVideoSettings() => isLocalVideoEnabled(): $mIsVideoEnabled"
)
if (mIsVideoEnabled) {
// bindCallService()
// init()
// initViews()
// setViews()
// setAudioDevice()
// setCurrentState()
call.stopVideo()
// setState(STATE.STATE_RECONNECTED, call)
// initViews()
// setViews()
// mDoLocalVideoStart = false
// updateCallService()
call.startVideo()
call.setLocalVideoView(mVideoViewSmall)
mImageViewVideoOff.isSelected = !mIsVideoEnabled
}
}
override fun setAudioDevice(
currentAudioDevice: AudioDevice?,
availableAudioDevices: Set<AudioDevice>?
) {
if (currentAudioDevice == AudioDevice.SPEAKERPHONE) {
mImageViewBluetooth.isSelected = false
} else if (currentAudioDevice == AudioDevice.BLUETOOTH) {
mImageViewBluetooth.isSelected = true
}
if (availableAudioDevices?.contains(AudioDevice.BLUETOOTH) == true) {
mImageViewBluetooth.isEnabled = true
} else if (!mImageViewBluetooth.isSelected) {
mImageViewBluetooth.isEnabled = false
}
}
override fun startCall(amICallee: Boolean) {
val callOptions = CallOptions()
callOptions.setVideoEnabled(mIsVideoEnabled).setAudioEnabled(mIsAudioEnabled)
if (amICallee) {
callOptions.setLocalVideoView(mVideoViewSmall)
.setRemoteVideoView(mVideoViewFullScreen)
} else {
callOptions.setLocalVideoView(mVideoViewFullScreen)
.setRemoteVideoView(mVideoViewSmall)
}
if (amICallee) {
Log.d(TAG, "[VideoCallActivity] :: accept()")
val call = mDirectCall
call?.accept(AcceptParams().setCallOptions(callOptions))
} else {
Log.d(TAG, "[VideoCallActivity] :: dial()")
val calleeId = mCalleeIdToDial
if (calleeId != null) {
mDirectCall = SendBirdCall.dial(
DialParams(calleeId).setVideoCall(mIsVideoCall).setCallOptions(callOptions),
object : DialHandler {
override fun onResult(call: DirectCall?, e: SendBirdException?) {
if (e != null) {
Log.d(TAG, "[VideoCallActivity] :: dial() => e: " + e.message)
if (e.message != null) {
ToastUtils.showToast(mContext, e.message)
}
finishWithEnding(e.message ?: "")
return
}
Log.d(TAG, "[VideoCallActivity] :: dial() => OK")
updateCallService()
}
})
mDirectCall?.let { setListener(it) }
}
}
}
@SuppressLint("SourceLockedOrientationActivity")
@TargetApi(18)
override fun setState(state: STATE, call: DirectCall?): Boolean {
if (!super.setState(state, call)) {
return false
}
Log.d(TAG, "[VideoCallActivity] :: state=$state ")
when (state) {
STATE.STATE_ACCEPTING -> {
mVideoViewFullScreen.visibility = View.GONE
mViewConnectingVideoViewFullScreenFg.visibility = View.GONE
mRelativeLayoutVideoViewSmall.visibility = View.GONE
mImageViewCameraSwitch.visibility = View.GONE
}
STATE.STATE_OUTGOING -> {
mVideoViewFullScreen.visibility = View.VISIBLE
mViewConnectingVideoViewFullScreenFg.visibility = View.VISIBLE
mRelativeLayoutVideoViewSmall.visibility = View.GONE
mImageViewCameraSwitch.visibility = View.VISIBLE
mImageViewVideoOff.visibility = View.VISIBLE
}
STATE.STATE_CONNECTED -> {
mVideoViewFullScreen.visibility = View.VISIBLE
mViewConnectingVideoViewFullScreenFg.visibility = View.GONE
mRelativeLayoutVideoViewSmall.visibility = View.VISIBLE
mImageViewCameraSwitch.visibility = View.VISIBLE
mImageViewVideoOff.visibility = View.VISIBLE
mLinearLayoutInfo.visibility = View.GONE
if (call != null && call.myRole == DirectCallUserRole.CALLER) {
call.setLocalVideoView(mVideoViewSmall)
call.setRemoteVideoView(mVideoViewFullScreen)
}
}
STATE.STATE_RECONNECTED -> {
mVideoViewFullScreen.visibility = View.VISIBLE
mViewConnectingVideoViewFullScreenFg.visibility = View.GONE
mRelativeLayoutVideoViewSmall.visibility = View.VISIBLE
mImageViewCameraSwitch.visibility = View.VISIBLE
mImageViewVideoOff.visibility = View.VISIBLE
mLinearLayoutInfo.visibility = View.GONE
if (call != null && call.myRole == DirectCallUserRole.CALLER) {
call.setLocalVideoView(mVideoViewSmall)
call.setRemoteVideoView(mVideoViewFullScreen)
}
}
STATE.STATE_ENDING, STATE.STATE_ENDED -> {
mLinearLayoutInfo.visibility = View.VISIBLE
mVideoViewFullScreen.visibility = View.GONE
mViewConnectingVideoViewFullScreenFg.visibility = View.GONE
mRelativeLayoutVideoViewSmall.visibility = View.GONE
mImageViewCameraSwitch.visibility = View.GONE
}
}
return true
}
override fun onStart() {
super.onStart()
Log.d(TAG, "[VideoCallActivity] :: onStart()")
if (mDirectCall != null && mDoLocalVideoStart) {
checkCameraAndAudioPermission()
mDoLocalVideoStart = false
updateCallService()
mDirectCall?.startVideo()
// checkPermissions()
}
}
override fun onStop() {
super.onStop()
Log.d(TAG, "[VideoCallActivity] :: onStop()")
if (mDirectCall != null && mDirectCall?.isLocalVideoEnabled == true) {
mDirectCall?.stopVideo()
mDoLocalVideoStart = true
updateCallService()
}
}
}