diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 7b58c90..0e73156 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -36,14 +36,18 @@
-
+
-
-
@@ -53,9 +57,9 @@
-
-
-
+
+
+
-
-
+
+ -->
+
+
+
\ No newline at end of file
diff --git a/app/src/main/java/com/permissionx/app/ExampleComponentActivity.kt b/app/src/main/java/com/permissionx/app/ExampleComponentActivity.kt
new file mode 100644
index 0000000..affb5fa
--- /dev/null
+++ b/app/src/main/java/com/permissionx/app/ExampleComponentActivity.kt
@@ -0,0 +1,81 @@
+package com.permissionx.app
+
+import android.Manifest
+import android.graphics.Color
+import android.os.Bundle
+import android.widget.Toast
+import androidx.activity.ComponentActivity
+import com.permissionx.app.databinding.ActivityExampleComponentBinding
+import com.permissionx.guolindev.PermissionX
+import com.permissionx.guolindev.patch.PermissionDelegateHolder
+
+class ExampleComponentActivity : ComponentActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ val layout = ActivityExampleComponentBinding.inflate(layoutInflater)
+ layout.makeRequestBtn.setOnClickListener {
+
+ PermissionX.init(this) {
+ it.permissions(Manifest.permission.CAMERA)
+ .request { allGranted, grantedList, deniedList ->
+ if (allGranted) {
+ Toast.makeText(this, "All permissions are granted", Toast.LENGTH_SHORT)
+ .show()
+ } else {
+ Toast.makeText(
+ this,
+ "The following permissions are denied:$deniedList",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ // or directly use PermissionDelegateHolder
+// requestPerms()
+ }
+ setContentView(layout.root)
+ }
+
+ fun requestPerms() {
+ PermissionDelegateHolder.delegate(this) {
+ PermissionX.init(it)
+ .permissions(
+ Manifest.permission.CAMERA,
+ Manifest.permission.ACCESS_FINE_LOCATION,
+ Manifest.permission.RECORD_AUDIO,
+// Manifest.permission.READ_CALENDAR,
+// Manifest.permission.READ_CALL_LOG,
+// Manifest.permission.READ_CONTACTS,
+// Manifest.permission.READ_PHONE_STATE,
+// Manifest.permission.BODY_SENSORS,
+// Manifest.permission.ACTIVITY_RECOGNITION,
+// Manifest.permission.SEND_SMS,
+// Manifest.permission.READ_EXTERNAL_STORAGE
+ )
+ .setDialogTintColor(Color.parseColor("#1972e8"), Color.parseColor("#8ab6f5"))
+ .onExplainRequestReason { scope, deniedList, beforeRequest ->
+ val message = "PermissionX needs following permissions to continue"
+ scope.showRequestReasonDialog(deniedList, message, "Allow", "Deny")
+// val message = "Please allow the following permissions in settings"
+// val dialog = CustomDialogFragment(message, deniedList)
+// scope.showRequestReasonDialog(dialog)
+ }
+ .onForwardToSettings { scope, deniedList ->
+ val message = "Please allow following permissions in settings"
+ scope.showForwardToSettingsDialog(deniedList, message, "Allow", "Deny")
+ }
+ .request { allGranted, grantedList, deniedList ->
+ if (allGranted) {
+ Toast.makeText(it, "All permissions are granted", Toast.LENGTH_SHORT)
+ .show()
+ } else {
+ Toast.makeText(
+ it,
+ "The following permissions are denied:$deniedList",
+ Toast.LENGTH_SHORT
+ ).show()
+ }
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/permissionx/app/MainFragment.kt b/app/src/main/java/com/permissionx/app/MainFragment.kt
index be3fff9..3139b2a 100644
--- a/app/src/main/java/com/permissionx/app/MainFragment.kt
+++ b/app/src/main/java/com/permissionx/app/MainFragment.kt
@@ -1,6 +1,7 @@
package com.permissionx.app
import android.Manifest
+import android.content.Intent
import android.graphics.Color
import android.os.Bundle
import android.view.LayoutInflater
@@ -17,7 +18,11 @@ class MainFragment : Fragment() {
private val binding get() = _binding!!
- override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
+ override fun onCreateView(
+ inflater: LayoutInflater,
+ container: ViewGroup?,
+ savedInstanceState: Bundle?
+ ): View? {
_binding = FragmentMainBinding.inflate(inflater, container, false)
return binding.root
}
@@ -28,7 +33,7 @@ class MainFragment : Fragment() {
binding.makeRequestBtn.setOnClickListener {
PermissionX.init(this)
.permissions(
- Manifest.permission.CAMERA,
+ Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION,
Manifest.permission.RECORD_AUDIO,
// Manifest.permission.READ_CALENDAR,
@@ -54,12 +59,33 @@ class MainFragment : Fragment() {
}
.request { allGranted, grantedList, deniedList ->
if (allGranted) {
- Toast.makeText(activity, "All permissions are granted", Toast.LENGTH_SHORT).show()
+ Toast.makeText(activity, "All permissions are granted", Toast.LENGTH_SHORT)
+ .show()
} else {
- Toast.makeText(activity, "The following permissions are denied:$deniedList", Toast.LENGTH_SHORT).show()
+ Toast.makeText(
+ activity,
+ "The following permissions are denied:$deniedList",
+ Toast.LENGTH_SHORT
+ ).show()
}
}
}
+ binding.makeRequestBtn2.setOnClickListener {
+ requireActivity().startActivity(
+ Intent(
+ requireActivity(),
+ ExampleComponentActivity::class.java
+ )
+ )
+ }
+ binding.makeRequestBtn3.setOnClickListener {
+ requireActivity().startActivity(
+ Intent(
+ requireActivity(),
+ MainJavaActivity::class.java
+ )
+ )
+ }
}
override fun onDestroyView() {
diff --git a/app/src/main/java/com/permissionx/app/MainJavaActivity.java b/app/src/main/java/com/permissionx/app/MainJavaActivity.java
index b38d871..b59cbdd 100644
--- a/app/src/main/java/com/permissionx/app/MainJavaActivity.java
+++ b/app/src/main/java/com/permissionx/app/MainJavaActivity.java
@@ -5,9 +5,15 @@
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity;
+import androidx.fragment.app.FragmentActivity;
import com.permissionx.app.databinding.ActivityMainJavaBinding;
+import com.permissionx.guolindev.PermissionMediator;
import com.permissionx.guolindev.PermissionX;
+import com.permissionx.guolindev.patch.PermissionDelegateHolder;
+
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
public class MainJavaActivity extends AppCompatActivity {
@@ -16,11 +22,40 @@ protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ActivityMainJavaBinding binding = ActivityMainJavaBinding.inflate(getLayoutInflater());
setContentView(binding.getRoot());
- binding.makeRequestBtn.setOnClickListener(view -> PermissionX.init(MainJavaActivity.this)
+
+ binding.makeRequestBtn.setOnClickListener(view -> {
+ requestCameraPermission(MainJavaActivity.this);
+ });
+
+ binding.makeRequestBtn2.setOnClickListener(view -> {
+ PermissionX.init(this, permissionMediator -> {
+ permissionMediator
+ .permissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ .explainReasonBeforeRequest()
+ .request((allGranted, grantedList, deniedList) -> {
+ if (allGranted) {
+ Toast.makeText(MainJavaActivity.this, "All permissions are granted", Toast.LENGTH_SHORT).show();
+ } else {
+ Toast.makeText(MainJavaActivity.this, "The following permissions are denied:" + deniedList, Toast.LENGTH_SHORT).show();
+ }
+ });
+ return null;
+ });
+
+ // or directly use PermissionDelegateHolder
+// PermissionDelegateHolder.delegate(this, fragmentActivity -> {
+// requestCameraPermission(fragmentActivity);// use the activity argument, do not use MainJavaActivity.this
+// return null;
+// });
+ });
+ }
+
+ private void requestCameraPermission(FragmentActivity activity) {
+ PermissionX.init(activity)
.permissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
.explainReasonBeforeRequest()
.onExplainRequestReason((scope, deniedList, beforeRequest) -> {
-// CustomDialog customDialog = new CustomDialog(MainJavaActivity.this, "PermissionX needs following permissions to continue", deniedList);
+// CustomDialog customDialog = new CustomDialog(activity, "PermissionX needs following permissions to continue", deniedList);
// scope.showRequestReasonDialog(customDialog);
scope.showRequestReasonDialog(deniedList, "PermissionX needs following permissions to continue", "Allow");
})
@@ -33,6 +68,6 @@ protected void onCreate(Bundle savedInstanceState) {
} else {
Toast.makeText(MainJavaActivity.this, "The following permissions are denied:" + deniedList, Toast.LENGTH_SHORT).show();
}
- }));
+ });
}
}
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_example_component.xml b/app/src/main/res/layout/activity_example_component.xml
new file mode 100644
index 0000000..7ec095b
--- /dev/null
+++ b/app/src/main/res/layout/activity_example_component.xml
@@ -0,0 +1,13 @@
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/activity_main_java.xml b/app/src/main/res/layout/activity_main_java.xml
index 1a392a0..5e38b5c 100644
--- a/app/src/main/res/layout/activity_main_java.xml
+++ b/app/src/main/res/layout/activity_main_java.xml
@@ -2,6 +2,7 @@
+
+
\ No newline at end of file
diff --git a/app/src/main/res/layout/fragment_main.xml b/app/src/main/res/layout/fragment_main.xml
index 1a392a0..8d92263 100644
--- a/app/src/main/res/layout/fragment_main.xml
+++ b/app/src/main/res/layout/fragment_main.xml
@@ -2,6 +2,7 @@
+
+
+
+
\ No newline at end of file
diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml
index fdfe9b0..21f3c85 100644
--- a/gradle/libs.versions.toml
+++ b/gradle/libs.versions.toml
@@ -1,5 +1,5 @@
[versions]
-agp = "8.4.1"
+agp = "8.5.1"
kotlin = "1.9.0"
coreKtx = "1.13.1"
junit = "4.13.2"
diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties
index c32859f..31d90cd 100644
--- a/gradle/wrapper/gradle-wrapper.properties
+++ b/gradle/wrapper/gradle-wrapper.properties
@@ -1,6 +1,6 @@
#Wed May 29 21:48:04 CST 2024
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
-distributionUrl=https\://services.gradle.org/distributions/gradle-8.6-bin.zip
+distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-all.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists
diff --git a/permissionx/src/main/AndroidManifest.xml b/permissionx/src/main/AndroidManifest.xml
index a5918e6..40fdf42 100644
--- a/permissionx/src/main/AndroidManifest.xml
+++ b/permissionx/src/main/AndroidManifest.xml
@@ -1,4 +1,9 @@
+
+
+
\ No newline at end of file
diff --git a/permissionx/src/main/java/com/permissionx/guolindev/PermissionX.java b/permissionx/src/main/java/com/permissionx/guolindev/PermissionX.java
index 84431cb..db69aca 100644
--- a/permissionx/src/main/java/com/permissionx/guolindev/PermissionX.java
+++ b/permissionx/src/main/java/com/permissionx/guolindev/PermissionX.java
@@ -16,6 +16,7 @@
package com.permissionx.guolindev;
+import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageManager;
@@ -25,6 +26,11 @@
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentActivity;
+import com.permissionx.guolindev.patch.PermissionDelegateHolder;
+
+import kotlin.Unit;
+import kotlin.jvm.functions.Function1;
+
/**
* An open source Android library that makes handling runtime permissions extremely easy.
*
@@ -37,6 +43,18 @@
* }
*
*
+ * if you are using component activity, you can use the following snippet:
+ *
+ * PermissionX.init(this, permissionMediator -> {
+ * permissionMediator
+ * .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA)
+ * .request { allGranted, grantedList, deniedList ->
+ * // handling the logic
+ * }
+ * return null;
+ * });
+ *
+ *
* @author guolin
* @since 2019/11/2
*/
@@ -62,6 +80,21 @@ public static PermissionMediator init(@NonNull Fragment fragment) {
return new PermissionMediator(fragment);
}
+ /**
+ * Init PermissionX to make everything prepare to work.
+ * request permissions in a component activity.
+ *
+ * @param context the context which can launch a new activity
+ * @param block the request permissions block to be executed
+ */
+ public static void init(@NonNull Context context, @NonNull Function1 block) {
+ PermissionDelegateHolder.delegate(context, fragmentActivity -> {
+ PermissionMediator permissionMediator = new PermissionMediator(fragmentActivity);
+ block.invoke(permissionMediator);
+ return null;
+ });
+ }
+
/**
* A helper function to check a permission is granted or not.
*
diff --git a/permissionx/src/main/java/com/permissionx/guolindev/patch/DelegateActivity.kt b/permissionx/src/main/java/com/permissionx/guolindev/patch/DelegateActivity.kt
new file mode 100644
index 0000000..bb20ac9
--- /dev/null
+++ b/permissionx/src/main/java/com/permissionx/guolindev/patch/DelegateActivity.kt
@@ -0,0 +1,51 @@
+package com.permissionx.guolindev.patch
+
+import android.graphics.Color
+import android.os.Build
+import android.os.Bundle
+import android.view.WindowManager
+import androidx.fragment.app.FragmentActivity
+import java.util.UUID
+
+/**
+ * Delegate activity
+ *
+ * author: knightwood
+ */
+class DelegateActivity : FragmentActivity() {
+ private lateinit var uuid: UUID
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ window.setBackgroundDrawableResource(android.R.color.transparent)
+ window.clearFlags(WindowManager.LayoutParams.FLAG_TRANSLUCENT_STATUS)
+ window.addFlags(WindowManager.LayoutParams.FLAG_DRAWS_SYSTEM_BAR_BACKGROUNDS)
+ window.statusBarColor = Color.TRANSPARENT
+
+
+ uuid = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
+ intent.getSerializableExtra("uuid", UUID::class.java)!!
+ } else {
+ intent.getSerializableExtra("uuid") as UUID
+ }
+
+ supportFragmentManager.setFragmentResultListener(
+ PermissionDelegateHolder.REQUEST_KEY,
+ this,
+ ) { _, bundle ->
+ val result = bundle.getBoolean(PermissionDelegateHolder.RESULT_KEY)
+ if (result) // Hahaha, in fact it will never be false here
+ release()
+ }
+
+ //execute permission request
+ PermissionDelegateHolder.holder[uuid]!!.invoke(this)
+ }
+
+ private fun release() {
+ PermissionDelegateHolder.holder.remove(uuid)
+ finish()
+ }
+
+}
\ No newline at end of file
diff --git a/permissionx/src/main/java/com/permissionx/guolindev/patch/PermissionDelegateHolder.kt b/permissionx/src/main/java/com/permissionx/guolindev/patch/PermissionDelegateHolder.kt
new file mode 100644
index 0000000..bab2c60
--- /dev/null
+++ b/permissionx/src/main/java/com/permissionx/guolindev/patch/PermissionDelegateHolder.kt
@@ -0,0 +1,62 @@
+package com.permissionx.guolindev.patch
+
+import android.content.Context
+import android.content.Intent
+import androidx.fragment.app.FragmentActivity
+import java.util.UUID
+
+/**
+ * Permission Delegate Holder
+ *
+ * author: knightwood
+ *
+ * in component activity, you can call this method to request permissions.
+ */
+object PermissionDelegateHolder {
+ const val REQUEST_KEY = "RequestFinish"
+ const val RESULT_KEY = "Result"
+
+ internal val holder: MutableMap Unit> = HashMap()
+
+ /**
+ * request permissions in a component activity.
+ *
+ * kotlin example:
+ * ```
+ * PermissionDelegateHolder.delegate(this) { activity ->
+ * PermissionX.init(activity)// use activity parameter to init PermissionX, do not use outside activity
+ * .permissions(Manifest.permission.READ_CONTACTS, Manifest.permission.CAMERA)
+ * .request { allGranted, grantedList, deniedList ->
+ * // handling the logic
+ * }
+ * }
+ *
+ * ```
+ *
+ * java example:
+ * ```
+ * PermissionDelegateHolder.delegate(this, activity -> {
+ * PermissionX.init(activity) // use activity parameter to init PermissionX, do not use outside activity
+ * .permissions(Manifest.permission.WRITE_EXTERNAL_STORAGE)
+ * .request((allGranted, grantedList, deniedList) -> {
+ * if (allGranted) {
+ * Toast.makeText(activity, "All permissions are granted", Toast.LENGTH_SHORT).show();
+ * } else {
+ * Toast.makeText(activity, "The following permissions are denied:" + deniedList, Toast.LENGTH_SHORT).show();
+ * }
+ * });
+ * return null;
+ * });
+ * ```
+ * @param ctx the context which can launch a new activity
+ * @param block the request permissions block to be executed
+ */
+ @JvmStatic
+ fun delegate(ctx: Context, block: (activity: FragmentActivity) -> Unit) {
+ val uuid = UUID.randomUUID()
+ holder[uuid] = block
+ val intent = Intent(ctx, DelegateActivity::class.java)
+ intent.putExtra("uuid", uuid)
+ ctx.startActivity(intent)
+ }
+}
\ 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 f6bec18..485e56c 100644
--- a/permissionx/src/main/java/com/permissionx/guolindev/request/PermissionBuilder.kt
+++ b/permissionx/src/main/java/com/permissionx/guolindev/request/PermissionBuilder.kt
@@ -21,6 +21,7 @@ import android.app.Dialog
import android.content.pm.ActivityInfo
import android.content.res.Configuration
import android.os.Build
+import android.os.Bundle
import android.view.View
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
@@ -33,6 +34,7 @@ import com.permissionx.guolindev.callback.RequestCallback
import com.permissionx.guolindev.dialog.DefaultDialog
import com.permissionx.guolindev.dialog.RationaleDialog
import com.permissionx.guolindev.dialog.RationaleDialogFragment
+import com.permissionx.guolindev.patch.PermissionDelegateHolder
import java.util.*
/**
@@ -579,6 +581,10 @@ class PermissionBuilder(
* Remove the InvisibleFragment from current FragmentManager.
*/
private fun removeInvisibleFragment() {
+ // notify that the request is finished.
+ fragmentManager.setFragmentResult(PermissionDelegateHolder.REQUEST_KEY, Bundle().apply {
+ putBoolean(PermissionDelegateHolder.RESULT_KEY, true)
+ })
val existedFragment = fragmentManager.findFragmentByTag(FRAGMENT_TAG)
if (existedFragment != null) {
fragmentManager.beginTransaction().remove(existedFragment).commitNowAllowingStateLoss()