From f40b1fe631a9bb5c3ae00e36a9d0d21508169cbf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=9D=BC=ED=98=81?= Date: Sun, 6 Sep 2026 17:50:48 +0900 Subject: [PATCH] =?UTF-8?q?fix:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20=EC=A4=91?= =?UTF-8?q?=20=EC=9E=90=EB=8F=99=20=EC=95=8C=EB=A6=BC=20=EA=B6=8C=ED=95=9C?= =?UTF-8?q?=20=EC=9A=94=EC=B2=AD=EC=9D=84=20=EC=A0=9C=EA=B1=B0=ED=95=9C?= =?UTF-8?q?=EB=8B=A4?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Keep notification consent behind the existing Main explanation and settings button. Verify no automatic settings navigation and preserve denied/allowed state after returning. Source: https://developer.android.com/develop/ui/compose/notifications/notification-permission --- .../com/example/slowclock/MainActivity.kt | 20 +---------- .../slowclock/ui/main/MainViewModelTest.kt | 35 +++++++++++++++++++ 2 files changed, 36 insertions(+), 19 deletions(-) diff --git a/app/src/main/java/com/example/slowclock/MainActivity.kt b/app/src/main/java/com/example/slowclock/MainActivity.kt index 231a34c..c329fd6 100644 --- a/app/src/main/java/com/example/slowclock/MainActivity.kt +++ b/app/src/main/java/com/example/slowclock/MainActivity.kt @@ -3,10 +3,8 @@ package com.example.slowclock import android.app.NotificationChannel import android.app.NotificationManager -import android.content.pm.PackageManager import android.media.AudioAttributes import android.media.RingtoneManager -import android.os.Build import android.os.Bundle import android.util.Log import androidx.activity.ComponentActivity @@ -14,7 +12,6 @@ import androidx.activity.compose.setContent import androidx.activity.enableEdgeToEdge import androidx.compose.foundation.isSystemInDarkTheme import androidx.compose.runtime.getValue -import androidx.core.content.ContextCompat import androidx.core.content.edit import androidx.lifecycle.compose.collectAsStateWithLifecycle import androidx.lifecycle.lifecycleScope @@ -136,7 +133,7 @@ class MainActivity : ComponentActivity() { } catch (e: Exception) { Log.e("MAIN", "onCreate 실패", e) } - requestNotificationPermission() + // 알림은 메인의 설명을 읽고 설정 버튼을 누른 뒤 허용한다. 로그인 위로 권한창을 띄우지 않는다. // 정확한 알람 권한은 메인 화면이 이유를 설명한 뒤 사용자가 원할 때 요청한다(#83). createNotificationChannel() // ← 반드시 호출 필요 } @@ -166,21 +163,6 @@ class MainActivity : ComponentActivity() { notificationManager.createNotificationChannel(channel) } - // POST_NOTIFICATIONS 는 API 33 에 생겼다. minSdk 32 기기는 설치 시점에 알림 권한을 갖는다. - private fun requestNotificationPermission() { - if (Build.VERSION.SDK_INT < Build.VERSION_CODES.TIRAMISU) return - if (ContextCompat.checkSelfPermission( - this, - android.Manifest.permission.POST_NOTIFICATIONS, - ) != PackageManager.PERMISSION_GRANTED - ) { - requestPermissions( - arrayOf(android.Manifest.permission.POST_NOTIFICATIONS), - 1001, - ) - } - } - private fun saveFcmTokenToFirestore() { lifecycleScope.launch { if (userRepository.saveCurrentUserFcmToken()) { diff --git a/feature/main/src/test/java/com/example/slowclock/ui/main/MainViewModelTest.kt b/feature/main/src/test/java/com/example/slowclock/ui/main/MainViewModelTest.kt index dd0c214..278b1f5 100644 --- a/feature/main/src/test/java/com/example/slowclock/ui/main/MainViewModelTest.kt +++ b/feature/main/src/test/java/com/example/slowclock/ui/main/MainViewModelTest.kt @@ -87,6 +87,41 @@ class MainViewModelTest { every { alarmScheduler.canShowAlarmControls() } returns true viewModel.onIntent(MainIntent.ScreenResumed) assertTrue(viewModel.uiState.value.alarmControlsAvailable) + assertNull(viewModel.uiState.value.openNotificationSettings) + } + + @Test + fun `알림 차단 상태로 로그인하고 복귀해도 설정을 자동으로 열지 않는다`() = + runTest { + val uid = MutableStateFlow(null) + every { authRepository.currentUid } answers { uid.value } + every { authRepository.observeCurrentUid() } returns uid + every { alarmScheduler.canShowAlarmControls() } returns false + val viewModel = createViewModel() + assertNull(viewModel.uiState.value.openNotificationSettings) + + uid.value = "uid-1" + viewModel.onIntent(MainIntent.ScreenResumed) + + assertFalse(viewModel.uiState.value.alarmControlsAvailable) + assertNull(viewModel.uiState.value.openNotificationSettings) + } + + @Test + fun `알림을 허용하지 않고 설정에서 돌아오면 안내를 유지하고 다시 누를 수 있다`() = + runTest { + every { alarmScheduler.canShowAlarmControls() } returns false + val viewModel = createViewModel() + viewModel.onIntent(MainIntent.OpenNotificationSettings) + assertNotNull(viewModel.uiState.value.openNotificationSettings) + viewModel.onIntent(MainIntent.ConsumeNotificationSettingsRequest) + + viewModel.onIntent(MainIntent.ScreenResumed) + + assertFalse(viewModel.uiState.value.alarmControlsAvailable) + assertNull(viewModel.uiState.value.openNotificationSettings) + viewModel.onIntent(MainIntent.OpenNotificationSettings) + assertNotNull(viewModel.uiState.value.openNotificationSettings) } private fun createViewModel() = MainViewModel(scheduleRepository, userRepository, authRepository, settingsRepository, alarmScheduler)