app/src/main/java/dev/equwal/inkrecents/SettingsActivity.kt (3843 bytes)
1 // SPDX-License-Identifier: GPL-3.0-or-later 2 // Copyright (c) 2026 equwal 3 package dev.equwal.inkrecents 4 5 import android.app.Activity 6 import android.content.Intent 7 import android.net.Uri 8 import android.provider.Settings 9 import android.widget.LinearLayout 10 import dev.equwal.inkrecents.Ui.button 11 import dev.equwal.inkrecents.Ui.header 12 import dev.equwal.inkrecents.Ui.note 13 import dev.equwal.inkrecents.Ui.row 14 15 /** 16 * The two ways this app can read the recent apps, and what the app is. 17 * 18 * Usage access is enough to put the apps in order of last use. Shizuku gives 19 * shell access, which gives the real task list and a real close. 20 */ 21 class SettingsActivity : Activity() { 22 23 private val redraw: () -> Unit = { if (!isFinishing) build() } 24 25 override fun onResume() { 26 super.onResume() 27 Shell.onChange(redraw) 28 Shell.connect(this) 29 build() 30 } 31 32 override fun onPause() { 33 super.onPause() 34 Shell.removeOnChange(redraw) 35 } 36 37 private fun build() { 38 val col = Ui.page(this, "Settings") 39 40 col.header("Usage access") 41 col.note("It puts your apps in order of last use.") 42 col.row("State", null, enabled = false, state = if (Apps.hasUsageAccess(this)) "On" else "Off") 43 col.button("Open usage access") { start(Intent(Settings.ACTION_USAGE_ACCESS_SETTINGS)) } 44 45 col.header("Shizuku") 46 col.note("It gives shell access. Then the cards are the real tasks, and a card closes its task.") 47 col.row("State", null, enabled = false, state = Shell.describe(this)) 48 if (Shell.state(this) != Shell.State.READY) steps(col) 49 50 col.header("About") 51 col.row("Version", null, enabled = false, state = BuildConfig.VERSION_NAME) 52 col.row("Licence", null, enabled = false, state = "GPL-3.0-or-later") 53 col.row("Source code", REPO) { start(Intent(Intent.ACTION_VIEW, Uri.parse(REPO))) } 54 col.row("Buy me a coffee", TIP.removePrefix("https://")) { start(Intent(Intent.ACTION_VIEW, Uri.parse(TIP))) } 55 56 col.header("More apps") 57 for (app in MoreApps.ALL) { 58 col.row(app.name, app.line) { start(Intent(Intent.ACTION_VIEW, Uri.parse(app.url))) } 59 } 60 } 61 62 /** The four steps to shell access, from the device itself. */ 63 private fun steps(col: LinearLayout) { 64 val state = Shell.state(this) 65 col.note("1. Install Shizuku. It is free.") 66 if (state == Shell.State.NOT_INSTALLED) { 67 col.button("Get Shizuku") { 68 if (!start(Intent(Intent.ACTION_VIEW, Uri.parse("market://details?id=" + Shell.SHIZUKU_PACKAGE)))) { 69 start(Intent(Intent.ACTION_VIEW, Uri.parse("https://shizuku.rikka.app/download/"))) 70 } 71 } 72 } 73 74 col.note("2. Turn on wireless debugging in Developer options.") 75 col.button("Open Developer options") { 76 if (!start(Intent(Settings.ACTION_APPLICATION_DEVELOPMENT_SETTINGS))) { 77 start(Intent(Settings.ACTION_DEVICE_INFO_SETTINGS)) 78 } 79 } 80 81 col.note("3. In Shizuku, pair with the code, then press Start.") 82 if (state != Shell.State.NOT_INSTALLED) { 83 col.button("Open Shizuku") { 84 packageManager.getLaunchIntentForPackage(Shell.SHIZUKU_PACKAGE)?.let { start(it) } 85 } 86 } 87 88 col.note("4. Let Ink Recents use Shizuku.") 89 if (state == Shell.State.NO_PERMISSION) { 90 col.button("Ask for permission") { Shell.requestPermission() } 91 } 92 } 93 94 private fun start(i: Intent): Boolean = 95 runCatching { startActivity(i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)); true }.getOrDefault(false) 96 97 private companion object { 98 const val REPO = "https://github.com/equwal/ink-recents" 99 const val TIP = "https://ko-fi.com/truex" 100 } 101 }