Coverage Summary for Class: RootActivity (kr.open.library.simple_ui.xml.ui.components.activity.root)
| Class |
Class, %
|
Method, %
|
Branch, %
|
Line, %
|
Instruction, %
|
| RootActivity |
100%
(1/1)
|
44.4%
(4/9)
|
12.5%
(2/16)
|
33.3%
(7/21)
|
29.7%
(41/138)
|
package kr.open.library.simple_ui.xml.ui.components.activity.root
import android.os.Bundle
import android.os.PersistableBundle
import androidx.annotation.CallSuper
import androidx.appcompat.app.AppCompatActivity
import kr.open.library.simple_ui.core.permissions.model.OrphanedDeniedRequestResult
import kr.open.library.simple_ui.core.permissions.model.PermissionDeniedItem
import kr.open.library.simple_ui.core.permissions.model.PermissionRationaleRequest
import kr.open.library.simple_ui.core.permissions.model.PermissionSettingsRequest
import kr.open.library.simple_ui.xml.permissions.api.PermissionRequester
import kr.open.library.simple_ui.xml.permissions.register.PermissionRequestInterface
/**
* Root Activity class providing comprehensive permission management and early initialization hooks.<br>
* Serves as the base for all Activity classes in the library with API version awareness.<br><br>
*
* 포괄적인 권한 관리 및 조기 초기화 훅을 제공하는 루트 Activity 클래스입니다.<br>
* API 버전을 인식하는 구현으로 라이브러리의 모든 Activity 클래스의 기반이 됩니다.<br>
*
* **Features / 기능:**<br>
* - Runtime permission management via PermissionRequester<br>
* - Lifecycle-aware permission state preservation<br>
* - Early initialization hook (beforeOnCreated) for theme/window setup before super.onCreate()<br>
* - Serves as the parent class for ParentsBindingActivity, which provides binding lifecycle for ViewBinding/DataBinding activities<br><br>
* - PermissionRequester를 통한 런타임 권한 관리<br>
* - 생명주기 인식 권한 상태 보존<br>
* - super.onCreate() 이전에 테마/윈도우 설정을 위한 조기 초기화 훅 (beforeOnCreated)<br>
* - ViewBinding/DataBinding Activity에 바인딩 생명주기를 제공하는 ParentsBindingActivity의 부모 클래스 역할<br>
*
* @see ParentsBindingActivity For the abstract parent class of all binding-enabled activities.<br><br>
* 모든 바인딩 지원 Activity의 추상 부모 클래스는 ParentsBindingActivity를 참조하세요.<br>
*
* @see BaseActivity For simple layout-based Activity.<br><br>
* 간단한 레이아웃 기반 Activity는 BaseActivity를 참조하세요.<br>
*
* @see BaseDataBindingActivity For DataBinding-enabled Activity.<br><br>
* DataBinding을 사용하는 Activity는 BaseDataBindingActivity를 참조하세요.<br>
*
* @see BaseViewBindingActivity For ViewBinding-enabled Activity.<br><br>
* ViewBinding을 사용하는 Activity는 BaseViewBindingActivity를 참조하세요.<br>
*/
abstract class RootActivity :
AppCompatActivity(),
PermissionRequestInterface {
/**
* Delegate for handling runtime permission requests.<br><br>
* 런타임 권한 요청을 처리하는 델리게이트입니다.<br>
*/
private lateinit var permissionRequester: PermissionRequester
/**
* Requests runtime permissions and returns denied results via callback.<br>
* Delegates to PermissionRequester for actual permission handling.<br><br>
* 런타임 권한을 요청하고 콜백을 통해 거부 결과를 반환합니다.<br>
* 실제 권한 처리는 PermissionRequester에 위임합니다.<br>
*
* **Important / 주의사항:**<br>
* - This method MUST be called AFTER super.onCreate() is called.<br>
* - Calling this before super.onCreate() will throw IllegalStateException with message:
* "PermissionRequester is not initialized. Please call super.onCreate() first."<br>
* - DO NOT call this method inside beforeOnCreated() hook.<br><br>
* - 이 메서드는 반드시 super.onCreate() 호출 이후에 호출해야 합니다.<br>
* - super.onCreate() 호출 전에 호출하면 IllegalStateException이 발생하며 다음 메시지가 표시됩니다:
* "PermissionRequester is not initialized. Please call super.onCreate() first."<br>
* - beforeOnCreated() 훅 내부에서는 절대 호출하지 마세요.<br>
*
* @param permissions Permissions to request.<br><br>
* 요청할 권한 목록입니다.<br>
* @param onDeniedResult Callback invoked with denied items.<br><br>
* 거부 항목을 전달받는 콜백입니다.<br>
* @param onRationaleNeeded Callback for rationale UI when needed.<br><br>
* Call `proceed()`, `cancel()`, or `defer(policy)` inside the callback. Returning without an action auto-cancels the flow.<br>
* 콜백 안에서 `proceed()`, `cancel()`, `defer(policy)` 중 하나를 호출해야 하며, 아무 액션 없이 반환되면 흐름은 자동 취소됩니다.<br>
* 필요 시 rationale UI를 제공하는 콜백입니다.<br>
* @param onNavigateToSettings Callback for settings navigation when needed.<br><br>
* Call `proceed()`, `cancel()`, or `defer(policy)` inside the callback. Returning without an action auto-cancels the flow.<br>
* 콜백 안에서 `proceed()`, `cancel()`, `defer(policy)` 중 하나를 호출해야 하며, 아무 액션 없이 반환되면 흐름은 자동 취소됩니다.<br>
* 필요 시 설정 이동을 안내하는 콜백입니다.<br>
*/
@CallSuper
final override fun requestPermissions(
permissions: List<String>,
onDeniedResult: (List<PermissionDeniedItem>) -> Unit,
onRationaleNeeded: ((PermissionRationaleRequest) -> Unit)?,
onNavigateToSettings: ((PermissionSettingsRequest) -> Unit)?
) {
check(::permissionRequester.isInitialized) {
"PermissionRequester is not initialized. Please call super.onCreate() first."
}
permissionRequester.requestPermissions(permissions, onDeniedResult, onRationaleNeeded, onNavigateToSettings)
}
/**
* Returns and clears denied results that lost their callbacks after process restore.<br>
* Call this in [onCreate] to handle results from requests that were interrupted by process kill.<br><br>
* 프로세스 복원 후 콜백을 잃은 거부 결과를 반환하고 비웁니다.<br>
* 프로세스 킬로 중단된 요청의 결과를 처리하려면 [onCreate]에서 호출하세요.<br>
*
* @return Return value: list of orphaned denied request results. Log behavior: none.<br><br>
* 반환값: orphaned 거부 요청 결과 목록. 로그 동작: 없음.<br>
*/
fun consumeOrphanedDeniedResults(): List<OrphanedDeniedRequestResult> {
check(::permissionRequester.isInitialized) {
"PermissionRequester is not initialized. Please call super.onCreate() first."
}
return permissionRequester.consumeOrphanedDeniedResults()
}
/**
* Requests runtime permissions and returns denied results via callback.<br>
* Delegates to PermissionRequester for actual permission handling.<br><br>
* 런타임 권한을 요청하고 콜백을 통해 거부 결과를 반환합니다.<br>
* 실제 권한 처리는 PermissionRequester에 위임합니다.<br>
*
* **Important / 주의사항:**<br>
* - This method MUST be called AFTER super.onCreate() is called.<br>
* - Calling this before super.onCreate() will throw IllegalStateException with message:
* "PermissionRequester is not initialized. Please call super.onCreate() first."<br>
* - DO NOT call this method inside beforeOnCreated() hook.<br><br>
* - 이 메서드는 반드시 super.onCreate() 호출 이후에 호출해야 합니다.<br>
* - super.onCreate() 호출 전에 호출하면 IllegalStateException이 발생하며 다음 메시지가 표시됩니다:
* "PermissionRequester is not initialized. Please call super.onCreate() first."<br>
* - beforeOnCreated() 훅 내부에서는 절대 호출하지 마세요.<br>
*
* @param permissions Permissions to request.<br><br>
* 요청할 권한 목록입니다.<br>
* @param onDeniedResult Callback invoked with denied items.<br><br>
* 거부 항목을 전달받는 콜백입니다.<br>
*/
@CallSuper
final override fun requestPermissions(permissions: List<String>, onDeniedResult: (List<PermissionDeniedItem>) -> Unit) {
check(::permissionRequester.isInitialized) { "PermissionRequester is not initialized. Please call super.onCreate() first." }
permissionRequester.requestPermissions(permissions, onDeniedResult, null, null)
}
/**
* Called when the activity is starting.
* Initializes PermissionRequester and restores permission state from savedInstanceState.<br><br>
* 액티비티가 시작될 때 호출됩니다.<br>
* PermissionRequester를 초기화하고 savedInstanceState에서 권한 상태를 복원합니다.<br>
*
* @param savedInstanceState If the activity is being re-initialized after previously being shut down,
* this Bundle contains the data it most recently supplied in onSaveInstanceState.<br><br>
* 액티비티가 이전에 종료된 후 다시 초기화되는 경우,
* 이 Bundle에는 onSaveInstanceState에서 가장 최근에 제공된 데이터가 포함됩니다.<br>
*/
@CallSuper
override fun onCreate(savedInstanceState: Bundle?) {
beforeOnCreated(savedInstanceState)
super.onCreate(savedInstanceState)
initPermission(savedInstanceState)
}
@CallSuper
override fun onCreate(savedInstanceState: Bundle?, persistentState: PersistableBundle?) {
beforeOnCreated(savedInstanceState)
super.onCreate(savedInstanceState, persistentState)
initPermission(savedInstanceState)
}
private fun initPermission(savedInstanceState: Bundle?) {
permissionRequester = PermissionRequester(this)
permissionRequester.restoreState(savedInstanceState)
}
/**
* Called to retrieve per-instance state from an activity before being killed.
* Saves the current permission state to the Bundle.<br><br>
* 액티비티가 종료되기 전에 인스턴스별 상태를 검색하기 위해 호출됩니다.<br>
* 현재 권한 상태를 Bundle에 저장합니다.<br>
*
* @param outState Bundle in which to place your saved state.<br><br>
* 저장된 상태를 배치할 Bundle.<br>
*/
@CallSuper
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
if (::permissionRequester.isInitialized) {
permissionRequester.saveState(outState)
}
}
/**
* Called BEFORE super.onCreate() for early initialization such as Theme or Window configuration.<br>
* ⚠️ WARNING: Most Activity resources (getString, getResources, FragmentManager, etc.)
* are NOT available at this point.<br><br>
* super.onCreate() 전에 호출되며, Theme이나 Window 설정 등 조기 초기화에 사용합니다.<br>
* ⚠️ 경고: 이 시점에서는 대부분의 Activity 리소스(getString, getResources, FragmentManager 등)를
* 사용할 수 없습니다.<br>
*
* Usage example / 사용 예시:<br>
* ```kotlin
* override fun beforeOnCreated(savedInstanceState: Bundle?) {
* setTheme(R.style.MyCustomTheme) // ✅ OK
* window.requestFeature(Window.FEATURE_NO_TITLE) // ✅ OK
* // getString(R.string.app_name) // ❌ Crash!
* }
* ```
*
* @param savedInstanceState The saved instance state bundle, if any.<br><br>
* 저장된 인스턴스 상태 번들 (있는 경우).<br><br>
*/
protected open fun beforeOnCreated(savedInstanceState: Bundle?) {}
}