diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/LocationPermissionManager.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/LocationPermissionManager.kt index e5dd0e578..9f28053a3 100644 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/LocationPermissionManager.kt +++ b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/LocationPermissionManager.kt @@ -1,18 +1,31 @@ package com.lighthouse.core.android.utils.permission import android.Manifest -import android.app.Activity +import android.content.Context +import android.content.Intent +import android.net.Uri import android.os.Build +import android.provider.Settings import com.lighthouse.core.android.utils.permission.core.PermissionManager -class LocationPermissionManager(activity: Activity) : PermissionManager(activity) { +class LocationPermissionManager(context: Context) : PermissionManager(context) { - override val additionalPermission = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { + override val additionalPermissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) { arrayOf(Manifest.permission.ACCESS_BACKGROUND_LOCATION) } else { emptyArray() } override val permissions = - arrayOf(Manifest.permission.ACCESS_FINE_LOCATION, Manifest.permission.ACCESS_COARSE_LOCATION) + arrayOf( + Manifest.permission.ACCESS_FINE_LOCATION, + Manifest.permission.ACCESS_COARSE_LOCATION + ) + + override fun settingIntent(): Intent { + return Intent( + Settings.ACTION_APPLICATION_DETAILS_SETTINGS, + Uri.fromParts("package", context.packageName, null) + ) + } } diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/StoragePermissionManager.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/StoragePermissionManager.kt index de5c0d7ec..83a445e05 100644 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/StoragePermissionManager.kt +++ b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/StoragePermissionManager.kt @@ -1,11 +1,11 @@ package com.lighthouse.core.android.utils.permission import android.Manifest -import android.app.Activity +import android.content.Context import android.os.Build import com.lighthouse.core.android.utils.permission.core.PermissionManager -class StoragePermissionManager(activity: Activity) : PermissionManager(activity) { +class StoragePermissionManager(context: Context) : PermissionManager(context) { override val permissions = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { arrayOf(Manifest.permission.READ_MEDIA_IMAGES) diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/ActivityPermissionDelegate.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/ActivityPermissionDelegate.kt deleted file mode 100644 index 1f331dd2b..000000000 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/ActivityPermissionDelegate.kt +++ /dev/null @@ -1,26 +0,0 @@ -package com.lighthouse.core.android.utils.permission.core - -import android.app.Activity -import androidx.core.app.ComponentActivity -import androidx.lifecycle.LifecycleOwner -import kotlin.reflect.KProperty - -class ActivityPermissionDelegate( - lifecycleOwner: LifecycleOwner, - private val activity: Activity, - private val managerClass: Class -) : PermissionDelegate(lifecycleOwner) { - - override fun getValue(thisRef: LifecycleOwner, property: KProperty<*>): PM { - manager?.let { - return it - } - - return PermissionFactory().create(activity, managerClass).also { - manager = it - } - } -} - -inline fun ComponentActivity.permissions() = - ActivityPermissionDelegate(this, this, PM::class.java) diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/BeepPermissionState.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/BeepPermissionState.kt deleted file mode 100644 index 169184bcd..000000000 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/BeepPermissionState.kt +++ /dev/null @@ -1,7 +0,0 @@ -package com.lighthouse.core.android.utils.permission.core - -sealed class BeepPermissionState { - object NotAllowedPermission : BeepPermissionState() - object AllAllowedPermission : BeepPermissionState() - object PartiallyAllowedPermission : BeepPermissionState() -} diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/FragmentPermissionDelegate.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/FragmentPermissionDelegate.kt deleted file mode 100644 index 9bc407100..000000000 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/FragmentPermissionDelegate.kt +++ /dev/null @@ -1,25 +0,0 @@ -package com.lighthouse.core.android.utils.permission.core - -import androidx.fragment.app.Fragment -import androidx.lifecycle.LifecycleOwner -import kotlin.reflect.KProperty - -class FragmentPermissionDelegate( - lifecycleOwner: LifecycleOwner, - private val fragment: Fragment, - private val managerClass: Class -) : PermissionDelegate(lifecycleOwner) { - - override fun getValue(thisRef: LifecycleOwner, property: KProperty<*>): PM { - manager?.let { - return it - } - - return PermissionFactory().create(fragment.requireActivity(), managerClass).also { - manager = it - } - } -} - -inline fun Fragment.permissions() = - FragmentPermissionDelegate(this, this, PM::class.java) diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionDelegate.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionDelegate.kt deleted file mode 100644 index e525e9092..000000000 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionDelegate.kt +++ /dev/null @@ -1,27 +0,0 @@ -package com.lighthouse.core.android.utils.permission.core - -import androidx.lifecycle.DefaultLifecycleObserver -import androidx.lifecycle.LifecycleOwner -import kotlin.properties.ReadOnlyProperty - -abstract class PermissionDelegate( - lifecycleOwner: LifecycleOwner -) : ReadOnlyProperty { - - protected var manager: PM? = null - - init { - lifecycleOwner.lifecycle.addObserver(object : DefaultLifecycleObserver { - override fun onStart(owner: LifecycleOwner) { - val manager = manager - if (manager != null) { - manager.permissionFlow.value = manager.isGrant - } - } - - override fun onDestroy(owner: LifecycleOwner) { - lifecycleOwner.lifecycle.removeObserver(this) - } - }) - } -} diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionFactory.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionFactory.kt deleted file mode 100644 index cb5150ba5..000000000 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionFactory.kt +++ /dev/null @@ -1,16 +0,0 @@ -package com.lighthouse.core.android.utils.permission.core - -import android.app.Activity -import com.lighthouse.core.android.utils.permission.LocationPermissionManager -import com.lighthouse.core.android.utils.permission.StoragePermissionManager - -@Suppress("UNCHECKED_CAST") -class PermissionFactory { - fun create(activity: Activity, managerClass: Class): PM { - return when (managerClass) { - StoragePermissionManager::class.java -> StoragePermissionManager(activity) - LocationPermissionManager::class.java -> LocationPermissionManager(activity) - else -> throw IllegalArgumentException("존재하지 않는 Permission Manager입니다.") - } as PM - } -} diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionManager.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionManager.kt index 7567431ce..1d3f37961 100644 --- a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionManager.kt +++ b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionManager.kt @@ -2,41 +2,47 @@ package com.lighthouse.core.android.utils.permission.core import android.app.Activity import android.content.Context +import android.content.Intent import android.content.pm.PackageManager -import kotlinx.coroutines.flow.MutableStateFlow abstract class PermissionManager( - private val activity: Activity + protected val context: Context ) { - abstract val permissions: Array + protected abstract val permissions: Array - open val additionalPermission = emptyArray() + protected open val additionalPermissions = emptyArray() - val basicPermission - get() = permissions.firstOrNull() ?: "" - - val permissionFlow by lazy { - MutableStateFlow(isGrant) + fun getPermissions(type: PermissionType = PermissionType.Basic): Array { + return when (type) { + PermissionType.All -> permissions + additionalPermissions + PermissionType.Basic -> permissions + PermissionType.Additional -> additionalPermissions + }.copyOf() } - val isGrant - get() = permissions.all { permission -> - activity.checkPermission(permission) + fun isGrant(type: PermissionType = PermissionType.Basic): Boolean { + val list = when (type) { + PermissionType.All -> permissions + additionalPermissions + PermissionType.Basic -> permissions + PermissionType.Additional -> additionalPermissions + } + return list.all { + context.checkSelfPermission(it) == PackageManager.PERMISSION_GRANTED } + } - val permissionState - get() = when { - (permissions + additionalPermission).all { activity.checkPermission(it) } -> { - BeepPermissionState.AllAllowedPermission - } - permissions.all { activity.checkPermission(it) } -> { - BeepPermissionState.PartiallyAllowedPermission - } - else -> { - BeepPermissionState.NotAllowedPermission + fun getManyTimesRejectedPermission(type: PermissionType = PermissionType.Basic): String? { + val activity = context as? Activity ?: return null + val permissions = getPermissions(type) + for (permission in permissions) { + if (activity.shouldShowRequestPermissionRationale(permission)) { + return permission } } -} + return null + } -fun Context.checkPermission(permission: String) = - checkSelfPermission(permission) == PackageManager.PERMISSION_GRANTED + open fun settingIntent(): Intent { + return Intent() + } +} diff --git a/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionType.kt b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionType.kt new file mode 100644 index 000000000..3e4a66b68 --- /dev/null +++ b/core-android/src/main/java/com/lighthouse/core/android/utils/permission/core/PermissionType.kt @@ -0,0 +1,7 @@ +package com.lighthouse.core.android.utils.permission.core + +enum class PermissionType { + All, + Basic, + Additional +} diff --git a/features/ui-main/src/main/java/com/lighthouse/features/main/ui/MainContainerFragment.kt b/features/ui-main/src/main/java/com/lighthouse/features/main/ui/MainContainerFragment.kt index 053122191..bf981f5eb 100644 --- a/features/ui-main/src/main/java/com/lighthouse/features/main/ui/MainContainerFragment.kt +++ b/features/ui-main/src/main/java/com/lighthouse/features/main/ui/MainContainerFragment.kt @@ -8,8 +8,6 @@ import androidx.fragment.app.viewModels import androidx.navigation.NavController import androidx.navigation.fragment.NavHostFragment import androidx.navigation.ui.setupWithNavController -import com.lighthouse.core.android.utils.permission.StoragePermissionManager -import com.lighthouse.core.android.utils.permission.core.permissions import com.lighthouse.features.common.binding.viewBindings import com.lighthouse.features.common.ext.repeatOnStarted import com.lighthouse.features.main.R @@ -30,8 +28,6 @@ class MainContainerFragment : Fragment(R.layout.fragment_main_container) { private val mainNavigationViewModel: MainNavigationViewModel by viewModels() - private val storagePermission: StoragePermissionManager by permissions() - private lateinit var navController: NavController override fun onViewCreated(view: View, savedInstanceState: Bundle?) { diff --git a/features/ui-setting/src/main/java/com/lighthouse/features/setting/ui/SettingFragment.kt b/features/ui-setting/src/main/java/com/lighthouse/features/setting/ui/SettingFragment.kt index d5c8665b0..636213de5 100644 --- a/features/ui-setting/src/main/java/com/lighthouse/features/setting/ui/SettingFragment.kt +++ b/features/ui-setting/src/main/java/com/lighthouse/features/setting/ui/SettingFragment.kt @@ -5,6 +5,7 @@ import android.os.Bundle import android.view.View import androidx.activity.addCallback import androidx.activity.result.contract.ActivityResultContracts +import androidx.annotation.StringRes import androidx.fragment.app.Fragment import androidx.fragment.app.activityViewModels import androidx.fragment.app.viewModels @@ -14,6 +15,7 @@ import com.google.android.material.snackbar.Snackbar import com.lighthouse.auth.google.model.GoogleAuthEvent import com.lighthouse.auth.google.repository.GoogleClient import com.lighthouse.auth.google.ui.GoogleAuthViewModel +import com.lighthouse.core.android.utils.permission.LocationPermissionManager import com.lighthouse.core.android.utils.resource.UIText import com.lighthouse.features.common.binding.viewBindings import com.lighthouse.features.common.dialog.progress.ProgressDialog @@ -78,6 +80,28 @@ class SettingFragment : Fragment(R.layout.fragment_setting) { } } + private val locationPermissionSettingLauncher = + registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result -> + val isGrant = locationPermissionManager.isGrant() + if (!isGrant) { + showSnackBar(R.string.error_permission_not_allowed) + } + viewModel.setLocationEnable(isGrant) + } + + private val locationPermissionLauncher = + registerForActivityResult(ActivityResultContracts.RequestMultiplePermissions()) { results -> + val isGrant = results.all { it.value } + if (!isGrant) { + showSnackBar(R.string.error_permission_not_allowed) + } + viewModel.setLocationEnable(isGrant) + } + + private val locationPermissionManager by lazy { + LocationPermissionManager(requireActivity()) + } + override fun onAttach(context: Context) { super.onAttach(context) @@ -93,9 +117,14 @@ class SettingFragment : Fragment(R.layout.fragment_setting) { override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) + setUpLocationPermission() + setUpSettingMenu() setUpGoogleAuthEvent() setUpSignInLoading() - setUpSettingMenu() + } + + private fun setUpLocationPermission() { + viewModel.setLocationEnable(locationPermissionManager.isGrant()) } private fun setUpSettingMenu() { @@ -141,7 +170,7 @@ class SettingFragment : Fragment(R.layout.fragment_setting) { SettingMenu.SECURITY -> appNavigationViewModel.navigate(AppNavigationItem.Security) - SettingMenu.LOCATION -> location() + SettingMenu.LOCATION -> gotoLocation() SettingMenu.SIGN_IN -> signIn() SettingMenu.SIGN_OUT -> signOut() SettingMenu.WITHDRAWAL -> withdrawal() @@ -161,7 +190,15 @@ class SettingFragment : Fragment(R.layout.fragment_setting) { } } - private fun location() { + private fun gotoLocation() { + if ( + locationPermissionManager.isGrant() || + locationPermissionManager.getManyTimesRejectedPermission() != null + ) { + locationPermissionSettingLauncher.launch(locationPermissionManager.settingIntent()) + } else { + locationPermissionLauncher.launch(locationPermissionManager.getPermissions()) + } } private fun signIn() { @@ -202,6 +239,10 @@ class SettingFragment : Fragment(R.layout.fragment_setting) { Snackbar.make(binding.root, string, Snackbar.LENGTH_SHORT).show() } + private fun showSnackBar(@StringRes resId: Int) { + Snackbar.make(binding.root, getString(resId), Snackbar.LENGTH_SHORT).show() + } + private fun showSnackBar(uiText: UIText) { showSnackBar(uiText.asString(requireContext()).toString()) } diff --git a/features/ui-setting/src/main/res/values/strings.xml b/features/ui-setting/src/main/res/values/strings.xml index cd213c6fa..757c813e9 100644 --- a/features/ui-setting/src/main/res/values/strings.xml +++ b/features/ui-setting/src/main/res/values/strings.xml @@ -12,6 +12,7 @@ 위치 정보 권한 허용됨 허용 안 함 + 권한을 허용하지 않았습니다. 사용자 로그아웃