v1.0.0 - ShiftRing 정식 첫 릴리즈\
This commit is contained in:
@@ -0,0 +1,253 @@
|
||||
package com.example.shiftalarm
|
||||
|
||||
import android.Manifest
|
||||
import android.app.Activity
|
||||
import android.app.AlarmManager
|
||||
import android.app.AlertDialog
|
||||
import android.app.NotificationManager
|
||||
import android.content.Context
|
||||
import android.content.Intent
|
||||
import android.content.pm.PackageManager
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.PowerManager
|
||||
import android.provider.Settings
|
||||
import android.widget.Toast
|
||||
import androidx.activity.ComponentActivity
|
||||
import androidx.activity.result.contract.ActivityResultContracts
|
||||
import androidx.core.app.ActivityCompat
|
||||
import androidx.core.content.ContextCompat
|
||||
|
||||
object AlarmPermissionUtil {
|
||||
|
||||
/**
|
||||
* 전체 권한 상태를 확인하고 필요한 경우 통합 안내 다이얼로그를 표시합니다.
|
||||
*/
|
||||
fun checkAndRequestAllPermissions(activity: ComponentActivity) {
|
||||
val missingPermissions = mutableListOf<String>()
|
||||
|
||||
// 1. 알림 권한 (Android 13+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
missingPermissions.add("알림 표시 (알람 울림 확인)")
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 정확한 알람 권한 (Android 12+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val am = activity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
if (!am.canScheduleExactAlarms()) {
|
||||
missingPermissions.add("정확한 알람 (정시에 울림 보장)")
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 배터리 최적화 제외 (Android 6+)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val pm = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
if (!pm.isIgnoringBatteryOptimizations(activity.packageName)) {
|
||||
missingPermissions.add("배터리 최적화 제외 (절전 모드 무시)")
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 전체화면 알림 권한 (Android 14+)
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val nm = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
if (!nm.canUseFullScreenIntent()) {
|
||||
missingPermissions.add("전체화면 알림 (잠금 화면에서 즉시 표시)")
|
||||
}
|
||||
}
|
||||
|
||||
if (missingPermissions.isNotEmpty()) {
|
||||
showIntegratedPermissionDialog(activity, missingPermissions)
|
||||
}
|
||||
}
|
||||
|
||||
private fun showIntegratedPermissionDialog(activity: ComponentActivity, missing: List<String>) {
|
||||
if (activity.isFinishing || activity.isDestroyed) return
|
||||
|
||||
val message = StringBuilder("안정적인 알람 작동을 위해 아래 권한들이 필요합니다:\n\n")
|
||||
missing.forEach { message.append("- $it\n") }
|
||||
message.append("\n[확인]을 누르면 설정 화면으로 순차적으로 안내합니다.")
|
||||
|
||||
try {
|
||||
AlertDialog.Builder(activity)
|
||||
.setTitle("권한 설정 안내")
|
||||
.setMessage(message.toString())
|
||||
.setPositiveButton("확인") { _, _ ->
|
||||
startPermissionFlow(activity)
|
||||
}
|
||||
.setNegativeButton("나중에", null)
|
||||
.setCancelable(false)
|
||||
.show()
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
|
||||
private fun startPermissionFlow(activity: ComponentActivity) {
|
||||
// 순차적으로 가장 중요한 것부터 요청
|
||||
|
||||
// 1. 알림 권한 (시스템 팝업)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
|
||||
ActivityCompat.requestPermissions(activity, arrayOf(Manifest.permission.POST_NOTIFICATIONS), 101)
|
||||
return // 알림 권한 결과 콜백 이후 다음으로 넘어가도록 유도 (혹은 그냥 연달아 띄움)
|
||||
}
|
||||
}
|
||||
|
||||
// 2. 배터리 최적화 (시스템 팝업)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val pm = activity.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
if (!pm.isIgnoringBatteryOptimizations(activity.packageName)) {
|
||||
requestBatteryOptimization(activity)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 3. 정확한 알람 (설정 화면)
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val am = activity.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
if (!am.canScheduleExactAlarms()) {
|
||||
val intent = Intent(Settings.ACTION_REQUEST_SCHEDULE_EXACT_ALARM).apply {
|
||||
data = Uri.parse("package:${activity.packageName}")
|
||||
}
|
||||
activity.startActivity(intent)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 4. 전체화면 알림 (설정 화면)
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val nm = activity.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
if (!nm.canUseFullScreenIntent()) {
|
||||
try {
|
||||
val intent = Intent("android.settings.MANAGE_APP_USE_FULL_SCREEN_INTENT").apply {
|
||||
data = Uri.parse("package:${activity.packageName}")
|
||||
}
|
||||
activity.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.parse("package:${activity.packageName}")
|
||||
}
|
||||
activity.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun requestBatteryOptimization(context: Context) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS).apply {
|
||||
data = Uri.parse("package:${context.packageName}")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS).apply {
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e2: Exception) {
|
||||
try {
|
||||
// Samsung Galaxy Device Care Battery Activity
|
||||
val intent = Intent().apply {
|
||||
setClassName("com.samsung.android.lool", "com.samsung.android.sm.ui.battery.BatteryActivity")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e3: Exception) {
|
||||
try {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.parse("package:${context.packageName}")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e4: Exception) {
|
||||
Toast.makeText(context, "배터리 설정 화면을 열 수 없습니다.", Toast.LENGTH_SHORT).show()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun requestOverlayPermission(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val intent = Intent(Settings.ACTION_MANAGE_OVERLAY_PERMISSION).apply {
|
||||
data = Uri.parse("package:${context.packageName}")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
|
||||
fun requestFullScreenIntentPermission(context: Context) {
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
try {
|
||||
val intent = Intent("android.settings.MANAGE_APP_USE_FULL_SCREEN_INTENT").apply {
|
||||
data = Uri.parse("package:${context.packageName}")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
} catch (e: Exception) {
|
||||
val intent = Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
||||
data = Uri.parse("package:${context.packageName}")
|
||||
addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
|
||||
}
|
||||
context.startActivity(intent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun isAllPermissionsGranted(context: Context): Boolean {
|
||||
var allGranted = true
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
|
||||
allGranted = allGranted && ContextCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
allGranted = allGranted && am.canScheduleExactAlarms()
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
allGranted = allGranted && pm.isIgnoringBatteryOptimizations(context.packageName)
|
||||
allGranted = allGranted && Settings.canDrawOverlays(context)
|
||||
}
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
allGranted = allGranted && nm.canUseFullScreenIntent()
|
||||
}
|
||||
return allGranted
|
||||
}
|
||||
|
||||
fun getBatteryOptimizationStatus(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
val pm = context.getSystemService(Context.POWER_SERVICE) as PowerManager
|
||||
return pm.isIgnoringBatteryOptimizations(context.packageName)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun getExactAlarmStatus(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) {
|
||||
val am = context.getSystemService(Context.ALARM_SERVICE) as AlarmManager
|
||||
return am.canScheduleExactAlarms()
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun getOverlayStatus(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
return Settings.canDrawOverlays(context)
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
fun getFullScreenIntentStatus(context: Context): Boolean {
|
||||
if (Build.VERSION.SDK_INT >= 34) {
|
||||
val nm = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager
|
||||
return nm.canUseFullScreenIntent()
|
||||
}
|
||||
return true
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user