# ShiftRing 알람 시스템 기술 문서 ## 버전 정보 - **Version**: 1.0.0 - **Build**: 100 - **지원 Android**: 8.0 (Oreo) ~ 16 --- ## 1. 알람 아키텍처 개요 ### 1.1 전체 흐름 ``` [알람 예약] → [AlarmManager] → [AlarmReceiver] → [AlarmActivity] ↑ ↓ ↓ ↓ [SharedPrefs] [Doze Mode] [WakeLock] [화면 켜짐] ``` ### 1.2 핵심 컴포넌트 1. **AlarmUtils.kt** - 알람 예약/취소 로직 2. **AlarmReceiver.kt** - 알람 수신 및 처리 3. **AlarmActivity.kt** - 알람 UI 및 해제 4. **AlarmForegroundService.kt** - 포그라운드 서비스 --- ## 2. 알람 예약 메커니즘 ### 2.1 ID 생성 체계 ```kotlin // 기본 근무 알람: 1YYMMDD0 // 예: 2026년 2월 13일 → 126021300 fun getShiftAlarmId(date: LocalDate): Int { return 100000000 + (date.year % 100) * 1000000 + date.monthValue * 10000 + date.dayOfMonth * 100 + 0 } // 사용자 알람: 2YYMMDDNN (NN = 인덱스) // 예: 2026년 2월 13일, 인덱스 1 → 226021301 fun getCustomAlarmId(date: LocalDate, index: Int): Int { return 200000000 + (date.year % 100) * 1000000 + date.monthValue * 10000 + date.dayOfMonth * 100 + index } ``` ### 2.2 Android 버전별 알람 설정 #### Android 8.0~8.1 (API 26-27) ```kotlin // Oreo: Background 제한 대응 alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent) ``` #### Android 9.0~13 (API 28-33) ```kotlin // Pie ~ Tiramisu: setAlarmClock 권장 val clockInfo = AlarmManager.AlarmClockInfo(triggerTime, viewPendingIntent) alarmManager.setAlarmClock(clockInfo, pendingIntent) ``` #### Android 14+ (API 34+) ```kotlin // Upside Down Cake+: 권한 필수 + setAlarmClock // 1. canScheduleExactAlarms() 권한 체크 // 2. setAlarmClock()으로 등록 // 3. USE_FULL_SCREEN_INTENT 권한 필요 ``` ### 2.3 Doze 모드 대응 ```kotlin // Doze 모드에서도 알람 실행 보장 setExactAndAllowWhileIdle() // API 23+ setAlarmClock() // API 21+ (권장) ``` --- ## 3. 알람 수신 및 실행 ### 3.1 AlarmReceiver 동작 ```kotlin override fun onReceive(context: Context, intent: Intent?) { // 1. WakeLock 획득 (10분) val wakeLock = pm.newWakeLock( FULL_WAKE_LOCK or ACQUIRE_CAUSES_WAKEUP or ON_AFTER_RELEASE, "ShiftRing::DeepWakeLock" ) wakeLock.acquire(10 * 60 * 1000L) // 2. Foreground Service 시작 (Oreo+ 필수) context.startForegroundService(serviceIntent) // 3. Notification 발행 (전체화면 인텐트 포함) notificationManager.notify(1001, notification) // 4. AlarmActivity 시작 context.startActivity(fullScreenIntent) } ``` ### 3.2 화면 켜짐 로직 (버전별) #### Android 8.0 (Oreo) ```kotlin // Deprecated 플래그 사용 window.addFlags( FLAG_SHOW_WHEN_LOCKED or FLAG_DISMISS_KEYGUARD or FLAG_TURN_SCREEN_ON ) ``` #### Android 8.1+ (Oreo MR1) ```kotlin // 새로운 API 사용 setShowWhenLocked(true) setTurnScreenOn(true) keyguardManager.requestDismissKeyguard(this, null) ``` #### Android 14+ (Upside Down Cake) ```kotlin // Keyguard dismiss 없이 위에 표시 setShowWhenLocked(true) setTurnScreenOn(true) window.addFlags( FLAG_LAYOUT_IN_SCREEN or FLAG_LAYOUT_INSET_DECOR ) // Keyguard 해제 없이 바로 알람 화면! ``` --- ## 4. 권한 체계 ### 4.1 필수 권한 #### Android 8.0~11 - `WAKE_LOCK` - 화면 켜짐 - `FOREGROUND_SERVICE` - 포그라운드 서비스 - `RECEIVE_BOOT_COMPLETED` - 부팅 시 알람 복구 #### Android 12+ (API 31+) 추가 권한: - `SCHEDULE_EXACT_ALARM` - 정확한 알람 예약 - 설정에서 "알람 및 리마인더" 허용 필요 #### Android 14+ (API 34+) 추가 권한: - `USE_FULL_SCREEN_INTENT` - 전체화면 알림 - 설정에서 "전체화면 알림" 허용 필요 - Foreground Service 타입: `specialUse` ### 4.2 권한 설정 플로우 ``` [앱 실행] → [Android 12+] "알람 및 리마인더" 권한 확인 → 없으면 설정 화면으로 이동 → 사용자 수동 허용 → canScheduleExactAlarms() = true [Android 14+] → "전체화면 알림" 권한 확인 → 설정 → 권한 → 전체화면 알림 → 허용 [모든 버전] → 배터리 최적화 "제한 없음" 설정 → 설정 → 배터리 → 배터리 사용량 → ShiftRing → 제한 없음 ``` --- ## 5. 근무 계산 로직 ### 5.1 전주 공장 (4팀 순환) ```kotlin val cycle = listOf( "석간", "석간", "석간", "휴 무", "휴 무", "주간", "주간", "주간", "주간", "주간", "휴 무", "휴 무", "야간", "야간", "야간", "야간", "야간", "휴 무", "석간", "석간" ) // 20일 주기 val TEAM_OFFSETS = mapOf("A" to 0, "B" to 15, "C" to 10, "D" to 5) ``` ### 5.2 논산 공장 (3팀 순환) ```kotlin // 주간 → 야간 → 석간 (3주 주기) // 월~금 근무, 토~일 휴 무 ``` ### 5.3 알람 시간 매핑 ```kotlin val shiftAlarmTimes = mapOf( "주간" to "06:00", "석간" to "14:00", "야간" to "22:00", "야간 맞교대" to "18:00" ) ``` --- ## 6. 데이터 저장 구조 ### 6.1 SharedPreferences ``` ShiftAlarmPrefs: - selected_team: String (A/B/C/D) - selected_factory: String (Jeonju/Nonsan) - time_ju: String (주간 알람 시간) - time_seok: String (석간 알람 시간) - time_ya: String (야간 알람 시간) - custom_alarms: String (JSON 배열) - snooze_min: Int (스누즈 시간) ``` ### 6.2 Room Database ```kotlin @Entity(tableName = "shift_overrides") data class ShiftOverride( val factory: String, val team: String, val date: String, // YYYY-MM-DD val shift: String, val manualAlarmTime: String? // HH:MM ) ``` --- ## 7. 알람 동기화 프로세스 ### 7.1 동기화 트리거 1. 앱 실행 시 (onResume) 2. 설정 변경 시 (근무/시간/팀) 3. 부팅 완료 시 (BootReceiver) 4. 날짜 변경 시 (매일 자정) ### 7.2 동기화 단계 ```kotlin suspend fun syncAllAlarms(context: Context) { // 1. 기존 알람 모두 취소 (7일치) for (date in today..today+7) { cancelShiftAlarm(date) cancelCustomAlarms(date) } // 2. 사용자 알람 JSON 파싱 val customAlarms = parseCustomAlarms() // 3. 알람 재등록 (7일치) for (date in today..today+7) { val shift = calculateShift(date) // 기본 알람 등록 if (isWorkShift(shift)) { scheduleShiftAlarm(date, shift, alarmTime) } // 사용자 알람 등록 for (alarm in customAlarms) { if (shouldTrigger(alarm, shift)) { scheduleCustomAlarm(date, alarm) } } } } ``` --- ## 8. 문제 해결 가이드 ### 8.1 알람이 안 울림 #### 원인 1: 권한 없음 (Android 12+) **증상**: Log에 `canScheduleExactAlarms() = false` **해결**: ``` 설정 → 앱 → ShiftRing → 권한 → "알람 및 리마인더" → 허용 ``` #### 원인 2: 배터리 최적화 **증상**: Doze 모드에서 알람 지연/실패 **해결**: ``` 설정 → 배터리 → 배터리 사용량 → ShiftRing → "제한 없음" ``` #### 원인 3: 잠금 화면 표시 안됨 (Android 14+) **증상**: 알람은 울리지만 화면 안 켜짐 **해결**: ``` 설정 → 앱 → ShiftRing → 권한 → "전체화면 알림" → 허용 ``` ### 8.2 로그 확인 방법 ```bash # 필수 로그 adb logcat -s AlarmReceiver:D ShiftAlarm:D *:S # 전체 로그 adb logcat | grep -E "ShiftRing|Alarm" ``` ### 8.3 정상 동작 확인 로그 ``` AlarmReceiver: ===== 알람 수신 ===== AlarmReceiver: 근무: 주간 | ID: 126021300 AlarmReceiver: WakeLock 획득 완료 AlarmReceiver: Foreground Service 시작 AlarmReceiver: Notification 발행 완료 AlarmActivity: 화면 켜짐 성공 ``` --- ## 9. 업데이트 시스템 ### 9.1 버전 확인 URL ``` https://git.webpluss.net/sanjeok77/ShiftRing/version.json ``` ### 9.2 version.json 형식 ```json { "versionCode": 100, "versionName": "1.0.0", "apkUrl": "https://git.webpluss.net/sanjeok77/ShiftRing/releases/download/v1.0.0/app.apk", "changelog": "버그 수정 및 성능 개선" } ``` ### 9.3 자동 업데이트 플로우 ``` [앱 실행] → [서버 버전 확인] → [최신 버전 비교] → [업데이트 다이얼로그 표시] → [APK 다운로드] → [설치 진행] ``` --- ## 10. 릴리즈 히스토리 ### v1.0.0 (Build 100) - 최초 릴리즈 - Android 8.0 ~ 16 지원 - Android 14+ 잠금 화면 위 알람 표시 개선 - Oreo 호환성 강화 --- ## 부록: 개발자 참고사항 ### A. PendingIntent Flags - `FLAG_UPDATE_CURRENT` - 기존 인텐트 업데이트 - `FLAG_IMMUTABLE` - Android 12+ 필수 (보안) - `FLAG_NO_CREATE` - 기존 확인용 ### B. WakeLock 종류 - `FULL_WAKE_LOCK` - 화면 + 키보드 백라이트 켜짐 - `ACQUIRE_CAUSES_WAKEUP` - 획득 시 즉시 화면 켜짐 - `ON_AFTER_RELEASE` - 해제 후에도 일정 시간 유지 ### C. Foreground Service Types (Android 14+) - `specialUse` - 특수 목적 (알람 앱) - `dataSync` - 데이터 동기화 - `location` - 위치 추적 --- **문서 버전**: 1.0.0 **최종 수정**: 2026-02-13