← Docs hub

SKMLauncher·SKMLauncher2 — UI와 장치 상태 연결

기준: 1398d109c391c4044cae26d0e9aea4d3f08d9670. 지정 커밋의 추적 파일을 직접 확인한 정적 구조 분석이며, 현재 HEAD·후속 TaskManager·SKIX 구현을 포함하지 않는다.

상대 Java 경로는 각 앱의 app/src/main/java/com/sk/airbot/skmlauncher/ 기준이다.

SKMLauncher

구조와 진입

apps/SKMLauncher/app/src/main/AndroidManifest.xml:26-118에서 Application은 ui.SKMLauncherApp이고, SplashActivity가 HOME/DEFAULT/LAUNCHER 진입점이다(37-48). Init/Stay/Home/AirClear/Schedule/Monitoring/Settings/LineTest/Test/Manage/Error/Speaking/Interaction/Movement 화면을 모두 exported activity로 선언한다(49-107). Boot receiver는 SKMLauncherApp$BootCompletedReceiver로 RECEIVE_BOOT_COMPLETED 보호를 사용한다(109-117).

Application ui/SKMLauncherApp.java:88-141는 static activity stack, main uiHandler, HandlerThread("SKMLauncherApp") 기반 worker handler, ExecutableScheduleManager, MediaPlayer를 초기화한다. onCreate()에서 connectDeviceControl()을 호출하고 uncaught exception handler를 등록한다(118-141). 예외 handler는 Splash를 NEW_TASK/CLEAR_TASK로 띄운 뒤 프로세스를 kill한다(143-154).

DeviceControl/콜백 흐름

data/common/DeviceControlResolver.java:8-15는 DeviceControlProxy.connected()가 false면 null을 반환하고, true일 때 getService()를 반환한다. Application의 connectDeviceControl()은 DeviceControlProxy.connect(context, callback)을 호출한다(SKMLauncherApp.java:157-185). 연결 callback은 DA 연결 상태를 갱신하고 boot-complete 음원을 재생한 뒤 배터리를 요청한다(160-177). 연결 해제 callback은 상태를 false로 만들고 재연결을 호출한다(179-185).

onModuleCallback(Bundle)은 DeviceAgent가 전달한 method 문자열을 분기한다(SKMLauncherApp.java:187 이후). setErrorInfo는 오류 기록을 지연 조회하고 toast/오류 Activity 종료/오류 Activity 시작을 결정한다(192-207). setLlmStatus/setLlmStt는 lock mode를 확인해 SpeakingActivity와 SettingsViewModel 상태를 갱신한다(209-246). 배터리·settings·schedule callback은 worker에서 repository를 갱신하고 UI handler에서 LiveData/Activity를 변경한다(267-281). 공기청정·초기화·self-test·스케줄·이동 callback도 repository 결과와 화면 상태를 통해 activity를 전환한다(커밋 SKMLauncherApp.java:300-585). 이 소스는 callback 수신과 UI 반영을 증명하지만 DeviceAgent가 실제 명령을 수행했다는 뜻은 아니다.

Repository와 저장소

주요 data 계층은 AirCleanerRepository, AirQualityRepository, AMROperationRepository, AirBotSettingRepository, ManageRepository, ScheduleRepository, SelfTestRepository, ErrorRepository, EventRepository, LCDRepository다(data/repository/). Repository 메서드들은 공통적으로 DeviceControlResolver.resolve() 후 IDeviceControl.sendModuleCommand(Bundle, Bundle)를 호출하는 형태이며 Bundle의 method/class 키가 실제 계약이다. ManageRepository.java:39에는 /mnt/vendor/persist/keystore/iotSharedPreferences.json 경로가 있다. ScheduleRepository.java:34-35는 MutableLiveData<ScheduleUiState>를 외부 LiveData로 노출한다. 실행 스케줄 모델(data/model/executableSchedule/)은 Handler와 지연 runnable을 사용한다(ExecutableSchedule.java:35, InteractionSchedule.java:88 부근).

화면은 각 domain Activity/Fragment와 ViewModel로 나뉜다. AirClear는 AirClearActivity, 여러 작업/config/report fragment, AirClearViewModel; Home은 HomeActivity, HomeViewModel; Init/Manage/Monitoring/Movement/Schedule/Settings/Speaking/Stay/Error/LineTest도 같은 Activity→ViewModel→Repository 방향이다. AirClearViewModel.java:48-57는 UI state/event/action LiveData와 Handler를 만들고, onCleared()에서 callback 제거를 수행한다(453-455). Fragment에는 onDestroyView()에서 view callback 정리 코드가 있다. 따라서 UI callback은 lifecycle-aware LiveData와 일부 직접 Handler 정리가 혼재한다.

SKMLauncher 주요 리스크/미확인

SKMLauncher2

SKMLauncher2는 같은 Java package com.sk.airbot.skmlauncher를 사용하지만 소스 트리와 manifest가 더 확장된 별도 Gradle 앱이다. app/src/main/AndroidManifest.xml:37-142에서 동일한 SKMLauncherApp, Splash HOME 진입과 핵심 화면을 선언하며, 추가로 Password/Guide/Wss/WssStreaming/MovementPause 화면을 exported로 포함한다(112-131). InitActivity와 AirClearActivity는 locale/layoutDirection configChanges를 선언한다(61-65, 74-79). Manifest는 SET_TIME, camera, 위치/Wi-Fi, external storage, cleartext traffic 등을 추가로 요청한다(6-24, 37-48).

Application/IPC 경계는 ui/SKMLauncherApp.java와 data/common/DeviceControlResolver.java가 SKMLauncher와 같은 형태다. DeviceControlResolver.java:8-15는 연결 여부를 확인한 뒤 DeviceControlProxy.getService()를 반환한다. Repository 집합은 ToastRepository, WifiRepository, WssRepository까지 추가되어 있고(data/repository/), data model에는 MapInfoManager, UiSettingManager, WssSchedule, airquality 하위 모델, WifiItem 등이 있다. UI에는 password, guide, wss, streaming, tmp, moving/MovementPauseActivity가 추가되어 있다.

소스 검색상 주요 호출 체인은 ui/*Activity/*ViewModel → data/repository/*Repository → DeviceControlResolver → IDeviceControl이다. WSS/streaming 화면은 이 API library의 WSS transaction/data classes와 연결되는 구조이고, WifiRepository/WifiSwitchingManager는 Android Wi-Fi API와 callback을 조합한다. 일정 실행 모델은 AirClearSchedule, AirQualityMapSchedule, InteractionSchedule, WssSchedule 및 ExecutableScheduleManager가 담당한다.

thread/lifecycle 측면에서 Application worker HandlerThread, Activity/Fragment Handler, LiveData ViewModel, onDestroyView/onCleared 정리가 함께 존재한다. AirClearMovementPauseFragment는 main Looper Handler로 timeout을 예약하고 onResume/onDestroyView에서 runnable을 조정한다(ui/airclear/AirClearMovementPauseFragment.java:160-204). SKMLauncher2는 manifest의 추가 화면과 device-control/WSS 기능을 제공하지만, 실제 IPC callback 계약은 포함된 DeviceControlAPIJavaLib 및 DeviceAgent 쪽 구현을 함께 봐야 한다.

미확인: SKMLauncher와 동일 package의 두 APK가 제품에서 동시에 선택되는지, 실제 product가 어느 하나를 SKMLauncher로 설치하는지, WSS endpoint/권한/cleartext 정책, callback thread에서 UI 접근 안전성, APK 서명·설치 상태는 commit 소스만으로 결정할 수 없다.

확대 구조도와 연결별 근거

Connections

전체 목차 · 앱 구성 · DeviceAgent 내부 · IPC · 실행 흐름 · 플랫폼·빌드 · 근거·확인 범위

Keyboard shortcuts

⌘K / Ctrl+KOpen command palette
/Focus search
g hGo to home
g pGo to projects
g sGo to sessions
j / kNext / prev row (tables)
?Show this help
EscClose dialogs

Structured queries

Mix key:value filters with free text in the palette:

type:sessionOnly session pages
project:llm-wikiFilter by project name (substring)
model:claudeFilter by model name (substring)
date:>2026-03-01Sessions after a date
date:<2026-04-01Sessions before a date
tags:rustPages mentioning a tag/topic
sort:dateSort results by date (newest first)

Example: type:session project:llm-wiki date:>2026-04 sort:date