2026-08-14 18:16:55 +08:00
|
|
|
/**
|
|
|
|
|
* @file CameraPermissions.kt
|
|
|
|
|
* @brief Runtime-permission requirements for the bowling camera feature.
|
|
|
|
|
*/
|
2026-08-11 19:46:54 +08:00
|
|
|
package com.example.jnicpp.bowling
|
|
|
|
|
|
|
|
|
|
import android.Manifest
|
|
|
|
|
import android.content.Context
|
|
|
|
|
import android.content.pm.PackageManager
|
|
|
|
|
import android.os.Build
|
|
|
|
|
import androidx.core.content.ContextCompat
|
|
|
|
|
|
|
|
|
|
/**
|
2026-08-14 18:16:55 +08:00
|
|
|
* @brief Single source of truth for which runtime permissions this feature
|
|
|
|
|
* needs and whether they're currently granted.
|
|
|
|
|
*
|
|
|
|
|
* The actual request flow (which must be owned by an Activity/Fragment via
|
|
|
|
|
* ActivityResultContracts) lives in [BowlingCameraActivity]; this object
|
|
|
|
|
* just centralizes the "what" so both the manifest expectations and the
|
|
|
|
|
* request flow can't drift apart.
|
2026-08-11 19:46:54 +08:00
|
|
|
*/
|
|
|
|
|
object CameraPermissions {
|
|
|
|
|
|
2026-08-14 18:16:55 +08:00
|
|
|
/**
|
|
|
|
|
* @brief The permissions this feature requires on the current device.
|
|
|
|
|
*
|
|
|
|
|
* Always includes camera and microphone. Also includes
|
|
|
|
|
* `WRITE_EXTERNAL_STORAGE` on API 28 and below, since scoped storage
|
|
|
|
|
* (API 29+) lets an app insert into MediaStore's shared Movies
|
|
|
|
|
* collection without it, but below that it's required to save the
|
|
|
|
|
* recorded video into the gallery.
|
|
|
|
|
*/
|
2026-08-11 19:46:54 +08:00
|
|
|
val REQUIRED: Array<String> = buildList {
|
|
|
|
|
add(Manifest.permission.CAMERA)
|
|
|
|
|
add(Manifest.permission.RECORD_AUDIO)
|
|
|
|
|
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P) {
|
|
|
|
|
add(Manifest.permission.WRITE_EXTERNAL_STORAGE)
|
|
|
|
|
}
|
|
|
|
|
}.toTypedArray()
|
|
|
|
|
|
2026-08-14 18:16:55 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Checks whether every permission in [REQUIRED] is currently granted.
|
|
|
|
|
* @param context Context used to query permission state.
|
|
|
|
|
* @return true if all required permissions are granted, false otherwise.
|
|
|
|
|
*/
|
2026-08-11 19:46:54 +08:00
|
|
|
fun allGranted(context: Context): Boolean =
|
|
|
|
|
REQUIRED.all { permission ->
|
|
|
|
|
ContextCompat.checkSelfPermission(context, permission) == PackageManager.PERMISSION_GRANTED
|
|
|
|
|
}
|
|
|
|
|
|
2026-08-14 18:16:55 +08:00
|
|
|
/**
|
|
|
|
|
* @brief Lists which of [REQUIRED] are not currently granted.
|
|
|
|
|
* @param context Context used to query permission state.
|
|
|
|
|
* @return The subset of [REQUIRED] that is not yet granted; empty if all are granted.
|
|
|
|
|
*/
|
2026-08-11 19:46:54 +08:00
|
|
|
fun missing(context: Context): List<String> =
|
|
|
|
|
REQUIRED.filter { permission ->
|
|
|
|
|
ContextCompat.checkSelfPermission(context, permission) != PackageManager.PERMISSION_GRANTED
|
|
|
|
|
}
|
|
|
|
|
}
|