Skip to content

Commit

Permalink
Merge pull request #97 from POLZZAK/feat/request_permission_on_start_app
Browse files Browse the repository at this point in the history
[FEAT] 앱 시작 시 권한요청, 회원가입 중 미디어 접근시 권한 허용 유도
  • Loading branch information
kim0hoon authored Sep 6, 2023
2 parents 41f6631 + ca1a6da commit 6646003
Show file tree
Hide file tree
Showing 7 changed files with 121 additions and 25 deletions.
4 changes: 4 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,11 @@
<uses-permission
android:name="android.permission.READ_EXTERNAL_STORAGE"
android:maxSdkVersion="32" />
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="28" />
<uses-permission android:name="android.permission.READ_MEDIA_IMAGES" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />

<!-- fixme http 사용안 할 경우 usesCleartextTraffic 제거 -->
<application
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,4 +24,6 @@ fun Fragment.hideKeyboard() {
)
}
}
}
}

fun Fragment.getPermissionManagerOrNull() = (activity as? MainActivity)?.permissionManager
Original file line number Diff line number Diff line change
@@ -0,0 +1,97 @@
package com.polzzak_android.presentation.common.util

import android.Manifest
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build
import android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS
import androidx.appcompat.app.AppCompatActivity
import androidx.core.app.ActivityCompat
import androidx.core.content.ContextCompat
import com.polzzak_android.R
import com.polzzak_android.presentation.common.model.ButtonCount
import com.polzzak_android.presentation.common.model.CommonButtonModel
import com.polzzak_android.presentation.component.dialog.CommonDialogContent
import com.polzzak_android.presentation.component.dialog.CommonDialogHelper
import com.polzzak_android.presentation.component.dialog.CommonDialogModel
import com.polzzak_android.presentation.component.dialog.DialogStyleType
import com.polzzak_android.presentation.component.dialog.OnButtonClickListener

class PermissionManager(private val activity: AppCompatActivity) {
private val permissions =
listOfNotNull(READ_MEDIA_PERMISSION, WRITE_MEDIA_PERMISSION, NOTIFICATION_PERMISSION)

/**
* 필요한 모든 권한에 대해 확인
* 1회 거절할 경우 다시 묻지 않음
* App 시작시만 실행
*/
fun requestAllPermissions() {
val needPermissions = permissions.filter { isFirstRequest(it) }.ifEmpty { return }
ActivityCompat.requestPermissions(
activity, needPermissions.toTypedArray(),
MULTIPLE_PERMISSION_REQUEST_CODE
)
}

private fun isFirstRequest(permission: String) =
(ContextCompat.checkSelfPermission(
activity,
permission
) != PackageManager.PERMISSION_GRANTED) && !(ActivityCompat.shouldShowRequestPermissionRationale(
activity,
permission
))

/**
* 권한들이 허용되었는지 확인 후 허용되지 않았을 경우(false) 앱의 setting 화면으로 이동하여 권한 허용 유도
* @param permissions 허용되었는지 확인할 권한들
* @return true if all permission is granted else false
*/
fun checkPermissionAndMoveSettingIfDenied(
vararg permissions: String,
dialogTitle: String
): Boolean {
if (!permissions.any { permission ->
ActivityCompat.checkSelfPermission(
activity,
permission
) != PackageManager.PERMISSION_GRANTED
}) return true

CommonDialogHelper.getInstance(
content = CommonDialogModel(
type = DialogStyleType.ALERT,
content = CommonDialogContent(title = dialogTitle),
button = CommonButtonModel(
buttonCount = ButtonCount.TWO,
negativeButtonText = activity.getString(R.string.permission_manager_dialog_btn_negative_text),
positiveButtonText = activity.getString(R.string.permission_manager_dialog_btn_positive_text)
)
),
onConfirmListener = {
object : OnButtonClickListener {
override fun setBusinessLogic() {
val settingIntent =
Intent(ACTION_APPLICATION_DETAILS_SETTINGS).setData(Uri.parse("package:${activity.packageName}"))
activity.startActivity(settingIntent)
}

override fun getReturnValue(value: Any) {
//do nothing
}
}
}).show(activity.supportFragmentManager, null)
return false
}

companion object {
val READ_MEDIA_PERMISSION =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) Manifest.permission.READ_MEDIA_IMAGES else Manifest.permission.READ_EXTERNAL_STORAGE
const val WRITE_MEDIA_PERMISSION = Manifest.permission.WRITE_EXTERNAL_STORAGE
val NOTIFICATION_PERMISSION =
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) Manifest.permission.POST_NOTIFICATIONS else null
const val MULTIPLE_PERMISSION_REQUEST_CODE = 91
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,12 @@ package com.polzzak_android.presentation.feature.auth.signup
import android.app.Activity.RESULT_OK
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.net.Uri
import android.os.Build.VERSION
import android.os.Build.VERSION_CODES
import android.provider.MediaStore
import android.widget.Toast
import androidx.activity.result.ActivityResultCaller
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import androidx.lifecycle.DefaultLifecycleObserver
import androidx.lifecycle.LifecycleOwner
Expand All @@ -25,8 +20,6 @@ class PhotoPicker : DefaultLifecycleObserver {
private var photoPickerResultCallback: ((uri: Uri) -> Unit)? = null
private var requestPermissionLauncher: ActivityResultLauncher<String>? = null
private var photoPickerLauncher: ActivityResultLauncher<Intent>? = null
private val mediaReadPermission =
if (VERSION.SDK_INT >= VERSION_CODES.TIRAMISU) android.Manifest.permission.READ_MEDIA_IMAGES else android.Manifest.permission.READ_EXTERNAL_STORAGE

constructor(activity: AppCompatActivity) {
activityResultCaller = activity
Expand All @@ -45,13 +38,6 @@ class PhotoPicker : DefaultLifecycleObserver {
}

private fun initLauncher() {
requestPermissionLauncher =
activityResultCaller?.registerForActivityResult(ActivityResultContracts.RequestPermission()) { isGranted ->
if (isGranted) launchPhotoPicker()
else {
context?.let { Toast.makeText(it, "미디어 접근 권한 취소", Toast.LENGTH_LONG).show() }
}
}
photoPickerLauncher = activityResultCaller?.registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
Expand All @@ -71,14 +57,7 @@ class PhotoPicker : DefaultLifecycleObserver {

operator fun invoke(callback: (Uri) -> Unit) {
photoPickerResultCallback = callback
val isGranted = context?.let {
ContextCompat.checkSelfPermission(
it,
mediaReadPermission
) == PackageManager.PERMISSION_GRANTED
} ?: false
if (isGranted) launchPhotoPicker()
else requestPermissionLauncher?.launch(mediaReadPermission)
launchPhotoPicker()
}

override fun onDestroy(owner: LifecycleOwner) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,8 @@ import com.polzzak_android.presentation.feature.auth.signup.model.SignUpTermsOfS
import com.polzzak_android.presentation.feature.root.MainViewModel
import com.polzzak_android.presentation.common.base.BaseFragment
import com.polzzak_android.presentation.common.model.ModelState
import com.polzzak_android.presentation.common.util.PermissionManager
import com.polzzak_android.presentation.common.util.getPermissionManagerOrNull
import com.polzzak_android.presentation.common.util.hideKeyboard
import dagger.hilt.android.AndroidEntryPoint
import timber.log.Timber
Expand Down Expand Up @@ -212,6 +214,11 @@ class SignUpFragment : BaseFragment<FragmentSignupBinding>() {
private fun initSelectProfileImageView(binding: FragmentSignupBinding) {
with(binding.inSelectProfileImage) {
clBtnSelectPicture.setOnClickListener {
if (getPermissionManagerOrNull()?.checkPermissionAndMoveSettingIfDenied(
PermissionManager.READ_MEDIA_PERMISSION,
dialogTitle = getString(R.string.permission_manager_dialog_storage_title)
) != true
) return@setOnClickListener
photoPicker?.invoke { uri ->
val path = getAbsPath(uri = uri)
signUpViewModel.setProfileImagePath(path = path)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import com.polzzak_android.presentation.feature.auth.login.sociallogin.GoogleLog
import com.polzzak_android.presentation.feature.auth.login.sociallogin.KakaoLoginHelper
import com.polzzak_android.presentation.feature.auth.login.sociallogin.SocialLoginManager
import com.polzzak_android.presentation.common.base.BaseActivity
import com.polzzak_android.presentation.common.util.PermissionManager
import com.polzzak_android.presentation.component.BackButtonPressedSnackBar
import dagger.hilt.android.AndroidEntryPoint
import io.reactivex.rxjava3.android.schedulers.AndroidSchedulers
Expand All @@ -36,11 +37,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>(), SocialLoginManager {

private var backPressedSnackBar: BackButtonPressedSnackBar? = null

val permissionManager = PermissionManager(this)

override fun onCreate(savedInstanceState: Bundle?) {
installSplashScreen()
super.onCreate(savedInstanceState)
permissionManager.requestAllPermissions()
initLoginHelper()

// set navigation
val navHostFragment =
supportFragmentManager.findFragmentById(binding.fcvContainer.id) as NavHostFragment
Expand Down
6 changes: 5 additions & 1 deletion app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -162,5 +162,9 @@
<string name="notification_setting_check_delivery_gift_title">선물 전달 확인 알림</string>
<string name="notification_setting_check_delivery_gift_content">선물 전달이 완료되었는지 확인하는 알림을 받을래요</string>


<!-- permission -->
<string name="permission_manager_dialog_btn_positive_text">설정하기</string>
<string name="permission_manager_dialog_btn_negative_text">취소</string>
<string name="permission_manager_dialog_storage_title">앱 설정에서 ‘저장소’ 권한을 허용해 주세요</string>
<string name="permission_manager_dialog_notification_title">앱 설정에서 알림 권한을 허용해주세요</string>
</resources>

0 comments on commit 6646003

Please sign in to comment.