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