Several changes

- Add different launcher icons
- Improve input method preset
- Improve settings hiding
- Add new translations
- Add "Random SSAID" option in settings templates
- Other fixes and improvements
This commit is contained in:
Furkan Karcıoğlu 2025-12-01 22:02:52 +03:00 • committed by GitHub
commit 6466cfbea0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
57 changed files with 1398 additions and 267 deletions

View file

@ -38,6 +38,42 @@
</intent-filter>
</activity-alias>
<activity-alias
android:name=".MainActivityLauncherAlt"
android:exported="true"
android:enabled="false"
android:icon="@mipmap/ic_launcher_alt"
android:targetActivity="org.frknkrc44.hma_oss.ui.activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".MainActivityLauncherAlt2"
android:exported="true"
android:enabled="false"
android:icon="@mipmap/ic_launcher_alt_2"
android:targetActivity="org.frknkrc44.hma_oss.ui.activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<activity-alias
android:name=".MainActivityLauncherAlt3"
android:exported="true"
android:enabled="false"
android:icon="@mipmap/ic_launcher_alt_3"
android:targetActivity="org.frknkrc44.hma_oss.ui.activity.MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity-alias>
<provider
android:name="icu.nullptr.hidemyapplist.service.ServiceProvider"
android:authorities="${applicationId}.ServiceProvider"

Binary file not shown.

After

Width:  |  Height:  |  Size: 48 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 38 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

View file

@ -0,0 +1,10 @@
package icu.nullptr.hidemyapplist.data
import org.frknkrc44.hma_oss.BuildConfig
object AppConstants {
const val COMPONENT_NAME_DEFAULT = "${BuildConfig.APPLICATION_ID}.MainActivityLauncher"
const val COMPONENT_NAME_ALT = "${BuildConfig.APPLICATION_ID}.MainActivityLauncherAlt"
const val COMPONENT_NAME_ALT_2 = "${BuildConfig.APPLICATION_ID}.MainActivityLauncherAlt2"
const val COMPONENT_NAME_ALT_3 = "${BuildConfig.APPLICATION_ID}.MainActivityLauncherAlt3"
}

View file

@ -258,19 +258,39 @@ object ConfigManager {
fun clearUninstalledAppConfigs(onFinish: (success: Boolean) -> Unit) {
PackageHelper.invalidateCache { throwable ->
if (throwable == null) {
val markedToRemove = mutableListOf<String>()
// --- STEP 1: Clear uninstalled app configs ---
val scopeMarkedToRemove = mutableListOf<String>()
config.scope.keys.forEach { packageName ->
if (!PackageHelper.exists(packageName)) {
markedToRemove.add(packageName)
scopeMarkedToRemove.add(packageName)
}
}
if (markedToRemove.isNotEmpty()) {
markedToRemove.forEach { config.scope.remove(it) }
saveConfig()
if (scopeMarkedToRemove.isNotEmpty()) {
scopeMarkedToRemove.forEach { config.scope.remove(it) }
}
ServiceClient.log(Log.INFO, TAG, "Pruned ${markedToRemove.size} app config(s)")
// --- STEP 2: Clear uninstalled apps from templates ---
var cleanedAppCount = 0
config.templates.forEach { (key, value) ->
val newList = value.appList.mapNotNull { if (PackageHelper.exists(it)) it else null }.toSet()
val count = value.appList.size - newList.size
if (count > 0) {
cleanedAppCount += count
config.templates[key] = JsonConfig.Template(
isWhitelist = value.isWhitelist,
appList = newList
)
}
}
if (scopeMarkedToRemove.isNotEmpty() || cleanedAppCount > 0) {
ServiceClient.log(Log.INFO, TAG, "Pruned ${scopeMarkedToRemove.size} app config(s) and $cleanedAppCount app(s) from template(s)")
saveConfig()
} else {
ServiceClient.log(Log.INFO, TAG, "No actions are required")
}
onFinish(true)
} else {

View file

@ -5,8 +5,12 @@ import android.content.Context.MODE_PRIVATE
import android.content.pm.PackageManager
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.content.edit
import icu.nullptr.hidemyapplist.data.AppConstants
import icu.nullptr.hidemyapplist.hmaApp
import org.frknkrc44.hma_oss.BuildConfig
import icu.nullptr.hidemyapplist.ui.util.get
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.runBlocking
object PrefManager {
@ -21,7 +25,6 @@ object PrefManager {
private const val PREF_FOLLOW_SYSTEM_ACCENT = "follow_system_accent"
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"
@ -35,6 +38,7 @@ object PrefManager {
}
private val pref = hmaApp.getSharedPreferences("settings", MODE_PRIVATE)
val isLauncherIconInvisible = MutableSharedFlow<Boolean>(replay = 1)
var lastVersion: Int
get() = pref.getInt(PREF_LAST_VERSION, 0)
@ -69,14 +73,24 @@ object PrefManager {
set(value) = pref.edit { putString(PREF_THEME_COLOR, value) }
var hideIcon: Boolean
get() = pref.getBoolean(PREF_HIDE_ICON, false)
get() = isLauncherIconInvisible.get()
set(value) {
pref.edit { putBoolean(PREF_HIDE_ICON, value) }
val component = ComponentName(hmaApp, "${BuildConfig.APPLICATION_ID}.MainActivityLauncher")
val status =
if (value) PackageManager.COMPONENT_ENABLED_STATE_DISABLED
else PackageManager.COMPONENT_ENABLED_STATE_ENABLED
hmaApp.packageManager.setComponentEnabledSetting(component, status, PackageManager.DONT_KILL_APP)
val enabled = findEnabledAppComponent(hmaApp)
if (value && enabled != null) {
hmaApp.packageManager.setComponentEnabledSetting(
enabled,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
} else if (!value && enabled == null) {
hmaApp.packageManager.setComponentEnabledSetting(
ComponentName(hmaApp, AppConstants.COMPONENT_NAME_DEFAULT),
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
runBlocking { isLauncherIconInvisible.emit(value) }
}
var bypassRiskyPackageWarning: Boolean

View file

@ -8,7 +8,6 @@ import android.view.View
import android.view.WindowInsets
import android.widget.Toast
import androidx.activity.addCallback
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.isVisible
import androidx.fragment.app.Fragment
import androidx.fragment.app.clearFragmentResultListener
@ -192,7 +191,7 @@ class AppSettingsFragment : Fragment(R.layout.fragment_settings) {
preferenceManager.preferenceDataStore = AppPreferenceDataStore(pack)
setPreferencesFromResource(R.xml.app_settings, rootKey)
findPreference<Preference>("appInfo")?.let {
it.icon = PackageHelper.loadAppIcon(pack.app).toDrawable(resources)
it.icon = PackageHelper.loadAppIcon(pack.app)
it.title = PackageHelper.loadAppLabel(pack.app)
it.summary = pack.app
it.setOnPreferenceClickListener { pref ->

View file

@ -9,6 +9,7 @@ import android.view.WindowInsets
import androidx.appcompat.app.AppCompatDelegate
import androidx.core.net.toUri
import androidx.fragment.app.Fragment
import androidx.lifecycle.flowWithLifecycle
import androidx.lifecycle.lifecycleScope
import androidx.preference.ListPreference
import androidx.preference.Preference
@ -31,11 +32,14 @@ import icu.nullptr.hidemyapplist.ui.util.setupToolbar
import icu.nullptr.hidemyapplist.ui.util.showToast
import icu.nullptr.hidemyapplist.util.ConfigUtils.Companion.getLocale
import icu.nullptr.hidemyapplist.util.LangList
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
import icu.nullptr.hidemyapplist.util.SuUtils
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import org.frknkrc44.hma_oss.R
import org.frknkrc44.hma_oss.databinding.FragmentSettingsBinding
import org.frknkrc44.hma_oss.ui.activity.BaseActivity
import org.frknkrc44.hma_oss.ui.preference.AppIconPreference
import java.util.Locale
class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmentCompat.OnPreferenceStartFragmentCallback {
@ -53,6 +57,10 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
// isTitleCentered = true
}
runBlocking {
PrefManager.isLauncherIconInvisible.emit(findEnabledAppComponent(hmaApp) == null)
}
if (childFragmentManager.findFragmentById(R.id.settings_container) == null) {
childFragmentManager.beginTransaction()
.replace(R.id.settings_container, SettingsPreferenceFragment())
@ -315,6 +323,16 @@ class SettingsFragment : Fragment(R.layout.fragment_settings), PreferenceFragmen
}
}
lifecycleScope.launch {
PrefManager.isLauncherIconInvisible
.flowWithLifecycle(lifecycle)
.collect { _ ->
findPreference<AppIconPreference>("launcherIcon")?.apply {
updateHolder()
}
}
}
findPreference<Preference>("clearUninstalledPackageConfigs")?.apply {
setOnPreferenceClickListener {
MaterialAlertDialogBuilder(requireContext())

View file

@ -1,6 +1,9 @@
package icu.nullptr.hidemyapplist.ui.util
import android.content.ComponentName
import android.content.pm.ActivityInfo
import android.content.res.Resources
import kotlinx.coroutines.flow.MutableSharedFlow
import org.frknkrc44.hma_oss.R
fun Boolean.enabledString(resources: Resources, lower: Boolean = false): String {
@ -9,3 +12,7 @@ fun Boolean.enabledString(resources: Resources, lower: Boolean = false): String
return if (lower) returnedStr.lowercase() else returnedStr
}
fun ActivityInfo.asComponentName() = ComponentName(packageName, name)
fun <T> MutableSharedFlow<T>.get() = replayCache.first()

View file

@ -8,6 +8,7 @@ import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.annotation.StyleRes
import androidx.core.content.res.ResourcesCompat
import androidx.fragment.app.Fragment
import com.google.android.material.color.DynamicColors
import icu.nullptr.hidemyapplist.service.PrefManager
@ -129,4 +130,6 @@ object ThemeUtils {
}
fun Fragment.homeItemBackgroundColor(forceNoTrans: Boolean = false) = requireContext().homeItemBackgroundColor(forceNoTrans)
fun Int.asDrawable(context: Context) = ResourcesCompat.getDrawable(context.resources, this, context.theme)!!
}

View file

@ -38,7 +38,7 @@ class AppItemView @JvmOverloads constructor(
binding.packageName.text = packageName
try {
binding.label.text = PackageHelper.loadAppLabel(packageName)
binding.icon.setImageBitmap(PackageHelper.loadAppIcon(packageName))
binding.icon.setImageDrawable(PackageHelper.loadAppIcon(packageName))
} catch (e: Throwable) {
binding.label.text = packageName
binding.icon.setImageResource(android.R.drawable.sym_def_app_icon)

View file

@ -1,20 +1,27 @@
package icu.nullptr.hidemyapplist.util
import android.content.ComponentName
import android.content.Context
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.content.pm.PackageManager
import android.graphics.drawable.Drawable
import androidx.core.graphics.drawable.toDrawable
import icu.nullptr.hidemyapplist.common.Constants
import icu.nullptr.hidemyapplist.hmaApp
import icu.nullptr.hidemyapplist.service.ConfigManager
import icu.nullptr.hidemyapplist.service.PrefManager
import icu.nullptr.hidemyapplist.service.ServiceClient
import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.asDrawable
import icu.nullptr.hidemyapplist.ui.util.asComponentName
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.flow.MutableSharedFlow
import kotlinx.coroutines.flow.first
import kotlinx.coroutines.launch
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.withContext
import org.frknkrc44.hma_oss.BuildConfig
import org.frknkrc44.hma_oss.R
import java.text.Collator
import java.util.Locale
@ -22,7 +29,7 @@ object PackageHelper {
class PackageCache(
val info: PackageInfo,
val label: String,
val icon: Bitmap
val icon: Drawable
)
object Comparators {
@ -85,7 +92,7 @@ object PackageHelper {
if (packageInfo.packageName in Constants.packagesShouldNotHide) continue
packageInfo.applicationInfo?.let { appInfo ->
val label = pm.getApplicationLabel(appInfo).toString()
val icon = hmaApp.appIconLoader.loadIcon(appInfo)
val icon = loadAppIconFromAppInfo(appInfo)
it[packageInfo.packageName] = PackageCache(packageInfo, label, icon)
}
}
@ -97,7 +104,7 @@ object PackageHelper {
if (packageInfo.packageName in Constants.packagesShouldNotHide) continue
packageInfo.applicationInfo?.let { appInfo ->
val label = pm.getApplicationLabel(appInfo).toString()
val icon = hmaApp.appIconLoader.loadIcon(appInfo)
val icon = loadAppIconFromAppInfo(appInfo)
it[packageInfo.packageName] = PackageCache(packageInfo, label, icon)
}
}
@ -144,15 +151,33 @@ object PackageHelper {
getCacheNoThrow()[packageName]?.label ?: packageName
}
fun loadAppIcon(packageName: String): Bitmap = runBlocking {
fun loadAppIcon(packageName: String): Drawable = runBlocking {
getCacheNoThrow()[packageName]?.icon ?:
BitmapFactory.decodeResource(
hmaApp.resources,
android.R.drawable.sym_def_app_icon
)
android.R.drawable.sym_def_app_icon.asDrawable(hmaApp)
}
fun isSystem(packageName: String): Boolean = runBlocking {
getCacheNoThrow()[packageName]?.info?.applicationInfo?.flags?.and(ApplicationInfo.FLAG_SYSTEM) != 0
}
fun loadAppIconFromAppInfo(appInfo: ApplicationInfo): Drawable {
return if (appInfo.packageName == BuildConfig.APPLICATION_ID) {
val activityName = findEnabledAppComponent(hmaApp)
if (activityName == null) {
R.mipmap.ic_launcher.asDrawable(hmaApp)
} else {
hmaApp.packageManager.getActivityIcon(activityName)
}
} else {
hmaApp.appIconLoader.loadIcon(appInfo).toDrawable(hmaApp.resources)
}
}
fun findEnabledAppComponent(context: Context): ComponentName? {
with (context.packageManager) {
val pkgInfo = getPackageInfo(BuildConfig.APPLICATION_ID, PackageManager.GET_ACTIVITIES)!!
return pkgInfo.activities?.firstOrNull { it.targetActivity != null }?.asComponentName()
}
}
}

View file

@ -20,6 +20,7 @@ import com.bumptech.glide.Glide
import icu.nullptr.hidemyapplist.service.PrefManager
import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.homeItemBackgroundColor
import icu.nullptr.hidemyapplist.ui.util.navController
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
import org.frknkrc44.hma_oss.R
import org.frknkrc44.hma_oss.common.BuildConfig
import org.frknkrc44.hma_oss.databinding.FragmentAboutBinding
@ -67,10 +68,14 @@ class AboutFragment : Fragment(R.layout.fragment_about) {
backgroundTintList = tint
}
Glide.with(this@AboutFragment)
.load(R.mipmap.ic_launcher)
.circleCrop()
.into(appIcon)
Glide.with(this@AboutFragment).let {
val activityName = findEnabledAppComponent(requireContext())
return@let if (activityName == null) {
it.load(R.mipmap.ic_launcher)
} else {
it.load(requireContext().packageManager.getActivityIcon(activityName))
}
}.circleCrop().into(appIcon)
appName.setText(R.string.app_name)
appVersion.text = BuildConfig.APP_VERSION_NAME
@ -120,6 +125,7 @@ class AboutFragment : Fragment(R.layout.fragment_about) {
// HMA-OSS devs
with(binding.listHmaOss) {
addDevItem(this, R.drawable.cont_fk, "frknkrc44", "HMA-OSS Developer", "https://github.com/frknkrc44")
addDevItem(this, R.drawable.cont_oukaromf, "OukaroMF", "HMA-OSS Alt Icon Designer", "https://github.com/OukaroMF")
}
// Original HMA devs

View file

@ -9,12 +9,15 @@ import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResult
import androidx.navigation.fragment.navArgs
import by.kirich1409.viewbindingdelegate.viewBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.textfield.MaterialAutoCompleteTextView
import com.google.android.material.textfield.TextInputLayout
import icu.nullptr.hidemyapplist.common.Constants
import icu.nullptr.hidemyapplist.service.ServiceClient
import icu.nullptr.hidemyapplist.ui.util.get
import icu.nullptr.hidemyapplist.ui.util.navController
import icu.nullptr.hidemyapplist.ui.util.setupToolbar
import kotlinx.coroutines.flow.MutableSharedFlow
import org.frknkrc44.hma_oss.R
import org.frknkrc44.hma_oss.databinding.FragmentEditSettingBinding
@ -23,6 +26,8 @@ class EditSettingFragment : Fragment(R.layout.fragment_edit_setting) {
private val args by navArgs<EditSettingFragmentArgs>()
var settingsItems = MutableSharedFlow<Array<String>>(replay = 1)
fun saveResult() {
val databaseName = getEditTextValue(binding.databaseSelector)
val settingName = getEditTextValue(binding.settingName)
@ -83,6 +88,20 @@ class EditSettingFragment : Fragment(R.layout.fragment_edit_setting) {
}
}
with(binding.settingsGroupShowAll) {
setOnClickListener {
if (settingsItems.replayCache.isEmpty()) return@setOnClickListener
MaterialAlertDialogBuilder(requireContext())
.setTitle(R.string.settings_templates_name)
.setItems(settingsItems.get()) { _, which ->
binding.settingName.editText?.setText(settingsItems.get()[which])
}
.setNegativeButton(android.R.string.cancel, null)
.show()
}
}
with(binding.settingName.editText as MaterialAutoCompleteTextView) {
setText(args.name)
}
@ -126,9 +145,10 @@ class EditSettingFragment : Fragment(R.layout.fragment_edit_setting) {
fun fillSettingNames(databaseName: String) {
with(binding.settingName) {
isEnabled = true
(editText as MaterialAutoCompleteTextView).setSimpleItems(
ServiceClient.listAllSettings(databaseName)
)
settingsItems.tryEmit(ServiceClient.listAllSettings(databaseName))
(editText as MaterialAutoCompleteTextView).setSimpleItems(settingsItems.get())
}
}
}

View file

@ -1,11 +1,15 @@
package org.frknkrc44.hma_oss.ui.fragment
import android.provider.Settings
import android.view.MenuItem
import androidx.fragment.app.clearFragmentResultListener
import androidx.fragment.app.setFragmentResult
import androidx.fragment.app.setFragmentResultListener
import androidx.navigation.fragment.navArgs
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import icu.nullptr.hidemyapplist.common.Constants
import icu.nullptr.hidemyapplist.common.Utils.generateRandomHex
import icu.nullptr.hidemyapplist.common.settings_presets.ReplacementItem
import icu.nullptr.hidemyapplist.ui.util.navigate
import org.frknkrc44.hma_oss.R
import org.frknkrc44.hma_oss.ui.adapter.SettingsTemplateListAdapter
@ -53,8 +57,28 @@ class SettingsTemplateInnerFragment : BaseSettingsPTFragment() {
fun onMenuOptionSelected(item: MenuItem) {
when (item.itemId) {
R.id.menu_add -> {
val args = EditSettingFragmentArgs(database = null, name = "", value = null)
launchEditSettingFragment(args)
MaterialAlertDialogBuilder(requireContext()).apply {
setTitle(R.string.add)
setItems(R.array.settings_template_inner_add_texts) { dialog, which ->
when (which) {
0 -> {
val args = EditSettingFragmentArgs(database = null, name = "", value = null)
launchEditSettingFragment(args)
}
1 -> {
processIncomingSetting(
ReplacementItem(
name = Settings.Secure.ANDROID_ID,
value = generateRandomHex(16),
database = Constants.SETTINGS_SECURE,
)
)
}
}
dialog.dismiss()
}
}.show()
}
}
}
@ -62,19 +86,8 @@ class SettingsTemplateInnerFragment : BaseSettingsPTFragment() {
fun launchEditSettingFragment(args: EditSettingFragmentArgs) {
setFragmentResultListener("edit_setting") { _, bundle ->
fun deal() {
val item = bundle.toTargetSettingList().firstOrNull()
if (item != null) {
val index = adapter.items.indexOfFirst { it.name == item.name && it.database == item.database }
if (index >= 0) {
adapter.items[index] = item
adapter.notifyItemChanged(index)
} else {
adapter.items.add(item)
adapter.notifyItemInserted(adapter.items.size - 1)
}
}
val item = bundle.toTargetSettingList().firstOrNull() ?: return
processIncomingSetting(item)
}
deal()
clearFragmentResultListener("edit_setting")
@ -83,6 +96,18 @@ class SettingsTemplateInnerFragment : BaseSettingsPTFragment() {
navigate(R.id.nav_settings_templates_edit_setting, args.toBundle())
}
private fun processIncomingSetting(item: ReplacementItem) {
val index = adapter.items.indexOfFirst { it.name == item.name && it.database == item.database }
if (index >= 0) {
adapter.items[index] = item
adapter.notifyItemChanged(index)
} else {
adapter.items.add(item)
adapter.notifyItemInserted(adapter.items.size - 1)
}
}
override val menu = Pair(
R.menu.menu_settings_template,
this::onMenuOptionSelected,

View file

@ -0,0 +1,125 @@
package org.frknkrc44.hma_oss.ui.preference
import android.annotation.SuppressLint
import android.content.ComponentName
import android.content.Context
import android.content.pm.PackageManager
import android.util.AttributeSet
import android.view.Gravity
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RadioGroup
import android.widget.RelativeLayout
import androidx.appcompat.widget.AppCompatRadioButton
import androidx.preference.Preference
import androidx.preference.PreferenceViewHolder
import icu.nullptr.hidemyapplist.data.AppConstants
import icu.nullptr.hidemyapplist.ui.util.ThemeUtils.asDrawable
import icu.nullptr.hidemyapplist.util.PackageHelper.findEnabledAppComponent
import org.frknkrc44.hma_oss.BuildConfig
import org.frknkrc44.hma_oss.R
@Suppress("deprecation")
class AppIconPreference(context: Context, attrs: AttributeSet?) : Preference(context, attrs) {
val appIconsList = listOf(
R.mipmap.ic_launcher.asDrawable(context),
R.mipmap.ic_launcher_alt.asDrawable(context),
R.mipmap.ic_launcher_alt_2.asDrawable(context),
R.mipmap.ic_launcher_alt_3.asDrawable(context),
)
val allAppIcons = listOf(
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_DEFAULT),
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_ALT),
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_ALT_2),
ComponentName(BuildConfig.APPLICATION_ID, AppConstants.COMPONENT_NAME_ALT_3),
)
var viewHolder: PreferenceViewHolder? = null
@SuppressLint("SetTextI18n")
@Deprecated("Deprecated in Java")
override fun onBindViewHolder(holder: PreferenceViewHolder) {
viewHolder = holder
super.onBindViewHolder(holder)
updateHolder()
}
fun updateHolder() {
if (viewHolder == null) return
(viewHolder!!.itemView as ViewGroup).apply {
val summary = findViewById<View>(android.R.id.summary)
val parent = summary.parent as ViewGroup
parent.removeView(summary)
val view = LayoutInflater.from(context).inflate(R.layout.preference_app_icon, parent, false)
view.id = android.R.id.summary
(view.layoutParams as RelativeLayout.LayoutParams).addRule(RelativeLayout.BELOW, android.R.id.title)
val appIconSelector: RadioGroup = view.findViewById(R.id.app_icon_selector)
val selected = findEnabledAppComponent(context)
val selectedIdx = allAppIcons.indexOfFirst { it.className == selected?.className }
for (idx in 0 ..< appIconsList.size) {
val radioButton = object : AppCompatRadioButton(context) {
override fun setChecked(checked: Boolean) {
super.setChecked(checked)
alpha = if (checked) 1.0f else 0.4f
if (checked) {
setEnabledComponent(allAppIcons[idx])
}
}
}
radioButton.layoutParams = RadioGroup.LayoutParams(-2, -2).apply {
val padding = context.resources.getDimensionPixelOffset(R.dimen.item_padding_mini2x)
setMargins(padding, padding, padding, padding)
}
radioButton.gravity = Gravity.CENTER_VERTICAL
radioButton.id = idx
radioButton.isChecked = idx == selectedIdx
radioButton.buttonDrawable = appIconsList.elementAt(idx)
radioButton.text = ""
radioButton.buttonTintList = null
appIconSelector.addView(radioButton)
}
appIconSelector.check(selectedIdx)
parent.addView(view)
}
}
private fun disableAppIcon() {
val enabled = findEnabledAppComponent(context)
if (enabled != null) {
context.packageManager.setComponentEnabledSetting(
enabled,
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
PackageManager.DONT_KILL_APP
)
}
}
private fun setEnabledComponent(componentName: ComponentName) {
disableAppIcon()
context.packageManager.setComponentEnabledSetting(
componentName,
PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
}
}

View file

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="utf-8"?>
<animated-selector xmlns:android="http://schemas.android.com/apk/res/android"
android:enterFadeDuration="200"
android:exitFadeDuration="200">
<item android:state_checked="true" android:drawable="@drawable/check_box_24px" />
<item android:state_checked="false" android:drawable="@drawable/check_box_outline_blank_24px" />
</animated-selector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="@color/switch_accent_enabled">
<path
android:fillColor="@android:color/white"
android:pathData="M424,648L706,366L650,310L424,536L310,422L254,478L424,648ZM200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840Z"/>
</vector>

View file

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="960"
android:viewportHeight="960"
android:tint="@color/switch_accent_enabled">
<path
android:fillColor="@android:color/white"
android:pathData="M200,840Q167,840 143.5,816.5Q120,793 120,760L120,200Q120,167 143.5,143.5Q167,120 200,120L760,120Q793,120 816.5,143.5Q840,167 840,200L840,760Q840,793 816.5,816.5Q793,840 760,840L200,840ZM200,760L760,760Q760,760 760,760Q760,760 760,760L760,200Q760,200 760,200Q760,200 760,200L200,200Q200,200 200,200Q200,200 200,200L200,760Q200,760 200,760Q200,760 200,760Z"/>
</vector>

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