Compare commits

..
Message SHA1
Fix Xposed module detection, add more packages to presets (thanks to ShirkNeko)
This version also contains translation updates

frknkrc44   authored and   Cuynu   commited 2025-09-16 23:44:40 +07:00
94fbc8babe
fix: strings.xml: duplicate strings
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-16 23:44:00 +07:00
53a85adbcd
Add risky package warning with bypass switch
frknkrc44   authored and   Cuynu   commited 2025-09-16 23:35:43 +07:00
3b1fb478ca
Fix a few crashes on search functions, remove useless permissions, update translations
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:49:46 +07:00
4942a02337
Optimize imports, try to add GitHub release support
This is not a code change release, so you can continue to use the previous version.

frknkrc44   authored and   Cuynu   commited 2025-09-16 22:49:35 +07:00
d9a8e0d5a9
Fix "Show presets" display language, fix freezing when loading preset details, update translations
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:49:08 +07:00
7d743b085e
Add "Show presets" option, fix backup/restore config buttons, update translations
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:48:58 +07:00
b51a3f695e
Prevent adding HMA-OSS to the scope, show info text in list the when app/scope list is empty, add working mode indicator to template settings
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:48:51 +07:00
11fc2fc206
Fix crash after editing uninstalled app config, update translations
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:48:41 +07:00
0b5935328e
Reflect indonesian translation changes (#7)
Change-Id: I9b00f45213e37169188aa25be8145840afcd5769

Neebe3289   authored and   Cuynu   commited 2025-09-16 22:47:37 +07:00
add8a2392c
Update Chinese translation (#5)
Chinese translation

idyll   authored and   Cuynu   commited 2025-09-16 22:46:56 +07:00
2302c77782
Revert channel message template to old one, improve multi-user support (WIP)
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:46:37 +07:00
7f21297ac9
Proper PT-BR (Brazilian Portuguese) translation (#2)
DanGLES3   authored and   Cuynu   commited 2025-09-16 22:44:59 +07:00
cb55dea35b
Import Indonesian strings.xml (#3)
Change-Id: Ica5a606007c75096124eab2a16b732e82fc6b334

Neebe3289   authored and   Cuynu   commited 2025-09-16 22:44:03 +07:00
cba451f01c
Update Japanese translation (#4)
* Update ja-rJP translation

* Fix minor Japanese translation

karigane   authored and   Cuynu   commited 2025-09-16 22:43:45 +07:00
fc89fe78ea
Fix signing info bug, simplify PmsHook, add caf and calyxos to custom ROM preset
frknkrc44   authored and   Cuynu   commited 2025-09-16 22:41:43 +07:00
8c1ea074e4
fix: WebViewPreset.kt: missing [,]
my eye issues

Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 15:00:10 +07:00
2891fc384f
fix: WebViewPreset.kt: wrong mulch webview packageName
my eye issues

Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 14:52:37 +07:00
0dee4195a7
chore: AboutActivity.kt: new fact about myself
this is true tho

Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 14:27:19 +07:00
0e10062bb9
Fix ReLSPosed module not activated issue
frknkrc44   authored and   Cuynu   commited 2025-09-08 14:13:34 +07:00
9f1dd0bb36
feat: about: move myself to fake dev category
im not a dev

Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 11:55:16 +07:00
91184f643f
feat: WebViewPreset.kt: add support for mulch webview
found on crdroid

Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 11:10:03 +07:00
ced2a93b48
feat: WebViewPreset.kt: new preset
this is weird preset, but useful for disabling ads on the MBBank/MBCP app

Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 01:58:41 +07:00
bdc2e446cb
Revert "Update Turkish translations (WIP) (#1)"
This reverts commit 4b8ce7737c.

Cuynu   commited 2025-09-08 01:08:13 +07:00
1180bd5899
Update Turkish translations (WIP) (#1)
* app/src/main/res: update values-tr-rTR strings.xml

Co-authored-by: cvnertnc <the.civanertunc@gmail.com>

* app: fixed values-tr-rTR strings.xml

Co-authored-by: cvnertnc <the.civanertunc@gmail.com>

cvnertnc   authored and   Cuynu   commited 2025-09-08 01:00:42 +07:00
4b8ce7737c
feat: add credit, links & translate strings in vietnamese
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-08 00:57:51 +07:00
aa72a2b5ea
feat: strings.xml: update vietnamese translation
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-07 06:58:03 +07:00
f61026feb6
Add spoofing for system apps too, also improve description of exclude option
frknkrc44   authored and   Cuynu   commited 2025-09-07 06:45:06 +07:00
1581e099f3
feat: strings.xml: update vietnamese translation
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-05 16:15:41 +07:00
f76df68fd0
chore: app_settings.xml: move preferences location
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-05 16:01:17 +07:00
2638d4e452
Add more checks for Play Store spoofing, add description for exclude option
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:34:05 +07:00
aa26ad5a72
Ignore presets for whitelist mode
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:33:55 +07:00
8a621958d5
Add new option to exclude the target app installation source spoofing, ignore invalid requests
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:33:45 +07:00
93da126d9b
Add a simple note to the Play Store spoofing for community
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:33:29 +07:00
ec60987a55
Try to fix the rotation crash
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:32:18 +07:00
c559b3f699
Add force stop required warning
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:32:00 +07:00
79636bc0dd
Add preset support for LineageOS overlays and EvoX (community request)
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:30:03 +07:00
60c657a8db
Add package installation info spoofer
It is similar to BKI, but it only spoofs for selected apps and it doesn't damage your packages list.

frknkrc44   authored and   Cuynu   commited 2025-09-05 15:29:10 +07:00
c45bc1fb83
Add counter for new hooks, refactor PmsHookTarget34 a bit
frknkrc44   authored and   Cuynu   commited 2025-09-05 15:23:26 +07:00
ee6e233152
feat: strings.xml: update vietnamese translation
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-09-01 15:43:42 +07:00
762e711de9
Changes for accessibility and content provider
- Remove the Settings Provider hook and switch to the ContentProvider$Transport hook
- Fix the accessibility manager hook

frknkrc44   authored and   Cuynu   commited 2025-09-01 15:33:43 +07:00
c0770cb5c0
fix: README.md: ugly markdown link
Signed-off-by: Cuynu <cuynu@proton.me>

Cuynu   commited 2025-08-29 23:21:26 +07:00
67e30fa6e4
67 changed files with 1696 additions and 595 deletions

View file

@ -1,6 +1,6 @@
# HMAL-OSS
Forked from [HMA-OSS]https://github.com/frknkrc44/HMA-OSS)
Forked from [HMA-OSS](https://github.com/frknkrc44/HMA-OSS)
[![License](https://img.shields.io/github/license/frknkrc44/HMA-OSS?label=License)](https://choosealicense.com/licenses/gpl-3.0/)

View file

@ -69,7 +69,7 @@ dependencies {
android.applicationVariants.all {
outputs.all {
(this as BaseVariantOutputImpl).apply {
outputFileName = "${rootProject.name.replace(" ", "_")}-v${versionName}-${buildType.name}.apk"
outputFileName = "${rootProject.name.replace(" ", "_")}-${versionName}-${buildType.name}.apk"
}
}
}

View file

@ -1,8 +1,3 @@
# Xposed
-keepclassmembers class icu.nullptr.hidemyapplist.MyApp {
boolean isHooked;
}
# Enum class
-keepclassmembers,allowoptimization enum * {
public static **[] values();

View file

@ -6,8 +6,6 @@
android:name="android.permission.QUERY_ALL_PACKAGES"
tools:ignore="PackageVisibilityPolicy,QueryAllPackagesPermission" />
<uses-permission android:name="android.permission.INTERNET" />
<application
android:name="icu.nullptr.hidemyapplist.MyApp"
android:allowBackup="true"

View file

@ -17,10 +17,6 @@ import kotlin.system.exitProcess
lateinit var hmaApp: MyApp
class MyApp : Application() {
@JvmField
var isHooked = false
val globalScope = CoroutineScope(Dispatchers.Default)
val appIconLoader by lazy {
val iconSize = resources.getDimensionPixelSize(R.dimen.app_icon_size)

View file

@ -12,6 +12,7 @@ import java.io.File
object ConfigManager {
data class TemplateInfo(val name: String?, val isWhiteList: Boolean)
data class PresetInfo(val name: String, val translation: String)
private const val TAG = "ConfigManager"
private lateinit var config: JsonConfig

View file

@ -19,6 +19,7 @@ object PrefManager {
private const val PREF_THEME_COLOR = "theme_color"
private const val PREF_HIDE_ICON = "hide_icon"
private const val PREF_BYPASS_RISKY_PACKAGE_WARNING = "bypass_risky_package_warning"
private const val PREF_APP_FILTER_SHOW_SYSTEM = "app_filter_show_system"
private const val PREF_APP_FILTER_SORT_METHOD = "app_filter_sort_method"
@ -67,6 +68,10 @@ object PrefManager {
hmaApp.packageManager.setComponentEnabledSetting(component, status, PackageManager.DONT_KILL_APP)
}
var bypassRiskyPackageWarning: Boolean
get() = pref.getBoolean(PREF_BYPASS_RISKY_PACKAGE_WARNING, false)
set(value) = pref.edit().putBoolean(PREF_BYPASS_RISKY_PACKAGE_WARNING, value).apply()
var appFilter_showSystem: Boolean
get() = pref.getBoolean(PREF_APP_FILTER_SHOW_SYSTEM, false)
set(value) = pref.edit().putBoolean(PREF_APP_FILTER_SHOW_SYSTEM, value).apply()

View file

@ -88,6 +88,9 @@ object ServiceClient : IHMAService, IBinder.DeathRecipient {
getServiceLegacy()?.handlePackageEvent(eventType, packageName)
}
override fun getPackagesForPreset(presetName: String) =
getServiceLegacy()?.getPackagesForPreset(presetName)
override fun syncConfig(json: String) {
getServiceLegacy()?.syncConfig(json)
}

View file

@ -22,6 +22,10 @@ class AboutActivity : AbsAboutActivity() {
}
override fun onItemsCreated(items: MutableList<Any>) {
items.add(Category(getString(R.string.about_mychanges_title)))
items.add(Card(getString(R.string.about_mychanges_summary)))
items.add(Category(getString(R.string.title_about_fork)))
items.add(Card(getString(R.string.about_fork_description)))
@ -46,10 +50,12 @@ class AboutActivity : AbsAboutActivity() {
items.add(Line())
items.add(Contributor(R.drawable.cont_cpp_master, "LoveSy", "Idea provider", "https://github.com/yujincheng08"))
items.add(Category(getString(R.string.about_fakedev)))
items.add(Contributor(R.drawable.cont_cuynu, "Cuynu", "another loser with no coding skills", "https://git.disroot.org/cuynu"))
items.add(Category(getString(R.string.about_support)))
items.add(Card("Github\nhttps://github.com/frknkrc44/HMA-OSS"))
items.add(Line())
items.add(Card("Telegram\nhttps://t.me/aerathfuns"))
items.add(Card("Disroot\nhttps://git.disroot.org/cuynu/HMAL-OSS"))
items.add(Category(getString(R.string.about_open_source)))
items.add(License("MultiType", "drakeet", License.APACHE_2, "https://github.com/drakeet/MultiType"))

View file

@ -1,16 +1,35 @@
package icu.nullptr.hidemyapplist.ui.adapter
import android.view.ViewGroup
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import icu.nullptr.hidemyapplist.common.Constants.GMS_PACKAGE_NAME
import icu.nullptr.hidemyapplist.common.Constants.GSF_PACKAGE_NAME
import icu.nullptr.hidemyapplist.service.ConfigManager
import icu.nullptr.hidemyapplist.service.PrefManager
import icu.nullptr.hidemyapplist.ui.view.AppItemView
import org.frknkrc44.hma_oss.R
class AppManageAdapter(
private val onItemClickListener: (String) -> Unit
) : AppSelectAdapter() {
private val riskyPackages = arrayOf(GMS_PACKAGE_NAME, GSF_PACKAGE_NAME)
inner class ViewHolder(view: AppItemView) : AppSelectAdapter.ViewHolder(view) {
init {
view.setOnClickListener {
if (!PrefManager.bypassRiskyPackageWarning && riskyPackages.contains(view.binding.packageName.text)) {
MaterialAlertDialogBuilder(view.context)
.setTitle(R.string.app_warning_risky_package_title)
.setMessage(R.string.app_warning_risky_package_desc)
.setNegativeButton(android.R.string.cancel, null)
.setPositiveButton(android.R.string.ok) { _, _ ->
onItemClickListener.invoke(filteredList[absoluteAdapterPosition])
}
.show()
return@setOnClickListener
}
onItemClickListener.invoke(filteredList[absoluteAdapterPosition])
}
}

View file

@ -8,6 +8,7 @@ import icu.nullptr.hidemyapplist.ui.view.AppItemView
import icu.nullptr.hidemyapplist.util.PackageHelper
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.runBlocking
import org.frknkrc44.hma_oss.BuildConfig
abstract class AppSelectAdapter(
private val firstFilter: ((String) -> Boolean)? = null
@ -20,13 +21,15 @@ abstract class AppSelectAdapter(
private inner class AppFilter : Filter() {
override fun performFiltering(constraint: CharSequence): FilterResults {
return runBlocking {
val constraintLowered = constraint.toString().lowercase()
val constraintLowered = constraint.toString().trim().lowercase()
val filteredList = PackageHelper.appList.first().filter {
if (firstFilter?.invoke(it) == false) return@filter false
if (!PrefManager.appFilter_showSystem && PackageHelper.isSystem(it)) return@filter false
if (it == BuildConfig.APPLICATION_ID &&
(this@AppSelectAdapter.javaClass == AppManageAdapter::class.java ||
(this@AppSelectAdapter.javaClass == AppScopeAdapter::class.java && firstFilter != null))) return@filter false
val label = PackageHelper.loadAppLabel(it)
val packageInfo = PackageHelper.loadPackageInfo(it)
label.lowercase().contains(constraintLowered) || packageInfo.packageName.lowercase().contains(constraintLowered)
label.lowercase().contains(constraintLowered) || it.lowercase().contains(constraintLowered)
}
FilterResults().also { it.values = filteredList }
@ -35,8 +38,11 @@ abstract class AppSelectAdapter(
@Suppress("UNCHECKED_CAST", "NotifyDataSetChanged")
override fun publishResults(constraint: CharSequence, results: FilterResults) {
filteredList = results.values as List<String>
notifyDataSetChanged()
val values = results.values
if (values != null) {
filteredList = values as List<String>
notifyDataSetChanged()
}
}
}

View file

@ -5,12 +5,14 @@ import android.os.Bundle
import android.view.MenuItem
import android.view.View
import android.view.WindowInsets
import android.widget.TextView
import androidx.activity.addCallback
import androidx.appcompat.widget.SearchView
import androidx.fragment.app.Fragment
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import by.kirich1409.viewbindingdelegate.viewBinding
import icu.nullptr.hidemyapplist.service.PrefManager
import icu.nullptr.hidemyapplist.ui.adapter.AppSelectAdapter
@ -20,10 +22,11 @@ import icu.nullptr.hidemyapplist.util.PackageHelper
import kotlinx.coroutines.launch
import org.frknkrc44.hma_oss.R
import org.frknkrc44.hma_oss.databinding.FragmentAppSelectBinding
import org.frknkrc44.hma_oss.ui.fragment.AppPresetFragment
abstract class AppSelectFragment : Fragment(R.layout.fragment_app_select) {
private val binding by viewBinding<FragmentAppSelectBinding>()
protected val binding by viewBinding<FragmentAppSelectBinding>()
protected abstract val firstComparator: Comparator<String>
protected abstract val adapter: AppSelectAdapter
@ -34,17 +37,21 @@ abstract class AppSelectFragment : Fragment(R.layout.fragment_app_select) {
navController.navigateUp()
}
private fun applyFilter() {
protected fun applyFilter() {
adapter.filter.filter(search)
}
private fun sortList() {
protected open fun sortList() {
lifecycleScope.launch {
PackageHelper.sortList(firstComparator)
applyFilter()
}
}
open fun invalidateCache() {
PackageHelper.invalidateCache()
}
private fun onMenuOptionSelected(item: MenuItem) {
when (item.itemId) {
R.id.menu_show_system -> {
@ -75,11 +82,13 @@ abstract class AppSelectFragment : Fragment(R.layout.fragment_app_select) {
sortList()
}
open fun getFragmentTitle() = getString(R.string.title_app_select)
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { onBack() }
setupToolbar(
toolbar = binding.toolbar,
title = getString(R.string.title_app_select),
title = getFragmentTitle(),
navigationIcon = R.drawable.baseline_arrow_back_24,
navigationOnClick = { onBack() },
menuRes = R.menu.menu_app_list,
@ -110,9 +119,16 @@ abstract class AppSelectFragment : Fragment(R.layout.fragment_app_select) {
binding.list.layoutManager = LinearLayoutManager(context)
binding.list.adapter = adapter
binding.swipeRefresh.setOnRefreshListener {
PackageHelper.invalidateCache()
invalidateCache()
}
adapter.registerAdapterDataObserver(
EmptyDataObserver(
binding.list,
binding.listEmptyContainer
)
)
lifecycleScope.launch {
PackageHelper.isRefreshing
.flowWithLifecycle(lifecycle)
@ -123,23 +139,66 @@ abstract class AppSelectFragment : Fragment(R.layout.fragment_app_select) {
sortList()
val insets = binding.root.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
binding.root.setOnApplyWindowInsetsListener { v, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
}
insets
}
}
// Credit: https://medium.com/nerd-for-tech/empty-dataset-in-recyclerview-ad86833dd5c6
inner class EmptyDataObserver(
private val recyclerView: RecyclerView,
private val emptyView: View
): RecyclerView.AdapterDataObserver() {
private val fragmentType by lazy {
when(this@AppSelectFragment.javaClass) {
ScopeFragment::class.java -> 0
AppPresetFragment::class.java -> 1
else -> 2
}
}
val atLeastEntryCount: Int get() {
if (!search.isBlank()) return 0
return if (fragmentType < 2) 1 else 2
}
private fun checkIfEmpty() {
val emptyViewVisible = recyclerView.adapter!!.itemCount < atLeastEntryCount
emptyView.visibility = if (emptyViewVisible) View.VISIBLE else View.GONE
if (emptyViewVisible) {
emptyView.findViewById<TextView>(R.id.list_empty_text).text = getString(
when (fragmentType) {
0 -> R.string.list_empty_no_enabled
1 -> R.string.list_empty_preset
else -> R.string.list_empty_no_apps
}
)
}
recyclerView.visibility = if (emptyViewVisible) View.GONE else View.VISIBLE
}
override fun onChanged() {
super.onChanged()
checkIfEmpty()
}
}
}

View file

@ -5,6 +5,7 @@ import android.os.Build
import android.os.Bundle
import android.view.View
import android.view.WindowInsets
import android.widget.Toast
import androidx.activity.addCallback
import androidx.core.graphics.drawable.toDrawable
import androidx.fragment.app.Fragment
@ -76,23 +77,26 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
.commit()
}
val insets = binding.root.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
binding.root.setOnApplyWindowInsetsListener { v, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
}
insets
}
}
@ -103,6 +107,9 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
"enableHide" -> pack.enabled
"useWhiteList" -> pack.config.useWhitelist
"excludeSystemApps" -> pack.config.excludeSystemApps
"hideInstallationSource" -> pack.config.hideInstallationSource
"hideSystemInstallationSource" -> pack.config.hideSystemInstallationSource
"excludeTargetInstallationSource" -> pack.config.excludeTargetInstallationSource
else -> throw IllegalArgumentException("Invalid key: $key")
}
}
@ -112,6 +119,9 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
"enableHide" -> pack.enabled = value
"useWhiteList" -> pack.config.useWhitelist = value
"excludeSystemApps" -> pack.config.excludeSystemApps = value
"hideInstallationSource" -> pack.config.hideInstallationSource = value
"hideSystemInstallationSource" -> pack.config.hideSystemInstallationSource = value
"excludeTargetInstallationSource" -> pack.config.excludeTargetInstallationSource = value
else -> throw IllegalArgumentException("Invalid key: $key")
}
}
@ -152,6 +162,21 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
it.title = PackageHelper.loadAppLabel(pack.app)
it.summary = PackageHelper.loadPackageInfo(pack.app).packageName
}
findPreference<SwitchPreferenceCompat>("hideInstallationSource")?.setOnPreferenceChangeListener { _, newValue ->
Toast.makeText(requireContext(),
R.string.app_force_stop_warning, Toast.LENGTH_LONG).show()
true
}
findPreference<SwitchPreferenceCompat>("hideSystemInstallationSource")?.setOnPreferenceChangeListener { _, newValue ->
Toast.makeText(requireContext(),
R.string.app_force_stop_warning, Toast.LENGTH_LONG).show()
true
}
findPreference<SwitchPreferenceCompat>("excludeTargetInstallationSource")?.setOnPreferenceChangeListener { _, newValue ->
Toast.makeText(requireContext(),
R.string.app_force_stop_warning, Toast.LENGTH_LONG).show()
true
}
findPreference<SwitchPreferenceCompat>("useWhiteList")?.setOnPreferenceChangeListener { _, newValue ->
pack.config.applyTemplates.clear()
pack.config.extraAppList.clear()

View file

@ -143,23 +143,26 @@ class LogsFragment : Fragment(R.layout.fragment_logs) {
binding.list.addItemDecoration(DividerItemDecoration(requireContext(), DividerItemDecoration.VERTICAL))
updateLogs()
val insets = binding.root.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
binding.root.setOnApplyWindowInsetsListener { v, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
}
insets
}
}
}

View file

@ -57,23 +57,26 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
.commit()
}
val insets = binding.root.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
binding.root.setOnApplyWindowInsetsListener { v, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
}
insets
}
}
@ -94,6 +97,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
"blackDarkTheme" -> PrefManager.blackDarkTheme
"detailLog" -> ConfigManager.detailLog
"hideIcon" -> PrefManager.hideIcon
"bypassRiskyPackageWarning" -> PrefManager.bypassRiskyPackageWarning
"appDataIsolation" -> CommonUtils.isAppDataIsolationEnabled
"voldAppDataIsolation" -> CommonUtils.isVoldAppDataIsolationEnabled
"forceMountData" -> ConfigManager.forceMountData
@ -118,6 +122,7 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
"detailLog" -> ConfigManager.detailLog = value
"forceMountData" -> ConfigManager.forceMountData = value
"hideIcon" -> PrefManager.hideIcon = value
"bypassRiskyPackageWarning" -> PrefManager.bypassRiskyPackageWarning = value
"appDataIsolation" -> Unit
"voldAppDataIsolation" -> Unit
else -> throw IllegalArgumentException("Invalid key: $key")
@ -264,6 +269,11 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
configureDataIsolation()
findPreference<SwitchPreferenceCompat>("bypassRiskyPackageWarning")?.setOnPreferenceChangeListener { _, newValue ->
activity?.recreate()
true
}
findPreference<Preference>("stopSystemService")?.setOnPreferenceClickListener {
if (ServiceClient.serviceVersion != 0) {
MaterialAlertDialogBuilder(requireContext())

View file

@ -1,6 +1,5 @@
package icu.nullptr.hidemyapplist.ui.fragment
import android.graphics.Color
import android.os.Build
import android.os.Bundle
import android.view.View
@ -12,7 +11,6 @@ import androidx.fragment.app.setFragmentResultListener
import androidx.navigation.fragment.FragmentNavigatorExtras
import androidx.recyclerview.widget.LinearLayoutManager
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.android.material.transition.MaterialContainerTransform
import icu.nullptr.hidemyapplist.common.JsonConfig
import icu.nullptr.hidemyapplist.service.ConfigManager
import icu.nullptr.hidemyapplist.ui.adapter.TemplateAdapter
@ -26,14 +24,6 @@ class TemplateManageFragment : Fragment(R.layout.fragment_template_manage) {
private val binding by viewBinding<FragmentTemplateManageBinding>()
private val adapter = TemplateAdapter(this::navigateToSettings)
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.nav_host_fragment
scrimColor = Color.TRANSPARENT
}
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
setupToolbar(
toolbar = binding.toolbar,
@ -53,23 +43,26 @@ class TemplateManageFragment : Fragment(R.layout.fragment_template_manage) {
binding.templateList.layoutManager = LinearLayoutManager(context)
binding.templateList.adapter = adapter
val insets = binding.root.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
binding.root.setOnApplyWindowInsetsListener { v, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
}
insets
}
}

View file

@ -56,16 +56,6 @@ class TemplateSettingsFragment : Fragment(R.layout.fragment_template_settings) {
navController.navigateUp()
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
/*
sharedElementEnterTransition = MaterialContainerTransform().apply {
drawingViewId = R.id.nav_host_fragment
scrimColor = Color.TRANSPARENT
}
*/
}
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
requireActivity().onBackPressedDispatcher.addCallback(viewLifecycleOwner) { onBack(false) }
setupToolbar(
@ -80,6 +70,7 @@ class TemplateSettingsFragment : Fragment(R.layout.fragment_template_settings) {
)
binding.templateName.setText(viewModel.name)
binding.workMode.setText(if (viewModel.isWhiteList) R.string.whitelist else R.string.blacklist)
binding.templateName.addTextChangedListener { viewModel.name = it.toString() }
binding.targetApps.setOnClickListener {
setFragmentResultListener("app_select") { _, bundle ->
@ -119,23 +110,26 @@ class TemplateSettingsFragment : Fragment(R.layout.fragment_template_settings) {
}
}
val insets = binding.root.rootWindowInsets
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
binding.root.setOnApplyWindowInsetsListener { v, insets ->
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
val barInsets = insets.getInsets(WindowInsets.Type.systemBars())
binding.root.setPadding(
barInsets.left,
barInsets.top,
barInsets.right,
barInsets.bottom,
)
} else {
@Suppress("deprecation")
binding.root.setPadding(
insets.systemWindowInsetLeft,
insets.systemWindowInsetTop,
insets.systemWindowInsetRight,
insets.systemWindowInsetBottom,
)
}
insets
}
}
}

View file

@ -15,7 +15,7 @@ class AppItemView @JvmOverloads constructor(
defStyleRes: Int = 0
) : LinearLayout(context, attrs, defStyleAttr, defStyleRes) {
private val binding by viewBinding<AppItemViewBinding>(createMethod = CreateMethod.INFLATE)
val binding by viewBinding<AppItemViewBinding>(createMethod = CreateMethod.INFLATE)
var showEnabled: Boolean
get() = binding.enabled.visibility == VISIBLE
@ -35,7 +35,12 @@ class AppItemView @JvmOverloads constructor(
fun load(packageName: String) {
binding.packageName.text = packageName
binding.label.text = PackageHelper.loadAppLabel(packageName)
binding.icon.setImageBitmap(PackageHelper.loadAppIcon(packageName))
try {
binding.label.text = PackageHelper.loadAppLabel(packageName)
binding.icon.setImageBitmap(PackageHelper.loadAppIcon(packageName))
} catch (e: Throwable) {
binding.label.text = packageName
binding.icon.setImageResource(android.R.drawable.sym_def_app_icon)
}
}
}

View file

@ -26,11 +26,15 @@ object PackageHelper {
val icon: Bitmap
)
private object Comparators {
object Comparators {
val byLabel = Comparator<String> { o1, o2 ->
val n1 = loadAppLabel(o1).lowercase(Locale.getDefault())
val n2 = loadAppLabel(o2).lowercase(Locale.getDefault())
Collator.getInstance(Locale.getDefault()).compare(n1, n2)
try {
val n1 = loadAppLabel(o1).lowercase(Locale.getDefault())
val n2 = loadAppLabel(o2).lowercase(Locale.getDefault())
Collator.getInstance(Locale.getDefault()).compare(n1, n2)
} catch (_: Throwable) {
byPackageName.compare(o1, o2)
}
}
val byPackageName = Comparator<String> { o1, o2 ->
val n1 = o1.lowercase(Locale.getDefault())
@ -38,14 +42,22 @@ object PackageHelper {
Collator.getInstance(Locale.getDefault()).compare(n1, n2)
}
val byInstallTime = Comparator<String> { o1, o2 ->
val n1 = loadPackageInfo(o1).firstInstallTime
val n2 = loadPackageInfo(o2).firstInstallTime
n2.compareTo(n1)
try {
val n1 = loadPackageInfo(o1).firstInstallTime
val n2 = loadPackageInfo(o2).firstInstallTime
n2.compareTo(n1)
} catch (_: Throwable) {
byPackageName.compare(o1, o2)
}
}
val byUpdateTime = Comparator<String> { o1, o2 ->
val n1 = loadPackageInfo(o1).lastUpdateTime
val n2 = loadPackageInfo(o2).lastUpdateTime
n2.compareTo(n1)
try {
val n1 = loadPackageInfo(o1).lastUpdateTime
val n2 = loadPackageInfo(o2).lastUpdateTime
n2.compareTo(n1)
} catch (_: Throwable) {
byPackageName.compare(o1, o2)
}
}
}
@ -99,6 +111,10 @@ object PackageHelper {
mAppList.emit(list)
}
fun exists(packageName: String) = runBlocking {
packageCache.first().contains(packageName)
}
fun loadPackageInfo(packageName: String): PackageInfo = runBlocking {
packageCache.first()[packageName]!!.info
}

View file

@ -0,0 +1,74 @@
package org.frknkrc44.hma_oss.ui.adapter
import android.view.ViewGroup
import android.widget.Filter
import icu.nullptr.hidemyapplist.service.ServiceClient
import icu.nullptr.hidemyapplist.ui.adapter.AppSelectAdapter
import icu.nullptr.hidemyapplist.ui.view.AppItemView
import icu.nullptr.hidemyapplist.util.PackageHelper
import kotlinx.coroutines.runBlocking
class AppPresetAdapter(
private val presetName: String
) : AppSelectAdapter() {
var packages = mutableListOf<String>()
fun updateList() {
packages.clear()
packages += ServiceClient.getPackagesForPreset(presetName)?.toList() ?: listOf()
}
inner class ViewHolder(view: AppItemView) : AppSelectAdapter.ViewHolder(view) {
override fun bind(packageName: String) {
(itemView as AppItemView).let {
it.load(packageName)
it.alpha = if (!PackageHelper.exists(packageName)) 0.5f else 1.0f
}
}
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val view = AppItemView(parent.context, false)
view.layoutParams = ViewGroup.LayoutParams(
ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT
)
return ViewHolder(view)
}
private inner class PresetFilter : Filter() {
override fun performFiltering(constraint: CharSequence): FilterResults {
return runBlocking {
val constraintLowered = constraint.toString().trim().lowercase()
val filteredList = packages.filter {
if (constraintLowered.isEmpty()) return@filter true
if (it.lowercase().contains(constraintLowered)) return@filter true
try {
val label = PackageHelper.loadAppLabel(it)
return@filter label.lowercase().contains(constraintLowered)
} catch (e: Throwable) {
return@filter false
}
}
FilterResults().also { it.values = filteredList }
}
}
@Suppress("UNCHECKED_CAST", "NotifyDataSetChanged")
override fun publishResults(constraint: CharSequence, results: FilterResults) {
val values = results.values
if (values != null) {
filteredList = values as List<String>
notifyDataSetChanged()
}
}
}
private val mFilter = PresetFilter()
override fun getFilter(): Filter = mFilter
}

Some files were not shown because too many files have changed in this diff Show more