app/src/main/java/ch/epfl/sdp/blindly/location/permissions/LocationPermission.kt
package ch.epfl.sdp.blindly.location.permissions
import android.Manifest
import android.app.AlertDialog
import android.app.Dialog
import android.content.DialogInterface
import android.content.pm.PackageManager
import android.os.Bundle
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.fragment.app.DialogFragment
import ch.epfl.sdp.blindly.R
/*
* Handle the location permission logic
*/
open class LocationPermission {
/**
* Utility class for access to runtime permissions.
*/
companion object {
/**
* Request code for location permission request.
*
* @see .onRequestPermissionsResult
*/
const val LOCATION_PERMISSION_REQUEST_CODE = 1
/**
* Requests the fine location permission. If a rationale with an additional explanation should
* be shown to the user, displays a dialog that triggers the request.
*/
@JvmStatic
fun requestPermission(
activity: AppCompatActivity, requestId: Int,
permission: String, finishActivity: Boolean
) {
if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) {
// Display a dialog with rationale.
RationaleDialog.newInstance(requestId, finishActivity)
.show(activity.supportFragmentManager, "dialog")
} else {
// Location permission has not been granted yet, request it.
ActivityCompat.requestPermissions(
activity,
arrayOf(permission),
requestId
)
}
}
/**
* Checks if the result contains a [PackageManager.PERMISSION_GRANTED] result for a
* permission from a runtime permissions request.
*
* @see androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback
*/
@JvmStatic
fun isPermissionGranted(
grantPermissions: Array<String>, grantResults: IntArray,
permission: String
): Boolean {
for (i in grantPermissions.indices) {
if (permission == grantPermissions[i]) {
return grantResults[i] == PackageManager.PERMISSION_GRANTED
}
}
return false
}
/**
* A dialog that displays a message and finish the activity when dismissed
*/
abstract class FinishOnDismissDialog : DialogFragment() {
var finishActivity = false
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
if (finishActivity) {
Toast.makeText(
activity, R.string.permission_required_toast,
Toast.LENGTH_SHORT
).show()
activity?.finish()
}
}
companion object {
const val ARGUMENT_FINISH_ACTIVITY = "finish"
}
}
/**
* A dialog that displays a permission denied message.
*/
class PermissionDeniedDialog : FinishOnDismissDialog() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
finishActivity =
arguments?.getBoolean(ARGUMENT_FINISH_ACTIVITY) ?: false
return AlertDialog.Builder(activity)
.setMessage(R.string.location_permission_denied)
.setPositiveButton(android.R.string.ok, null)
.create()
}
companion object {
/**
* Creates a new instance of this dialog and optionally finishes the calling Activity
* when the 'Ok' button is clicked.
*/
@JvmStatic
fun newInstance(finishActivity: Boolean): PermissionDeniedDialog {
val arguments = Bundle().apply {
putBoolean(ARGUMENT_FINISH_ACTIVITY, finishActivity)
}
return PermissionDeniedDialog().apply {
this.arguments = arguments
}
}
}
}
/**
* A dialog that explains the use of the location permission and requests the necessary
* permission.
*
*
* The activity should implement
* [androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback]
* to handle permit or denial of this permission request.
*/
class RationaleDialog : FinishOnDismissDialog() {
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val requestCode =
arguments?.getInt(ARGUMENT_PERMISSION_REQUEST_CODE) ?: 0
finishActivity =
arguments?.getBoolean(ARGUMENT_FINISH_ACTIVITY) ?: false
return AlertDialog.Builder(activity)
.setMessage(R.string.permission_rationale_location)
.setPositiveButton(android.R.string.ok) { _, _ -> // After click on Ok, request the permission.
ActivityCompat.requestPermissions(
requireActivity(),
arrayOf(Manifest.permission.ACCESS_FINE_LOCATION),
requestCode
)
// Do not finish the Activity while requesting permission.
finishActivity = false
}
.setNegativeButton(android.R.string.cancel, null)
.create()
}
companion object {
private const val ARGUMENT_PERMISSION_REQUEST_CODE = "requestCode"
/**
* Creates a new instance of a dialog displaying the rationale for the use of the location
* permission.
*
*
* The permission is requested after clicking 'ok'.
*
* @param requestCode Id of the request that is used to request the permission. It is
* returned to the
* [androidx.core.app.ActivityCompat.OnRequestPermissionsResultCallback].
* @param finishActivity Whether the calling Activity should be finished if the dialog is
* cancelled.
*/
fun newInstance(requestCode: Int, finishActivity: Boolean): RationaleDialog {
val arguments = Bundle().apply {
putInt(ARGUMENT_PERMISSION_REQUEST_CODE, requestCode)
putBoolean(ARGUMENT_FINISH_ACTIVITY, finishActivity)
}
return RationaleDialog().apply {
this.arguments = arguments
}
}
}
}
}
}