mirror of
https://github.com/xtclovver/RKNHardering.git
synced 2026-07-09 17:19:25 +00:00
This commit is contained in:
parent
e2d2d1fb11
commit
4a9ed45762
45 changed files with 973 additions and 93 deletions
|
|
@ -15,8 +15,8 @@ android {
|
|||
applicationId = "com.notcvnt.rknhardering"
|
||||
minSdk = 26
|
||||
targetSdk = 36
|
||||
versionCode = 20611
|
||||
versionName = "2.6.11"
|
||||
versionCode = 20612
|
||||
versionName = "2.6.12"
|
||||
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
|
||||
androidResources.localeFilters += listOf("en", "ru", "fa", "zh-rCN")
|
||||
|
||||
|
|
|
|||
|
|
@ -56,10 +56,10 @@
|
|||
android:allowBackup="false"
|
||||
android:dataExtractionRules="@xml/data_extraction_rules"
|
||||
android:fullBackupContent="@xml/backup_rules"
|
||||
android:icon="@mipmap/ic_launcher"
|
||||
android:icon="@mipmap/ic_launcher_n04_original"
|
||||
android:label="@string/app_name"
|
||||
android:usesCleartextTraffic="false"
|
||||
android:roundIcon="@mipmap/ic_launcher_round"
|
||||
android:roundIcon="@mipmap/ic_launcher_n04_original_round"
|
||||
android:supportsRtl="true"
|
||||
android:theme="@style/Theme.RKNHardering"
|
||||
android:networkSecurityConfig="@xml/network_security_config"
|
||||
|
|
@ -67,13 +67,83 @@
|
|||
tools:targetApi="tiramisu">
|
||||
<activity
|
||||
android:name=".MainActivity"
|
||||
android:exported="true">
|
||||
android:exported="true" />
|
||||
|
||||
<activity-alias
|
||||
android:name=".LauncherOriginal"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:enabled="true"
|
||||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_n04_original"
|
||||
android:roundIcon="@mipmap/ic_launcher_n04_original_round"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".LauncherProtanopia"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:enabled="false"
|
||||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_n04_protanopia"
|
||||
android:roundIcon="@mipmap/ic_launcher_n04_protanopia_round"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".LauncherDeuteranopia"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:enabled="false"
|
||||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_n04_deuteranopia"
|
||||
android:roundIcon="@mipmap/ic_launcher_n04_deuteranopia_round"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".LauncherTritanopia"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:enabled="false"
|
||||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_n04_tritanopia"
|
||||
android:roundIcon="@mipmap/ic_launcher_n04_tritanopia_round"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity-alias
|
||||
android:name=".LauncherMonochrome"
|
||||
android:targetActivity=".MainActivity"
|
||||
android:enabled="false"
|
||||
android:exported="true"
|
||||
android:icon="@mipmap/ic_launcher_n04_monochrome"
|
||||
android:roundIcon="@mipmap/ic_launcher_n04_monochrome_round"
|
||||
android:label="@string/app_name">
|
||||
<intent-filter>
|
||||
<action android:name="android.intent.action.MAIN" />
|
||||
|
||||
<category android:name="android.intent.category.LAUNCHER" />
|
||||
</intent-filter>
|
||||
</activity-alias>
|
||||
|
||||
<activity
|
||||
android:name=".SettingsActivity"
|
||||
android:exported="false" />
|
||||
|
|
|
|||
|
|
@ -0,0 +1,55 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.util.Log
|
||||
|
||||
internal object LauncherIconManager {
|
||||
private const val TAG = "LauncherIconManager"
|
||||
|
||||
internal var setComponentEnabledSettingForTests:
|
||||
((PackageManager, ComponentName, Int) -> Unit)? = null
|
||||
|
||||
fun apply(context: Context, target: LauncherIconVariant): Boolean {
|
||||
return try {
|
||||
val pm = context.packageManager
|
||||
val pkg = context.packageName
|
||||
|
||||
setStateIfNeeded(pm, ComponentName(pkg, target.aliasClass), PackageManager.COMPONENT_ENABLED_STATE_ENABLED)
|
||||
LauncherIconVariant.entries
|
||||
.filterNot { it == target }
|
||||
.forEach { variant ->
|
||||
setStateIfNeeded(
|
||||
pm,
|
||||
ComponentName(pkg, variant.aliasClass),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
)
|
||||
}
|
||||
true
|
||||
} catch (e: SecurityException) {
|
||||
Log.w(TAG, "Failed to toggle launcher alias", e)
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun current(context: Context): LauncherIconVariant {
|
||||
val pm = context.packageManager
|
||||
val pkg = context.packageName
|
||||
return LauncherIconVariant.entries.firstOrNull { variant ->
|
||||
pm.getComponentEnabledSetting(ComponentName(pkg, variant.aliasClass)) ==
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
} ?: LauncherIconVariant.ORIGINAL
|
||||
}
|
||||
|
||||
private fun setStateIfNeeded(
|
||||
pm: PackageManager,
|
||||
component: ComponentName,
|
||||
newState: Int,
|
||||
) {
|
||||
if (pm.getComponentEnabledSetting(component) != newState) {
|
||||
setComponentEnabledSettingForTests?.invoke(pm, component, newState)
|
||||
?: pm.setComponentEnabledSetting(component, newState, PackageManager.DONT_KILL_APP)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
internal enum class LauncherIconVariant(
|
||||
val aliasClass: String,
|
||||
val prefValue: String,
|
||||
) {
|
||||
ORIGINAL("com.notcvnt.rknhardering.LauncherOriginal", "original"),
|
||||
PROTANOPIA("com.notcvnt.rknhardering.LauncherProtanopia", "protanopia"),
|
||||
DEUTERANOPIA("com.notcvnt.rknhardering.LauncherDeuteranopia", "deuteranopia"),
|
||||
TRITANOPIA("com.notcvnt.rknhardering.LauncherTritanopia", "tritanopia"),
|
||||
MONOCHROME("com.notcvnt.rknhardering.LauncherMonochrome", "monochrome");
|
||||
|
||||
companion object {
|
||||
fun fromCvd(
|
||||
mode: ColorVisionMode,
|
||||
redGreenSub: LauncherIconVariant?,
|
||||
): LauncherIconVariant {
|
||||
return when (mode) {
|
||||
ColorVisionMode.OFF -> ORIGINAL
|
||||
ColorVisionMode.RED_GREEN ->
|
||||
redGreenSub?.takeIf { it == PROTANOPIA } ?: DEUTERANOPIA
|
||||
ColorVisionMode.BLUE_YELLOW -> TRITANOPIA
|
||||
ColorVisionMode.ACHROMATOPSIA -> MONOCHROME
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
import android.app.Application
|
||||
import android.content.SharedPreferences
|
||||
import androidx.core.content.edit
|
||||
import com.notcvnt.rknhardering.probe.NativeCurlBridge
|
||||
|
||||
class RknHarderingApp : Application() {
|
||||
|
|
@ -9,5 +11,54 @@ class RknHarderingApp : Application() {
|
|||
super.onCreate()
|
||||
NativeCurlBridge.initIfNeeded(this)
|
||||
AppUiSettings.applySavedTheme(this)
|
||||
migrateLauncherIconIfNeeded()
|
||||
}
|
||||
|
||||
internal fun migrateLauncherIconIfNeeded() {
|
||||
val prefs = AppUiSettings.prefs(this)
|
||||
if (prefs.getBoolean(SettingsPrefs.PREF_ICON_MIGRATION_DONE, false)) return
|
||||
|
||||
val rawMode = prefs.getString(SettingsPrefs.PREF_COLOR_VISION_MODE, null)
|
||||
syncLegacyRedGreenSubVariant(prefs, rawMode)
|
||||
|
||||
val mode = ColorVisionMode.fromPref(rawMode)
|
||||
val ok = if (mode == ColorVisionMode.OFF) {
|
||||
true
|
||||
} else {
|
||||
LauncherIconManager.apply(
|
||||
this,
|
||||
LauncherIconVariant.fromCvd(mode, redGreenSubVariantForMigration(prefs, rawMode)),
|
||||
)
|
||||
}
|
||||
if (ok) {
|
||||
prefs.edit { putBoolean(SettingsPrefs.PREF_ICON_MIGRATION_DONE, true) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun syncLegacyRedGreenSubVariant(prefs: SharedPreferences, rawMode: String?) {
|
||||
if (rawMode != LauncherIconVariant.PROTANOPIA.prefValue) return
|
||||
prefs.edit {
|
||||
putBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, true)
|
||||
putString(SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT, LauncherIconVariant.PROTANOPIA.prefValue)
|
||||
}
|
||||
}
|
||||
|
||||
private fun redGreenSubVariantForMigration(
|
||||
prefs: SharedPreferences,
|
||||
rawMode: String?,
|
||||
): LauncherIconVariant {
|
||||
if (rawMode == LauncherIconVariant.PROTANOPIA.prefValue) {
|
||||
return LauncherIconVariant.PROTANOPIA
|
||||
}
|
||||
val unlocked = prefs.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false)
|
||||
val storedVariant = prefs.getString(
|
||||
SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT,
|
||||
LauncherIconVariant.DEUTERANOPIA.prefValue,
|
||||
)
|
||||
return if (unlocked && storedVariant == LauncherIconVariant.PROTANOPIA.prefValue) {
|
||||
LauncherIconVariant.PROTANOPIA
|
||||
} else {
|
||||
LauncherIconVariant.DEUTERANOPIA
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -5,18 +5,23 @@ import android.os.Bundle
|
|||
import android.view.View
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.edit
|
||||
import androidx.core.view.isVisible
|
||||
import androidx.fragment.app.Fragment
|
||||
import com.google.android.material.chip.ChipGroup
|
||||
import com.google.android.material.snackbar.Snackbar
|
||||
|
||||
internal class SettingsAccessibilityFragment : Fragment(R.layout.fragment_settings_accessibility) {
|
||||
|
||||
private lateinit var prefs: SharedPreferences
|
||||
private lateinit var chipGroupColorVision: ChipGroup
|
||||
private lateinit var chipGroupRedGreenIcon: ChipGroup
|
||||
private var easterEggTapCount = 0
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
prefs = AppUiSettings.prefs(requireContext())
|
||||
chipGroupColorVision = view.findViewById(R.id.chipGroupColorVision)
|
||||
chipGroupRedGreenIcon = view.findViewById(R.id.chipGroupRedGreenIcon)
|
||||
loadSettings(view)
|
||||
setupListeners(view)
|
||||
}
|
||||
|
|
@ -24,7 +29,9 @@ internal class SettingsAccessibilityFragment : Fragment(R.layout.fragment_settin
|
|||
private fun loadSettings(root: View) {
|
||||
val mode = currentMode()
|
||||
chipGroupColorVision.check(chipIdForMode(mode))
|
||||
chipGroupRedGreenIcon.check(chipIdForRedGreenSubVariant(redGreenSubVariantFromPrefs()))
|
||||
renderPreview(root, mode)
|
||||
refreshRedGreenSubGroup(root, mode)
|
||||
}
|
||||
|
||||
private fun setupListeners(root: View) {
|
||||
|
|
@ -33,6 +40,33 @@ internal class SettingsAccessibilityFragment : Fragment(R.layout.fragment_settin
|
|||
val mode = modeForChipId(checkedIds.first())
|
||||
prefs.edit { putString(SettingsPrefs.PREF_COLOR_VISION_MODE, mode.prefValue) }
|
||||
renderPreview(root, mode)
|
||||
refreshRedGreenSubGroup(root, mode)
|
||||
applyLauncherIcon(root, mode)
|
||||
}
|
||||
|
||||
chipGroupRedGreenIcon.setOnCheckedStateChangeListener { _, checkedIds ->
|
||||
if (checkedIds.isEmpty()) return@setOnCheckedStateChangeListener
|
||||
val variant = when (checkedIds.first()) {
|
||||
R.id.chipRedGreenProtanopia -> LauncherIconVariant.PROTANOPIA
|
||||
else -> LauncherIconVariant.DEUTERANOPIA
|
||||
}
|
||||
prefs.edit { putString(SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT, variant.prefValue) }
|
||||
applyLauncherIcon(root, currentMode())
|
||||
}
|
||||
|
||||
root.findViewById<View>(R.id.easterEggTapZone).setOnClickListener {
|
||||
if (prefs.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false)) {
|
||||
return@setOnClickListener
|
||||
}
|
||||
easterEggTapCount++
|
||||
if (easterEggTapCount >= EASTER_EGG_TAP_TARGET) {
|
||||
prefs.edit {
|
||||
putBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, true)
|
||||
putString(SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT, LauncherIconVariant.DEUTERANOPIA.prefValue)
|
||||
}
|
||||
Snackbar.make(root, R.string.settings_easter_egg_protanopia_unlocked, Snackbar.LENGTH_LONG).show()
|
||||
refreshRedGreenSubGroup(root, currentMode())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -105,6 +139,31 @@ internal class SettingsAccessibilityFragment : Fragment(R.layout.fragment_settin
|
|||
getString(R.string.settings_accessibility_status_preview_content, label)
|
||||
}
|
||||
|
||||
private fun refreshRedGreenSubGroup(root: View, mode: ColorVisionMode) {
|
||||
val unlocked = prefs.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false)
|
||||
root.findViewById<View>(R.id.redGreenSubGroupContainer).isVisible =
|
||||
mode == ColorVisionMode.RED_GREEN && unlocked
|
||||
}
|
||||
|
||||
private fun applyLauncherIcon(root: View, mode: ColorVisionMode) {
|
||||
val target = LauncherIconVariant.fromCvd(mode, redGreenSubVariantFromPrefs())
|
||||
val message = if (LauncherIconManager.apply(requireContext(), target)) {
|
||||
R.string.settings_color_vision_icon_changed_warning
|
||||
} else {
|
||||
R.string.settings_color_vision_icon_change_failed
|
||||
}
|
||||
Snackbar.make(root, message, Snackbar.LENGTH_LONG).show()
|
||||
}
|
||||
|
||||
private fun redGreenSubVariantFromPrefs(): LauncherIconVariant {
|
||||
val unlocked = prefs.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false)
|
||||
if (!unlocked) return LauncherIconVariant.DEUTERANOPIA
|
||||
return when (prefs.getString(SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT, LauncherIconVariant.DEUTERANOPIA.prefValue)) {
|
||||
LauncherIconVariant.PROTANOPIA.prefValue -> LauncherIconVariant.PROTANOPIA
|
||||
else -> LauncherIconVariant.DEUTERANOPIA
|
||||
}
|
||||
}
|
||||
|
||||
private fun chipIdForMode(mode: ColorVisionMode): Int {
|
||||
return when (mode) {
|
||||
ColorVisionMode.OFF -> R.id.chipColorVisionOff
|
||||
|
|
@ -122,4 +181,15 @@ internal class SettingsAccessibilityFragment : Fragment(R.layout.fragment_settin
|
|||
else -> ColorVisionMode.OFF
|
||||
}
|
||||
}
|
||||
|
||||
private fun chipIdForRedGreenSubVariant(variant: LauncherIconVariant): Int {
|
||||
return when (variant) {
|
||||
LauncherIconVariant.PROTANOPIA -> R.id.chipRedGreenProtanopia
|
||||
else -> R.id.chipRedGreenDeuteranopia
|
||||
}
|
||||
}
|
||||
|
||||
private companion object {
|
||||
const val EASTER_EGG_TAP_TARGET = 10
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -105,6 +105,9 @@ class SettingsActivity : AppCompatActivity() {
|
|||
const val PREF_THEME = SettingsPrefs.PREF_THEME
|
||||
const val PREF_LANGUAGE = SettingsPrefs.PREF_LANGUAGE
|
||||
const val PREF_COLOR_VISION_MODE = SettingsPrefs.PREF_COLOR_VISION_MODE
|
||||
const val PREF_EASTER_EGG_PROTANOPIA_UNLOCKED = SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED
|
||||
const val PREF_RED_GREEN_ICON_VARIANT = SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT
|
||||
const val PREF_ICON_MIGRATION_DONE = SettingsPrefs.PREF_ICON_MIGRATION_DONE
|
||||
const val EXTRA_REQUEST_PERMISSIONS = "extra_request_permissions"
|
||||
|
||||
fun applyTheme(theme: String) {
|
||||
|
|
|
|||
|
|
@ -25,4 +25,7 @@ internal object SettingsPrefs {
|
|||
const val PREF_THEME = "pref_theme"
|
||||
const val PREF_LANGUAGE = "pref_language"
|
||||
const val PREF_COLOR_VISION_MODE = "pref_color_vision_mode"
|
||||
const val PREF_EASTER_EGG_PROTANOPIA_UNLOCKED = "pref_easter_egg_protanopia_unlocked"
|
||||
const val PREF_RED_GREEN_ICON_VARIANT = "pref_red_green_icon_variant"
|
||||
const val PREF_ICON_MIGRATION_DONE = "pref_icon_migration_done"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,74 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
|
||||
<!-- Magnifier glass background -->
|
||||
<path
|
||||
android:fillColor="#20203A"
|
||||
android:pathData="M54,54m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0" />
|
||||
|
||||
<!-- Magnifier glass border -->
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M54,54m-28,0a28,28 0,1 1,56 0a28,28 0,1 1,-56 0"
|
||||
android:strokeColor="#C8C5D0"
|
||||
android:strokeWidth="3" />
|
||||
|
||||
<!-- Outer pulse ring -->
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M54,54m-21,0a21,21 0,1 1,42 0a21,21 0,1 1,-42 0"
|
||||
android:strokeColor="#B3261E"
|
||||
android:strokeWidth="1.2"
|
||||
android:strokeAlpha="0.25" />
|
||||
|
||||
<!-- Dashed detection ring (approximated with arc segments) -->
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M54,38 A16,16 0 0,1 70,54"
|
||||
android:strokeColor="#B3261E"
|
||||
android:strokeWidth="2"
|
||||
android:strokeLineCap="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M70,54 A16,16 0 0,1 54,70"
|
||||
android:strokeColor="#B3261E"
|
||||
android:strokeWidth="2"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeAlpha="0.4" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M54,70 A16,16 0 0,1 38,54"
|
||||
android:strokeColor="#B3261E"
|
||||
android:strokeWidth="2"
|
||||
android:strokeLineCap="round" />
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M38,54 A16,16 0 0,1 54,38"
|
||||
android:strokeColor="#B3261E"
|
||||
android:strokeWidth="2"
|
||||
android:strokeLineCap="round"
|
||||
android:strokeAlpha="0.4" />
|
||||
|
||||
<!-- Centre red dot -->
|
||||
<path
|
||||
android:fillColor="#B3261E"
|
||||
android:pathData="M54,54m-6,0a6,6 0,1 1,12 0a6,6 0,1 1,-12 0" />
|
||||
|
||||
<!-- Centre highlight -->
|
||||
<path
|
||||
android:fillColor="#FFDAD6"
|
||||
android:pathData="M54,54m-3,0a3,3 0,1 1,6 0a3,3 0,1 1,-6 0" />
|
||||
|
||||
<!-- Handle -->
|
||||
<path
|
||||
android:fillColor="#00000000"
|
||||
android:pathData="M73.8,73.8 L86,86"
|
||||
android:strokeColor="#C8C5D0"
|
||||
android:strokeWidth="5.5"
|
||||
android:strokeLineCap="round" />
|
||||
|
||||
</vector>
|
||||
|
|
@ -5,6 +5,6 @@
|
|||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#1A1A26"
|
||||
android:fillColor="#F4EFE6"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#0E1116"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillColor="#D55E00"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
<path
|
||||
android:fillColor="#0072B2"
|
||||
android:pathData="M90.703,16.875m-2.953,0a2.953,2.953 0,1 1,5.906 0a2.953,2.953 0,1 1,-5.906 0" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#F4EFE6"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#0E1116"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillColor="#5A5A5A"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
<path
|
||||
android:fillColor="#9A9A9A"
|
||||
android:pathData="M90.703,16.875m-2.953,0a2.953,2.953 0,1 1,5.906 0a2.953,2.953 0,1 1,-5.906 0" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#F4EFE6"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#0E1116"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillColor="#C8332C"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
<path
|
||||
android:fillColor="#1F8A5B"
|
||||
android:pathData="M90.703,16.875m-2.953,0a2.953,2.953 0,1 1,5.906 0a2.953,2.953 0,1 1,-5.906 0" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#F4EFE6"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#0E1116"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillColor="#0072B2"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
<path
|
||||
android:fillColor="#E69F00"
|
||||
android:pathData="M90.703,16.875m-2.953,0a2.953,2.953 0,1 1,5.906 0a2.953,2.953 0,1 1,-5.906 0" />
|
||||
</vector>
|
||||
25
app/src/main/res/drawable/ic_launcher_n04_themed.xml
Normal file
25
app/src/main/res/drawable/ic_launcher_n04_themed.xml
Normal file
|
|
@ -0,0 +1,25 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillAlpha="0.22"
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
<group>
|
||||
<clip-path
|
||||
android:name="n04Slash"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
</group>
|
||||
<path
|
||||
android:fillColor="#FFFFFF"
|
||||
android:pathData="M90.703,16.875m-2.953,0a2.953,2.953 0,1 1,5.906 0a2.953,2.953 0,1 1,-5.906 0" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#F4EFE6"
|
||||
android:pathData="M0,0h108v108h-108z" />
|
||||
</vector>
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="108dp"
|
||||
android:height="108dp"
|
||||
android:viewportWidth="108"
|
||||
android:viewportHeight="108">
|
||||
<path
|
||||
android:fillColor="#0E1116"
|
||||
android:pathData="M-4.219,80.156 L67.5,-4.219 L88.594,0 L16.875,84.375 Z" />
|
||||
<path
|
||||
android:fillColor="#CC79A7"
|
||||
android:pathData="M31.640625 35.02880859375H40.4736328125L39.056396484375 41.818359375Q44.000244140625 34.204833984375 49.76806640625 34.204833984375Q51.8115234375 34.204833984375 54.151611328125 35.2265625L50.526123046875 42.971923828125Q49.24072265625 42.510498046875 47.79052734375 42.510498046875Q45.3515625 42.510498046875 42.8302001953125 44.356201171875Q40.308837890625 46.201904296875 38.8916015625 49.2835693359375Q37.474365234375 52.365234375 36.090087890625 59.055908203125L33.782958984375 70.03125H24.32373046875Z M56.91357421875 70.03125H47.454345703125L57.57275390625 21.71337890625H67.031982421875L63.406494140625 38.91796875Q66.603515625 36.4130859375 69.3720703125 35.3089599609375Q72.140625 34.204833984375 75.3046875 34.204833984375Q79.556396484375 34.204833984375 82.0283203125 36.643798828125Q84.500244140625 39.082763671875 84.500244140625 43.037841796875Q84.500244140625 45.147216796875 83.577392578125 49.563720703125L79.292724609375 70.03125H69.83349609375L74.217041015625 49.168212890625Q74.9091796875 45.7734375 74.9091796875 44.817626953125Q74.9091796875 43.07080078125 73.821533203125 42.01611328125Q72.73388671875 40.96142578125 70.855224609375 40.96142578125Q68.482177734375 40.96142578125 66.306884765625 42.609375Q63.472412109375 44.78466796875 61.9892578125 47.94873046875Q61.165283203125 49.695556640625 59.81396484375 56.155517578125Z" />
|
||||
<path
|
||||
android:fillColor="#009E73"
|
||||
android:pathData="M90.703,16.875m-2.953,0a2.953,2.953 0,1 1,5.906 0a2.953,2.953 0,1 1,-5.906 0" />
|
||||
</vector>
|
||||
|
|
@ -73,6 +73,53 @@
|
|||
android:text="@string/settings_color_vision_achromatopsia"
|
||||
app:checkedIconVisible="false" />
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
|
||||
<View
|
||||
android:id="@+id/easterEggTapZone"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="48dp"
|
||||
android:background="@android:color/transparent" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/redGreenSubGroupContainer"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:visibility="gone">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_color_vision_red_green_icon_label"
|
||||
android:textColor="?android:attr/textColorPrimary"
|
||||
android:textSize="15sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<com.google.android.material.chip.ChipGroup
|
||||
android:id="@+id/chipGroupRedGreenIcon"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="12dp"
|
||||
app:selectionRequired="true"
|
||||
app:singleSelection="true">
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chipRedGreenDeuteranopia"
|
||||
style="@style/Widget.Material3.Chip.Filter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_color_vision_icon_deuteranopia"
|
||||
app:checkedIconVisible="false" />
|
||||
|
||||
<com.google.android.material.chip.Chip
|
||||
android:id="@+id/chipRedGreenProtanopia"
|
||||
style="@style/Widget.Material3.Chip.Filter"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/settings_color_vision_icon_protanopia"
|
||||
app:checkedIconVisible="false" />
|
||||
</com.google.android.material.chip.ChipGroup>
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
</com.google.android.material.card.MaterialCardView>
|
||||
|
||||
|
|
|
|||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_deuteranopia_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_deuteranopia_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_deuteranopia_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_deuteranopia_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_monochrome_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_monochrome_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_monochrome_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_monochrome_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_original_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_original_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_original_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_original_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_protanopia_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_protanopia_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_protanopia_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_protanopia_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_tritanopia_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_tritanopia_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_n04_tritanopia_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_n04_tritanopia_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_n04_themed" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -1,6 +0,0 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<background android:drawable="@drawable/ic_launcher_background" />
|
||||
<foreground android:drawable="@drawable/ic_launcher_foreground" />
|
||||
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
|
||||
</adaptive-icon>
|
||||
|
|
@ -100,6 +100,12 @@
|
|||
<string name="settings_color_vision_red_green">قرمز-سبز</string>
|
||||
<string name="settings_color_vision_blue_yellow">آبی-زرد</string>
|
||||
<string name="settings_color_vision_achromatopsia">Achromatopsia</string>
|
||||
<string name="settings_color_vision_icon_changed_warning">نماد برنامه بهروزرسانی شد. در بعضی لانچرها ممکن است برای لحظهای ناپدید و دوباره ظاهر شود.</string>
|
||||
<string name="settings_color_vision_icon_change_failed">بهروزرسانی نماد برنامه ناموفق بود.</string>
|
||||
<string name="settings_easter_egg_protanopia_unlocked">گونهٔ نماد پروتانوپیا باز شد.</string>
|
||||
<string name="settings_color_vision_red_green_icon_label">سبک نماد قرمز-سبز</string>
|
||||
<string name="settings_color_vision_icon_deuteranopia">دوترانوپیا</string>
|
||||
<string name="settings_color_vision_icon_protanopia">پروتانوپیا</string>
|
||||
<string name="settings_accessibility_status_preview_content">وضعیت: %1$s</string>
|
||||
<string name="settings_permissions">مجوزها</string>
|
||||
<string name="settings_permissions_desc">مدیریت مجوزهای برنامه</string>
|
||||
|
|
|
|||
|
|
@ -100,6 +100,12 @@
|
|||
<string name="settings_color_vision_red_green">Красно-зелёный</string>
|
||||
<string name="settings_color_vision_blue_yellow">Сине-жёлтый</string>
|
||||
<string name="settings_color_vision_achromatopsia">Ахроматопсия</string>
|
||||
<string name="settings_color_vision_icon_changed_warning">Иконка приложения обновлена. В некоторых лаунчерах она может ненадолго исчезнуть и появиться снова.</string>
|
||||
<string name="settings_color_vision_icon_change_failed">Не удалось обновить иконку приложения.</string>
|
||||
<string name="settings_easter_egg_protanopia_unlocked">Вариант иконки для протанопии разблокирован.</string>
|
||||
<string name="settings_color_vision_red_green_icon_label">Стиль иконки для красно-зелёного режима</string>
|
||||
<string name="settings_color_vision_icon_deuteranopia">Дейтеранопия</string>
|
||||
<string name="settings_color_vision_icon_protanopia">Протанопия</string>
|
||||
<string name="settings_accessibility_status_preview_content">Статус: %1$s</string>
|
||||
<string name="settings_permissions">Разрешения</string>
|
||||
<string name="settings_permissions_desc">Управление разрешениями приложения</string>
|
||||
|
|
|
|||
|
|
@ -100,6 +100,12 @@
|
|||
<string name="settings_color_vision_red_green">红绿色</string>
|
||||
<string name="settings_color_vision_blue_yellow">蓝黄色</string>
|
||||
<string name="settings_color_vision_achromatopsia">Achromatopsia</string>
|
||||
<string name="settings_color_vision_icon_changed_warning">应用图标已更新。在某些启动器上,它可能会短暂消失后重新出现。</string>
|
||||
<string name="settings_color_vision_icon_change_failed">更新应用图标失败。</string>
|
||||
<string name="settings_easter_egg_protanopia_unlocked">已解锁红色盲图标变体。</string>
|
||||
<string name="settings_color_vision_red_green_icon_label">红绿色图标样式</string>
|
||||
<string name="settings_color_vision_icon_deuteranopia">绿色盲</string>
|
||||
<string name="settings_color_vision_icon_protanopia">红色盲</string>
|
||||
<string name="settings_accessibility_status_preview_content">状态:%1$s</string>
|
||||
<string name="settings_permissions">权限</string>
|
||||
<string name="settings_permissions_desc">管理应用权限</string>
|
||||
|
|
|
|||
|
|
@ -99,6 +99,12 @@
|
|||
<string name="settings_color_vision_red_green">Red-green</string>
|
||||
<string name="settings_color_vision_blue_yellow">Blue-yellow</string>
|
||||
<string name="settings_color_vision_achromatopsia">Achromatopsia</string>
|
||||
<string name="settings_color_vision_icon_changed_warning">App icon updated. On some launchers it may briefly disappear and re-appear.</string>
|
||||
<string name="settings_color_vision_icon_change_failed">Failed to update app icon.</string>
|
||||
<string name="settings_easter_egg_protanopia_unlocked">Protanopia icon variant unlocked.</string>
|
||||
<string name="settings_color_vision_red_green_icon_label">Red-green icon style</string>
|
||||
<string name="settings_color_vision_icon_deuteranopia">Deuteranopia</string>
|
||||
<string name="settings_color_vision_icon_protanopia">Protanopia</string>
|
||||
<string name="settings_accessibility_status_preview_content">%1$s status</string>
|
||||
<string name="settings_permissions">Permissions</string>
|
||||
<string name="settings_permissions_desc">Manage app permissions</string>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,108 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class LauncherIconManagerTest {
|
||||
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
resetLauncherAliases()
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = null
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = null
|
||||
resetLauncherAliases()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `apply enables target alias and disables other aliases`() {
|
||||
assertTrue(LauncherIconManager.apply(context, LauncherIconVariant.TRITANOPIA))
|
||||
|
||||
LauncherIconVariant.entries.forEach { variant ->
|
||||
val expected = if (variant == LauncherIconVariant.TRITANOPIA) {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
|
||||
} else {
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|
||||
}
|
||||
assertEquals(expected, componentState(variant))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `apply is idempotent for the same target`() {
|
||||
val calls = mutableListOf<Pair<ComponentName, Int>>()
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = { pm, component, state ->
|
||||
calls += component to state
|
||||
pm.setComponentEnabledSetting(component, state, PackageManager.DONT_KILL_APP)
|
||||
}
|
||||
|
||||
assertTrue(LauncherIconManager.apply(context, LauncherIconVariant.PROTANOPIA))
|
||||
val firstCallCount = calls.size
|
||||
assertTrue(LauncherIconManager.apply(context, LauncherIconVariant.PROTANOPIA))
|
||||
|
||||
assertEquals(firstCallCount, calls.size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `current returns enabled variant`() {
|
||||
LauncherIconManager.apply(context, LauncherIconVariant.MONOCHROME)
|
||||
|
||||
assertEquals(LauncherIconVariant.MONOCHROME, LauncherIconManager.current(context))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `current returns original when no alias is enabled`() {
|
||||
LauncherIconVariant.entries.forEach { variant ->
|
||||
context.packageManager.setComponentEnabledSetting(
|
||||
componentName(variant),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DISABLED,
|
||||
PackageManager.DONT_KILL_APP,
|
||||
)
|
||||
}
|
||||
|
||||
assertEquals(LauncherIconVariant.ORIGINAL, LauncherIconManager.current(context))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `apply returns false when package manager rejects alias toggle`() {
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = { _, _, _ ->
|
||||
throw SecurityException("blocked")
|
||||
}
|
||||
|
||||
assertFalse(LauncherIconManager.apply(context, LauncherIconVariant.DEUTERANOPIA))
|
||||
}
|
||||
|
||||
private fun resetLauncherAliases() {
|
||||
LauncherIconVariant.entries.forEach { variant ->
|
||||
context.packageManager.setComponentEnabledSetting(
|
||||
componentName(variant),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
|
||||
PackageManager.DONT_KILL_APP,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun componentState(variant: LauncherIconVariant): Int {
|
||||
return context.packageManager.getComponentEnabledSetting(componentName(variant))
|
||||
}
|
||||
|
||||
private fun componentName(variant: LauncherIconVariant): ComponentName {
|
||||
return ComponentName(context.packageName, variant.aliasClass)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|
||||
class LauncherIconVariantTest {
|
||||
|
||||
@Test
|
||||
fun `maps color vision modes to launcher icon variants`() {
|
||||
assertEquals(
|
||||
LauncherIconVariant.ORIGINAL,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.OFF, LauncherIconVariant.PROTANOPIA),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.DEUTERANOPIA,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.RED_GREEN, null),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.PROTANOPIA,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.RED_GREEN, LauncherIconVariant.PROTANOPIA),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.DEUTERANOPIA,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.RED_GREEN, LauncherIconVariant.DEUTERANOPIA),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.DEUTERANOPIA,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.RED_GREEN, LauncherIconVariant.ORIGINAL),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.TRITANOPIA,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.BLUE_YELLOW, LauncherIconVariant.PROTANOPIA),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.MONOCHROME,
|
||||
LauncherIconVariant.fromCvd(ColorVisionMode.ACHROMATOPSIA, LauncherIconVariant.PROTANOPIA),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,104 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import androidx.core.content.edit
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.notcvnt.rknhardering.probe.NativeCurlBridge
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class RknHarderingAppTest {
|
||||
|
||||
private val app: RknHarderingApp = ApplicationProvider.getApplicationContext()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
NativeCurlBridge.resetForTests()
|
||||
AppUiSettings.prefs(app).edit().clear().commit()
|
||||
resetLauncherAliases()
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = null
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
NativeCurlBridge.resetForTests()
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = null
|
||||
resetLauncherAliases()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `first launch migrates blue yellow mode to tritanopia icon`() {
|
||||
AppUiSettings.prefs(app).edit {
|
||||
putString(SettingsPrefs.PREF_COLOR_VISION_MODE, ColorVisionMode.BLUE_YELLOW.prefValue)
|
||||
}
|
||||
|
||||
app.migrateLauncherIconIfNeeded()
|
||||
|
||||
assertEquals(LauncherIconVariant.TRITANOPIA, LauncherIconManager.current(app))
|
||||
assertTrue(AppUiSettings.prefs(app).getBoolean(SettingsPrefs.PREF_ICON_MIGRATION_DONE, false))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `migration preserves legacy protanopia preference`() {
|
||||
AppUiSettings.prefs(app).edit {
|
||||
putString(SettingsPrefs.PREF_COLOR_VISION_MODE, LauncherIconVariant.PROTANOPIA.prefValue)
|
||||
}
|
||||
|
||||
app.migrateLauncherIconIfNeeded()
|
||||
|
||||
assertEquals(LauncherIconVariant.PROTANOPIA, LauncherIconManager.current(app))
|
||||
assertTrue(
|
||||
AppUiSettings.prefs(app)
|
||||
.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false),
|
||||
)
|
||||
assertEquals(
|
||||
LauncherIconVariant.PROTANOPIA.prefValue,
|
||||
AppUiSettings.prefs(app).getString(SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT, null),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `second launch does not rerun migration when flag is set`() {
|
||||
AppUiSettings.prefs(app).edit {
|
||||
putString(SettingsPrefs.PREF_COLOR_VISION_MODE, ColorVisionMode.BLUE_YELLOW.prefValue)
|
||||
putBoolean(SettingsPrefs.PREF_ICON_MIGRATION_DONE, true)
|
||||
}
|
||||
|
||||
app.migrateLauncherIconIfNeeded()
|
||||
|
||||
assertEquals(LauncherIconVariant.ORIGINAL, LauncherIconManager.current(app))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `failed icon migration is retried on next launch`() {
|
||||
AppUiSettings.prefs(app).edit {
|
||||
putString(SettingsPrefs.PREF_COLOR_VISION_MODE, ColorVisionMode.BLUE_YELLOW.prefValue)
|
||||
}
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = { _, _, _ ->
|
||||
throw SecurityException("blocked")
|
||||
}
|
||||
|
||||
app.migrateLauncherIconIfNeeded()
|
||||
|
||||
assertFalse(AppUiSettings.prefs(app).getBoolean(SettingsPrefs.PREF_ICON_MIGRATION_DONE, false))
|
||||
}
|
||||
|
||||
private fun resetLauncherAliases() {
|
||||
LauncherIconVariant.entries.forEach { variant ->
|
||||
app.packageManager.setComponentEnabledSetting(
|
||||
ComponentName(app.packageName, variant.aliasClass),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
|
||||
PackageManager.DONT_KILL_APP,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,156 @@
|
|||
package com.notcvnt.rknhardering
|
||||
|
||||
import android.content.ComponentName
|
||||
import android.content.Context
|
||||
import android.content.pm.PackageManager
|
||||
import android.os.Looper
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.TextView
|
||||
import androidx.core.content.edit
|
||||
import androidx.test.core.app.ApplicationProvider
|
||||
import com.google.android.material.chip.Chip
|
||||
import org.junit.After
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Assert.assertFalse
|
||||
import org.junit.Assert.assertTrue
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.junit.runner.RunWith
|
||||
import org.robolectric.Robolectric
|
||||
import org.robolectric.RobolectricTestRunner
|
||||
import org.robolectric.Shadows.shadowOf
|
||||
|
||||
@RunWith(RobolectricTestRunner::class)
|
||||
class SettingsAccessibilityFragmentTest {
|
||||
|
||||
private val context: Context = ApplicationProvider.getApplicationContext()
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
AppUiSettings.prefs(context).edit().clear().commit()
|
||||
resetLauncherAliases()
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = null
|
||||
}
|
||||
|
||||
@After
|
||||
fun tearDown() {
|
||||
LauncherIconManager.setComponentEnabledSettingForTests = null
|
||||
resetLauncherAliases()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `selecting red green applies deuteranopia launcher icon`() {
|
||||
val scenario = accessibilityFragment()
|
||||
|
||||
scenario.root.findViewById<Chip>(R.id.chipColorVisionRedGreen).performClick()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
|
||||
assertEquals(LauncherIconVariant.DEUTERANOPIA, LauncherIconManager.current(context))
|
||||
assertEquals(
|
||||
scenario.activity.getString(R.string.settings_color_vision_icon_changed_warning),
|
||||
latestSnackbarText(scenario.activity.findViewById(android.R.id.content)),
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `ten easter egg taps unlock protanopia sub group`() {
|
||||
val scenario = accessibilityFragment()
|
||||
scenario.root.findViewById<Chip>(R.id.chipColorVisionRedGreen).performClick()
|
||||
val tapZone = scenario.root.findViewById<View>(R.id.easterEggTapZone)
|
||||
|
||||
repeat(10) { tapZone.performClick() }
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
|
||||
assertTrue(
|
||||
AppUiSettings.prefs(context)
|
||||
.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false),
|
||||
)
|
||||
assertEquals(View.VISIBLE, scenario.root.findViewById<View>(R.id.redGreenSubGroupContainer).visibility)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `fewer than ten easter egg taps keep protanopia locked`() {
|
||||
val scenario = accessibilityFragment()
|
||||
val tapZone = scenario.root.findViewById<View>(R.id.easterEggTapZone)
|
||||
|
||||
repeat(9) { tapZone.performClick() }
|
||||
|
||||
assertFalse(
|
||||
AppUiSettings.prefs(context)
|
||||
.getBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, false),
|
||||
)
|
||||
assertEquals(View.GONE, scenario.root.findViewById<View>(R.id.redGreenSubGroupContainer).visibility)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `selecting protanopia sub variant applies protanopia launcher icon`() {
|
||||
AppUiSettings.prefs(context).edit {
|
||||
putString(SettingsPrefs.PREF_COLOR_VISION_MODE, ColorVisionMode.RED_GREEN.prefValue)
|
||||
putBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, true)
|
||||
putString(SettingsPrefs.PREF_RED_GREEN_ICON_VARIANT, LauncherIconVariant.DEUTERANOPIA.prefValue)
|
||||
}
|
||||
val scenario = accessibilityFragment()
|
||||
|
||||
scenario.root.findViewById<Chip>(R.id.chipRedGreenProtanopia).performClick()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
|
||||
assertEquals(LauncherIconVariant.PROTANOPIA, LauncherIconManager.current(context))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `switching from red green to achromatopsia hides sub group and applies monochrome icon`() {
|
||||
AppUiSettings.prefs(context).edit {
|
||||
putString(SettingsPrefs.PREF_COLOR_VISION_MODE, ColorVisionMode.RED_GREEN.prefValue)
|
||||
putBoolean(SettingsPrefs.PREF_EASTER_EGG_PROTANOPIA_UNLOCKED, true)
|
||||
}
|
||||
val scenario = accessibilityFragment()
|
||||
|
||||
scenario.root.findViewById<Chip>(R.id.chipColorVisionAchromatopsia).performClick()
|
||||
shadowOf(Looper.getMainLooper()).idle()
|
||||
|
||||
assertEquals(View.GONE, scenario.root.findViewById<View>(R.id.redGreenSubGroupContainer).visibility)
|
||||
assertEquals(LauncherIconVariant.MONOCHROME, LauncherIconManager.current(context))
|
||||
}
|
||||
|
||||
private fun accessibilityFragment(): AccessibilityScenario {
|
||||
val activity = Robolectric.buildActivity(SettingsActivity::class.java).setup().get()
|
||||
activity.supportFragmentManager.beginTransaction()
|
||||
.replace(R.id.settingsFragmentContainer, SettingsAccessibilityFragment())
|
||||
.commitNow()
|
||||
val fragment = activity.supportFragmentManager
|
||||
.findFragmentById(R.id.settingsFragmentContainer) as SettingsAccessibilityFragment
|
||||
return AccessibilityScenario(activity, fragment.requireView())
|
||||
}
|
||||
|
||||
private fun latestSnackbarText(root: View): String {
|
||||
return findSnackbarText(root)?.text?.toString().orEmpty()
|
||||
}
|
||||
|
||||
private fun findSnackbarText(view: View): TextView? {
|
||||
if (view.id == com.google.android.material.R.id.snackbar_text) {
|
||||
return view as TextView
|
||||
}
|
||||
if (view is ViewGroup) {
|
||||
for (index in 0 until view.childCount) {
|
||||
findSnackbarText(view.getChildAt(index))?.let { return it }
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun resetLauncherAliases() {
|
||||
LauncherIconVariant.entries.forEach { variant ->
|
||||
context.packageManager.setComponentEnabledSetting(
|
||||
ComponentName(context.packageName, variant.aliasClass),
|
||||
PackageManager.COMPONENT_ENABLED_STATE_DEFAULT,
|
||||
PackageManager.DONT_KILL_APP,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private data class AccessibilityScenario(
|
||||
val activity: SettingsActivity,
|
||||
val root: View,
|
||||
)
|
||||
}
|
||||
1
fastlane/metadata/android/en-US/changelogs/20612.txt
Normal file
1
fastlane/metadata/android/en-US/changelogs/20612.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Launcher icon now follows the selected color-vision accessibility mode.
|
||||
1
fastlane/metadata/android/fa/changelogs/20612.txt
Normal file
1
fastlane/metadata/android/fa/changelogs/20612.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
نماد برنامه اکنون از حالت دید رنگ انتخابشده پیروی میکند.
|
||||
1
fastlane/metadata/android/ru-RU/changelogs/20612.txt
Normal file
1
fastlane/metadata/android/ru-RU/changelogs/20612.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
Иконка приложения теперь следует выбранному режиму цветового зрения.
|
||||
1
fastlane/metadata/android/zh-CN/changelogs/20612.txt
Normal file
1
fastlane/metadata/android/zh-CN/changelogs/20612.txt
Normal file
|
|
@ -0,0 +1 @@
|
|||
应用图标现在会跟随所选的色觉辅助模式。
|
||||
Loading…
Add table
Add a link
Reference in a new issue