Skip to content

Commit

Permalink
Merge branch 'master' into whp98
Browse files Browse the repository at this point in the history
  • Loading branch information
whp98 committed Oct 21, 2023
2 parents ded93e2 + 3e35fed commit 838b237
Show file tree
Hide file tree
Showing 16 changed files with 189 additions and 101 deletions.
8 changes: 4 additions & 4 deletions app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ val props =
val keyStoreFile = file(signFolder + props.getProperty("storeFile"))
android {
namespace = "com.aistra.hail"
compileSdk = 33
compileSdk = 34

defaultConfig {
applicationId = "com.aistra.hail"
Expand Down Expand Up @@ -66,7 +66,6 @@ android {
}

dependencies {
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("androidx.core:core-ktx:1.9.0")
implementation("androidx.appcompat:appcompat:1.6.1")
implementation("androidx.biometric:biometric:1.1.0")
Expand All @@ -76,13 +75,14 @@ dependencies {
implementation("androidx.preference:preference-ktx:1.2.0")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")
implementation("androidx.work:work-runtime-ktx:2.8.1")
implementation("com.belerweb:pinyin4j:2.5.1")
implementation("com.google.android.material:material:1.9.0")
implementation("dev.rikka.rikkax.preference:simplemenu-preference:1.0.3")
implementation("dev.rikka.shizuku:api:13.1.4")
implementation("dev.rikka.shizuku:provider:13.1.4")
implementation("io.github.iamr0s:Dhizuku-API:2.4")
implementation("me.zhanghai.android.appiconloader:appiconloader:1.5.0")
implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
implementation("com.belerweb:pinyin4j:2.5.1")
implementation("org.apache.commons:commons-text:1.10.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("org.lsposed.hiddenapibypass:hiddenapibypass:4.3")
}
2 changes: 2 additions & 0 deletions app/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@
android:name="android.permission.PACKAGE_USAGE_STATS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="com.oasisfeng.island.permission.FREEZE_PACKAGE"/>
<uses-permission android:name="com.oasisfeng.island.permission.SUSPEND_PACKAGE"/>

<application
android:name=".HailApp"
Expand Down
3 changes: 3 additions & 0 deletions app/src/main/kotlin/com/aistra/hail/app/AppManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package com.aistra.hail.app
import android.content.Intent
import com.aistra.hail.BuildConfig
import com.aistra.hail.utils.HDhizuku
import com.aistra.hail.utils.HIsland
import com.aistra.hail.utils.HPackages
import com.aistra.hail.utils.HPolicy
import com.aistra.hail.utils.HShell
Expand Down Expand Up @@ -42,6 +43,8 @@ object AppManager {
HailData.MODE_SHIZUKU_DISABLE -> 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
}

Expand Down
3 changes: 3 additions & 0 deletions app/src/main/kotlin/com/aistra/hail/app/HailData.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ val View.isRtl get() = layoutDirection == View.LAYOUT_DIRECTION_RTL

/**
* Very easy to apply insets to a view.
* */
*/
fun View.applyInsetsPadding(
start: Boolean = false,
end: Boolean = false,
Expand Down
8 changes: 8 additions & 0 deletions app/src/main/kotlin/com/aistra/hail/ui/home/PagerFragment.kt
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import com.aistra.hail.app.HailApi.addTag
import com.aistra.hail.app.HailData
import com.aistra.hail.databinding.DialogInputBinding
import com.aistra.hail.databinding.FragmentPagerBinding
import com.aistra.hail.extensions.applyInsetsPadding
import com.aistra.hail.extensions.isLandscape
import com.aistra.hail.ui.main.MainFragment
import com.aistra.hail.utils.FuzzySearch
import com.aistra.hail.utils.HPackages
Expand Down Expand Up @@ -89,6 +91,12 @@ class PagerFragment : MainFragment(), PagerAdapter.OnItemClickListener,
}
}
})

this.applyInsetsPadding(
start = !activity.isLandscape,
end = true,
bottom = activity.isLandscape
)
}
binding.refresh.setOnRefreshListener {
updateCurrentList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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
Expand Down
58 changes: 15 additions & 43 deletions app/src/main/kotlin/com/aistra/hail/utils/FuzzySearch.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,64 +2,36 @@ package com.aistra.hail.utils

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

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

/**
* 两个字符串差异小于搜索字符串长度 且 搜索字符全部包含在搜索字符串中 则显示在搜索结果中
* @param textToSearch 尝试匹配的字符串
* @param query 用户输入字符串
* */
fun search(textToSearch: String?, query: String?): Boolean {
if (query.isNullOrEmpty()) {
return true
}
if (textToSearch.isNullOrEmpty()) {
return false
}
if (textToSearch.contains(query, true)) {
return true
}
val textToSearchUpp = textToSearch.uppercase()
* 两个字符串差异小于原始字符串长度 且 原始字符串依次包含输入字符串的每个字符 则显示在搜索结果中
* @param raw 需要匹配的原始字符串
* @param query 输入的字符串
*/
fun search(raw: String?, query: String?): Boolean {
if (query.isNullOrEmpty()) return true
if (raw.isNullOrEmpty()) return false
if (raw.contains(query, true)) return true
val rawUpp = raw.uppercase()
val queryUpp = query.uppercase()
val diff = levenshteinDistance.apply(textToSearchUpp, queryUpp)
val lenTextToSearch = textToSearchUpp.length
return diff < lenTextToSearch && containsInOrder(textToSearchUpp, queryUpp)
val diff = levenshteinDistance.apply(rawUpp, queryUpp)
return diff < rawUpp.length && containsInOrder(rawUpp, queryUpp)
}

/**
* 判断一个字符串A是否依次包含另一个字符串B的每个字符,并且这些字符是按顺序从A的开头开始的
* @param strA
* @param strB
* */
/** 判断字符串A是否依次包含字符串B的每个字符 */
private fun containsInOrder(strA: String, strB: String): Boolean {
var indexA = 0 // 用于跟踪字符串A中的位置
for (charB in strB) {
// 在字符串A的当前位置之后查找字符charB
val foundIndex = strA.indexOf(charB, indexA)
// 如果未找到字符或者字符的位置不是当前位置,表示不包含按顺序的字符
if (foundIndex == -1) {
return false
}
if (foundIndex == -1) return false
// 移动到下一个位置,以便查找下一个字符
indexA = foundIndex + 1
}
return true
}

private fun assertTrue(res: Boolean) {
if (!res){
throw RuntimeException("测试失败!")
}
}

@JvmStatic
fun main(args: Array<String>) {
assertTrue(search("支付宝", ""))
assertTrue(search("World Peace", "wp"))
assertTrue(search("World Peace", "pee"))
assertTrue(!search("World Peace", "dow"))
assertTrue(containsInOrder("小费计算器", "小器"))
}
}
77 changes: 77 additions & 0 deletions app/src/main/kotlin/com/aistra/hail/utils/HIsland.kt
Original file line number Diff line number Diff line change
@@ -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<Boolean>()
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)
}
Loading

0 comments on commit 838b237

Please sign in to comment.