Skip to content

Commit db7f531

Browse files
committed
Upload file
1 parent a6c408e commit db7f531

4 files changed

Lines changed: 265 additions & 17 deletions

File tree

32 Bytes
Binary file not shown.

pio/src/main/assets/home/etc/start-early.rc

Lines changed: 6 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,8 @@ rm -fr $TMPDIR/* $HOME/cache/* $START_DIR/cache/* $TEMP/documents $TEMP/WebView
55

66
(
77
# Tải về nhật ký
8-
echo -e "\nDownload the log and the latest version..." &>>$TEMP/Install.log
9-
timeout 20 Taive 'https://raw.githubusercontent.com/Zenlua/Tool-Tree/refs/heads/main/Version.md' $TEMP/Version.md &>>$TEMP/Install.log
8+
echo -e "\nDownload the log and the latest version..."
9+
timeout 20 Taive 'https://raw.githubusercontent.com/Zenlua/Tool-Tree/refs/heads/main/Version.md' $TEMP/Version.md
1010
text_num_1="$(grep -nm1 Version: $TEMP/Version.md | tail -1 | cut -d: -f1)"
1111
text_num_2="$(grep -nm4 Version: $TEMP/Version.md | tail -1 | cut -d: -f1)"
1212
sed -n "$text_num_1,$((text_num_2 - 1))p" $TEMP/Version.md | sed -e "s|\*\*||g" -e "s|+|•|g" | trans -b "$LANGUAGE-$COUNTRY" > $TEMP/version.txt
@@ -21,7 +21,7 @@ if [[ "$websum" != "$(checksum "$PATH_APK")" ]];then
2121
else
2222
[ -f $TEMP/update ] && rm -f $TEMP/update
2323
fi
24-
) &
24+
) &>>$TEMP/Install.log &
2525

2626
(
2727
# Cấp quyền tự động nếu đã root
@@ -43,15 +43,14 @@ if [ "$ROT" == 1 ];then
4343
# Loaded sẵn danh sách img
4444
search_image &>/dev/null
4545
fi
46-
) &>>$TEMP/Install.log &
47-
4846
# Khởi động các file shell ở add-on
4947
chmod 777 $AON/*/* $AOK/*/*
5048
for vadd in $AON/*/early_start.sh $AOK/*/early_start.sh; do
5149
if [ -f "$vadd" ];then
5250
(
53-
echo "run shell: $vadd" &>>$TEMP/Install.log
54-
$vadd &>>$TEMP/Install.log
51+
echo "run shell: $vadd"
52+
$vadd
5553
) &
5654
fi
5755
done
56+
) &>>$TEMP/Install.log &

pio/src/main/java/com/projectkr/shell/SplashActivity.kt

Lines changed: 6 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -196,10 +196,12 @@ class SplashActivity : AppCompatActivity() {
196196
}
197197

198198
private fun runBeforeStartSh(config: KrScriptConfig, hasRoot: Boolean) {
199-
// Coroutine IO
200199
lifecycleScope.launch(Dispatchers.IO) {
201200
try {
202-
val process = if (hasRoot) ShellExecutor.getSuperUserRuntime() else ShellExecutor.getRuntime()
201+
val process = if (hasRoot)
202+
ShellExecutor.getSuperUserRuntime()
203+
else
204+
ShellExecutor.getRuntime()
203205
process?.let {
204206
DataOutputStream(it.outputStream).use { os ->
205207
ScriptEnvironmen.executeShell(
@@ -211,17 +213,11 @@ class SplashActivity : AppCompatActivity() {
211213
"pio-splash"
212214
)
213215
}
214-
215-
// Đọc stdout và stderr bằng coroutine con
216-
launch { readStreamAsync(it.inputStream.bufferedReader()) }
217-
launch { readStreamAsync(it.errorStream.bufferedReader()) }
218-
219-
it.waitFor()
220216
}
221-
} finally {
222-
withContext(Dispatchers.Main) { gotoHome() }
217+
} catch (_: Exception) {
223218
}
224219
}
220+
gotoHome()
225221
}
226222

227223
// Buffer lưu 4 dòng cuối
Lines changed: 253 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,253 @@
1+
package com.tool.tree
2+
3+
import android.content.Context
4+
import android.content.Intent
5+
import android.content.pm.PackageManager
6+
import android.content.res.Configuration
7+
import android.graphics.Color
8+
import android.net.Uri
9+
import android.os.Build
10+
import android.os.Bundle
11+
import android.os.Environment
12+
import android.os.Handler
13+
import android.provider.Settings
14+
import android.view.animation.AnimationUtils
15+
import android.widget.TextView
16+
import androidx.appcompat.app.AppCompatActivity
17+
import androidx.core.app.ActivityCompat
18+
import androidx.core.content.ContextCompat
19+
import androidx.core.view.WindowCompat
20+
import androidx.core.view.WindowInsetsControllerCompat
21+
import androidx.lifecycle.lifecycleScope
22+
import com.omarea.common.shell.KeepShellPublic
23+
import com.omarea.common.shell.ShellExecutor
24+
import com.omarea.common.ui.DialogHelper
25+
import com.omarea.krscript.executor.ScriptEnvironmen
26+
import com.tool.tree.databinding.ActivitySplashBinding
27+
import com.tool.tree.R
28+
import kotlinx.coroutines.Dispatchers
29+
import kotlinx.coroutines.launch
30+
import kotlinx.coroutines.withContext
31+
import java.io.BufferedReader
32+
import java.io.DataOutputStream
33+
import java.io.File
34+
import java.util.Locale
35+
36+
class SplashActivity : AppCompatActivity() {
37+
38+
private lateinit var binding: ActivitySplashBinding
39+
private val REQUEST_CODE_PERMISSIONS = 1001
40+
41+
private var hasRoot = false
42+
private var started = false
43+
private var starting = false
44+
45+
override fun onCreate(savedInstanceState: Bundle?) {
46+
applyAppLanguage()
47+
super.onCreate(savedInstanceState)
48+
ThemeModeState.switchTheme(this)
49+
50+
if (ScriptEnvironmen.isInited() && isTaskRoot) {
51+
gotoHome()
52+
return
53+
}
54+
55+
if (!hasAgreed()) showAgreementDialog()
56+
57+
binding = ActivitySplashBinding.inflate(layoutInflater)
58+
setContentView(binding.root)
59+
60+
binding.startLogoXml.postDelayed({
61+
binding.startLogoXml.startAnimation(AnimationUtils.loadAnimation(this, R.anim.blink))
62+
}, 2000)
63+
64+
applyTheme()
65+
}
66+
67+
private fun applyAppLanguage() {
68+
runCatching {
69+
val langFile = File(filesDir, "home/log/language")
70+
val lang = langFile.takeIf { it.exists() }?.readText()?.trim()?.takeIf { it.isNotEmpty() } ?: return
71+
val locale = Locale.forLanguageTag(lang.replace("_", "-"))
72+
if (Locale.getDefault() != locale) {
73+
Locale.setDefault(locale)
74+
val config = Configuration(resources.configuration).apply { setLocale(locale) }
75+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
76+
resources.updateConfiguration(config, resources.displayMetrics)
77+
} else {
78+
@Suppress("DEPRECATION")
79+
resources.updateConfiguration(config, resources.displayMetrics)
80+
}
81+
}
82+
}
83+
}
84+
85+
private fun applyTheme() {
86+
WindowCompat.setDecorFitsSystemWindows(window, false)
87+
window.statusBarColor = Color.TRANSPARENT
88+
window.navigationBarColor = ContextCompat.getColor(this, R.color.splash_bg_color)
89+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
90+
WindowCompat.getInsetsController(window, window.decorView).isAppearanceLightStatusBars = true
91+
}
92+
}
93+
94+
// =================== AGREEMENT ===================
95+
private fun showAgreementDialog() {
96+
DialogHelper.warning(
97+
this,
98+
getString(R.string.permission_dialog_title),
99+
getString(R.string.permission_dialog_message),
100+
Runnable { requestAppPermissions() },
101+
Runnable { finish() }
102+
).setCancelable(false)
103+
}
104+
105+
private fun hasAgreed(): Boolean =
106+
getSharedPreferences("kr-script-config", MODE_PRIVATE)
107+
.getBoolean("agreed_permissions", false)
108+
109+
private fun saveAgreement() {
110+
getSharedPreferences("kr-script-config", MODE_PRIVATE)
111+
.edit()
112+
.putBoolean("agreed_permissions", true)
113+
.apply()
114+
}
115+
116+
// =================== PERMISSION ===================
117+
private fun hasAllFilesPermission(): Boolean =
118+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R)
119+
Environment.isExternalStorageManager()
120+
else ContextCompat.checkSelfPermission(this, android.Manifest.permission.READ_EXTERNAL_STORAGE) ==
121+
PackageManager.PERMISSION_GRANTED
122+
123+
private fun requestAllFilesPermission() {
124+
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
125+
startActivity(Intent(Settings.ACTION_MANAGE_APP_ALL_FILES_ACCESS_PERMISSION).apply {
126+
data = Uri.parse("package:$packageName")
127+
})
128+
} else {
129+
// Legacy permission
130+
ActivityCompat.requestPermissions(
131+
this,
132+
arrayOf(android.Manifest.permission.READ_EXTERNAL_STORAGE, android.Manifest.permission.WRITE_EXTERNAL_STORAGE),
133+
REQUEST_CODE_PERMISSIONS
134+
)
135+
}
136+
}
137+
138+
private fun requestAppPermissions() {
139+
saveAgreement()
140+
if (!hasAllFilesPermission()) requestAllFilesPermission()
141+
else {
142+
started = true
143+
checkRootAndStart()
144+
}
145+
}
146+
147+
override fun onResume() {
148+
super.onResume()
149+
if (hasAgreed() && !started) {
150+
started = true
151+
checkRootAndStart()
152+
}
153+
}
154+
155+
override fun onRequestPermissionsResult(requestCode: Int, permissions: Array<out String>, grantResults: IntArray) {
156+
if (requestCode == REQUEST_CODE_PERMISSIONS) {
157+
if (grantResults.all { it == PackageManager.PERMISSION_GRANTED }) {
158+
started = true
159+
checkRootAndStart()
160+
} else finish()
161+
}
162+
super.onRequestPermissionsResult(requestCode, permissions, grantResults)
163+
}
164+
165+
// =================== ROOT ===================
166+
@Synchronized
167+
private fun checkRootAndStart() {
168+
if (!started || starting) return
169+
starting = true
170+
171+
lifecycleScope.launch(Dispatchers.IO) {
172+
hasRoot = KeepShellPublic.checkRoot()
173+
withContext(Dispatchers.Main) {
174+
starting = false
175+
startToFinish()
176+
}
177+
}
178+
}
179+
180+
private fun startToFinish() {
181+
binding.startStateText.text = getString(R.string.pop_started)
182+
val config = KrScriptConfig().init(this)
183+
184+
if (config.beforeStartSh.isNotEmpty()) {
185+
runBeforeStartSh(config, hasRoot)
186+
} else gotoHome()
187+
}
188+
189+
private fun gotoHome() {
190+
startActivity(
191+
if (intent?.getBooleanExtra("JumpActionPage", false) == true)
192+
Intent(this, ActionPage::class.java).apply { putExtras(intent!!) }
193+
else Intent(this, MainActivity::class.java)
194+
)
195+
finish()
196+
}
197+
198+
private fun runBeforeStartSh(config: KrScriptConfig, hasRoot: Boolean) {
199+
// Coroutine IO
200+
lifecycleScope.launch(Dispatchers.IO) {
201+
try {
202+
val process = if (hasRoot) ShellExecutor.getSuperUserRuntime() else ShellExecutor.getRuntime()
203+
process?.let {
204+
DataOutputStream(it.outputStream).use { os ->
205+
ScriptEnvironmen.executeShell(
206+
this@SplashActivity,
207+
os,
208+
config.beforeStartSh,
209+
config.variables,
210+
null,
211+
"pio-splash"
212+
)
213+
}
214+
215+
// Đọc stdout và stderr bằng coroutine con
216+
launch { readStreamAsync(it.inputStream.bufferedReader()) }
217+
launch { readStreamAsync(it.errorStream.bufferedReader()) }
218+
219+
it.waitFor()
220+
}
221+
} finally {
222+
withContext(Dispatchers.Main) { gotoHome() }
223+
}
224+
}
225+
}
226+
227+
// Buffer lưu 4 dòng cuối
228+
private val rows = mutableListOf<String>()
229+
private var ignored = false
230+
private val maxLines = 5
231+
private val handler = android.os.Handler(android.os.Looper.getMainLooper())
232+
233+
private fun readStreamAsync(reader: BufferedReader) {
234+
Thread {
235+
reader.forEachLine { line ->
236+
onLogOutput(line)
237+
}
238+
}.start()
239+
}
240+
241+
private fun onLogOutput(log: String) {
242+
handler.post {
243+
synchronized(rows) {
244+
if (rows.size >= maxLines) {
245+
rows.removeAt(0)
246+
ignored = true
247+
}
248+
rows.add(log)
249+
binding.startStateText.text = rows.joinToString("\n", if (ignored) "……\n" else "")
250+
}
251+
}
252+
}
253+
}

0 commit comments

Comments
 (0)