diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 5c3394c9..f1417dfc 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -17,6 +17,8 @@
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
+
+
HShizuku.setAppDisabled(packageName, frozen)
HailData.MODE_SHIZUKU_HIDE -> HShizuku.setAppHidden(packageName, frozen)
HailData.MODE_SHIZUKU_SUSPEND -> HShizuku.setAppSuspended(packageName, frozen)
+ HailData.MODE_ISLAND_HIDE -> HIsland.setAppHidden(packageName, frozen)
+ HailData.MODE_ISLAND_SUSPEND -> HIsland.setAppSuspended(packageName, frozen)
else -> false
}
diff --git a/app/src/main/kotlin/com/aistra/hail/app/HailData.kt b/app/src/main/kotlin/com/aistra/hail/app/HailData.kt
index 15724dd2..a70c4a21 100644
--- a/app/src/main/kotlin/com/aistra/hail/app/HailData.kt
+++ b/app/src/main/kotlin/com/aistra/hail/app/HailData.kt
@@ -32,6 +32,7 @@ object HailData {
const val DHIZUKU = "dhizuku_"
const val SU = "su_"
const val SHIZUKU = "shizuku_"
+ const val ISLAND = "island_"
const val DISABLE = "disable"
const val HIDE = "hide"
const val SUSPEND = "suspend"
@@ -45,6 +46,8 @@ object HailData {
const val MODE_SHIZUKU_DISABLE = SHIZUKU + DISABLE
const val MODE_SHIZUKU_HIDE = SHIZUKU + HIDE
const val MODE_SHIZUKU_SUSPEND = SHIZUKU + SUSPEND
+ const val MODE_ISLAND_HIDE = ISLAND + HIDE
+ const val MODE_ISLAND_SUSPEND = ISLAND + SUSPEND
private const val TILE_ACTION = "tile_action"
const val DYNAMIC_SHORTCUT_ACTION = "dynamic_shortcut_action"
const val ACTION_NONE = "none"
diff --git a/app/src/main/kotlin/com/aistra/hail/ui/settings/SettingsFragment.kt b/app/src/main/kotlin/com/aistra/hail/ui/settings/SettingsFragment.kt
index 348a1459..a5f93043 100644
--- a/app/src/main/kotlin/com/aistra/hail/ui/settings/SettingsFragment.kt
+++ b/app/src/main/kotlin/com/aistra/hail/ui/settings/SettingsFragment.kt
@@ -6,6 +6,7 @@ import android.os.Bundle
import android.provider.Settings
import android.view.*
import android.widget.FrameLayout
+import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.content.res.AppCompatResources
import androidx.core.app.NotificationManagerCompat
import androidx.core.view.MenuHost
@@ -42,6 +43,7 @@ import rikka.shizuku.Shizuku
class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener,
MenuProvider {
+ private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
override fun onCreateView(
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
): View {
@@ -292,6 +294,27 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan
HUI.showToast(R.string.shizuku_missing)
false
}
+
+ mode.startsWith(HailData.ISLAND) -> return runCatching{
+ when{
+ mode == HailData.MODE_ISLAND_HIDE && HIsland.freezePermissionGranted() -> true
+ mode == HailData.MODE_ISLAND_SUSPEND && HIsland.suspendPermissionGranted() -> true
+ else -> {
+ lifecycleScope.launch {
+ requestPermissionLauncher.launch(if(mode == HailData.MODE_ISLAND_HIDE)
+ HIsland.PERMISSION_FREEZE_PACKAGE
+ else
+ HIsland.PERMISSION_SUSPEND_PACKAGE
+ )
+ }
+ false
+ }
+ }
+ }.getOrElse {
+ HLog.e(it)
+ HUI.showToast(R.string.permission_denied)
+ false
+ }
}
return true
diff --git a/app/src/main/kotlin/com/aistra/hail/utils/HIsland.kt b/app/src/main/kotlin/com/aistra/hail/utils/HIsland.kt
new file mode 100644
index 00000000..9eabea3d
--- /dev/null
+++ b/app/src/main/kotlin/com/aistra/hail/utils/HIsland.kt
@@ -0,0 +1,77 @@
+package com.aistra.hail.utils
+
+import android.app.Activity
+import android.app.PendingIntent
+import android.content.BroadcastReceiver
+import android.content.Context
+import android.content.Intent
+import android.content.pm.PackageManager
+import android.net.Uri
+import android.os.Handler
+import android.os.HandlerThread
+import androidx.core.content.ContextCompat
+import com.aistra.hail.HailApp.Companion.app
+import kotlinx.coroutines.CompletableDeferred
+import kotlinx.coroutines.runBlocking
+import kotlinx.coroutines.withTimeout
+
+object HIsland {
+ const val PERMISSION_FREEZE_PACKAGE = "com.oasisfeng.island.permission.FREEZE_PACKAGE"
+ const val PERMISSION_SUSPEND_PACKAGE = "com.oasisfeng.island.permission.SUSPEND_PACKAGE"
+ private const val ACTION_SUSPEND = "com.oasisfeng.island.action.SUSPEND"
+ private const val ACTION_UNSUSPEND = "com.oasisfeng.island.action.UNSUSPEND"
+ private const val ACTION_FREEZE = "com.oasisfeng.island.action.FREEZE"
+ private const val ACTION_UNFREEZE = "com.oasisfeng.island.action.UNFREEZE"
+ private const val EXTRA_CALLER_ID = "caller"
+
+ private val thread by lazy { HandlerThread("HIsland").apply { start() } }
+ private val handler by lazy { Handler(thread.looper) }
+
+ fun freezePermissionGranted(): Boolean {
+ return ContextCompat.checkSelfPermission(
+ app, PERMISSION_FREEZE_PACKAGE
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+
+ fun suspendPermissionGranted(): Boolean {
+ return ContextCompat.checkSelfPermission(
+ app, PERMISSION_SUSPEND_PACKAGE
+ ) == PackageManager.PERMISSION_GRANTED
+ }
+
+ private fun setAppFrozen(packageName: String, action: String): Boolean {
+ val intent = Intent(action).apply {
+ data = Uri.fromParts("package", packageName, null)
+ setPackage("com.oasisfeng.island")
+ addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
+ putExtra(
+ EXTRA_CALLER_ID,
+ PendingIntent.getActivity(app, 0, Intent(), PendingIntent.FLAG_IMMUTABLE)
+ )
+ }
+ val result = CompletableDeferred()
+ app.sendOrderedBroadcast(
+ intent, null, object : BroadcastReceiver() {
+ override fun onReceive(context: Context, intent: Intent) {
+ if (resultCode != Activity.RESULT_OK) {
+ HLog.i("HIsland", resultData)
+ }
+ result.complete(resultCode == Activity.RESULT_OK)
+ }
+ }, handler, Activity.RESULT_OK, null, null
+ )
+ return runBlocking {
+ runCatching {
+ withTimeout(500L) {
+ result.await()
+ }
+ }.getOrElse { false }
+ }
+ }
+
+ fun setAppHidden(packageName: String, hidden: Boolean): Boolean =
+ HTarget.N && setAppFrozen(packageName, if (hidden) ACTION_FREEZE else ACTION_UNFREEZE)
+
+ fun setAppSuspended(packageName: String, suspended: Boolean): Boolean =
+ HTarget.N && setAppFrozen(packageName, if (suspended) ACTION_SUSPEND else ACTION_UNSUSPEND)
+}
\ No newline at end of file
diff --git a/app/src/main/res/values-zh-rCN/strings.xml b/app/src/main/res/values-zh-rCN/strings.xml
index bc04c7d2..620554f6 100644
--- a/app/src/main/res/values-zh-rCN/strings.xml
+++ b/app/src/main/res/values-zh-rCN/strings.xml
@@ -137,6 +137,8 @@
终端
Dhizuku - 隐藏
Dhizuku - 暂停
+ 炼妖壶 - 隐藏
+ 炼妖壶 - 暂停
超级用户 - 隐藏
F-Droid
跳过
diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml
index 703018d9..2a6b19f8 100644
--- a/app/src/main/res/values/arrays.xml
+++ b/app/src/main/res/values/arrays.xml
@@ -41,6 +41,8 @@
- @string/mode_dhizuku_suspend
- @string/mode_owner_hide
- @string/mode_owner_suspend
+ - @string/mode_island_hide
+ - @string/mode_island_suspend
- default
@@ -54,6 +56,8 @@
- dhizuku_suspend
- owner_hide
- owner_suspend
+ - island_hide
+ - island_suspend
- @string/donate_alipay
diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml
index a1f5de1a..8fb3d28c 100644
--- a/app/src/main/res/values/strings.xml
+++ b/app/src/main/res/values/strings.xml
@@ -139,4 +139,6 @@
Superuser - Hide
F-Droid
Skip
+ Island - Hide
+ Island - Suspend
\ No newline at end of file