Skip to content

Commit 838b237

Browse files
committed
Merge branch 'master' into whp98
2 parents ded93e2 + 3e35fed commit 838b237

File tree

16 files changed

+189
-101
lines changed

16 files changed

+189
-101
lines changed

app/build.gradle.kts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ val props =
1111
val keyStoreFile = file(signFolder + props.getProperty("storeFile"))
1212
android {
1313
namespace = "com.aistra.hail"
14-
compileSdk = 33
14+
compileSdk = 34
1515

1616
defaultConfig {
1717
applicationId = "com.aistra.hail"
@@ -66,7 +66,6 @@ android {
6666
}
6767

6868
dependencies {
69-
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
7069
implementation("androidx.core:core-ktx:1.9.0")
7170
implementation("androidx.appcompat:appcompat:1.6.1")
7271
implementation("androidx.biometric:biometric:1.1.0")
@@ -76,13 +75,14 @@ dependencies {
7675
implementation("androidx.preference:preference-ktx:1.2.0")
7776
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
7877
implementation("androidx.work:work-runtime-ktx:2.8.1")
78+
implementation("com.belerweb:pinyin4j:2.5.1")
7979
implementation("com.google.android.material:material:1.9.0")
8080
implementation("dev.rikka.rikkax.preference:simplemenu-preference:1.0.3")
8181
implementation("dev.rikka.shizuku:api:13.1.4")
8282
implementation("dev.rikka.shizuku:provider:13.1.4")
8383
implementation("io.github.iamr0s:Dhizuku-API:2.4")
8484
implementation("me.zhanghai.android.appiconloader:appiconloader:1.5.0")
85-
implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
86-
implementation("com.belerweb:pinyin4j:2.5.1")
8785
implementation("org.apache.commons:commons-text:1.10.0")
86+
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
87+
implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
8888
}

app/src/main/AndroidManifest.xml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,8 @@
1717
android:name="android.permission.PACKAGE_USAGE_STATS"
1818
tools:ignore="ProtectedPermissions" />
1919
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
20+
<uses-permission android:name="com.oasisfeng.island.permission.FREEZE_PACKAGE"/>
21+
<uses-permission android:name="com.oasisfeng.island.permission.SUSPEND_PACKAGE"/>
2022

2123
<application
2224
android:name=".HailApp"

app/src/main/kotlin/com/aistra/hail/app/AppManager.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package com.aistra.hail.app
33
import android.content.Intent
44
import com.aistra.hail.BuildConfig
55
import com.aistra.hail.utils.HDhizuku
6+
import com.aistra.hail.utils.HIsland
67
import com.aistra.hail.utils.HPackages
78
import com.aistra.hail.utils.HPolicy
89
import com.aistra.hail.utils.HShell
@@ -42,6 +43,8 @@ object AppManager {
4243
HailData.MODE_SHIZUKU_DISABLE -> HShizuku.setAppDisabled(packageName, frozen)
4344
HailData.MODE_SHIZUKU_HIDE -> HShizuku.setAppHidden(packageName, frozen)
4445
HailData.MODE_SHIZUKU_SUSPEND -> HShizuku.setAppSuspended(packageName, frozen)
46+
HailData.MODE_ISLAND_HIDE -> HIsland.setAppHidden(packageName, frozen)
47+
HailData.MODE_ISLAND_SUSPEND -> HIsland.setAppSuspended(packageName, frozen)
4548
else -> false
4649
}
4750

app/src/main/kotlin/com/aistra/hail/app/HailData.kt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ object HailData {
3232
const val DHIZUKU = "dhizuku_"
3333
const val SU = "su_"
3434
const val SHIZUKU = "shizuku_"
35+
const val ISLAND = "island_"
3536
const val DISABLE = "disable"
3637
const val HIDE = "hide"
3738
const val SUSPEND = "suspend"
@@ -45,6 +46,8 @@ object HailData {
4546
const val MODE_SHIZUKU_DISABLE = SHIZUKU + DISABLE
4647
const val MODE_SHIZUKU_HIDE = SHIZUKU + HIDE
4748
const val MODE_SHIZUKU_SUSPEND = SHIZUKU + SUSPEND
49+
const val MODE_ISLAND_HIDE = ISLAND + HIDE
50+
const val MODE_ISLAND_SUSPEND = ISLAND + SUSPEND
4851
private const val TILE_ACTION = "tile_action"
4952
const val DYNAMIC_SHORTCUT_ACTION = "dynamic_shortcut_action"
5053
const val ACTION_NONE = "none"

app/src/main/kotlin/com/aistra/hail/extensions/ViewExtensions.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ val View.isRtl get() = layoutDirection == View.LAYOUT_DIRECTION_RTL
99

1010
/**
1111
* Very easy to apply insets to a view.
12-
* */
12+
*/
1313
fun View.applyInsetsPadding(
1414
start: Boolean = false,
1515
end: Boolean = false,

app/src/main/kotlin/com/aistra/hail/ui/home/PagerFragment.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,8 @@ import com.aistra.hail.app.HailApi.addTag
2626
import com.aistra.hail.app.HailData
2727
import com.aistra.hail.databinding.DialogInputBinding
2828
import com.aistra.hail.databinding.FragmentPagerBinding
29+
import com.aistra.hail.extensions.applyInsetsPadding
30+
import com.aistra.hail.extensions.isLandscape
2931
import com.aistra.hail.ui.main.MainFragment
3032
import com.aistra.hail.utils.FuzzySearch
3133
import com.aistra.hail.utils.HPackages
@@ -89,6 +91,12 @@ class PagerFragment : MainFragment(), PagerAdapter.OnItemClickListener,
8991
}
9092
}
9193
})
94+
95+
this.applyInsetsPadding(
96+
start = !activity.isLandscape,
97+
end = true,
98+
bottom = activity.isLandscape
99+
)
92100
}
93101
binding.refresh.setOnRefreshListener {
94102
updateCurrentList()

app/src/main/kotlin/com/aistra/hail/ui/settings/SettingsFragment.kt

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import android.os.Bundle
66
import android.provider.Settings
77
import android.view.*
88
import android.widget.FrameLayout
9+
import androidx.activity.result.contract.ActivityResultContracts
910
import androidx.appcompat.content.res.AppCompatResources
1011
import androidx.core.app.NotificationManagerCompat
1112
import androidx.core.view.MenuHost
@@ -42,6 +43,7 @@ import rikka.shizuku.Shizuku
4243

4344
class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener,
4445
MenuProvider {
46+
private val requestPermissionLauncher = registerForActivityResult(ActivityResultContracts.RequestPermission()) {}
4547
override fun onCreateView(
4648
inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?
4749
): View {
@@ -292,6 +294,27 @@ class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChan
292294
HUI.showToast(R.string.shizuku_missing)
293295
false
294296
}
297+
298+
mode.startsWith(HailData.ISLAND) -> return runCatching{
299+
when{
300+
mode == HailData.MODE_ISLAND_HIDE && HIsland.freezePermissionGranted() -> true
301+
mode == HailData.MODE_ISLAND_SUSPEND && HIsland.suspendPermissionGranted() -> true
302+
else -> {
303+
lifecycleScope.launch {
304+
requestPermissionLauncher.launch(if(mode == HailData.MODE_ISLAND_HIDE)
305+
HIsland.PERMISSION_FREEZE_PACKAGE
306+
else
307+
HIsland.PERMISSION_SUSPEND_PACKAGE
308+
)
309+
}
310+
false
311+
}
312+
}
313+
}.getOrElse {
314+
HLog.e(it)
315+
HUI.showToast(R.string.permission_denied)
316+
false
317+
}
295318
}
296319

297320
return true

app/src/main/kotlin/com/aistra/hail/utils/FuzzySearch.kt

Lines changed: 15 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -2,64 +2,36 @@ package com.aistra.hail.utils
22

33
import org.apache.commons.text.similarity.LevenshteinDistance
44

5-
/**使用莱文斯坦距离 (Levenshtein distance)实现模糊搜索*/
5+
/** 使用莱文斯坦距离 (Levenshtein distance) 实现模糊搜索 */
66
object FuzzySearch {
7-
private val levenshteinDistance: LevenshteinDistance = LevenshteinDistance()
7+
private val levenshteinDistance = LevenshteinDistance()
88

99
/**
10-
* 两个字符串差异小于搜索字符串长度 且 搜索字符全部包含在搜索字符串中 则显示在搜索结果中
11-
* @param textToSearch 尝试匹配的字符串
12-
* @param query 用户输入字符串
13-
* */
14-
fun search(textToSearch: String?, query: String?): Boolean {
15-
if (query.isNullOrEmpty()) {
16-
return true
17-
}
18-
if (textToSearch.isNullOrEmpty()) {
19-
return false
20-
}
21-
if (textToSearch.contains(query, true)) {
22-
return true
23-
}
24-
val textToSearchUpp = textToSearch.uppercase()
10+
* 两个字符串差异小于原始字符串长度 且 原始字符串依次包含输入字符串的每个字符 则显示在搜索结果中
11+
* @param raw 需要匹配的原始字符串
12+
* @param query 输入的字符串
13+
*/
14+
fun search(raw: String?, query: String?): Boolean {
15+
if (query.isNullOrEmpty()) return true
16+
if (raw.isNullOrEmpty()) return false
17+
if (raw.contains(query, true)) return true
18+
val rawUpp = raw.uppercase()
2519
val queryUpp = query.uppercase()
26-
val diff = levenshteinDistance.apply(textToSearchUpp, queryUpp)
27-
val lenTextToSearch = textToSearchUpp.length
28-
return diff < lenTextToSearch && containsInOrder(textToSearchUpp, queryUpp)
20+
val diff = levenshteinDistance.apply(rawUpp, queryUpp)
21+
return diff < rawUpp.length && containsInOrder(rawUpp, queryUpp)
2922
}
3023

31-
/**
32-
* 判断一个字符串A是否依次包含另一个字符串B的每个字符,并且这些字符是按顺序从A的开头开始的
33-
* @param strA
34-
* @param strB
35-
* */
24+
/** 判断字符串A是否依次包含字符串B的每个字符 */
3625
private fun containsInOrder(strA: String, strB: String): Boolean {
3726
var indexA = 0 // 用于跟踪字符串A中的位置
3827
for (charB in strB) {
3928
// 在字符串A的当前位置之后查找字符charB
4029
val foundIndex = strA.indexOf(charB, indexA)
4130
// 如果未找到字符或者字符的位置不是当前位置,表示不包含按顺序的字符
42-
if (foundIndex == -1) {
43-
return false
44-
}
31+
if (foundIndex == -1) return false
4532
// 移动到下一个位置,以便查找下一个字符
4633
indexA = foundIndex + 1
4734
}
4835
return true
4936
}
50-
51-
private fun assertTrue(res: Boolean) {
52-
if (!res){
53-
throw RuntimeException("测试失败!")
54-
}
55-
}
56-
57-
@JvmStatic
58-
fun main(args: Array<String>) {
59-
assertTrue(search("支付宝", ""))
60-
assertTrue(search("World Peace", "wp"))
61-
assertTrue(search("World Peace", "pee"))
62-
assertTrue(!search("World Peace", "dow"))
63-
assertTrue(containsInOrder("小费计算器", "小器"))
64-
}
6537
}
Lines changed: 77 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package com.aistra.hail.utils
2+
3+
import android.app.Activity
4+
import android.app.PendingIntent
5+
import android.content.BroadcastReceiver
6+
import android.content.Context
7+
import android.content.Intent
8+
import android.content.pm.PackageManager
9+
import android.net.Uri
10+
import android.os.Handler
11+
import android.os.HandlerThread
12+
import androidx.core.content.ContextCompat
13+
import com.aistra.hail.HailApp.Companion.app
14+
import kotlinx.coroutines.CompletableDeferred
15+
import kotlinx.coroutines.runBlocking
16+
import kotlinx.coroutines.withTimeout
17+
18+
object HIsland {
19+
const val PERMISSION_FREEZE_PACKAGE = "com.oasisfeng.island.permission.FREEZE_PACKAGE"
20+
const val PERMISSION_SUSPEND_PACKAGE = "com.oasisfeng.island.permission.SUSPEND_PACKAGE"
21+
private const val ACTION_SUSPEND = "com.oasisfeng.island.action.SUSPEND"
22+
private const val ACTION_UNSUSPEND = "com.oasisfeng.island.action.UNSUSPEND"
23+
private const val ACTION_FREEZE = "com.oasisfeng.island.action.FREEZE"
24+
private const val ACTION_UNFREEZE = "com.oasisfeng.island.action.UNFREEZE"
25+
private const val EXTRA_CALLER_ID = "caller"
26+
27+
private val thread by lazy { HandlerThread("HIsland").apply { start() } }
28+
private val handler by lazy { Handler(thread.looper) }
29+
30+
fun freezePermissionGranted(): Boolean {
31+
return ContextCompat.checkSelfPermission(
32+
app, PERMISSION_FREEZE_PACKAGE
33+
) == PackageManager.PERMISSION_GRANTED
34+
}
35+
36+
fun suspendPermissionGranted(): Boolean {
37+
return ContextCompat.checkSelfPermission(
38+
app, PERMISSION_SUSPEND_PACKAGE
39+
) == PackageManager.PERMISSION_GRANTED
40+
}
41+
42+
private fun setAppFrozen(packageName: String, action: String): Boolean {
43+
val intent = Intent(action).apply {
44+
data = Uri.fromParts("package", packageName, null)
45+
setPackage("com.oasisfeng.island")
46+
addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
47+
putExtra(
48+
EXTRA_CALLER_ID,
49+
PendingIntent.getActivity(app, 0, Intent(), PendingIntent.FLAG_IMMUTABLE)
50+
)
51+
}
52+
val result = CompletableDeferred<Boolean>()
53+
app.sendOrderedBroadcast(
54+
intent, null, object : BroadcastReceiver() {
55+
override fun onReceive(context: Context, intent: Intent) {
56+
if (resultCode != Activity.RESULT_OK) {
57+
HLog.i("HIsland", resultData)
58+
}
59+
result.complete(resultCode == Activity.RESULT_OK)
60+
}
61+
}, handler, Activity.RESULT_OK, null, null
62+
)
63+
return runBlocking {
64+
runCatching {
65+
withTimeout(500L) {
66+
result.await()
67+
}
68+
}.getOrElse { false }
69+
}
70+
}
71+
72+
fun setAppHidden(packageName: String, hidden: Boolean): Boolean =
73+
HTarget.N && setAppFrozen(packageName, if (hidden) ACTION_FREEZE else ACTION_UNFREEZE)
74+
75+
fun setAppSuspended(packageName: String, suspended: Boolean): Boolean =
76+
HTarget.N && setAppFrozen(packageName, if (suspended) ACTION_SUSPEND else ACTION_UNSUSPEND)
77+
}

0 commit comments

Comments
 (0)