1+ package com.tool.tree
2+
3+ import android.app.Activity
4+ import android.Manifest
5+ import android.content.ComponentName
6+ import android.content.Intent
7+ import android.content.pm.PackageManager
8+ import android.net.Uri
9+ import android.os.Build
10+ import android.os.Bundle
11+ import android.os.Handler
12+ import android.provider.Settings
13+ import android.util.DisplayMetrics
14+ import android.view.LayoutInflater
15+ import android.view.Menu
16+ import android.view.MenuItem
17+ import android.view.View
18+ import android.widget.CompoundButton
19+ import android.widget.Toast
20+ import androidx.appcompat.app.AppCompatActivity
21+ import androidx.appcompat.widget.Toolbar
22+ import androidx.core.content.ContextCompat
23+ import com.omarea.common.shared.FilePathResolver
24+ import com.omarea.common.ui.DialogHelper
25+ import com.omarea.common.ui.ProgressBarDialog
26+ import com.omarea.krscript.config.PageConfigReader
27+ import com.omarea.krscript.config.PageConfigSh
28+ import com.omarea.krscript.model.*
29+ import com.omarea.krscript.ui.ActionListFragment
30+ import com.omarea.krscript.ui.ParamsFileChooserRender
31+ import com.omarea.vtools.FloatMonitor
32+ import com.tool.tree.databinding.ActivityMainBinding
33+ import com.omarea.common.shell.KeepShellPublic
34+ import com.tool.tree.ui.TabIconHelper
35+ import androidx.core.view.isVisible
36+ import androidx.activity.OnBackPressedDispatcher
37+ import androidx.activity.ComponentActivity
38+ import androidx.activity.OnBackPressedCallback
39+
40+ class MainActivity : AppCompatActivity() {
41+ private val progressBarDialog = ProgressBarDialog(this)
42+ private var handler = Handler()
43+ private var krScriptConfig = KrScriptConfig()
44+ private val hasRoot by lazy { KeepShellPublic.checkRoot() }
45+ private lateinit var binding: ActivityMainBinding
46+
47+ override fun onCreate(savedInstanceState: Bundle?) {
48+ super.onCreate(savedInstanceState)
49+ ThemeModeState.switchTheme(this)
50+ binding = ActivityMainBinding.inflate(layoutInflater)
51+ setContentView(binding.root)
52+
53+ val toolbar = findViewById<View>(R.id.toolbar) as Toolbar
54+ setSupportActionBar(toolbar)
55+ setTitle(R.string.app_name)
56+ krScriptConfig = KrScriptConfig()
57+ binding.mainTabhost.setup()
58+
59+ val tabIconHelper = TabIconHelper(binding.mainTabhost, this)
60+ if (tabIconHelper != null) {
61+ if (hasRoot && krScriptConfig.allowHomePage) {
62+ tabIconHelper.newTabSpec(getString(R.string.tab_home), getDrawable(R.drawable.tab_home)!!, R.id.main_tabhost_cpu)
63+ } else {
64+ binding.mainTabhostCpu.visibility = View.GONE
65+ }
66+ }
67+ binding.mainTabhost.setOnTabChangedListener {
68+ tabIconHelper.updateHighlight()
69+ }
70+
71+ progressBarDialog.showDialog(getString(R.string.please_wait))
72+ Thread {
73+ val page2Config = krScriptConfig.pageListConfig
74+ val favoritesConfig = krScriptConfig.favoriteConfig
75+
76+ val pages = getItems(page2Config)
77+ val favorites = getItems(favoritesConfig)
78+ handler.post {
79+ progressBarDialog.hideDialog()
80+
81+ if (favorites != null && favorites.isNotEmpty()) {
82+ updateFavoritesTab(favorites, favoritesConfig)
83+ tabIconHelper.newTabSpec(
84+ getString(R.string.tab_favorites),
85+ ContextCompat.getDrawable(this, R.drawable.tab_favorites)!!,
86+ R.id.main_tabhost_2
87+ )
88+ } else {
89+ binding.mainTabhost2.visibility = View.GONE
90+ }
91+
92+ if (pages != null && pages.isNotEmpty()) {
93+ updateMoreTab(pages, page2Config)
94+ tabIconHelper.newTabSpec(
95+ getString(R.string.tab_pages),
96+ ContextCompat.getDrawable(this, R.drawable.tab_pages)!!,
97+ R.id.main_tabhost_3
98+ )
99+ } else {
100+ binding.mainTabhost3.visibility = View.GONE
101+ }
102+ }
103+ }.start()
104+
105+ if (hasRoot && krScriptConfig.allowHomePage) {
106+ val home = FragmentHome()
107+ val fragmentManager = supportFragmentManager
108+ val transaction = fragmentManager.beginTransaction()
109+ transaction.replace(R.id.main_tabhost_cpu, home)
110+ transaction.commitAllowingStateLoss()
111+ }
112+
113+ val themeConfig = ThemeConfig(applicationContext)
114+ if (themeConfig.getAllowNotificationUI()) {
115+ WakeLockService.startService(applicationContext)
116+ }
117+
118+ onBackPressedDispatcher.addCallback(this, object : OnBackPressedCallback(true) {
119+ override fun handleOnBackPressed() {
120+ startService(Intent(this@MainActivity, WakeLockService::class.java).apply { action = WakeLockService.ACTION_END_WAKELOCK })
121+ isEnabled = false
122+ onBackPressedDispatcher.onBackPressed()
123+ }
124+ })
125+ }
126+
127+ private fun getItems(pageNode: PageNode): ArrayList<NodeInfoBase>? {
128+ var items: ArrayList<NodeInfoBase>? = null
129+
130+ if (pageNode.pageConfigSh.isNotEmpty()) {
131+ items = PageConfigSh(this, pageNode.pageConfigSh, null).execute()
132+ }
133+ if (items == null && pageNode.pageConfigPath.isNotEmpty()) {
134+ items = PageConfigReader(this.applicationContext, pageNode.pageConfigPath, null).readConfigXml()
135+ }
136+
137+ return items
138+ }
139+
140+ private fun updateFavoritesTab(items: ArrayList<NodeInfoBase>, pageNode: PageNode) {
141+ val favoritesFragment = ActionListFragment.create(items, getKrScriptActionHandler(pageNode, true), null, ThemeModeState.getThemeMode())
142+ supportFragmentManager.beginTransaction().replace(R.id.list_favorites, favoritesFragment).commitAllowingStateLoss()
143+ }
144+
145+ private fun updateMoreTab(items: ArrayList<NodeInfoBase>, pageNode: PageNode) {
146+ val allItemFragment = ActionListFragment.create(items, getKrScriptActionHandler(pageNode, false), null, ThemeModeState.getThemeMode())
147+ supportFragmentManager.beginTransaction().replace(R.id.list_pages, allItemFragment).commitAllowingStateLoss()
148+ }
149+
150+ private fun reloadFavoritesTab() {
151+ Thread {
152+ val favoritesConfig = krScriptConfig.favoriteConfig
153+ val favorites = getItems(favoritesConfig)
154+ favorites?.run {
155+ handler.post {
156+ updateFavoritesTab(this, favoritesConfig)
157+ }
158+ }
159+ }.start()
160+ }
161+
162+ private fun reloadMoreTab() {
163+ Thread {
164+ val page2Config = krScriptConfig.pageListConfig
165+ val pages = getItems(page2Config)
166+
167+ pages?.run {
168+ handler.post {
169+ updateMoreTab(this, page2Config)
170+ }
171+ }
172+ }.start()
173+ }
174+
175+ private fun getKrScriptActionHandler(pageNode: PageNode, isFavoritesTab: Boolean): KrScriptActionHandler {
176+ return object : KrScriptActionHandler {
177+ override fun onActionCompleted(runnableNode: RunnableNode) {
178+ if (runnableNode.autoFinish) {
179+ finishAndRemoveTask()
180+ } else if (runnableNode.reloadPage) {
181+ if (isFavoritesTab) {
182+ reloadFavoritesTab()
183+ } else {
184+ reloadMoreTab()
185+ }
186+ } else if (runnableNode.autoKill) {
187+ startService(Intent(this@MainActivity, WakeLockService::class.java).apply { action = WakeLockService.ACTION_END_WAKELOCK })
188+ finishAffinity()
189+ System.exit(0)
190+ }
191+ }
192+
193+ override fun addToFavorites(clickableNode: ClickableNode, addToFavoritesHandler: KrScriptActionHandler.AddToFavoritesHandler) {
194+ val page = clickableNode as? PageNode
195+ ?: if (clickableNode is RunnableNode) {
196+ pageNode
197+ } else {
198+ return
199+ }
200+
201+ val intent = Intent()
202+
203+ intent.component = ComponentName(this@MainActivity.applicationContext, ActionPage::class.java)
204+ intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
205+ intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
206+
207+ if (clickableNode is RunnableNode) {
208+ intent.putExtra("autoRunItemId", clickableNode.key)
209+ }
210+ intent.putExtra("page", page)
211+
212+ addToFavoritesHandler.onAddToFavorites(clickableNode, intent)
213+ }
214+
215+ override fun onSubPageClick(pageNode: PageNode) {
216+ _openPage(pageNode)
217+ }
218+
219+ override fun openFileChooser(fileSelectedInterface: ParamsFileChooserRender.FileSelectedInterface): Boolean {
220+ return chooseFilePath(fileSelectedInterface)
221+ }
222+ }
223+ }
224+
225+ private var fileSelectedInterface: ParamsFileChooserRender.FileSelectedInterface? = null
226+ private val ACTION_FILE_PATH_CHOOSER = 65400
227+ private val ACTION_FILE_PATH_CHOOSER_INNER = 65300
228+
229+ private fun chooseFilePath(extension: String) {
230+ try {
231+ val intent = Intent(this, ActivityFileSelector::class.java)
232+ intent.putExtra("extension", extension)
233+ startActivityForResult(intent, ACTION_FILE_PATH_CHOOSER_INNER)
234+ } catch (ex: java.lang.Exception) {
235+ Toast.makeText(this, "Failed to launch the built-in file selector!", Toast.LENGTH_SHORT).show()
236+ }
237+ }
238+
239+ private fun chooseFilePath(fileSelectedInterface: ParamsFileChooserRender.FileSelectedInterface): Boolean {
240+ return try {
241+ val suffix = fileSelectedInterface.suffix()
242+ if (suffix != null && suffix.isNotEmpty()) {
243+ chooseFilePath(suffix)
244+ } else {
245+ val intent = Intent(Intent.ACTION_OPEN_DOCUMENT).apply {
246+ addCategory(Intent.CATEGORY_OPENABLE)
247+ val mimeType = fileSelectedInterface.mimeType() ?: "*/*"
248+ type = mimeType
249+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
250+ putExtra(Intent.EXTRA_MIME_TYPES, arrayOf(mimeType))
251+ }
252+ }
253+ startActivityForResult(intent, ACTION_FILE_PATH_CHOOSER)
254+ }
255+ this.fileSelectedInterface = fileSelectedInterface
256+ true
257+ } catch (e: Exception) {
258+ Toast.makeText(this, "Unable to open picker file: ${e.message}", Toast.LENGTH_SHORT).show()
259+ false
260+ }
261+ }
262+
263+ override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
264+ if (requestCode == ACTION_FILE_PATH_CHOOSER) {
265+ val result = if (data == null || resultCode != RESULT_OK) null else data.data
266+ if (fileSelectedInterface != null) {
267+ if (result != null) {
268+ val absPath = getPath(result)
269+ fileSelectedInterface?.onFileSelected(absPath)
270+ } else {
271+ fileSelectedInterface?.onFileSelected(null)
272+ }
273+ }
274+ this.fileSelectedInterface = null
275+ } else if (requestCode == ACTION_FILE_PATH_CHOOSER_INNER) {
276+ val absPath = if (data == null || resultCode != RESULT_OK) null else data.getStringExtra("file")
277+ fileSelectedInterface?.onFileSelected(absPath)
278+ this.fileSelectedInterface = null
279+ }
280+ super.onActivityResult(requestCode, resultCode, data)
281+ }
282+
283+ private fun getPath(uri: Uri): String? {
284+ return try {
285+ FilePathResolver().getPath(this, uri)
286+ } catch (ex: Exception) {
287+ null
288+ }
289+ }
290+
291+ fun _openPage(pageNode: PageNode) {
292+ OpenPageHelper(this).openPage(pageNode)
293+ }
294+
295+ private fun getDensity(): Int {
296+ val dm = DisplayMetrics()
297+ windowManager.defaultDisplay.getMetrics(dm)
298+ return dm.densityDpi
299+ }
300+
301+ override fun onCreateOptionsMenu(menu: Menu): Boolean {
302+ menuInflater.inflate(R.menu.main, menu)
303+ menu.findItem(R.id.action_graph).isVisible = (binding.mainTabhostCpu.isVisible)
304+ return true
305+ }
306+
307+ override fun onOptionsItemSelected(item: MenuItem): Boolean {
308+ when (item.itemId) {
309+ R.id.option_menu_info -> {
310+ val layoutInflater = LayoutInflater.from(this)
311+ val layout = layoutInflater.inflate(R.layout.dialog_about, null)
312+ val themeConfig = ThemeConfig(this)
313+
314+ val transparentUi = layout.findViewById<CompoundButton>(R.id.transparent_ui)
315+ transparentUi.setOnClickListener {
316+ val isChecked = (it as CompoundButton).isChecked
317+ themeConfig.setAllowTransparentUI(isChecked)
318+ }
319+ transparentUi.isChecked = themeConfig.getAllowTransparentUI()
320+
321+ val notificationUi = layout.findViewById<CompoundButton>(R.id.notification_ui)
322+ notificationUi.setOnClickListener {
323+ val isChecked = (it as CompoundButton).isChecked
324+ themeConfig.setAllowNotificationUI(isChecked)
325+ }
326+ notificationUi.isChecked = themeConfig.getAllowNotificationUI()
327+
328+ DialogHelper.customDialog(this, layout)
329+ }
330+ R.id.option_menu_reboot -> {
331+ DialogPower(this).showPowerMenu()
332+ }
333+ R.id.action_graph -> {
334+ if (FloatMonitor.isShown == true) {
335+ FloatMonitor(this).hidePopupWindow()
336+ return false
337+ }
338+ if (Settings.canDrawOverlays(this)) {
339+ FloatMonitor(this).showPopupWindow()
340+ Toast.makeText(this, getString(R.string.float_monitor_tips), Toast.LENGTH_LONG).show()
341+ } else {
342+ val intent = Intent()
343+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
344+ intent.action = "android.settings.APPLICATION_DETAILS_SETTINGS"
345+ intent.data = Uri.fromParts("package", this.packageName, null)
346+
347+ Toast.makeText(applicationContext, getString(R.string.permission_float), Toast.LENGTH_LONG).show()
348+
349+ try {
350+ startActivity(intent)
351+ } catch (_: Exception) {
352+ }
353+ }
354+ }
355+ }
356+ return super.onOptionsItemSelected(item)
357+ }
358+ }
0 commit comments