BlindlyTeam/Blindly

View on GitHub
app/src/main/java/ch/epfl/sdp/blindly/location/permissions/LocationPermission.kt

Summary

Maintainability
A
0 mins
Test Coverage
B
82%
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
                    }
                }
            }
        }
    }
}