refactor(app): improve permissions management

This commit is contained in:
ThibaultBee
2022-11-12 15:38:30 +01:00
parent 968134d9e8
commit 544b648c91
4 changed files with 93 additions and 23 deletions

View File

@@ -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()
}

View File

@@ -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()
}

View File

@@ -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()
}
}
}

View File

@@ -1,3 +1,5 @@
<resources>
<string name="app_name">My Streaming App</string>
<string name="denied">Denied</string>
<string name="accept">Accept</string>
</resources>