diff --git a/permissionx/src/main/java/com/permissionx/guolindev/request/InvisibleFragment.kt b/permissionx/src/main/java/com/permissionx/guolindev/request/InvisibleFragment.kt index 94dcf64..f1529f8 100644 --- a/permissionx/src/main/java/com/permissionx/guolindev/request/InvisibleFragment.kt +++ b/permissionx/src/main/java/com/permissionx/guolindev/request/InvisibleFragment.kt @@ -18,11 +18,11 @@ package com.permissionx.guolindev.request import android.Manifest import android.os.Build import android.content.Intent -import android.content.pm.PackageManager import android.net.Uri import android.os.Environment import android.provider.Settings import android.util.Log +import androidx.activity.result.contract.ActivityResultContracts import androidx.fragment.app.Fragment import com.permissionx.guolindev.PermissionX import java.util.ArrayList @@ -45,6 +45,55 @@ class InvisibleFragment : Fragment() { */ private lateinit var task: ChainTask + /** + * Used to get the result for request multiple permissions. + */ + private val requestNormalPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { grantResults -> + onRequestNormalPermissionsResult(grantResults) + } + + /** + * Used to get the result for ACCESS_BACKGROUND_LOCATION permission. + */ + private val requestBackgroundLocationLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) { granted -> + onRequestBackgroundLocationPermissionResult(granted) + } + + /** + * Used to get the result for SYSTEM_ALERT_WINDOW permission. + */ + private val requestSystemAlertWindowLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + onRequestSystemAlertWindowPermissionResult() + } + + /** + * Used to get the result for WRITE_SETTINGS permission. + */ + private val requestWriteSettingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + onRequestWriteSettingsPermissionResult() + } + + /** + * Used to get the result for MANAGE_EXTERNAL_STORAGE permission. + */ + private val requestManageExternalStorageLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + onRequestManageExternalStoragePermissionResult() + } + + /** + * Used to get the result for REQUEST_INSTALL_PACKAGES permission. + */ + private val requestInstallPackagesLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + onRequestInstallPackagesPermissionResult() + } + + /** + * Used to get the result when user switch back from Settings. + */ + private val forwardToSettingsLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { + task.requestAgain(ArrayList(pb.forwardPermissions)) + } + /** * Request permissions at once by calling [Fragment.requestPermissions], * and handle request result in ActivityCompat.OnRequestPermissionsResultCallback. @@ -56,7 +105,7 @@ class InvisibleFragment : Fragment() { fun requestNow(permissionBuilder: PermissionBuilder, permissions: Set, chainTask: ChainTask) { pb = permissionBuilder task = chainTask - requestPermissions(permissions.toTypedArray(), REQUEST_NORMAL_PERMISSIONS) + requestNormalPermissionLauncher.launch(permissions.toTypedArray()) } /** @@ -69,10 +118,7 @@ class InvisibleFragment : Fragment() { fun requestAccessBackgroundLocationNow(permissionBuilder: PermissionBuilder, chainTask: ChainTask) { pb = permissionBuilder task = chainTask - requestPermissions( - arrayOf(RequestBackgroundLocationPermission.ACCESS_BACKGROUND_LOCATION), - REQUEST_BACKGROUND_LOCATION_PERMISSION - ) + requestBackgroundLocationLauncher.launch(RequestBackgroundLocationPermission.ACCESS_BACKGROUND_LOCATION) } /** @@ -85,7 +131,7 @@ class InvisibleFragment : Fragment() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.canDrawOverlays(context)) { val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION) intent.data = Uri.parse("package:${requireActivity().packageName}") - startActivityForResult(intent, ACTION_MANAGE_OVERLAY_PERMISSION) + requestSystemAlertWindowLauncher.launch(intent) } else { onRequestSystemAlertWindowPermissionResult() } @@ -101,7 +147,7 @@ class InvisibleFragment : Fragment() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && !Settings.System.canWrite(context)) { val intent = Intent(Settings.ACTION_MANAGE_WRITE_SETTINGS) intent.data = Uri.parse("package:${requireActivity().packageName}") - startActivityForResult(intent, ACTION_WRITE_SETTINGS_PERMISSION) + requestWriteSettingsLauncher.launch(intent) } else { onRequestWriteSettingsPermissionResult() } @@ -116,7 +162,7 @@ class InvisibleFragment : Fragment() { task = chainTask if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R && !Environment.isExternalStorageManager()) { val intent = Intent(Settings.ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) - startActivityForResult(intent, ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION) + requestManageExternalStorageLauncher.launch(intent) } else { onRequestManageExternalStoragePermissionResult() } @@ -132,35 +178,20 @@ class InvisibleFragment : Fragment() { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES) intent.data = Uri.parse("package:${requireActivity().packageName}") - startActivityForResult(intent, ACTION_MANAGE_UNKNOWN_APP_SOURCES_PERMISSION) + requestInstallPackagesLauncher.launch(intent) } else { onRequestInstallPackagesPermissionResult() } } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { - if (requestCode == REQUEST_NORMAL_PERMISSIONS) { - onRequestNormalPermissionsResult(permissions, grantResults) - } else if (requestCode == REQUEST_BACKGROUND_LOCATION_PERMISSION) { - onRequestBackgroundLocationPermissionResult() - } - } - /** - * Handle the request result when user switch back from Settings. + * Go to your app's Settings page to let user turn on the necessary permissions. */ - override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { - super.onActivityResult(requestCode, resultCode, data) - // When user switch back from settings, just request again. - if (checkForGC()) { - when (requestCode) { - FORWARD_TO_SETTINGS -> task.requestAgain(ArrayList(pb.forwardPermissions)) - ACTION_MANAGE_OVERLAY_PERMISSION -> onRequestSystemAlertWindowPermissionResult() - ACTION_WRITE_SETTINGS_PERMISSION -> onRequestWriteSettingsPermissionResult() - ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION -> onRequestManageExternalStoragePermissionResult() - ACTION_MANAGE_UNKNOWN_APP_SOURCES_PERMISSION -> onRequestInstallPackagesPermissionResult() - } - } + fun forwardToSettings() { + val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) + val uri = Uri.fromParts("package", requireActivity().packageName, null) + intent.data = uri + forwardToSettingsLauncher.launch(intent) } override fun onDestroy() { @@ -178,16 +209,15 @@ class InvisibleFragment : Fragment() { /** * Handle result of normal permissions request. */ - private fun onRequestNormalPermissionsResult(permissions: Array?, grantResults: IntArray?) { - if (checkForGC() && permissions != null && grantResults != null && permissions.size == grantResults.size) { + private fun onRequestNormalPermissionsResult(grantResults: Map) { + if (checkForGC()) { // We can never holds granted permissions for safety, because user may turn some permissions off in settings. // So every time request, must request the already granted permissions again and refresh the granted permission set. pb.grantedPermissions.clear() val showReasonList: MutableList = ArrayList() // holds denied permissions in the request permissions. val forwardList: MutableList = ArrayList() // hold permanently denied permissions in the request permissions. - for (i in permissions.indices) { - val permission = permissions[i] - if (grantResults[i] == PackageManager.PERMISSION_GRANTED) { + for ((permission, granted) in grantResults) { + if (granted) { pb.grantedPermissions.add(permission) // Remove granted permissions from deniedPermissions and permanentDeniedPermissions set in PermissionBuilder. pb.deniedPermissions.remove(permission) @@ -196,11 +226,11 @@ class InvisibleFragment : Fragment() { // Denied permission can turn into permanent denied permissions, but permanent denied permission can not turn into denied permissions. val shouldShowRationale = shouldShowRequestPermissionRationale(permission) if (shouldShowRationale) { - showReasonList.add(permissions[i]) + showReasonList.add(permission) pb.deniedPermissions.add(permission) // So there's no need to remove the current permission from permanentDeniedPermissions because it won't be there. } else { - forwardList.add(permissions[i]) + forwardList.add(permission) pb.permanentDeniedPermissions.add(permission) // We must remove the current permission from deniedPermissions because it is permanent denied permission now. pb.deniedPermissions.remove(permission) @@ -257,9 +287,9 @@ class InvisibleFragment : Fragment() { /** * Handle result of ACCESS_BACKGROUND_LOCATION permission request. */ - private fun onRequestBackgroundLocationPermissionResult() { + private fun onRequestBackgroundLocationPermissionResult(granted: Boolean) { if (checkForGC()) { - if (PermissionX.isGranted(context, RequestBackgroundLocationPermission.ACCESS_BACKGROUND_LOCATION)) { + if (granted) { pb.grantedPermissions.add(RequestBackgroundLocationPermission.ACCESS_BACKGROUND_LOCATION) // Remove granted permissions from deniedPermissions and permanentDeniedPermissions set in PermissionBuilder. pb.deniedPermissions.remove(RequestBackgroundLocationPermission.ACCESS_BACKGROUND_LOCATION) @@ -400,41 +430,4 @@ class InvisibleFragment : Fragment() { } return true } - - companion object { - /** - * Code for request normal permissions. - */ - const val REQUEST_NORMAL_PERMISSIONS = 1 - - /** - * Code for request ACCESS_BACKGROUND_LOCATION permissions. This permissions can't be requested with others over Android R. - */ - const val REQUEST_BACKGROUND_LOCATION_PERMISSION = 2 - - /** - * Code for forward to settings page of current app. - */ - const val FORWARD_TO_SETTINGS = 1 - - /** - * Code for request SYSTEM_ALERT_WINDOW permission. - */ - const val ACTION_MANAGE_OVERLAY_PERMISSION = 2 - - /** - * Code for request WRITE_SETTINGS permission. - */ - const val ACTION_WRITE_SETTINGS_PERMISSION = 3 - - /** - * Code for request MANAGE_EXTERNAL_STORAGE permission. - */ - const val ACTION_MANAGE_ALL_FILES_ACCESS_PERMISSION = 4 - - /** - * Code for request ACTION_MANAGE_UNKNOWN_APP_SOURCES permission. - */ - const val ACTION_MANAGE_UNKNOWN_APP_SOURCES_PERMISSION = 5 - } } \ No newline at end of file diff --git a/permissionx/src/main/java/com/permissionx/guolindev/request/PermissionBuilder.kt b/permissionx/src/main/java/com/permissionx/guolindev/request/PermissionBuilder.kt index ef0fc99..1eedee6 100644 --- a/permissionx/src/main/java/com/permissionx/guolindev/request/PermissionBuilder.kt +++ b/permissionx/src/main/java/com/permissionx/guolindev/request/PermissionBuilder.kt @@ -17,9 +17,6 @@ package com.permissionx.guolindev.request import android.Manifest import android.app.Dialog -import android.content.Intent -import android.net.Uri -import android.provider.Settings import android.view.View import androidx.fragment.app.Fragment import androidx.fragment.app.FragmentActivity @@ -502,10 +499,7 @@ class PermissionBuilder( private fun forwardToSettings(permissions: List) { forwardPermissions.clear() forwardPermissions.addAll(permissions) - val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS) - val uri = Uri.fromParts("package", activity.packageName, null) - intent.data = uri - invisibleFragment.startActivityForResult(intent, InvisibleFragment.FORWARD_TO_SETTINGS) + invisibleFragment.forwardToSettings() } /**