refactor(app): improve permissions management
This commit is contained in:
@@ -16,6 +16,7 @@ import io.github.thibaultbee.streampack.data.VideoConfig
|
||||
import io.github.thibaultbee.streampack.error.StreamPackError
|
||||
import io.github.thibaultbee.streampack.example.databinding.ActivityMainBinding
|
||||
import io.github.thibaultbee.streampack.example.utils.PermissionsManager
|
||||
import io.github.thibaultbee.streampack.example.utils.showDialog
|
||||
import io.github.thibaultbee.streampack.example.utils.toast
|
||||
import io.github.thibaultbee.streampack.ext.rtmp.streamers.CameraRtmpLiveStreamer
|
||||
import io.github.thibaultbee.streampack.ext.srt.streamers.CameraSrtLiveStreamer
|
||||
@@ -36,13 +37,30 @@ class MainActivity : AppCompatActivity() {
|
||||
private val permissionsManager = PermissionsManager(this,
|
||||
streamerRequiredPermissions,
|
||||
onAllGranted = { inflateStreamer() },
|
||||
onShowPermissionRationale = { true },
|
||||
onDenied = {})
|
||||
onShowPermissionRationale = { permissions, onRequiredPermissionLastTime ->
|
||||
// Explain why we need permissions
|
||||
showDialog(
|
||||
title = "Permissions denied",
|
||||
message = "Explain why you need to grant $permissions permissions to stream",
|
||||
positiveButtonText = R.string.accept,
|
||||
onPositiveButtonClick = { onRequiredPermissionLastTime() },
|
||||
negativeButtonText = R.string.denied
|
||||
)
|
||||
},
|
||||
onDenied = {
|
||||
showDialog(
|
||||
"Permissions denied",
|
||||
"You need to grant all permissions to stream",
|
||||
positiveButtonText = 0,
|
||||
negativeButtonText = 0
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
// Reports and manages error with [OnErrorListener]
|
||||
private val errorListener = object : OnErrorListener {
|
||||
override fun onError(error: StreamPackError) {
|
||||
toast("An error occured: $error")
|
||||
toast("An error occurred: $error")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -114,8 +132,8 @@ class MainActivity : AppCompatActivity() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
override fun onStart() {
|
||||
super.onStart()
|
||||
permissionsManager.requestPermissions()
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,40 @@
|
||||
package io.github.thibaultbee.streampack.example.utils
|
||||
|
||||
import android.content.Context
|
||||
import android.content.DialogInterface
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.appcompat.app.AlertDialog
|
||||
|
||||
fun Context.toast(message: String) =
|
||||
Toast.makeText(this, message, Toast.LENGTH_SHORT).show()
|
||||
|
||||
fun Context.showDialog(
|
||||
title: String,
|
||||
message: String = "",
|
||||
@StringRes
|
||||
positiveButtonText: Int = android.R.string.ok,
|
||||
@StringRes
|
||||
negativeButtonText: Int = android.R.string.cancel,
|
||||
onPositiveButtonClick: () -> Unit = {},
|
||||
onNegativeButtonClick: () -> Unit = {}
|
||||
) {
|
||||
AlertDialog.Builder(this)
|
||||
.setTitle(title)
|
||||
.setMessage(message)
|
||||
.apply {
|
||||
if (positiveButtonText != 0) {
|
||||
setPositiveButton(positiveButtonText) { dialogInterface: DialogInterface, _: Int ->
|
||||
dialogInterface.dismiss()
|
||||
onPositiveButtonClick()
|
||||
}
|
||||
}
|
||||
if (negativeButtonText != 0) {
|
||||
setNegativeButton(negativeButtonText) { dialogInterface: DialogInterface, _: Int ->
|
||||
dialogInterface.dismiss()
|
||||
onNegativeButtonClick()
|
||||
}
|
||||
}
|
||||
}
|
||||
.show()
|
||||
}
|
||||
@@ -8,43 +8,60 @@ class PermissionsManager(
|
||||
private val activity: ComponentActivity,
|
||||
private val requiredPermissions: List<String>,
|
||||
private val onAllGranted: () -> Unit,
|
||||
private val onShowPermissionRationale: (List<String>) -> Boolean,
|
||||
private val onShowPermissionRationale: (List<String>, () -> Unit) -> Unit,
|
||||
private val onDenied: (List<String>) -> Unit
|
||||
) {
|
||||
private fun hasPermissions(): Boolean {
|
||||
private fun hasAllPermissions(): Boolean {
|
||||
return requiredPermissions.all {
|
||||
activity.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
}
|
||||
|
||||
private fun hasShownAllRationales(): Boolean {
|
||||
return requiredPermissions.all {
|
||||
!activity.shouldShowRequestPermissionRationale(it)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestPermissions() {
|
||||
if (hasPermissions()) {
|
||||
if (hasAllPermissions()) {
|
||||
onAllGranted()
|
||||
} else {
|
||||
var hasShownRationale = false
|
||||
requiredPermissions.forEach {
|
||||
if (activity.shouldShowRequestPermissionRationale(it)) {
|
||||
hasShownRationale = true
|
||||
// Last chance to show rationale
|
||||
if (onShowPermissionRationale(requiredPermissions)) {
|
||||
requestMultiplePermissions.launch(arrayOf(it))
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!hasShownRationale) {
|
||||
// Either we ask for rationale or we ask for all permissions
|
||||
if (requestRationales()) {
|
||||
requestMultiplePermissions.launch(requiredPermissions.toTypedArray())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun requestRationales(): Boolean {
|
||||
// List of permissions that have been denied once. In this case, we should explain why we need them.
|
||||
val rationalesPermission = mutableListOf<String>()
|
||||
requiredPermissions.filter {
|
||||
activity.shouldShowRequestPermissionRationale(it)
|
||||
}.forEach {
|
||||
rationalesPermission.add(it)
|
||||
}
|
||||
if (rationalesPermission.isNotEmpty()) {
|
||||
onShowPermissionRationale(rationalesPermission) {
|
||||
requestMultiplePermissions.launch(rationalesPermission.toTypedArray())
|
||||
}
|
||||
}
|
||||
|
||||
return rationalesPermission.isEmpty()
|
||||
}
|
||||
|
||||
private val requestMultiplePermissions =
|
||||
activity.registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { permissions ->
|
||||
permissions.filter { !it.value }.keys.toList().let {
|
||||
if (it.isNotEmpty()) {
|
||||
onDenied(it)
|
||||
val deniedPermissions = permissions.filter { !it.value }.keys.toList()
|
||||
if (deniedPermissions.isNotEmpty()) {
|
||||
if (!hasShownAllRationales()) {
|
||||
requestRationales()
|
||||
} else {
|
||||
onAllGranted()
|
||||
onDenied(deniedPermissions)
|
||||
}
|
||||
} else {
|
||||
onAllGranted()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name">My Streaming App</string>
|
||||
<string name="denied">Denied</string>
|
||||
<string name="accept">Accept</string>
|
||||
</resources>
|
||||
Reference in New Issue
Block a user