Files
ShiftRing/TECHNICAL_DOCUMENTATION.md

9.1 KiB

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 생성 체계

// 기본 근무 알람: 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)

// Oreo: Background 제한 대응
alarmManager.setExactAndAllowWhileIdle(AlarmManager.RTC_WAKEUP, triggerTime, pendingIntent)

Android 9.0~13 (API 28-33)

// Pie ~ Tiramisu: setAlarmClock 권장
val clockInfo = AlarmManager.AlarmClockInfo(triggerTime, viewPendingIntent)
alarmManager.setAlarmClock(clockInfo, pendingIntent)

Android 14+ (API 34+)

// Upside Down Cake+: 권한 필수 + setAlarmClock
// 1. canScheduleExactAlarms() 권한 체크
// 2. setAlarmClock()으로 등록
// 3. USE_FULL_SCREEN_INTENT 권한 필요

2.3 Doze 모드 대응

// Doze 모드에서도 알람 실행 보장
setExactAndAllowWhileIdle()  // API 23+
setAlarmClock()              // API 21+ (권장)

3. 알람 수신 및 실행

3.1 AlarmReceiver 동작

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)

// Deprecated 플래그 사용
window.addFlags(
    FLAG_SHOW_WHEN_LOCKED or
    FLAG_DISMISS_KEYGUARD or
    FLAG_TURN_SCREEN_ON
)

Android 8.1+ (Oreo MR1)

// 새로운 API 사용
setShowWhenLocked(true)
setTurnScreenOn(true)
keyguardManager.requestDismissKeyguard(this, null)

Android 14+ (Upside Down Cake)

// 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팀 순환)

val cycle = listOf(
    "석간", "석간", "석간", "휴 무", "휴 무",
    "주간", "주간", "주간", "주간", "주간", "휴 무", "휴 무",
    "야간", "야간", "야간", "야간", "야간", "휴 무",
    "석간", "석간"
) // 20일 주기

val TEAM_OFFSETS = mapOf("A" to 0, "B" to 15, "C" to 10, "D" to 5)

5.2 논산 공장 (3팀 순환)

// 주간 → 야간 → 석간 (3주 주기)
// 월~금 근무, 토~일 휴 무

5.3 알람 시간 매핑

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

@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 동기화 단계

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 로그 확인 방법

# 필수 로그
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 형식

{
  "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