Skip to content
This repository was archived by the owner on Jul 18, 2026. It is now read-only.

Commit 0f32d82

Browse files
authored
Merge pull request #103 from misaka10032w/develop
[Feature] 增加应用图标伪装功能
2 parents eadf5b3 + 930db73 commit 0f32d82

93 files changed

Lines changed: 353 additions & 13 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

app/build.gradle.kts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@ android {
3838
applicationId = "com.yenaly.han1meviewer"
3939
minSdk = property("min.sdk")?.toString()?.toIntOrNull()
4040
targetSdk = property("target.sdk")?.toString()?.toIntOrNull()
41-
val (code, name) = createVersion(major = 0, minor = 16, patch = 0)
41+
val (code, name) = createVersion(major = 0, minor = 16, patch = 2)
4242
versionCode = code
4343
versionName = name
4444

@@ -68,6 +68,7 @@ android {
6868
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
6969
)
7070
signingConfig = signingConfigs.getByName("release")
71+
manifestPlaceholders.put("appIcon", "@mipmap/ic_launcher")
7172
applicationVariants.all variant@{
7273
this@variant.outputs.all output@{
7374
val output = this@output as BaseVariantOutputImpl
@@ -81,6 +82,7 @@ android {
8182
getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro"
8283
)
8384
applicationIdSuffix = ".debug"
85+
manifestPlaceholders.put("appIcon", "@mipmap/ic_launcher_debug")
8486
}
8587
}
8688
buildFeatures {
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<resources>
3+
<string name="hanime_app_name" translatable="false">HANi [Debug]</string>
4+
</resources>

app/src/main/AndroidManifest.xml

Lines changed: 57 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@
2525
android:dataExtractionRules="@xml/data_extraction_rules"
2626
android:enableOnBackInvokedCallback="true"
2727
android:fullBackupContent="@xml/backup_rules"
28-
android:icon="@mipmap/ic_launcher"
28+
android:icon="${appIcon}"
2929
android:label="@string/hanime_app_name"
3030
android:roundIcon="@mipmap/ic_launcher_round"
3131
android:supportsRtl="true"
@@ -72,31 +72,80 @@
7272
android:screenOrientation="portrait"
7373
tools:ignore="LockedOrientationActivity">
7474
</activity>
75+
<!-- MainActivity 本体:无 launcher 配置 -->
7576
<activity
7677
android:name=".ui.activity.MainActivity"
7778
android:supportsPictureInPicture="true"
7879
android:configChanges="orientation|smallestScreenSize|screenLayout|screenSize|keyboardHidden"
7980
android:exported="true"
8081
android:launchMode="singleTask"
8182
android:theme="@style/Theme.Hanime1.Main">
82-
<intent-filter>
83-
<action android:name="android.intent.action.MAIN" />
84-
85-
<category android:name="android.intent.category.LAUNCHER" />
86-
</intent-filter>
8783
<intent-filter android:autoVerify="true">
8884
<action android:name="android.intent.action.VIEW" />
89-
9085
<category android:name="android.intent.category.DEFAULT" />
9186
<category android:name="android.intent.category.BROWSABLE" />
92-
9387
<data android:scheme="http" />
9488
<data android:scheme="https" />
9589
<data android:host="hanime1.com" />
9690
<data android:host="hanime1.me" />
9791
<data android:path="/watch" />
9892
</intent-filter>
9993
</activity>
94+
95+
<!-- 默认启动器别名 -->
96+
<activity-alias
97+
android:name=".LauncherAliasDefault"
98+
android:enabled="true"
99+
android:exported="true"
100+
android:icon="@mipmap/ic_launcher"
101+
android:label="@string/hanime_app_name"
102+
android:targetActivity=".ui.activity.MainActivity">
103+
<intent-filter>
104+
<action android:name="android.intent.action.MAIN" />
105+
<category android:name="android.intent.category.LAUNCHER" />
106+
</intent-filter>
107+
</activity-alias>
108+
109+
<!-- 伪装1 -->
110+
<activity-alias
111+
android:name=".LauncherFakeCalc"
112+
android:enabled="false"
113+
android:exported="true"
114+
android:icon="@mipmap/ic_launcher_calc"
115+
android:label="@string/app_name_fake_calc"
116+
android:targetActivity=".ui.activity.MainActivity">
117+
<intent-filter>
118+
<action android:name="android.intent.action.MAIN" />
119+
<category android:name="android.intent.category.LAUNCHER" />
120+
</intent-filter>
121+
</activity-alias>
122+
<!-- 伪装2 -->
123+
<activity-alias
124+
android:name=".LauncherFakeCornhub"
125+
android:enabled="false"
126+
android:exported="true"
127+
android:icon="@mipmap/ic_launcher_cornhub"
128+
android:label="@string/app_name_fake_cornhub"
129+
android:targetActivity=".ui.activity.MainActivity">
130+
<intent-filter>
131+
<action android:name="android.intent.action.MAIN" />
132+
<category android:name="android.intent.category.LAUNCHER" />
133+
</intent-filter>
134+
</activity-alias>
135+
<!-- 伪装3 -->
136+
<activity-alias
137+
android:name=".LauncherFakeXxt"
138+
android:enabled="false"
139+
android:exported="true"
140+
android:icon="@mipmap/ic_launcher_xxt"
141+
android:label="@string/app_name_fake_xxt"
142+
android:targetActivity=".ui.activity.MainActivity">
143+
<intent-filter>
144+
<action android:name="android.intent.action.MAIN" />
145+
<category android:name="android.intent.category.LAUNCHER" />
146+
</intent-filter>
147+
</activity-alias>
148+
100149
<activity
101150
android:name=".ui.activity.SearchActivity"
102151
android:configChanges="orientation|screenSize"
-11.3 KB
Binary file not shown.

app/src/main/java/com/yenaly/han1meviewer/HanimeApplication.kt

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
package com.yenaly.han1meviewer
22

3+
import android.content.ComponentName
4+
import android.content.pm.PackageManager
35
import androidx.core.app.NotificationChannelCompat
46
import androidx.core.app.NotificationManagerCompat
57
import com.google.android.material.color.DynamicColors
@@ -46,9 +48,10 @@ class HanimeApplication : YenalyApplication() {
4648
super.onCreate()
4749
DynamicColors.applyToActivitiesIfAvailable(this)
4850
HProxySelector.rebuildNetwork()
49-
5051
initFirebase()
5152
initNotificationChannel()
53+
val selected = Preferences.fakeLauncherIcon
54+
switchLauncher(selected)
5255
}
5356

5457
private fun initFirebase() {
@@ -96,4 +99,27 @@ class HanimeApplication : YenalyApplication() {
9699
).setName("App Update").build()
97100
nm.createNotificationChannel(appUpdateChannel)
98101
}
102+
fun switchLauncher(alias: String) {
103+
val pm = packageManager
104+
105+
val allAliases = listOf(
106+
"com.yenaly.han1meviewer.LauncherAliasDefault",
107+
"com.yenaly.han1meviewer.LauncherFakeCalc",
108+
"com.yenaly.han1meviewer.LauncherFakeCornhub",
109+
"com.yenaly.han1meviewer.LauncherFakeXxt"
110+
)
111+
112+
allAliases.forEach { a ->
113+
val state = if (a == alias)
114+
PackageManager.COMPONENT_ENABLED_STATE_ENABLED
115+
else
116+
PackageManager.COMPONENT_ENABLED_STATE_DISABLED
117+
118+
pm.setComponentEnabledSetting(
119+
ComponentName(this, a),
120+
state,
121+
PackageManager.DONT_KILL_APP
122+
)
123+
}
124+
}
99125
}

app/src/main/java/com/yenaly/han1meviewer/Preferences.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,14 @@ object Preferences {
118118
val videoLanguage: String
119119
get() = preferenceSp.getString(HomeSettingsFragment.VIDEO_LANGUAGE, "zhs") ?: "zht"
120120

121+
val videoQuality: String
122+
get() = preferenceSp.getString(HomeSettingsFragment.DEFAULT_VIDEO_QUALITY, "1080P") ?: "1080P"
123+
124+
val fakeLauncherIcon: String
125+
get() = preferenceSp.getString(
126+
HomeSettingsFragment.FAKE_LAUNCHER_ICON,
127+
"com.yenaly.han1meviewer.LauncherAliasDefault") ?: "com.yenaly.han1meviewer.LauncherAliasDefault"
128+
121129
val baseUrl: String
122130
get() = preferenceSp.getString(NetworkSettingsFragment.DOMAIN_NAME, HANIME_MAIN_BASE_URL)
123131
?: HANIME_MAIN_BASE_URL

app/src/main/java/com/yenaly/han1meviewer/ui/fragment/settings/HomeSettingsFragment.kt

Lines changed: 69 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,8 +10,14 @@ import android.os.Bundle
1010
import android.os.Handler
1111
import android.os.Looper
1212
import android.provider.Settings
13+
import android.view.LayoutInflater
1314
import android.view.View
15+
import android.view.ViewGroup
16+
import android.widget.ArrayAdapter
17+
import android.widget.ImageView
18+
import android.widget.TextView
1419
import android.widget.Toast
20+
import androidx.annotation.DrawableRes
1521
import androidx.annotation.RequiresApi
1622
import androidx.core.net.toUri
1723
import androidx.core.text.parseAsHtml
@@ -58,6 +64,11 @@ import kotlinx.datetime.LocalDateTime
5864
import kotlinx.datetime.TimeZone
5965
import kotlinx.datetime.format
6066
import kotlinx.datetime.toLocalDateTime
67+
import kotlin.apply
68+
import androidx.core.content.edit
69+
import com.google.android.material.dialog.MaterialAlertDialogBuilder
70+
import com.yenaly.han1meviewer.HanimeApplication
71+
import com.yenaly.yenaly_libs.utils.showLongToast
6172

6273
/**
6374
* @project Han1meViewer
@@ -85,8 +96,8 @@ class HomeSettingsFragment : YenalySettingsFragment(R.xml.settings_home) {
8596
const val LAST_UPDATE_POPUP_TIME = "last_update_popup_time"
8697
const val UPDATE_POPUP_INTERVAL_DAYS = "update_popup_interval_days"
8798
const val USE_CI_UPDATE_CHANNEL = "use_ci_update_channel"
88-
8999
const val USE_ANALYTICS = "use_analytics"
100+
const val FAKE_LAUNCHER_ICON = "pref_fake_launcher_icon"
90101
}
91102

92103
private val videoLanguage
@@ -123,9 +134,17 @@ class HomeSettingsFragment : YenalySettingsFragment(R.xml.settings_home) {
123134
by safePreference<HPrivacyPreference>(USE_ANALYTICS)
124135
private val ossLicense
125136
by safePreference<Preference>("oss_license")
137+
private val fakeLauncherIcon
138+
by safePreference<Preference>(FAKE_LAUNCHER_ICON)
126139

127140
private var checkUpdateTimes = 0
128141

142+
data class LauncherItem(
143+
val name: String,
144+
@param:DrawableRes val iconRes: Int,
145+
val alias: String
146+
)
147+
129148
override fun onStart() {
130149
super.onStart()
131150
(activity as? ToolbarHost)?.showToolbar()
@@ -134,11 +153,25 @@ class HomeSettingsFragment : YenalySettingsFragment(R.xml.settings_home) {
134153
canNavigateBack = true
135154
)
136155

137-
}
156+
}
138157

139158
@RequiresApi(Build.VERSION_CODES.Q)
140159
override fun onPreferencesCreated(savedInstanceState: Bundle?) {
141160
val lockSwitch = findPreference<SwitchPreferenceCompat>("use_lock_screen")
161+
val items = listOf(
162+
LauncherItem(getString(R.string.hanime_app_name),
163+
R.drawable.ic_launcher,
164+
"com.yenaly.han1meviewer.LauncherAliasDefault"),
165+
LauncherItem(getString(R.string.app_name_fake_calc),
166+
R.drawable.ic_launcher_calc,
167+
"com.yenaly.han1meviewer.LauncherFakeCalc"),
168+
LauncherItem(getString(R.string.app_name_fake_cornhub),
169+
R.drawable.ic_launcher_cornhub,
170+
"com.yenaly.han1meviewer.LauncherFakeCornhub"),
171+
LauncherItem(getString(R.string.app_name_fake_xxt),
172+
R.drawable.ic_launcher_xxt,
173+
"com.yenaly.han1meviewer.LauncherFakeXxt")
174+
)
142175
lockSwitch?.setOnPreferenceChangeListener { _, newValue ->
143176
if (newValue == true) {
144177
if (!isDeviceSecureCompat(requireContext())) {
@@ -203,7 +236,7 @@ class HomeSettingsFragment : YenalySettingsFragment(R.xml.settings_home) {
203236
if (value == null) setValueIndex(2)
204237

205238
setOnPreferenceChangeListener { _, newValue ->
206-
if (newValue != Preferences.videoLanguage) {
239+
if (newValue != Preferences.videoQuality) {
207240
Toast.makeText(application, "Success:$newValue", Toast.LENGTH_SHORT).show()
208241
}
209242
return@setOnPreferenceChangeListener true
@@ -339,6 +372,39 @@ class HomeSettingsFragment : YenalySettingsFragment(R.xml.settings_home) {
339372
true
340373
}
341374
}
375+
376+
fakeLauncherIcon.apply {
377+
// summary = getString(R.string.select_fake_icon)
378+
val currentAlias = preferenceManager.sharedPreferences?.getString(FAKE_LAUNCHER_ICON, "default_alias")
379+
val currentItem = items.find { it.alias == currentAlias } ?: items[0]
380+
fakeLauncherIcon.summary = currentItem.name
381+
setOnPreferenceClickListener {
382+
val adapter = object : ArrayAdapter<LauncherItem>(context, 0, items) {
383+
override fun getView(position: Int, convertView: View?, parent: ViewGroup): View {
384+
val view = convertView ?: LayoutInflater.from(context)
385+
.inflate(R.layout.item_simple_icon_with_text, parent, false)
386+
val item = getItem(position)!!
387+
view.findViewById<ImageView>(R.id.icon).setImageResource(item.iconRes)
388+
view.findViewById<TextView>(R.id.name).text = item.name
389+
return view
390+
}
391+
}
392+
MaterialAlertDialogBuilder(context)
393+
.setTitle(getString(R.string.fake_app_icon))
394+
.setAdapter(adapter) { _, which ->
395+
val selected = items[which]
396+
preferenceManager.sharedPreferences?.edit {
397+
putString(FAKE_LAUNCHER_ICON, selected.alias)
398+
}
399+
val app = context.applicationContext as? HanimeApplication
400+
app?.switchLauncher(selected.alias)
401+
summary = selected.name
402+
showLongToast(getString(R.string.fake_icon_hint))
403+
}
404+
.show()
405+
true
406+
}
407+
}
342408
}
343409

344410
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
<vector xmlns:android="http://schemas.android.com/apk/res/android" android:height="13.204384dp" android:viewportHeight="1024" android:viewportWidth="1861" android:width="24dp">
2+
3+
<path android:fillColor="#ffffff" android:pathData="M1739.2,98.4s-56.6,77 -373.5,-27.5c-150.3,-34.8 -308.3,40 -442.8,95.9 -134.8,-54.5 -293.3,-128.3 -443.4,-92.2C163.4,181.8 106.4,105.2 106.4,105.2s-54.7,744.3 459.7,849.4c156.1,40 257.3,-96.2 358.9,-96.6s203.8,134.7 359.5,93.6c513.7,-109.4 454.6,-853.3 454.6,-853.3zM844.9,587S424.4,784.6 316.7,351.7l205.5,-3.1a309.6,309.6 0,0 1,322.6 238.5zM1529.7,351.7c-107.5,432.9 -528.2,235.4 -528.2,235.4a309.7,309.7 0,0 1,322.6 -238.5l205.5,3.1z"/>
4+
5+
</vector>
2.36 KB
Loading
5.2 KB
Loading

0 commit comments

Comments
 (0)