diff --git a/app/src/main/java/io/github/thibaultbee/streampack/example/MainActivity.kt b/app/src/main/java/io/github/thibaultbee/streampack/example/MainActivity.kt index 795a911..4d5f649 100644 --- a/app/src/main/java/io/github/thibaultbee/streampack/example/MainActivity.kt +++ b/app/src/main/java/io/github/thibaultbee/streampack/example/MainActivity.kt @@ -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() } diff --git a/app/src/main/java/io/github/thibaultbee/streampack/example/utils/Extensions.kt b/app/src/main/java/io/github/thibaultbee/streampack/example/utils/Extensions.kt index a870b6f..aad0605 100644 --- a/app/src/main/java/io/github/thibaultbee/streampack/example/utils/Extensions.kt +++ b/app/src/main/java/io/github/thibaultbee/streampack/example/utils/Extensions.kt @@ -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() +} \ No newline at end of file diff --git a/app/src/main/java/io/github/thibaultbee/streampack/example/utils/PermissionsManager.kt b/app/src/main/java/io/github/thibaultbee/streampack/example/utils/PermissionsManager.kt index ec67de5..5e313d8 100644 --- a/app/src/main/java/io/github/thibaultbee/streampack/example/utils/PermissionsManager.kt +++ b/app/src/main/java/io/github/thibaultbee/streampack/example/utils/PermissionsManager.kt @@ -8,43 +8,60 @@ class PermissionsManager( private val activity: ComponentActivity, private val requiredPermissions: List, private val onAllGranted: () -> Unit, - private val onShowPermissionRationale: (List) -> Boolean, + private val onShowPermissionRationale: (List, () -> Unit) -> Unit, private val onDenied: (List) -> 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() + 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() } } } \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 57a139f..29f88b4 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1,3 +1,5 @@ My Streaming App + Denied + Accept \ No newline at end of file