diff --git a/app/src/main/kotlin/com/livetyping/activitybinder/BinderExampleApplication.kt b/app/src/main/kotlin/com/livetyping/activitybinder/BinderExampleApplication.kt index 3846626..763ecbe 100644 --- a/app/src/main/kotlin/com/livetyping/activitybinder/BinderExampleApplication.kt +++ b/app/src/main/kotlin/com/livetyping/activitybinder/BinderExampleApplication.kt @@ -1,6 +1,7 @@ package com.livetyping.activitybinder import android.app.Application +import com.livetyping.core.NewBinder import com.livetyping.facebook.FacebookInitializer import com.livetyping.google.GoogleInitializer import com.livetyping.images.ImagesBinder @@ -22,6 +23,10 @@ class BinderExampleApplication : Application() { ImagesBinder(applicationContext.packageName + ".provider", R.xml.file_path) } + val newBinder: NewBinder by lazy { + NewBinder() + } + override fun onCreate() { super.onCreate() val socialsInitializers = listOf( diff --git a/app/src/main/kotlin/com/livetyping/activitybinder/PermissionExampleActivity.kt b/app/src/main/kotlin/com/livetyping/activitybinder/PermissionExampleActivity.kt index 95e59e7..973f525 100644 --- a/app/src/main/kotlin/com/livetyping/activitybinder/PermissionExampleActivity.kt +++ b/app/src/main/kotlin/com/livetyping/activitybinder/PermissionExampleActivity.kt @@ -5,7 +5,9 @@ import android.content.Intent import android.os.Bundle import android.util.Log import androidx.appcompat.app.AppCompatActivity +import com.livetyping.core.NewBinder import com.livetyping.permission.PermissionBinder +import com.livetyping.permission.request.PassivePermissionRequest import kotlinx.android.synthetic.main.activity_permissions.* class PermissionExampleActivity : AppCompatActivity() { @@ -16,11 +18,13 @@ class PermissionExampleActivity : AppCompatActivity() { } private lateinit var permissionBinder: PermissionBinder + private lateinit var newBinder: NewBinder override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_permissions) permissionBinder = (application as BinderExampleApplication).permissionBinder + newBinder = (application as BinderExampleApplication).newBinder handleButtonSinglePermissions() handleButtonMultiplyPermissions() } @@ -33,7 +37,9 @@ class PermissionExampleActivity : AppCompatActivity() { private fun setOnSinglePassivePermissionClickListener() { single_passive.setOnClickListener { - permissionBinder.passivePermission(READ_EXTERNAL_STORAGE) { isGranted -> onPermissionResult(isGranted) } + newBinder.request(PassivePermissionRequest(READ_EXTERNAL_STORAGE)) { + onPermissionResult(it) + } } } @@ -89,7 +95,11 @@ class PermissionExampleActivity : AppCompatActivity() { private fun setOnMultiplePassivePermissionClickListener() { val passivePermissions = listOf(READ_CONTACTS, ACCESS_FINE_LOCATION) multiply_passive.setOnClickListener { - permissionBinder.passivePermissions(passivePermissions) { results -> onPermissionsResults(results) } + permissionBinder.passivePermissions(passivePermissions) { results -> + onPermissionsResults( + results + ) + } } } @@ -124,10 +134,12 @@ class PermissionExampleActivity : AppCompatActivity() { override fun onStart() { super.onStart() permissionBinder.attach(this) + newBinder.attach(this) } override fun onStop() { permissionBinder.detach(this) + newBinder.detach(this) super.onStop() } @@ -136,8 +148,13 @@ class PermissionExampleActivity : AppCompatActivity() { permissionBinder.onActivityResult(requestCode, this) } - override fun onRequestPermissionsResult(requestCode: Int, permissions: Array, grantResults: IntArray) { + override fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { super.onRequestPermissionsResult(requestCode, permissions, grantResults) permissionBinder.onRequestPermissionResult(requestCode) + newBinder.onRequestPermissionsResult(requestCode, permissions, grantResults) } } diff --git a/core/src/main/kotlin/com/livetyping/core/BinderRequest.kt b/core/src/main/kotlin/com/livetyping/core/BinderRequest.kt new file mode 100644 index 0000000..ab33016 --- /dev/null +++ b/core/src/main/kotlin/com/livetyping/core/BinderRequest.kt @@ -0,0 +1,47 @@ +package com.livetyping.core + +import android.app.Activity +import android.content.Intent + + +abstract class BinderRequest { + + protected var requestCode: Int = 0 + protected lateinit var block: (result: T) -> Unit + + internal fun setRequestCode(requestCode: Int) { + this.requestCode = requestCode + } + + internal fun setBlock(block: (result: T) -> Unit) { + this.block = block + } + + internal fun internalActivityResult(resultCode: Int, data: Intent?) { + onActivityResult(resultCode, data) + } + + internal fun internalPermissionResult( + activity: Activity, + permissions: Array, + grantResults: IntArray + ) { + onRequestPermissionsResult(activity, permissions, grantResults) + } + + internal fun internalRequest(activity: Activity) = request(activity) + + protected open fun onActivityResult(resultCode: Int, data: Intent?) { + //for override + } + + protected open fun onRequestPermissionsResult( + activity: Activity, + permissions: Array, + grantResults: IntArray + ) { + //for override + } + + protected abstract fun request(activity: Activity) +} \ No newline at end of file diff --git a/core/src/main/kotlin/com/livetyping/core/NewBinder.kt b/core/src/main/kotlin/com/livetyping/core/NewBinder.kt new file mode 100644 index 0000000..172921b --- /dev/null +++ b/core/src/main/kotlin/com/livetyping/core/NewBinder.kt @@ -0,0 +1,43 @@ +package com.livetyping.core + +import android.content.Intent +import kotlin.random.Random + + +class NewBinder : Binder() { + + private val requests by lazy { + mutableMapOf>() + } + + fun request(request: BinderRequest, resultBlock: (result: T) -> Unit) { + val generateRequestCode = generateRequestCode() + request.setRequestCode(generateRequestCode) + request.setBlock(resultBlock) + requests[generateRequestCode] = request + getAttachedObject()?.let { request.internalRequest(it) } + } + + fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) { + requests[requestCode]?.internalActivityResult(resultCode, data) + } + + fun onRequestPermissionsResult( + requestCode: Int, + permissions: Array, + grantResults: IntArray + ) { + getAttachedObject()?.let { + requests[requestCode]?.internalPermissionResult(it, permissions, grantResults) + } + + } + + + //TODO need generator for request codes + private val random = Random(100) + + private fun generateRequestCode(): Int { + return random.nextInt(100) + 100 + } +} \ No newline at end of file diff --git a/images/src/main/AndroidManifest.xml b/images/src/main/AndroidManifest.xml index 2d097be..feebc64 100644 --- a/images/src/main/AndroidManifest.xml +++ b/images/src/main/AndroidManifest.xml @@ -1,15 +1 @@ - - - - - - - - + diff --git a/images/src/main/kotlin/com/livetyping/images/photo/DefaultProvider.kt b/images/src/main/kotlin/com/livetyping/images/photo/DefaultProvider.kt deleted file mode 100644 index 879b316..0000000 --- a/images/src/main/kotlin/com/livetyping/images/photo/DefaultProvider.kt +++ /dev/null @@ -1,6 +0,0 @@ -package com.livetyping.images.photo - -import androidx.core.content.FileProvider - - -class DefaultProvider : FileProvider() diff --git a/images/src/main/res/xml/default_file_paths.xml b/images/src/main/res/xml/default_file_paths.xml deleted file mode 100644 index 97cfd6b..0000000 --- a/images/src/main/res/xml/default_file_paths.xml +++ /dev/null @@ -1,8 +0,0 @@ - - - - - - diff --git a/permission/src/main/kotlin/com/livetyping/permission/ActivePermissionRequest.kt b/permission/src/main/kotlin/com/livetyping/permission/ActivePermissionRequest.kt index 76c41f3..8ff2c7a 100644 --- a/permission/src/main/kotlin/com/livetyping/permission/ActivePermissionRequest.kt +++ b/permission/src/main/kotlin/com/livetyping/permission/ActivePermissionRequest.kt @@ -34,11 +34,16 @@ internal class ActivePermissionRequest( } override fun afterRequest(activity: Activity, @StyleRes themeResId: Int) { - val isAllPermissionsGrantedOrRationalShowed = rationaleShowed || areAllPermissionsGranted(activity) + val isAllPermissionsGrantedOrRationalShowed = + rationaleShowed || areAllPermissionsGranted(activity) if (isAllPermissionsGrantedOrRationalShowed) { invokeResult(activity) } else { - showOpenSettingsDialog(activity, themeResId) + if (!rationaleShowed && getPermissionsWithoutRationale(activity).isNotEmpty()) { + showOpenSettingsDialog(activity, themeResId) + } else { + invokeResult(activity) + } } } diff --git a/permission/src/main/kotlin/com/livetyping/permission/PermissionRequest.kt b/permission/src/main/kotlin/com/livetyping/permission/PermissionRequest.kt index 98fb8bc..ceb3cc1 100644 --- a/permission/src/main/kotlin/com/livetyping/permission/PermissionRequest.kt +++ b/permission/src/main/kotlin/com/livetyping/permission/PermissionRequest.kt @@ -87,4 +87,10 @@ internal abstract class PermissionRequest( syncPermissionsGrantedResult(activity) resultListener.invoke(permissionMap) } + + protected fun getPermissionsWithoutRationale(activity: Activity): List { + return permissions.filter { + !ActivityCompat.shouldShowRequestPermissionRationale(activity, it) + } + } } diff --git a/permission/src/main/kotlin/com/livetyping/permission/request/ActivePermissionBinderRequest.kt b/permission/src/main/kotlin/com/livetyping/permission/request/ActivePermissionBinderRequest.kt new file mode 100644 index 0000000..6846eca --- /dev/null +++ b/permission/src/main/kotlin/com/livetyping/permission/request/ActivePermissionBinderRequest.kt @@ -0,0 +1,84 @@ +package com.livetyping.permission.request + +import android.app.Activity +import android.content.Intent +import android.content.pm.PackageManager +import android.net.Uri +import android.provider.Settings +import androidx.annotation.StringRes +import androidx.appcompat.app.AlertDialog +import androidx.core.app.ActivityCompat +import com.livetyping.permission.R + + +class ActivePermissionBinderRequest( + private val permission: String, + @StringRes private val rationaleTextStringRes: Int, + @StringRes private val buttonOkTextStringRes: Int = android.R.string.ok, + @StringRes private val buttonSettingsStringRes: Int = R.string.permission_settings_default_button_text +) : + SinglePermissionBinderRequest() { + + private var rationaleShowed = false + + override fun request(activity: Activity) { + if (isPermissionGranted(permission, activity)) { + block(true) + } else { + if (shouldShowRationale(activity)) { + rationaleShowed = true + showRationaleDialog(activity, buttonOkTextStringRes) { requestPermission(activity) } + } else { + requestPermission(activity) + } + } + } + + override fun onRequestPermissionsResult( + activity: Activity, + permissions: Array, + grantResults: IntArray + ) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + block(true) + } else { + if (rationaleShowed.not() && shouldShowRationale(activity)) { + block(false) + } else { + if (rationaleShowed) { + block(false) + } else { + showRationaleDialog(activity, buttonSettingsStringRes) { openAppSettings(activity) } + } + } + } + } + + private fun shouldShowRationale(activity: Activity): Boolean { + return ActivityCompat.shouldShowRequestPermissionRationale(activity, permission) + } + + private fun showRationaleDialog(activity: Activity, buttonResId: Int, buttonBlock: () -> Unit) { + AlertDialog.Builder(activity) + .setMessage(rationaleTextStringRes) + .setPositiveButton(buttonResId) { _, _ -> buttonBlock() } + .show() + } + + private fun requestPermission(activity: Activity) { + ActivityCompat.requestPermissions( + activity, + arrayOf(permission), + requestCode + ) + } + + private fun openAppSettings(activity: Activity) { + val intent = Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.parse("package:${activity.packageName}") + ) + intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY) + activity.startActivityForResult(intent, requestCode) + } +} \ No newline at end of file diff --git a/permission/src/main/kotlin/com/livetyping/permission/request/MultiplyGeneralPermissionBinderRequest.kt b/permission/src/main/kotlin/com/livetyping/permission/request/MultiplyGeneralPermissionBinderRequest.kt new file mode 100644 index 0000000..5e87b21 --- /dev/null +++ b/permission/src/main/kotlin/com/livetyping/permission/request/MultiplyGeneralPermissionBinderRequest.kt @@ -0,0 +1,44 @@ +package com.livetyping.permission.request + +import android.app.Activity +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat +import androidx.core.content.ContextCompat +import com.livetyping.core.BinderRequest + + +class MultiplyGeneralPermissionBinderRequest( + private val permissions: Iterable +) : BinderRequest>() { + + private val result = mutableMapOf() + + override fun request(activity: Activity) { + val groupedByGranted = permissions.groupBy { + ContextCompat.checkSelfPermission( + activity, + it + ) == PackageManager.PERMISSION_GRANTED + } + groupedByGranted[true]?.forEach { result[it] = true } + val denied = groupedByGranted[false] + if (denied == null) { + block(result) + } else { + denied.toTypedArray().let { + ActivityCompat.requestPermissions(activity, it, requestCode) + } + } + } + + override fun onRequestPermissionsResult( + activity: Activity, + permissions: Array, + grantResults: IntArray + ) { + permissions.forEachIndexed { index, permission -> + result[permission] = grantResults[index] == PackageManager.PERMISSION_GRANTED + } + block(result) + } +} \ No newline at end of file diff --git a/permission/src/main/kotlin/com/livetyping/permission/request/PassivePermissionRequest.kt b/permission/src/main/kotlin/com/livetyping/permission/request/PassivePermissionRequest.kt new file mode 100644 index 0000000..261c414 --- /dev/null +++ b/permission/src/main/kotlin/com/livetyping/permission/request/PassivePermissionRequest.kt @@ -0,0 +1,34 @@ +package com.livetyping.permission.request + +import android.app.Activity +import android.content.pm.PackageManager +import androidx.core.app.ActivityCompat + + +class PassivePermissionRequest( + private val permission: String +) : + SinglePermissionBinderRequest() { + + override fun request(activity: Activity) { + if (isPermissionGranted(permission, activity)) { + block(true) + } else { + if (ActivityCompat.shouldShowRequestPermissionRationale(activity, permission)) { + block(false) + } else ActivityCompat.requestPermissions(activity, arrayOf(permission), requestCode) + } + } + + override fun onRequestPermissionsResult( + activity: Activity, + permissions: Array, + grantResults: IntArray + ) { + if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED) { + block(true) + } else block(false) + } + + +} \ No newline at end of file diff --git a/permission/src/main/kotlin/com/livetyping/permission/request/SinglePermissionBinderRequest.kt b/permission/src/main/kotlin/com/livetyping/permission/request/SinglePermissionBinderRequest.kt new file mode 100644 index 0000000..00bed66 --- /dev/null +++ b/permission/src/main/kotlin/com/livetyping/permission/request/SinglePermissionBinderRequest.kt @@ -0,0 +1,18 @@ +package com.livetyping.permission.request + +import android.app.Activity +import androidx.core.content.ContextCompat +import androidx.core.content.PermissionChecker +import com.livetyping.core.BinderRequest + + +abstract class SinglePermissionBinderRequest : BinderRequest() { + + @PermissionChecker.PermissionResult + protected fun isPermissionGranted(permission: String, activity: Activity): Boolean { + return ContextCompat.checkSelfPermission( + activity, + permission + ) == PermissionChecker.PERMISSION_GRANTED + } +} \ No newline at end of file diff --git a/permission/src/main/res/values/strings.xml b/permission/src/main/res/values/strings.xml index 8ed2bb5..ea6d270 100644 --- a/permission/src/main/res/values/strings.xml +++ b/permission/src/main/res/values/strings.xml @@ -1,3 +1,3 @@ - permission + settings