Files
ShiftRing/TECHNICAL_DOCUMENTATION.md

381 lines
9.1 KiB
Markdown

# 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