@@ -51,7 +51,6 @@ class SplashActivity : AppCompatActivity() {
5151 binding = ActivitySplashBinding .inflate(layoutInflater)
5252 setContentView(binding.root)
5353
54- // Edge-to-edge hỗ trợ từ Android 6.0+ qua thư viện Compat
5554 WindowCompat .setDecorFitsSystemWindows(window, false )
5655
5756 if (ScriptEnvironmen .isInited() && isTaskRoot &&
@@ -64,40 +63,57 @@ class SplashActivity : AppCompatActivity() {
6463 showAgreementDialog()
6564 }
6665
67- // Animation xoay logo
6866 val rotateAnim = AnimationUtils .loadAnimation(this , R .anim.ic_settings_rotate)
6967 binding.startLogoXml.startAnimation(rotateAnim)
7068
7169 applyTheme()
7270 }
7371
74- // =================== QUẢN LÝ QUYỀN HẠN (SDK 23+) ===================
72+ // =================== PERMISSIONS & STORAGE ===================
7573
74+ private fun getRequiredPermissions (): Array <String > {
75+ return when {
76+ Build .VERSION .SDK_INT >= Build .VERSION_CODES .TIRAMISU -> {
77+ arrayOf(Manifest .permission.READ_MEDIA_IMAGES , Manifest .permission.READ_MEDIA_VIDEO )
78+ }
79+ else -> arrayOf(Manifest .permission.READ_EXTERNAL_STORAGE )
80+ }
81+ }
82+
7683 private fun hasPermissions (): Boolean {
77- // Ưu tiên kiểm tra quyền mạnh nhất trên Android 11+
78- if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . R ) {
79- if ( Environment .isExternalStorageManager()) return true
84+ // 1. Kiểm tra các quyền Runtime cơ bản
85+ val basicPermissions = getRequiredPermissions().all {
86+ ContextCompat .checkSelfPermission( this , it) == PackageManager . PERMISSION_GRANTED
8087 }
81-
82- // Kiểm tra quyền Storage truyền thống
83- val read = ContextCompat .checkSelfPermission(this , Manifest .permission.READ_EXTERNAL_STORAGE ) == PackageManager .PERMISSION_GRANTED
84- val write = ContextCompat .checkSelfPermission(this , Manifest .permission.WRITE_EXTERNAL_STORAGE ) == PackageManager .PERMISSION_GRANTED
85- return read && write
88+
89+ // 2. Kiểm tra quyền MANAGE_EXTERNAL_STORAGE (Android 11+)
90+ val manageStoragePermission = if (Build .VERSION .SDK_INT >= Build .VERSION_CODES .R ) {
91+ Environment .isExternalStorageManager()
92+ } else {
93+ true // Các bản cũ không có quyền này
94+ }
95+
96+ return basicPermissions && manageStoragePermission
8697 }
8798
8899 private fun requestAppPermissions () {
89100 saveAgreement()
101+
102+ // Bước 1: Xin các quyền Runtime cơ bản trước
103+ val missingBasic = getRequiredPermissions().filter {
104+ ContextCompat .checkSelfPermission(this , it) != PackageManager .PERMISSION_GRANTED
105+ }
90106
91- if (Build . VERSION . SDK_INT >= Build . VERSION_CODES . R ) {
92- // Android 11+: Thử xin quyền All Files Access trước
93- if ( ! Environment .isExternalStorageManager()) {
94- requestManageStoragePermission()
95- } else {
96- startLogic ()
97- }
98- } else {
99- // Android 6.0 - 10: Xin quyền READ/WRITE
100- checkFallbackPermissions ()
107+ if (missingBasic.isNotEmpty() ) {
108+ ActivityCompat .requestPermissions( this , missingBasic.toTypedArray(), REQUEST_CODE_PERMISSIONS )
109+ }
110+ // Bước 2: Nếu quyền cơ bản có rồi nhưng thiếu MANAGE_EXTERNAL_STORAGE trên A11+
111+ else if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . R && ! Environment .isExternalStorageManager()) {
112+ requestManageStoragePermission ()
113+ }
114+ // Bước 3: Đã đủ hết quyền
115+ else {
116+ startLogic ()
101117 }
102118 }
103119
@@ -113,19 +129,19 @@ class SplashActivity : AppCompatActivity() {
113129 }
114130 }
115131
116- private fun checkFallbackPermissions ( ) {
117- val permissions = arrayOf(
118- Manifest .permission. READ_EXTERNAL_STORAGE ,
119- Manifest .permission. WRITE_EXTERNAL_STORAGE
120- )
121- val missing = permissions.filter {
122- ContextCompat .checkSelfPermission( this , it) != PackageManager . PERMISSION_GRANTED
123- }
124-
125- if (missing.isNotEmpty()) {
126- ActivityCompat .requestPermissions( this , missing.toTypedArray(), REQUEST_CODE_PERMISSIONS )
127- } else {
128- startLogic()
132+ override fun onRequestPermissionsResult ( requestCode : Int , permissions : Array < out String >, grantResults : IntArray ) {
133+ super .onRequestPermissionsResult(requestCode, permissions, grantResults)
134+ if (requestCode == REQUEST_CODE_PERMISSIONS ) {
135+ if (grantResults.isNotEmpty() && grantResults.all { it == PackageManager . PERMISSION_GRANTED }) {
136+ // Sau khi có quyền cơ bản, kiểm tra tiếp MANAGE_STORAGE nếu cần
137+ if ( Build . VERSION . SDK_INT >= Build . VERSION_CODES . R && ! Environment .isExternalStorageManager()) {
138+ requestManageStoragePermission()
139+ } else {
140+ startLogic()
141+ }
142+ } else {
143+ finish()
144+ }
129145 }
130146 }
131147
@@ -136,25 +152,12 @@ class SplashActivity : AppCompatActivity() {
136152 if (Environment .isExternalStorageManager()) {
137153 startLogic()
138154 } else {
139- // FALLBACK: Nếu người dùng không cấp quyền MANAGE, xin quyền READ/WRITE cũ
140- checkFallbackPermissions()
155+ finish() // Người dùng từ chối cấp quyền All Files Access
141156 }
142157 }
143158 }
144159 }
145160
146- override fun onRequestPermissionsResult (requestCode : Int , permissions : Array <out String >, grantResults : IntArray ) {
147- super .onRequestPermissionsResult(requestCode, permissions, grantResults)
148- if (requestCode == REQUEST_CODE_PERMISSIONS ) {
149- if (grantResults.isNotEmpty() && grantResults.all { it == PackageManager .PERMISSION_GRANTED }) {
150- startLogic()
151- } else {
152- // Nếu cả quyền cũ cũng bị từ chối -> Thoát
153- finish()
154- }
155- }
156- }
157-
158161 private fun startLogic () {
159162 if (! started) {
160163 started = true
@@ -164,13 +167,13 @@ class SplashActivity : AppCompatActivity() {
164167
165168 override fun onResume () {
166169 super .onResume()
167- // Kiểm tra lại quyền khi người dùng quay lại từ Settings
170+ // Tự động kiểm tra nếu đã đồng nhất thỏa thuận nhưng chưa khởi chạy
168171 if (hasAgreed() && ! started && hasPermissions()) {
169172 startLogic()
170173 }
171174 }
172175
173- // =================== SHELL & LOGS (COROUTINES) ===================
176+ // =================== SHELL & LOGS ===================
174177
175178 private fun runBeforeStartSh (config : KrScriptConfig , hasRoot : Boolean ) {
176179 lifecycleScope.launch(Dispatchers .IO ) {
@@ -185,7 +188,6 @@ class SplashActivity : AppCompatActivity() {
185188 }
186189 }
187190
188- // Đọc log song song
189191 val outJob = launch { readStreamAsync(p.inputStream.bufferedReader()) }
190192 val errJob = launch { readStreamAsync(p.errorStream.bufferedReader()) }
191193
@@ -227,12 +229,12 @@ class SplashActivity : AppCompatActivity() {
227229 }
228230 }
229231
230- // =================== GIAO DIỆN & TIỆN ÍCH ===================
232+ // =================== HELPERS ===================
231233
232234 private fun applyAppLanguage () {
233235 runCatching {
234236 val langFile = File (filesDir, " home/log/language" )
235- val lang = langFile.takeIf { it.exists() }?.readText()?.trim() ? : return
237+ val lang = langFile.takeIf { it.exists() }?.readText()?.trim()?. takeIf { it.isNotEmpty() } ? : return
236238 val appLocale: LocaleListCompat = LocaleListCompat .forLanguageTags(lang.replace(" _" , " -" ))
237239 AppCompatDelegate .setApplicationLocales(appLocale)
238240 }
@@ -242,25 +244,16 @@ class SplashActivity : AppCompatActivity() {
242244 val typedValue = TypedValue ()
243245 theme.resolveAttribute(android.R .attr.windowBackground, typedValue, true )
244246 val bgColor = if (typedValue.resourceId != 0 ) ContextCompat .getColor(this , typedValue.resourceId) else typedValue.data
245-
246247 window.statusBarColor = bgColor
247248 window.navigationBarColor = bgColor
248-
249249 val controller = WindowCompat .getInsetsController(window, window.decorView)
250250 val isDark = ThemeModeState .isDarkMode()
251-
252251 controller.isAppearanceLightStatusBars = ! isDark
253252 controller.isAppearanceLightNavigationBars = ! isDark
254253 }
255254
256255 private fun showAgreementDialog () {
257- DialogHelper .warning(
258- this ,
259- getString(R .string.permission_dialog_title),
260- getString(R .string.permission_dialog_message),
261- { requestAppPermissions() },
262- { finish() }
263- ).setCancelable(false )
256+ DialogHelper .warning(this , getString(R .string.permission_dialog_title), getString(R .string.permission_dialog_message), { requestAppPermissions() }, { finish() }).setCancelable(false )
264257 }
265258
266259 private fun hasAgreed () = getSharedPreferences(" kr-script-config" , MODE_PRIVATE ).getBoolean(" agreed_permissions" , false )
@@ -283,21 +276,13 @@ class SplashActivity : AppCompatActivity() {
283276 private fun startToFinish () {
284277 binding.startStateText.text = getString(R .string.pop_started)
285278 val config = KrScriptConfig ().init (this )
286- if (config.beforeStartSh.isNotEmpty()) {
287- runBeforeStartSh(config, hasRoot)
288- } else {
289- gotoHome()
290- }
279+ if (config.beforeStartSh.isNotEmpty()) runBeforeStartSh(config, hasRoot) else gotoHome()
291280 }
292281
293282 private fun gotoHome () {
294283 val nextIntent = if (intent?.getBooleanExtra(" JumpActionPage" , false ) == true ) {
295- Intent (this , ActionPage ::class .java).apply {
296- intent?.extras?.let { putExtras(it) }
297- }
298- } else {
299- Intent (this , MainActivity ::class .java)
300- }
284+ Intent (this , ActionPage ::class .java).apply { intent?.extras?.let { putExtras(it) } }
285+ } else Intent (this , MainActivity ::class .java)
301286 startActivity(nextIntent)
302287 finish()
303288 }
0 commit comments