45 Commits
2.101 ... 2.110

Author SHA1 Message Date
9465286ce1 Bump version to 2.110 2023-11-03 13:23:46 +08:00
61849cebe0 docs: update download links and description 2023-11-03 13:19:46 +08:00
1f71fbda9a feat: add classic (MIUI) style notification icon replacement 2023-11-03 12:18:18 +08:00
8f01e649fe feat: display HyperOS when decided and add HyperOS description 2023-11-03 11:32:57 +08:00
ae15d72923 refactor: optimize code 2023-11-03 10:33:02 +08:00
3b82c33c2e feat: remove warn dialog, support A14 and HyperOS 2023-11-02 11:58:08 +08:00
621f973a2f refactor: use legacy updateIconColor function to reset icon and color 2023-11-02 11:56:27 +08:00
ef2c8afe3f fix: notification panel refresh function
- Use SettingsManager instead StatusBarNotificationPresenter on A14 and HyperOS
2023-11-02 11:47:25 +08:00
3d7e4d8825 feat: shrink padding of notification icon on HyperOS 2023-11-02 09:57:35 +08:00
19b2efbb83 fix: ExpandableNotificationRow on A14 and HyperOS 2023-11-02 09:29:19 +08:00
d330510788 fix: handleAppIcon on A14 and HyperOS 2023-11-02 09:18:12 +08:00
25a23d7e1a fix: calculateIconTranslations on A14 and HyperOS 2023-11-02 09:11:06 +08:00
db4b418ed4 fix: updateNotificationIcons on A14 and HyperOS 2023-11-02 09:10:50 +08:00
8a97e38d20 fix: updateStatusBarIconAlpha on A14 and HyperOS 2023-11-02 08:12:40 +08:00
Fankesyooni
f294120fa8 Merge pull request #194 from hosizoraru/master
fix: A13 ignored A14 Adapt
2023-10-31 21:35:20 +08:00
hosizoraru
d244658aa6 fix: A13 ignored A14 Adapt 2023-10-31 15:03:52 +08:00
Fankesyooni
445ac85d8d Merge pull request #192 from hosizoraru/master
fix: statusBarMaxStaticIcons on A14/HyperOS
2023-10-31 13:10:02 +08:00
hosizoraru
e3b22671c1 fix: statusBarMaxStaticIcons on A14/HyperOS 2023-10-31 12:57:31 +08:00
d574449e4a docs: update explore history 2023-10-31 09:15:01 +08:00
85a2e730e0 docs: update release channel 2023-10-26 21:26:46 +08:00
ca367bde9e feat: simple support HyperOS 2023-10-23 00:45:42 +08:00
03ce7fbbe6 docs: add HyperOS support 2023-10-23 00:45:26 +08:00
88e3f79878 fix: catch toast when no looper 2023-10-22 22:36:16 +08:00
ba67bd0a62 chore: update target sdk to 34 2023-10-21 01:18:53 +08:00
0c0cf9bfba feat(docs): update YukiHookAPI owner link 2023-10-21 01:18:49 +08:00
0e98ec16c7 refactor: remove RECEIVER_NOT_EXPORTED_PERMISSION 2023-10-21 01:13:39 +08:00
f1fd3f2679 refactor: migrate to YukiHookAPI new usage 2023-10-07 21:02:34 +08:00
97065494b0 chore: bump dependency versions 2023-10-07 21:02:27 +08:00
b172d7a090 chore: bump plugin versions
- bump "com.highcapable.sweetdependency" version to 1.0.2
- bump "com.highcapable.sweetproperty" version to 1.0.3
2023-09-26 09:06:34 +08:00
b86988a310 refactor: add new R8 rules to fix possible problems 2023-09-19 08:18:38 +08:00
32f8ca9d63 ci: fix artifacts name 2023-09-19 01:51:56 +08:00
3cf67eb7fc feat: simple support Android 14 display name 2023-09-18 00:21:12 +08:00
9f39f297f9 docs: optimize comments 2023-09-18 00:19:03 +08:00
7feab98a1e feat: lots of changes
- add BuildConfigWrapper
- merge to new project promote
- add ci version tag support
- Fix system api compat issues
2023-09-18 00:17:23 +08:00
b297b43dfb docs: update README, EXPLORE_HISTORY 2023-09-18 00:15:54 +08:00
c7c03e891f style: optimize code 2023-09-18 00:15:08 +08:00
5ddc5de475 docs: move images to img-src 2023-09-18 00:13:17 +08:00
d09c11f026 refactor: use new payment code 2023-09-18 00:12:16 +08:00
bf22cae957 fix: class not found when R8 since android gradle plugin 8+ 2023-09-18 00:11:26 +08:00
a08e085b2b ci: optimize and add artifacts post to Telegram 2023-09-18 00:10:57 +08:00
9690e27511 chore: add Android 14 option 2023-09-18 00:10:31 +08:00
f9dde5f549 chore: migrate build script from groovy to kts
- using SweetDependency, SweetProperty
- merge singing key file configs to properties
- update gradle and dependencies
2023-09-18 00:10:06 +08:00
8ddb938883 chore: clean up build step files 2023-09-18 00:08:14 +08:00
8664d7b285 [Change Commit Specification] Use the new commit spec from here on
child commits:
chore: add .editorconfig
2023-09-18 00:05:26 +08:00
d70d01cf6c Fix SystemUI crashed when StatusBarNotification's tag is null by NotificationStat method "isUnimportantEntry" in SystemUIHooker 2023-08-27 14:38:05 +08:00
70 changed files with 1307 additions and 853 deletions

17
.editorconfig Normal file
View File

@@ -0,0 +1,17 @@
# noinspection EditorConfigKeyCorrectness
[{*.kt,*.kts}]
ktlint_standard_annotation = disabled
ktlint_standard_filename = disabled
ktlint_standard_wrapping = disabled
ktlint_standard_import-ordering = enabled
ktlint_standard_max-line-length = disabled
ktlint_standard_multiline-if-else = disabled
ktlint_standard_argument-list-wrapping = disabled
ktlint_standard_parameter-list-wrapping = disabled
ktlint_standard_trailing-comma-on-declaration-site = disabled
ktlint_function_signature_body_expression_wrapping = multiline
ij_continuation_indent_size = 2
indent_size = 4
indent_style = space
insert_final_newline = false
max_line_length = 150

View File

@@ -1,6 +1,6 @@
name: 问题与 BUG 反馈
description: 问题反馈必须使用此模板进行提交
labels: [bug]
labels: [ bug ]
title: "[问题与 BUG 反馈] (在这里简要描述问题原因)"
body:
- type: markdown
@@ -8,7 +8,7 @@ body:
value: |
### 请在下方填写问题发生的具体原因和复现步骤。
我们只接受 MIUI 正规官方版本系统,如果你正在使用 MIUI 官改(第三方修改版)请不要提交任何 BUG 与问题,我们无义务去解决,请自求多福。
我们只接受 MIUI 或 HyperOS 正规官方版本系统,如果你正在使用官改 (第三方修改版) 请不要提交任何 BUG 与问题,我们无义务去解决,请自求多福。
发生异常、崩溃、闪退或功能性问题,必须提交问题 Log (日志),没有 Log 的 issues 将直接被关闭。
- type: input
@@ -19,16 +19,16 @@ body:
required: true
- type: input
attributes:
label: MIUI 版本
label: 系统版本
description: |
这里填写当前的 MIUI 版本,例如:**13.0.1**
开发版需要标注具体的版本号,例如:**13 22.9.27**
这里填写当前的系统,例如:**MIUI 13.0.1** 或 **HyperOS 1.0**
开发版需要标注具体的版本号,例如:**MIUI 13 22.9.27** 或 **HyperOS 1.0 22.9.27**
validations:
required: true
- type: dropdown
attributes:
label: MIUI 版本类型
description: 请选择你使用的 MIUI 版本类型。
label: 系统版本类型
description: 请选择你使用的系统版本类型。
options:
- 稳定版
- 稳定内测版
@@ -41,6 +41,7 @@ body:
attributes:
label: Android 版本
options:
- 14
- 13
- 12L/12.1
- 12

View File

@@ -13,17 +13,34 @@ on:
jobs:
build:
name: Build CI
if: ${{ success() }}
runs-on: ubuntu-latest
env:
APK_OUTPUT_PATH: 'app/build/outputs/apk'
TG_BOT_TOKEN: ${{ secrets.TELEGRAM_BOT_TOKEN }}
TG_CHAT_ID: ${{ secrets.TELEGRAM_CHAT_ID }}
COMMIT_MESSAGE: |+
New push to GitHub\!
```
${{ github.event.head_commit.message }}
```by `${{ github.event.head_commit.author.name }}`
See commit detail [here](${{ github.event.head_commit.url }})
COMMIT_URL: ${{ github.event.head_commit.url }}
steps:
- uses: actions/checkout@v3
- name: Prepare GitHub Env
run: |
GITHUB_SHA=${{ github.sha }}
GITHUB_CI_COMMIT_ID=${GITHUB_SHA:0:7}
echo "GITHUB_CI_COMMIT_ID=$GITHUB_CI_COMMIT_ID" >> $GITHUB_ENV
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1
with:
cmake-version: '3.22.1'
- name: Prepare Java 11
- name: Prepare Java 17
uses: actions/setup-java@v3
with:
java-version: 11
java-version: 17
java-package: jdk
distribution: 'temurin'
cache: 'gradle'
@@ -34,7 +51,7 @@ jobs:
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/caches/build-cache-*
key: gradle-deps-core-${{ hashFiles('**/build.gradle') }}
key: gradle-deps-core-${{ hashFiles('**/build.gradle.kts') }}
restore-keys: |
gradle-deps
- name: Cache Gradle Build
@@ -49,15 +66,23 @@ jobs:
run: |
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
echo "DEBUG_APK_FILE=$(find app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(debug)
echo "DEBUG_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts (Debug)
uses: actions/upload-artifact@v3
with:
path: ${{ env.DEBUG_APK_FILE }}
name: app-debug
- name: Upload Artifacts(release)
path: ${{ env.DEBUG_APK_PATH }}
name: MIUINativeNotifyIcon-debug-${{ github.event.head_commit.id }}
- name: Upload Artifacts (Release)
uses: actions/upload-artifact@v3
with:
path: ${{ env.RELEASE_APK_FILE }}
name: app-release
path: ${{ env.RELEASE_APK_PATH }}
name: MIUINativeNotifyIcon-release-${{ github.event.head_commit.id }}
- name: Post Artifacts to Telegram
run: |
export debug=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name "*.apk")
export release=$(find ${{ env.APK_OUTPUT_PATH }}/release -name "*.apk")
ESCAPED=`python3 -c 'import json,os,urllib.parse; msg = json.dumps(os.environ["COMMIT_MESSAGE"]); print(urllib.parse.quote(msg if len(msg) <= 1024 else json.dumps(os.environ["COMMIT_URL"])))'`
curl -v "https://api.telegram.org/bot${TG_BOT_TOKEN}/sendMediaGroup?chat_id=${TG_CHAT_ID}&media=%5B%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Fdebug%22%7D%2C%7B%22type%22%3A%22document%22%2C%20%22media%22%3A%22attach%3A%2F%2Frelease%22%2C%22parse_mode%22%3A%22MarkdownV2%22%2C%22caption%22:${ESCAPED}%7D%5D" \
-F debug="@$debug" \
-F release="@$release"

View File

@@ -11,18 +11,26 @@ on:
jobs:
build:
name: Pull request check
name: Pull Request Check
if: ${{ success() }}
runs-on: ubuntu-latest
env:
APK_OUTPUT_PATH: 'app/build/outputs/apk'
steps:
- uses: actions/checkout@v3
- name: Prepare GitHub Env
run: |
GITHUB_SHA=${{ github.sha }}
GITHUB_CI_COMMIT_ID=${GITHUB_SHA:0:7}
echo "GITHUB_CI_COMMIT_ID=$GITHUB_CI_COMMIT_ID" >> $GITHUB_ENV
- name: Setup cmake
uses: jwlawson/actions-setup-cmake@v1
with:
cmake-version: '3.22.1'
- name: Prepare Java 11
- name: Prepare Java 17
uses: actions/setup-java@v3
with:
java-version: 11
java-version: 17
java-package: jdk
distribution: 'temurin'
cache: 'gradle'
@@ -33,7 +41,7 @@ jobs:
~/.gradle/caches
~/.gradle/wrapper
!~/.gradle/caches/build-cache-*
key: gradle-deps-core-${{ hashFiles('**/build.gradle') }}
key: gradle-deps-core-${{ hashFiles('**/build.gradle.kts') }}
restore-keys: |
gradle-deps
- name: Cache Gradle Build
@@ -48,15 +56,15 @@ jobs:
run: |
./gradlew :app:assembleDebug
./gradlew :app:assembleRelease
echo "DEBUG_APK_FILE=$(find app/build/outputs/apk/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_FILE=$(find app/build/outputs/apk/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts(debug)
echo "DEBUG_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/debug -name '*.apk')" >> $GITHUB_ENV
echo "RELEASE_APK_PATH=$(find ${{ env.APK_OUTPUT_PATH }}/release -name '*.apk')" >> $GITHUB_ENV
- name: Upload Artifacts (Debug)
uses: actions/upload-artifact@v3
with:
path: ${{ env.DEBUG_APK_FILE }}
name: app-debug
- name: Upload Artifacts(release)
path: ${{ env.DEBUG_APK_PATH }}
name: MIUINativeNotifyIcon-debug-${{ github.event.head_commit.id }}
- name: Upload Artifacts (Release)
uses: actions/upload-artifact@v3
with:
path: ${{ env.RELEASE_APK_FILE }}
name: app-release
path: ${{ env.RELEASE_APK_PATH }}
name: MIUINativeNotifyIcon-release-${{ github.event.head_commit.id }}

2
.idea/.gitignore generated vendored
View File

@@ -1,3 +1,5 @@
# Default ignored files
/shelf/
/workspace.xml
/gradle.xml
/misc.xml

1
.idea/.name generated
View File

@@ -1 +0,0 @@
MIUINativeNotifyIcon

26
.idea/appInsightsSettings.xml generated Normal file
View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="AppInsightsSettings">
<option name="tabSettings">
<map>
<entry key="Firebase Crashlytics">
<value>
<InsightsFilterSettings>
<option name="connection">
<ConnectionSetting>
<option name="appId" value="PLACEHOLDER" />
<option name="mobileSdkAppId" value="" />
<option name="projectId" value="" />
<option name="projectNumber" value="" />
</ConnectionSetting>
</option>
<option name="signal" value="SIGNAL_UNSPECIFIED" />
<option name="timeIntervalDays" value="THIRTY_DAYS" />
<option name="visibilityType" value="ALL" />
</InsightsFilterSettings>
</value>
</entry>
</map>
</option>
</component>
</project>

2
.idea/compiler.xml generated
View File

@@ -1,6 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<bytecodeTargetLevel target="11" />
<bytecodeTargetLevel target="17" />
</component>
</project>

10
.idea/deploymentTargetDropDown.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<value>
<entry key="app">
<State />
</entry>
</value>
</component>
</project>

20
.idea/gradle.xml generated
View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="GradleMigrationSettings" migrationVersion="1" />
<component name="GradleSettings">
<option name="linkedExternalProjectsSettings">
<GradleProjectSettings>
<option name="testRunner" value="GRADLE" />
<option name="distributionType" value="DEFAULT_WRAPPED" />
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="gradleJvm" value="11" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
</set>
</option>
</GradleProjectSettings>
</option>
</component>
</project>

View File

@@ -6,5 +6,6 @@
<option name="processLiterals" value="true" />
<option name="processComments" value="true" />
</inspection_tool>
<inspection_tool class="YAMLSchemaValidation" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

6
.idea/kotlinc.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KotlinJpsPluginSettings">
<option name="version" value="1.9.10" />
</component>
</project>

6
.idea/ktlint.xml generated Normal file
View File

@@ -0,0 +1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="KtlintProjectConfiguration">
<treatAsErrors>false</treatAsErrors>
</component>
</project>

10
.idea/migrations.xml generated Normal file
View File

@@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectMigrations">
<option name="MigrateToGradleLocalJavaHome">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</component>
</project>

43
.idea/misc.xml generated
View File

@@ -1,43 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="DesignSurface">
<option name="filePathToZoomLevelMap">
<map>
<entry key="app/src/main/res/drawable-night/dark_round.xml" value="0.256" />
<entry key="app/src/main/res/drawable-night/permotion_round.xml" value="0.256" />
<entry key="app/src/main/res/drawable-v24/ic_launcher_foreground.xml" value="0.44871794871794873" />
<entry key="app/src/main/res/drawable/bg_dark_round.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_dialog_background.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_green_round.xml" value="0.255" />
<entry key="app/src/main/res/drawable/bg_orange_round.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_warn_round.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/bg_yellow_round.xml" value="0.255" />
<entry key="app/src/main/res/drawable/ic_nf_icon_refresh.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/ic_nf_icon_update.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/ic_notify_icon.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/ic_system_clock.xml" value="0.2325" />
<entry key="app/src/main/res/drawable/permotion_round.xml" value="0.256" />
<entry key="app/src/main/res/drawable/white_round.xml" value="0.256" />
<entry key="app/src/main/res/layout-w1240dp/dia_source_from.xml" value="0.36484375" />
<entry key="app/src/main/res/layout-w1240dp/dia_source_from_string.xml" value="0.36484375" />
<entry key="app/src/main/res/layout-w936dp/dia_status_icon_cout.xml" value="0.935546875" />
<entry key="app/src/main/res/layout/activity_config.xml" value="0.42168674698795183" />
<entry key="app/src/main/res/layout/activity_login.xml" value="0.4375" />
<entry key="app/src/main/res/layout/activity_main.xml" value="0.30387540746106484" />
<entry key="app/src/main/res/layout/adapter_config.xml" value="0.375" />
<entry key="app/src/main/res/layout/dia_icon_filter.xml" value="0.4307692307692308" />
<entry key="app/src/main/res/layout/dia_icon_search.xml" value="0.4307692307692308" />
<entry key="app/src/main/res/layout/dia_source_from.xml" value="0.3591278324070115" />
<entry key="app/src/main/res/layout/dia_source_from_string.xml" value="0.4307692307692308" />
<entry key="app/src/main/res/layout/dia_status_icon_count.xml" value="0.45" />
<entry key="app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml" value="0.44871794871794873" />
</map>
</option>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_11" default="true" project-jdk-name="11" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/build/classes" />
</component>
<component name="ProjectType">
<option name="id" value="Android" />
</component>
</project>

View File

@@ -1,6 +0,0 @@
{
"keyAlias": "public",
"keyPassword": "123456",
"storeFileName": "universal.p12",
"storePassword": "123456"
}

View File

@@ -12,22 +12,34 @@
但是,这个模块就是为了修复被 MIUI 开发组忽略的图标问题才诞生的,并完美地给 MIUI 修复了黑白块图标的问题。
补充:现在这个 [开发文档](https://dev.mi.com/distribute/doc/details?pId=1582) 竟然还在,那就放在这里鞭个尸吧。
## 效果展示
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/style.png?raw=true"/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/style.png?raw=true" alt="Screenshot"/>
## 探索历程
原生 Android 的小图标和通知图标具有状态性。<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native.jpg?raw=true" height = "35"/><br/><br/>
而 MIUI 最近的版本直接破坏了这一状态性,全部设置为 APP 的图标,不仅难看而且你无法下拉通知栏区别这些图标代表什么。<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui.jpg?raw=true" height = "40"/><br/><br/>
同样地,通知面板的图标同样遵守这一状态性。<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native_n_1.jpg?raw=true" height = "100"/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/native_n_2.jpg?raw=true" height = "100"/><br/><br/>
而 MIUI 做了什么呢?<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui_n_1.jpg?raw=true" height = "100"/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/images/miui_n_2.jpg?raw=true" height = "100"/><br/><br/>
原生 Android 的小图标和通知图标具有状态性。
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/native.jpg?raw=true" height = "35" alt="Screenshot"/>
而 MIUI 最近的版本直接破坏了这一状态性,全部设置为 APP 的图标,不仅难看而且你无法下拉通知栏区别这些图标代表什么。
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/miui.jpg?raw=true" height = "40" alt="Screenshot"/>
同样地,通知面板的图标同样遵守这一状态性。
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/native_n_1.jpg?raw=true" height = "100" alt="Screenshot"/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/native_n_2.jpg?raw=true" height = "100" alt="Screenshot"/>
而 MIUI 做了什么呢?
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/miui_n_1.jpg?raw=true" height = "100" alt="Screenshot"/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/miui_n_2.jpg?raw=true" height = "100" alt="Screenshot"/>
不曾记得是什么版本开始MIUI 把通知图标改成了这个鬼样子,寻找开发组提案也是无人问津,最后转念一想,自己干吧。
由于目前大量通知图标都来自 `MIPUSH` 发出的营销通知,而 `MIPUSH` 的图标都是统一的彩色应用图标,很多应用也没有适配这一特性, 在通知栏广告满天飞的情况下MIUI

View File

@@ -1,20 +1,25 @@
# MIUI 原生通知图标
[![Blank](https://img.shields.io/badge/build-passing-brightgreen)](https://github.com/fankes/MIUINativeNotifyIcon)
[![Blank](https://img.shields.io/badge/license-AGPL3.0-blue)](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
[![Blank](https://img.shields.io/badge/version-v2.101-green)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/fankes/MIUINativeNotifyIcon/total?label=Release)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
[![Blank](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.miui.notify/total?label=LSPosed%20Repo&logo=Android&style=flat&labelColor=F48FB1&logoColor=ffffff)](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
[![Telegram](https://img.shields.io/badge/Follow-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)
<br/><br/>
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/app/src/main/ic_launcher-playstore.png?raw=true" width = "100" height = "100"/>
<br/>
Fix the native notification bar icon function abandoned by the MIUI development team.<br/>
修复被 MIUI 开发组丢弃的原生通知图标,支持 MIUI 11、12、12.5、13、14 以及最新版本。
[![GitHub license](https://img.shields.io/github/license/fankes/MIUINativeNotifyIcon?color=blue)](https://github.com/fankes/MIUINativeNotifyIcon/blob/master/LICENSE)
[![GitHub CI](https://img.shields.io/github/actions/workflow/status/fankes/MIUINativeNotifyIcon/commit_ci.yml?label=CI%20builds)](https://github.com/fankes/MIUINativeNotifyIcon/actions/workflows/commit_ci.yml)
[![GitHub release](https://img.shields.io/github/v/release/fankes/MIUINativeNotifyIcon?display_name=release&logo=github&color=green)](https://github.com/fankes/MIUINativeNotifyIcon/releases)
![GitHub all releases](https://img.shields.io/github/downloads/fankes/MIUINativeNotifyIcon/total?label=downloads)
![GitHub all releases](https://img.shields.io/github/downloads/Xposed-Modules-Repo/com.fankes.miui.notify/total?label=LSPosed%20downloads&labelColor=F48FB1)
## Developer
[![Telegram CI](https://img.shields.io/badge/CI%20builds-Telegram-blue.svg?logo=telegram)](https://t.me/MIUINativeNotifyIcon_CI)
[![Telegram](https://img.shields.io/badge/discussion-Telegram-blue.svg?logo=telegram)](https://t.me/XiaofangInternet)
[![QQ](https://img.shields.io/badge/discussion-QQ-blue.svg?logo=tencent-qq&logoColor=red)](https://qm.qq.com/cgi-bin/qm/qr?k=dp2h5YhWiga9WWb_Oh7kSHmx01X8I8ii&jump_from=webapi&authKey=Za5CaFP0lk7+Zgsk2KpoBD7sSaYbeXbsDgFjiWelOeH4VSionpxFJ7V0qQBSqvFM)
[![QQ 频道](https://img.shields.io/badge/discussion-QQ%20频道-blue.svg?logo=tencent-qq&logoColor=red)](https://pd.qq.com/s/44gcy28h)
[酷安 @星夜不荟](http://www.coolapk.com/u/876977)
<img src="https://github.com/fankes/MIUINativeNotifyIcon/blob/master/img-src/icon.png?raw=true" width = "100" height = "100" alt="LOGO"/>
Fix the native notification bar icon function abandoned by the MIUI development team.
修复被 MIUI 开发组丢弃的原生通知图标,支持 MIUI 11~14 以及 HyperOS 1.0。
## For Non-Chinese Users
This project will not be adapted i18n, please stay tuned for my new projects in the future.
## 项目迁移公告
@@ -24,7 +29,7 @@ Fix the native notification bar icon function abandoned by the MIUI development
## 适配说明
- 此模块仅支持 <b>LSPosed</b>(作用域“系统界面”)、<b>~~EdXposed(随时停止支持)~~</b>、不支持<b>太极、无极</b>
- 此模块仅支持 **LSPosed** (作用域“系统界面”)、**~~EdXposed(随时停止支持)~~**、不支持**太极、无极**
- 请确保你使用的是 MIUI 官方版本,任何第三方官改包发生的问题,开发者没有义务去解决和修复,请自求多福
@@ -32,7 +37,7 @@ Fix the native notification bar icon function abandoned by the MIUI development
- 建议最低从 MIUI 12.5 `2021-5-18` 开发版以后开始使用模块,之前的版本可能或多或少存在 MIUI 自身 BUG 不生效、图标黑白块的问题
- 请始终保持最新版本的 LSPosed旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面”(“系统 UI”)选择重新优化
- 请始终保持最新版本的 **LSPosed**,旧版本可能会出现 Hook 不生效的问题,若最新版本依然不生效请在作用域中长按“系统界面” (“系统 UI”) 选择重新优化
## 历史背景
@@ -46,41 +51,49 @@ Fix the native notification bar icon function abandoned by the MIUI development
- [Android 通知图标规范适配计划](https://github.com/fankes/AndroidNotifyIconAdapt)
## 发行渠道
| <img src="https://avatars.githubusercontent.com/in/15368?s=64&v=4" width = "30" height = "30" alt="LOGO"/> | [GitHub CI](https://github.com/fankes/MIUINativeNotifyIcon/actions/workflows/commit_ci.yml) | CI 自动构建 (测试版) |
|------------------------------------------------------------------------------------------------------------|---------------------------------------------------------------------------------------------|---------------|
| <img src="https://github.com/peter-iakovlev/Telegram/blob/public/Icon.png?raw=true" width = "30" height = "30" alt="LOGO"/> | [Telegram CI 频道](https://t.me/MIUINativeNotifyIcon_CI) | CI 自动构建 (测试版) |
|-----------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------|---------------|
| <img src="https://avatars.githubusercontent.com/in/15368?s=64&v=4" width = "30" height = "30" alt="LOGO"/> | [GitHub Releases](https://github.com/fankes/MIUINativeNotifyIcon/releases) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------|-----------|
| <img src="https://avatars.githubusercontent.com/u/78217009?s=200&v=4?raw=true" width = "30" height = "30" alt="LOGO"/> | [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------|-----------|
| <img src="https://github.com/fankes/fankes/assets/37344460/82113d3c-aa7b-4dd1-95c7-cda650065c12" width = "30" height = "30" alt="LOGO"/> | [123 云盘 **(密码62ll)**](https://www.123pan.com/s/5SlUVv-W8DBh.html) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------------|-----------|
| <img src="https://github.com/fankes/fankes/assets/37344460/3cd43efd-785e-411d-a5c3-a8c9dc02308a" width = "30" height = "30" alt="LOGO"/> | [酷安应用市场](https://www.coolapk.com/apk/com.fankes.miui.notify) | 正式版 (稳定版) |
|------------------------------------------------------------------------------------------------------------------------------------------|--------------------------------------------------------------|-----------|
本模块发布地址仅限于上述所列出的地址,从其他非正规渠道下载到的版本或对您造成任何影响均与我们无关。
## 请勿用于非法用途
- 本模块完全开源免费,如果好用你可以打赏支持开发,但是请不要用于非法用途。
## 发行渠道说明
## 项目推广
- [Automatic Build on Commit](https://github.com/fankes/MIUINativeNotifyIcon/actions/workflows/commit_ci.yml)
如果你正在寻找一个可以自动管理 Gradle 项目依赖的 Gradle 插件,你可以了解一下 [SweetDependency](https://github.com/HighCapable/SweetDependency) 项目。
上述更新为代码 `commit` 后自动触发,具体更新内容可点击上方的文字前往 **GitHub Actions** 进行查看,本更新由开源的流程自动编译发布,**不保证其稳定性**,所发布的版本**仅供测试**,且不会特殊说明甚至可能会变更版本号或保持与当前稳定版相同的版本号
如果你正在寻找一个可以自动生成属性键值的 Gradle 插件,你可以了解一下 [SweetProperty](https://github.com/HighCapable/SweetProperty) 项目
- [Release](https://github.com/fankes/MIUINativeNotifyIcon/releases)
- [Xposed-Modules-Repo](https://github.com/Xposed-Modules-Repo/com.fankes.miui.notify/releases)
- [蓝奏云 **密码62ll**](https://fankes.lanzouy.com/b030o2e8h)
- [酷安应用市场](https://www.coolapk.com/apk/com.fankes.miui.notify)
上述更新为手动发布的稳定版,具体更新内容可点击上方的文字前往指定的发布页面查看,稳定版的更新将会同时发布到上述地址中,同步更新。
## 发行状态说明
![Blank](https://img.shields.io/badge/build-passing-brightgreen)
上述状态为当前稳定版与自动构建版本一致或当前代码改动与稳定版无功能差异。
![Blank](https://img.shields.io/badge/build-pending-dbab09)
上述状态为存在自动构建版本和新功能的更新但当前并未发布稳定版,处于预发行状态。
![Blank](https://img.shields.io/badge/build-problem-red)
上述状态为当前发行的稳定版可能存在严重问题但并未及时进行修复且并未发布稳定版。
本项目同样使用了 **SweetDependency****SweetProperty**
## 捐赠支持
- 工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。<br/><br/>
<img src="https://github.com/fankes/YuKiHookAPI/blob/master/img-src/wechat_code.jpg?raw=true" width = "200" height = "200"/>
工作不易,无意外情况此项目将继续维护下去,提供更多可能,欢迎打赏。
<img src="https://github.com/fankes/fankes/blob/main/img-src/payment_code.jpg?raw=true" width = "500" alt="Payment Code"/>
## Star History
![Star History Chart](https://api.star-history.com/svg?repos=fankes/MIUINativeNotifyIcon&type=Date)
## 隐私政策
@@ -104,9 +117,9 @@ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
along with this program. If not, see <https://www.gnu.org/licenses/>.
```
Powered by [YukiHookAPI](https://github.com/fankes/YukiHookAPI)
Powered by [YukiHookAPI](https://github.com/HighCapable/YukiHookAPI)
版权所有 © 2017-2023 Fankes Studio(qzmmcn@163.com)

View File

@@ -1,88 +0,0 @@
import groovy.json.JsonSlurper
plugins {
id 'com.android.application'
id 'org.jetbrains.kotlin.android'
id 'com.google.devtools.ksp'
}
android {
signingConfigs {
universal {
def dirPath = rootProject.ext.app.signingConfigs.secretConfigsDirPath
def fileName = rootProject.ext.app.signingConfigs.secretConfigsFileName
def configs = new JsonSlurper().parse(file("${dirPath}/${fileName}"))
keyAlias configs.keyAlias
keyPassword configs.keyPassword
storeFile file("${dirPath}/${configs.storeFileName}")
storePassword configs.storePassword
v1SigningEnabled true
v2SigningEnabled true
}
}
namespace 'com.fankes.miui.notify'
compileSdk rootProject.ext.android.compileSdk
defaultConfig {
applicationId 'com.fankes.miui.notify'
minSdk rootProject.ext.android.minSdk
targetSdk rootProject.ext.android.targetSdk
versionCode rootProject.ext.app.versionCode
versionName rootProject.ext.app.versionName
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
}
buildTypes {
debug {
minifyEnabled false
signingConfig signingConfigs.universal
}
release {
minifyEnabled true
shrinkResources true
zipAlignEnabled true
signingConfig signingConfigs.universal
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_11
targetCompatibility JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = '11'
freeCompilerArgs = [
'-Xno-param-assertions',
'-Xno-call-assertions',
'-Xno-receiver-assertions'
]
}
buildFeatures {
viewBinding true
}
lintOptions {
checkReleaseBuilds false
}
aaptOptions.additionalParameters '--allow-reserved-package-id', '--package-id', '0x64'
}
dependencies {
compileOnly 'de.robv.android.xposed:api:82'
implementation 'com.highcapable.yukihookapi:api:1.1.11'
ksp 'com.highcapable.yukihookapi:ksp-xposed:1.1.11'
implementation 'com.github.duanhong169:drawabletoolbox:1.0.7'
implementation "com.github.topjohnwu.libsu:core:5.0.4"
implementation 'androidx.annotation:annotation:1.6.0'
implementation 'com.squareup.okhttp3:okhttp:5.0.0-alpha.7'
implementation 'androidx.core:core-ktx:1.10.0'
implementation 'androidx.appcompat:appcompat:1.6.1'
implementation 'com.google.android.material:material:1.8.0'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
}

84
app/build.gradle.kts Normal file
View File

@@ -0,0 +1,84 @@
plugins {
autowire(libs.plugins.android.application)
autowire(libs.plugins.kotlin.android)
autowire(libs.plugins.kotlin.ksp)
}
android {
namespace = property.project.app.packageName
compileSdk = property.project.android.compileSdk
signingConfigs {
create("universal") {
keyAlias = property.project.app.signing.keyAlias
keyPassword = property.project.app.signing.keyPassword
storeFile = rootProject.file(property.project.app.signing.storeFilePath)
storePassword = property.project.app.signing.storePassword
enableV1Signing = true
enableV2Signing = true
}
}
defaultConfig {
applicationId = property.project.app.packageName
minSdk = property.project.android.minSdk
targetSdk = property.project.android.targetSdk
versionName = property.project.app.versionName
versionCode = property.project.app.versionCode
testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
all { signingConfig = signingConfigs.getByName("universal") }
release {
isMinifyEnabled = true
isShrinkResources = true
proguardFiles(getDefaultProguardFile("proguard-android-optimize.txt"), "proguard-rules.pro")
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_17
targetCompatibility = JavaVersion.VERSION_17
}
kotlinOptions {
jvmTarget = "17"
freeCompilerArgs = listOf(
"-Xno-param-assertions",
"-Xno-call-assertions",
"-Xno-receiver-assertions"
)
}
buildFeatures {
buildConfig = true
viewBinding = true
}
lint { checkReleaseBuilds = false }
androidResources.additionalParameters += listOf("--allow-reserved-package-id", "--package-id", "0x37")
}
androidComponents {
onVariants(selector().all()) {
it.outputs.forEach { output ->
val currentType = it.buildType
val currentSuffix = property.github.ci.commit.id.let { suffix -> if (suffix.isNotBlank()) "-$suffix" else "" }
val currentVersion = "${output.versionName.get()}$currentSuffix(${output.versionCode.get()})"
if (output is com.android.build.api.variant.impl.VariantOutputImpl)
output.outputFileName.set("${property.project.name}-v$currentVersion-$currentType.apk")
}
}
}
dependencies {
compileOnly(de.robv.android.xposed.api)
implementation(com.highcapable.yukihookapi.api)
ksp(com.highcapable.yukihookapi.ksp.xposed)
implementation(com.fankes.projectpromote.project.promote)
implementation(com.github.topjohnwu.libsu.core)
implementation(com.github.duanhong169.drawabletoolbox)
implementation(com.squareup.okhttp3.okhttp)
implementation(androidx.core.core.ktx)
implementation(androidx.appcompat.appcompat)
implementation(com.google.android.material.material)
implementation(androidx.constraintlayout.constraintlayout)
testImplementation(junit.junit)
androidTestImplementation(androidx.test.ext.junit)
androidTestImplementation(androidx.test.espresso.espresso.core)
}

View File

@@ -32,13 +32,15 @@
-adaptresourcefilecontents
-renamesourcefileattribute P
-keepattributes SourceFile,LineNumberTable
-keepattributes SourceFile,Signature,LineNumberTable
-assumenosideeffects class kotlin.jvm.internal.Intrinsics {
public static *** throwUninitializedProperty(...);
public static *** throwUninitializedPropertyAccessException(...);
}
-keepclassmembers class * implements androidx.viewbinding.ViewBinding {
-keep class * extends android.app.Activity
-keep class * implements androidx.viewbinding.ViewBinding {
<init>();
*** inflate(android.view.LayoutInflater);
}

View File

@@ -1,12 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.fankes.miui.notify">
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
tools:node="remove" />
<permission
android:name="${applicationId}.DYNAMIC_RECEIVER_NOT_EXPORTED_PERMISSION"
tools:node="remove" />
<application
android:name=".application.MNNApplication"
android:allowBackup="true"

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/24.
* This file is created by fankes on 2022/1/24.
*/
@file:Suppress("unused")

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/30.
* This file is created by fankes on 2022/1/30.
*/
package com.fankes.miui.notify.bean
@@ -47,13 +47,15 @@ data class IconDataBean(
) : Serializable {
fun toEnabledName() = ("$appName$packageName").base64 + "_enable"
fun toEnabledAllName() = ("$appName$packageName").base64 + "_enable_all"
override fun toString() = "{\n" +
" \"appName\": \"$appName\",\n" +
" \"packageName\": \"$packageName\",\n" +
" \"iconBitmap\": \"${iconBitmap.base64}\",\n" +
" \"iconColor\": \"#${Integer.toHexString(iconColor)}\",\n" +
" \"contributorName\": \"$contributorName\",\n" +
" \"isEnabled\": $isEnabled,\n" +
" \"isEnabledAll\": $isEnabledAll\n" +
" }"
override fun toString() = """
{
"appName": "$appName",
"packageName": "$packageName",
"iconBitmap": "${iconBitmap.base64}",
"iconColor": "#${Integer.toHexString(iconColor)}",
"contributorName": "$contributorName",
"isEnabled": $isEnabled,
"isEnabledAll": $isEnabledAll
}
""".trimIndent()
}

View File

@@ -18,10 +18,15 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/2/2.
* This file is created by fankes on 2023/2/2.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
package com.fankes.miui.notify.const
import com.fankes.miui.notify.generated.AppProperties
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
/**
* 包名常量定义类
*/
@@ -47,4 +52,27 @@ object IconRuleSourceSyncType {
/** 自定义地址 */
const val CUSTOM_URL = 3000
}
/**
* 模块版本常量定义类
*/
object ModuleVersion {
/** 当前 GitHub 提交的 ID (CI 自动构建) */
const val GITHUB_COMMIT_ID = AppProperties.GITHUB_CI_COMMIT_ID
/** 版本名称 */
const val NAME = BuildConfigWrapper.VERSION_NAME
/** 版本号 */
const val CODE = BuildConfigWrapper.VERSION_CODE
/** 是否为 CI 自动构建版本 */
val isCiMode = GITHUB_COMMIT_ID.isNotBlank()
/** 当前版本名称后缀 */
val suffix = GITHUB_COMMIT_ID.let { if (it.isNotBlank()) "-$it" else "" }
override fun toString() = "$NAME$suffix($CODE)"
}

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/2/2.
* This file is created by fankes on 2023/2/2.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
@@ -27,7 +27,7 @@ package com.fankes.miui.notify.data
import android.content.Context
import com.fankes.miui.notify.const.IconRuleSourceSyncType
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
@@ -60,6 +60,9 @@ object ConfigData {
/** 通知栏中的通知图标圆角程度 */
val NOTIFY_ICON_CORNER_SIZE = PrefsData("_notify_icon_corner", 15)
/** 替换 MIUI 样式通知栏的通知图标 */
val ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON = PrefsData("_replace_miui_style_notify_icon", true)
/** 强制通知栏中的通知图标使用系统着色 */
val ENABLE_NOTIFY_ICON_FORCE_SYSTEM_COLOR = PrefsData("_notify_icon_force_system_color", false)
@@ -127,7 +130,7 @@ object ConfigData {
private fun putString(data: PrefsData<String>, value: String) {
when (instance) {
is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method")
is PackageParam -> YLog.warn("Not support for this method")
else -> error("Unknown type for put prefs data")
}
}
@@ -151,7 +154,7 @@ object ConfigData {
internal fun putInt(data: PrefsData<Int>, value: Int) {
when (instance) {
is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method")
is PackageParam -> YLog.warn("Not support for this method")
else -> error("Unknown type for put prefs data")
}
}
@@ -175,7 +178,7 @@ object ConfigData {
internal fun putBoolean(data: PrefsData<Boolean>, value: Boolean) {
when (instance) {
is Context -> (instance as Context).prefs().edit { put(data, value) }
is PackageParam -> loggerW(msg = "Not support for this method")
is PackageParam -> YLog.warn("Not support for this method")
else -> error("Unknown type for put prefs data")
}
}
@@ -260,6 +263,16 @@ object ConfigData {
putInt(NOTIFY_ICON_CORNER_SIZE, value)
}
/**
* 是否替换 MIUI 样式通知栏的通知图标
* @return [Boolean]
*/
var isEnableReplaceMiuiStyleNotifyIcon
get() = getBoolean(ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON)
set(value) {
putBoolean(ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON, value)
}
/**
* 是否强制通知栏中的通知图标使用系统着色
* @return [Boolean]

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/2/3.
* This file is created by fankes on 2023/2/3.
*/
@file:Suppress("unused", "MemberVisibilityCanBePrivate")

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/2/4.
* This file is created by fankes on 2023/2/4.
*/
@file:Suppress("SetTextI18n")

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/2/15.
* This file is created by fankes on 2022/2/15.
*/
package com.fankes.miui.notify.hook
@@ -26,16 +26,16 @@ import com.fankes.miui.notify.const.PackageName
import com.fankes.miui.notify.data.ConfigData
import com.fankes.miui.notify.hook.entity.SystemUIHooker
import com.fankes.miui.notify.utils.factory.isLowerAndroidP
import com.fankes.miui.notify.utils.factory.isNotMIUI
import com.fankes.miui.notify.utils.factory.isNotSupportMiuiVersion
import com.fankes.miui.notify.utils.factory.miuiVersion
import com.fankes.miui.notify.utils.factory.isNotMiSystem
import com.fankes.miui.notify.utils.factory.isNotSupportMiSystemVersion
import com.fankes.miui.notify.utils.factory.miSystemVersion
import com.highcapable.yukihookapi.annotation.xposed.InjectYukiHookWithXposed
import com.highcapable.yukihookapi.hook.factory.configs
import com.highcapable.yukihookapi.hook.factory.encase
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.xposed.proxy.IYukiHookXposedInit
@InjectYukiHookWithXposed(isUsingResourcesHook = false)
@InjectYukiHookWithXposed
object HookEntry : IYukiHookXposedInit {
override fun onInit() = configs {
@@ -51,10 +51,10 @@ object HookEntry : IYukiHookXposedInit {
loadApp(PackageName.SYSTEMUI) {
ConfigData.init(instance = this)
when {
isNotMIUI -> loggerW(msg = "Aborted Hook -> This System is not MIUI")
isLowerAndroidP -> loggerW(msg = "Aborted Hook -> This System is lower than Android P")
isNotSupportMiuiVersion -> loggerW(msg = "Aborted Hook -> This MIUI Version ${miuiVersion.ifBlank { "unknown" }} not supported")
ConfigData.isEnableModule.not() -> loggerW(msg = "Aborted Hook -> Hook Closed")
isNotMiSystem -> YLog.warn("Aborted Hook -> This System is not MIUI or HyperOS")
isLowerAndroidP -> YLog.warn("Aborted Hook -> This System is lower than Android P")
isNotSupportMiSystemVersion -> YLog.warn("Aborted Hook -> This System Version ${miSystemVersion.ifBlank { "unknown" }} not supported")
ConfigData.isEnableModule.not() -> YLog.warn("Aborted Hook -> Hook Closed")
else -> loadHooker(SystemUIHooker)
}
}

View File

@@ -18,9 +18,9 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/25.
* This file is created by fankes on 2022/3/25.
*/
@file:Suppress("StaticFieldLeak")
@file:Suppress("StaticFieldLeak", "ConstPropertyName")
package com.fankes.miui.notify.hook.entity
@@ -46,6 +46,7 @@ import androidx.core.graphics.drawable.toBitmap
import androidx.core.graphics.drawable.toDrawable
import androidx.core.view.children
import androidx.core.view.isVisible
import androidx.core.view.setPadding
import com.fankes.miui.notify.R
import com.fankes.miui.notify.bean.IconDataBean
import com.fankes.miui.notify.const.PackageName
@@ -53,17 +54,41 @@ import com.fankes.miui.notify.data.ConfigData
import com.fankes.miui.notify.params.IconPackParams
import com.fankes.miui.notify.params.factory.isAppNotifyHookAllOf
import com.fankes.miui.notify.params.factory.isAppNotifyHookOf
import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.factory.appIconOf
import com.fankes.miui.notify.utils.factory.appNameOf
import com.fankes.miui.notify.utils.factory.brighterColor
import com.fankes.miui.notify.utils.factory.delayedRun
import com.fankes.miui.notify.utils.factory.dp
import com.fankes.miui.notify.utils.factory.dpFloat
import com.fankes.miui.notify.utils.factory.drawableOf
import com.fankes.miui.notify.utils.factory.isMIOS
import com.fankes.miui.notify.utils.factory.isNotSystemInDarkMode
import com.fankes.miui.notify.utils.factory.isSystemInDarkMode
import com.fankes.miui.notify.utils.factory.isUpperOfAndroidS
import com.fankes.miui.notify.utils.factory.miuiIncrementalVersion
import com.fankes.miui.notify.utils.factory.round
import com.fankes.miui.notify.utils.factory.runInSafe
import com.fankes.miui.notify.utils.factory.safeOf
import com.fankes.miui.notify.utils.factory.safeOfFalse
import com.fankes.miui.notify.utils.factory.systemAccentColor
import com.fankes.miui.notify.utils.tool.ActivationPromptTool
import com.fankes.miui.notify.utils.tool.BitmapCompatTool
import com.fankes.miui.notify.utils.tool.IconAdaptationTool
import com.fankes.miui.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.hook.bean.VariousClass
import com.highcapable.yukihookapi.hook.entity.YukiBaseHooker
import com.highcapable.yukihookapi.hook.factory.*
import com.highcapable.yukihookapi.hook.log.loggerD
import com.highcapable.yukihookapi.hook.log.loggerW
import com.highcapable.yukihookapi.hook.type.android.*
import com.highcapable.yukihookapi.hook.factory.constructor
import com.highcapable.yukihookapi.hook.factory.current
import com.highcapable.yukihookapi.hook.factory.extends
import com.highcapable.yukihookapi.hook.factory.field
import com.highcapable.yukihookapi.hook.factory.hasMethod
import com.highcapable.yukihookapi.hook.factory.injectModuleAppResources
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.android.ContextClass
import com.highcapable.yukihookapi.hook.type.android.DrawableClass
import com.highcapable.yukihookapi.hook.type.android.ImageViewClass
import com.highcapable.yukihookapi.hook.type.android.StatusBarNotificationClass
import com.highcapable.yukihookapi.hook.type.java.BooleanType
import com.highcapable.yukihookapi.hook.type.java.IntType
import top.defaults.drawabletoolbox.DrawableBuilder
@@ -74,68 +99,87 @@ import top.defaults.drawabletoolbox.DrawableBuilder
object SystemUIHooker : YukiBaseHooker() {
/** MIUI 新版本存在的类 */
private const val SystemUIApplicationClass = "${PackageName.SYSTEMUI}.SystemUIApplication"
private val SystemUIApplicationClass by lazyClassOrNull("${PackageName.SYSTEMUI}.SystemUIApplication")
/** MIUI 新版本存在的类 */
private const val MiuiNotificationViewWrapperClass = "${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.MiuiNotificationViewWrapper"
private val MiuiNotificationViewWrapperClass
by lazyClassOrNull("${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.MiuiNotificationViewWrapper")
/** MIUI 新版本存在的类 */
private const val MiuiNotificationChildrenContainerClass =
"${PackageName.SYSTEMUI}.statusbar.notification.stack.MiuiNotificationChildrenContainer"
private val MiuiNotificationChildrenContainerClass
by lazyClassOrNull("${PackageName.SYSTEMUI}.statusbar.notification.stack.MiuiNotificationChildrenContainer")
/** MIUI 新版本存在的类 */
private const val NotificationHeaderViewWrapperInjectorClass =
"${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector"
private val NotificationHeaderViewWrapperInjectorClass
by lazyClassOrNull("${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.NotificationHeaderViewWrapperInjector")
/** MIUI 未确定版本存在的类 */
private val SettingsManagerClass by lazyClassOrNull("com.miui.systemui.SettingsManager")
/** MIUI 新版本存在的类 */
private val NotificationStatClass by lazyClassOrNull("${PackageName.SYSTEMUI}.statusbar.notification.analytics.NotificationStat")
/** 原生存在的类 */
private const val NotificationChildrenContainerClass = "${PackageName.SYSTEMUI}.statusbar.notification.stack.NotificationChildrenContainer"
private val NotificationChildrenContainerClass by lazyClass("${PackageName.SYSTEMUI}.statusbar.notification.stack.NotificationChildrenContainer")
/** 原生存在的类 */
private const val NotificationIconAreaControllerClass = "${PackageName.SYSTEMUI}.statusbar.phone.NotificationIconAreaController"
private val NotificationIconAreaControllerClass by lazyClass("${PackageName.SYSTEMUI}.statusbar.phone.NotificationIconAreaController")
/** 原生存在的类 */
private const val ContrastColorUtilClass = "com.android.internal.util.ContrastColorUtil"
private val ContrastColorUtilClass by lazyClass("com.android.internal.util.ContrastColorUtil")
/** 原生存在的类 */
private const val StatusBarIconViewClass = "${PackageName.SYSTEMUI}.statusbar.StatusBarIconView"
private val StatusBarIconViewClass by lazyClass("${PackageName.SYSTEMUI}.statusbar.StatusBarIconView")
/** 原生存在的类 */
private const val NotificationIconContainerClass = "${PackageName.SYSTEMUI}.statusbar.phone.NotificationIconContainer"
private val NotificationIconContainerClass by lazyClass("${PackageName.SYSTEMUI}.statusbar.phone.NotificationIconContainer")
/** 根据多个版本存在不同的包名相同的类 */
private val StatusBarNotificationPresenterClass = VariousClass(
"${PackageName.SYSTEMUI}.statusbar.phone.StatusBarNotificationPresenter",
"${PackageName.SYSTEMUI}.statusbar.phone.StatusBar"
private val StatusBarNotificationPresenterClass by lazyClass(
VariousClass(
"${PackageName.SYSTEMUI}.statusbar.phone.StatusBarNotificationPresenter",
"${PackageName.SYSTEMUI}.statusbar.phone.StatusBar"
)
)
/** 根据多个版本存在不同的包名相同的类 */
private val ExpandableNotificationRowClass = VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.row.ExpandableNotificationRow",
"${PackageName.SYSTEMUI}.statusbar.ExpandableNotificationRow"
private val ExpandableNotificationRowClass by lazyClass(
VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.row.ExpandableNotificationRow",
"${PackageName.SYSTEMUI}.statusbar.ExpandableNotificationRow"
)
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationViewWrapperClass = VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.NotificationViewWrapper",
"${PackageName.SYSTEMUI}.statusbar.notification.NotificationViewWrapper"
private val NotificationViewWrapperClass by lazyClass(
VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.NotificationViewWrapper",
"${PackageName.SYSTEMUI}.statusbar.notification.NotificationViewWrapper"
)
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationHeaderViewWrapperClass = VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper",
"${PackageName.SYSTEMUI}.statusbar.notification.NotificationHeaderViewWrapper"
private val NotificationHeaderViewWrapperClass by lazyClass(
VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.row.wrapper.NotificationHeaderViewWrapper",
"${PackageName.SYSTEMUI}.statusbar.notification.NotificationHeaderViewWrapper"
)
)
/** 根据多个版本存在不同的包名相同的类 */
private val NotificationUtilClass = VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.NotificationUtil",
"${PackageName.SYSTEMUI}.miui.statusbar.notification.NotificationUtil"
private val NotificationUtilClass by lazyClass(
VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.NotificationUtil",
"${PackageName.SYSTEMUI}.miui.statusbar.notification.NotificationUtil"
)
)
/** 根据多个版本存在不同的包名相同的类 */
private val ExpandedNotificationClass = VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.ExpandedNotification",
"${PackageName.SYSTEMUI}.miui.statusbar.ExpandedNotification"
private val ExpandedNotificationClass by lazyClass(
VariousClass(
"${PackageName.SYSTEMUI}.statusbar.notification.ExpandedNotification",
"${PackageName.SYSTEMUI}.miui.statusbar.ExpandedNotification"
)
)
/** 缓存的通知图标优化数组 */
@@ -159,6 +203,9 @@ object SystemUIHooker : YukiBaseHooker() {
/** 通知栏通知控制器 */
private var notificationPresenter: Any? = null
/** 设置管理器 */
private var settingsManager: Any? = null
/** 仅监听一次主题壁纸颜色变化 */
private var isWallpaperColorListenerSetUp = false
@@ -167,20 +214,19 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [Context] or null
*/
private val globalContext
get() = SystemUIApplicationClass.toClassOrNull()?.method { name = "getContext" }?.ignored()?.get()?.invoke<Context?>() ?: appContext
get() = SystemUIApplicationClass?.method { name = "getContext" }?.ignored()?.get()?.invoke<Context?>() ?: appContext
/**
* 是否为 MIUI 样式通知栏 - 旧版 - 新版一律返回 false
* @return [Boolean]
*/
private val isShowMiuiStyle
get() = NotificationUtilClass.toClassOrNull()?.method { name = "showMiuiStyle" }?.ignored()?.get()?.boolean() ?: false
private val isShowMiuiStyle get() = NotificationUtilClass.method { name = "showMiuiStyle" }.ignored().get().boolean()
/**
* 是否没有单独的 MIUI 通知栏样式
* @return [Boolean]
*/
private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass.hasClass().not()
private val isNotHasAbsoluteMiuiStyle get() = MiuiNotificationViewWrapperClass == null
/**
* 获取状态栏通知图标透明度
@@ -223,6 +269,13 @@ object SystemUIHooker : YukiBaseHooker() {
return xmsfPkg.ifBlank { targetPkg.ifBlank { packageName } }
}
/**
* 获取 MIUI 自己设置的通知图标
* @return [Icon] or null
*/
@Suppress("DEPRECATION")
private val StatusBarNotification.miuiAppIcon get() = notification?.extras?.getParcelable<Icon?>("miui.appIcon")
/**
* 打印日志
* @param tag 标识
@@ -232,17 +285,17 @@ object SystemUIHooker : YukiBaseHooker() {
* @param isGrayscale 是否为灰度图标
*/
private fun loggerDebug(tag: String, context: Context, nf: StatusBarNotification?, isCustom: Boolean, isGrayscale: Boolean) {
if (ConfigData.isEnableModuleLog) loggerD(
if (ConfigData.isEnableModuleLog) YLog.debug(
msg = "(Processing $tag) ↓\n" +
"[Title]: ${nf?.notification?.extras?.getString(Notification.EXTRA_TITLE)}\n" +
"[Content]: ${nf?.notification?.extras?.getString(Notification.EXTRA_TEXT)}\n" +
"[App Name]: ${context.appNameOf(packageName = nf?.packageName ?: "")}\n" +
"[Package Name]: ${nf?.packageName}\n" +
"[Sender Package Name]: ${nf?.compatOpPkgName}\n" +
"[Custom Icon]: $isCustom\n" +
"[Grayscale Icon]: $isGrayscale\n" +
"[From Xmsf]: ${nf?.isXmsf}\n" +
"[String]: ${nf?.notification}"
"[Title]: ${nf?.notification?.extras?.getString(Notification.EXTRA_TITLE)}\n" +
"[Content]: ${nf?.notification?.extras?.getString(Notification.EXTRA_TEXT)}\n" +
"[App Name]: ${context.appNameOf(packageName = nf?.packageName ?: "")}\n" +
"[Package Name]: ${nf?.packageName}\n" +
"[Sender Package Name]: ${nf?.compatOpPkgName}\n" +
"[Custom Icon]: $isCustom\n" +
"[Grayscale Icon]: $isGrayscale\n" +
"[From Xmsf]: ${nf?.isXmsf}\n" +
"[String]: ${nf?.notification}"
)
}
@@ -256,7 +309,7 @@ object SystemUIHooker : YukiBaseHooker() {
*/
private fun isGrayscaleIcon(context: Context, drawable: Drawable) =
if (ConfigData.isEnableColorIconCompat.not()) safeOfFalse {
ContrastColorUtilClass.toClass().let {
ContrastColorUtilClass.let {
it.method {
name = "isGrayscaleIcon"
param(DrawableClass)
@@ -304,7 +357,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新状态栏小图标 */
private fun refreshStatusBarIcons() = runInSafe {
StatusBarIconViewClass.toClassOrNull()?.field { name = "mNotification" }?.also { result ->
StatusBarIconViewClass.field { name = "mNotification" }.also { result ->
notificationIconContainer?.children?.forEach {
/** 得到通知实例 */
val nf = result.get(it).cast<StatusBarNotification>() ?: return
@@ -318,10 +371,16 @@ object SystemUIHooker : YukiBaseHooker() {
/** 刷新通知小图标 */
private fun refreshNotificationIcons() = runInSafe {
notificationPresenter?.current()?.method {
name = "updateNotificationsOnDensityOrFontScaleChanged"
emptyParam()
}?.call()
val updateNotificationMethodName = "updateNotificationsOnDensityOrFontScaleChanged"
if (StatusBarNotificationPresenterClass.hasMethod { name = updateNotificationMethodName })
notificationPresenter?.current(ignored = true)?.method {
name = updateNotificationMethodName
emptyParam()
}?.call()
else settingsManager?.current {
field { name = "notifStyle" }.set(-100)
method { name = "onNotifStyleChanged" }.call()
}
}
/**
@@ -389,13 +448,15 @@ object SystemUIHooker : YukiBaseHooker() {
* @param iconView 通知图标实例
* @param isExpanded 通知是否展开 - 可做最小化通知处理 - 默认:是
* @param isUseMaterial3Style 是否使用 Material 3 通知图标风格 - 默认跟随系统版本决定
* @param isMiuiPanel 是否来自 MIUI 自己的通知面板
*/
private fun compatNotifyIcon(
context: Context,
nf: StatusBarNotification?,
iconView: ImageView,
isExpanded: Boolean = true,
isUseMaterial3Style: Boolean = isUpperOfAndroidS
isUseMaterial3Style: Boolean = isUpperOfAndroidS,
isMiuiPanel: Boolean = false
) = runInSafe(msg = "compatNotifyIcon") {
/**
* 设置默认通知图标
@@ -452,7 +513,7 @@ object SystemUIHooker : YukiBaseHooker() {
/** 获取通知小图标 */
val iconDrawable = notifyInstance.notification.smallIcon.loadDrawable(context)
?: return@let loggerW(msg = "compatNotifyIcon got null smallIcon")
?: return@let YLog.warn("compatNotifyIcon got null smallIcon")
/** 判断图标风格 */
val isGrayscaleIcon = notifyInstance.isXmsf.not() && isGrayscaleIcon(context, iconDrawable)
@@ -474,11 +535,8 @@ object SystemUIHooker : YukiBaseHooker() {
loggerDebug(tag = "Notification Panel Icon", context, notifyInstance, isCustom = customIcon != null, isGrayscaleIcon)
/** 处理自定义通知图标优化 */
when {
ConfigData.isEnableNotifyIconForceAppIcon -> {
@Suppress("DEPRECATION")
val miuiAppIcon = notifyInstance.notification?.extras?.getParcelable<Icon?>("miui.appIcon")
setDefaultNotifyIcon(drawable = miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(notifyInstance.nfPkgName))
}
ConfigData.isEnableNotifyIconForceAppIcon ->
setDefaultNotifyIcon(drawable = notifyInstance.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(notifyInstance.nfPkgName))
customIcon != null -> iconView.apply {
/** 设置不要裁切到边界 */
clipToOutline = false
@@ -493,8 +551,12 @@ object SystemUIHooker : YukiBaseHooker() {
.cornerRadius(ConfigData.notifyIconCornerSize.dp(context))
.solidColor(if (context.isSystemInDarkMode) customIconColor.brighterColor else customIconColor)
.build()
/** 设置原生的背景边距 */
if (isUseMaterial3Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context))
when {
/** 缩小 HyperOS 的通知图标 */
isMIOS && isMiuiPanel -> setPadding(7.dp(context))
/** 设置原生的背景边距 */
isUseMaterial3Style -> setPadding(4.dp(context))
}
}
else -> {
/** 重新设置图标 - 防止系统更改它 */
@@ -514,8 +576,12 @@ object SystemUIHooker : YukiBaseHooker() {
.solidColor(if (context.isSystemInDarkMode) it.brighterColor else it)
.build()
}
/** 设置原生的背景边距 */
if (isUseMaterial3Style) setPadding(4.dp(context), 4.dp(context), 4.dp(context), 4.dp(context))
when {
/** 缩小 HyperOS 的通知图标 */
isMIOS && isMiuiPanel -> setPadding(7.dp(context))
/** 设置原生的背景边距 */
isUseMaterial3Style -> setPadding(4.dp(context))
}
} else setDefaultNotifyIcon(notifyInstance.compatPushingIcon(context, iconDrawable))
}
}
@@ -528,12 +594,10 @@ object SystemUIHooker : YukiBaseHooker() {
*/
private fun ImageView.isGrayscaleIcon(): Boolean {
/** 获取 [StatusBarNotification] 实例 */
val notifyInstance = current().field { name = "mNotification" }.cast<StatusBarNotification>()
?: return loggerW(msg = "isGrayscaleIcon got null mNotification").let { false }
val notifyInstance = current().field { name = "mNotification" }.cast<StatusBarNotification>() ?: return false
/** 获取通知小图标 */
val iconDrawable = notifyInstance.notification?.smallIcon?.loadDrawable(context)
?: return loggerW(msg = "isGrayscaleIcon got null smallIcon").let { false }
val iconDrawable = notifyInstance.notification?.smallIcon?.loadDrawable(context) ?: return false
/** 判断是否不是灰度图标 */
val isGrayscaleIcon = notifyInstance.isXmsf.not() && isGrayscaleIcon(context, iconDrawable)
@@ -553,20 +617,29 @@ object SystemUIHooker : YukiBaseHooker() {
* @param isDarkIconMode 是否为深色图标模式
* @param animColor 动画过渡颜色
*/
private fun updateStatusBarIconColor(container: ViewGroup, isDarkIconMode: Boolean = this.isDarkIconMode, animColor: Int? = null) {
private fun updateStatusBarIconsColor(container: ViewGroup, isDarkIconMode: Boolean = this.isDarkIconMode, animColor: Int? = null) {
if (container.childCount > 0) container.children.forEach { iconView ->
if (iconView !is ImageView) return@forEach
if (iconView.isGrayscaleIcon()) {
/**
* 防止图标不是纯黑的问题
* 图标在任何场景下跟随状态栏其它图标保持半透明
*/
iconView.alpha = if (animColor != null) 1f else statusBarIconAlpha
iconView.setColorFilter(animColor ?: (if (isDarkIconMode) Color.BLACK else Color.WHITE))
} else {
iconView.alpha = 1f
iconView.colorFilter = null
}
updateStatusBarIconColor(iconView, isDarkIconMode, animColor)
}
}
/**
* 更新状态栏每个通知图标的颜色
* @param isDarkIconMode 是否为深色图标模式
* @param animColor 动画过渡颜色
*/
private fun updateStatusBarIconColor(iconView: ImageView, isDarkIconMode: Boolean = this.isDarkIconMode, animColor: Int? = null) {
if (iconView.isGrayscaleIcon()) {
/**
* 防止图标不是纯黑的问题
* 图标在任何场景下跟随状态栏其它图标保持半透明
*/
iconView.alpha = if (animColor != null) 1f else statusBarIconAlpha
iconView.setColorFilter(animColor ?: (if (isDarkIconMode) Color.BLACK else Color.WHITE))
} else {
iconView.alpha = 1f
iconView.colorFilter = null
}
}
@@ -574,16 +647,30 @@ object SystemUIHooker : YukiBaseHooker() {
* 更新状态栏通知图标透明度
* @param container 当前 [NotificationIconContainerClass] 的实例
*/
private fun updateStatusBarIconAlpha(container: ViewGroup) {
val iconStateMethod = container.current().method { name = "getIconState"; param(StatusBarIconViewClass) }
private fun updateStatusBarIconsAlpha(container: ViewGroup) {
val iconStatesMap = container.current().field { name = "mIconStates" }.cast<HashMap<View, Any>>()
if (container.childCount > 0) container.children.forEach { iconView ->
if (iconView !is ImageView) return@forEach
val iconAlpha = if (iconView.isGrayscaleIcon()) statusBarIconAlpha else 1f
iconView.alpha = iconAlpha
iconStateMethod.call(iconView)?.current()?.field { name = "alpha"; superClass() }?.set(iconAlpha)
iconStatesMap?.get(iconView)?.current()?.field { name { it == "alpha" || it == "mAlpha" }; superClass() }?.set(iconAlpha)
}
}
/**
* Hook 状态栏通知图标最大数量
* @param fieldName 最大通知图标数量 的变量名
* @param instance 被 Hook 的 Method 的实例
*/
private fun hookStatusBarMaxStaticIcons(fieldName: String, instance: Any) {
val maxStaticIconsField = NotificationIconContainerClass.field { name = fieldName }.get(instance)
if (statusBarMaxStaticIcons == -1) statusBarMaxStaticIcons = maxStaticIconsField.int()
/** 解除状态栏通知图标个数限制 */
if (isShowNotificationIcons && ConfigData.isEnableLiftedStatusIconCount)
maxStaticIconsField.set(ConfigData.liftedStatusIconCount.let { if (it in 0..100) it else 5 })
else maxStaticIconsField.set(if (isShowNotificationIcons) statusBarMaxStaticIcons else 0)
}
/**
* Hook 原生通知包装纸实例内容
* @param wrapper 通知包装纸实例
@@ -593,8 +680,8 @@ object SystemUIHooker : YukiBaseHooker() {
if (isNotHasAbsoluteMiuiStyle && isShowMiuiStyle) return
/** 获取小图标 */
val iconImageView = NotificationHeaderViewWrapperClass.toClassOrNull()
?.field { name = "mIcon" }?.get(wrapper)?.cast<ImageView>() ?: return
val iconImageView = NotificationHeaderViewWrapperClass
.field { name = "mIcon" }.get(wrapper).cast<ImageView>() ?: return
/** 获取 [ExpandableNotificationRowClass] */
val rowPair = wrapper.getRowPair()
@@ -627,13 +714,14 @@ object SystemUIHooker : YukiBaseHooker() {
* 从父类中得到 mRow 变量 - [ExpandableNotificationRowClass]
* 获取其中的得到通知方法
*/
val row = NotificationViewWrapperClass.toClassOrNull()?.field {
val row = NotificationViewWrapperClass.field {
name = "mRow"
}?.get(this)?.any()?.also {
isExpanded = ExpandableNotificationRowClass.toClassOrNull()?.method {
}.get(this).any()?.also {
isExpanded = ExpandableNotificationRowClass.method {
name = "isExpanded"
param(BooleanType)
returnType = BooleanType
}?.get(it)?.boolean() ?: false
}.get(it).boolean(false)
}
return Pair(isExpanded, row)
}
@@ -643,15 +731,15 @@ object SystemUIHooker : YukiBaseHooker() {
* @return [StatusBarNotification] or null
*/
private fun Any?.getSbn() =
ExpandableNotificationRowClass.toClassOrNull()
?.method { name = "getEntry" }
?.get(this)?.call()?.let {
it.javaClass.method {
name = "getSbn"
}.ignored().get(it).invoke<StatusBarNotification>()
} ?: ExpandableNotificationRowClass.toClassOrNull()
?.method { name = "getStatusBarNotification" }
?.get(this)?.invoke<StatusBarNotification>()
ExpandableNotificationRowClass
.method { name = "getEntry" }
.get(this).call()
?.current(ignored = true)
?.field { name = "mSbn" }
?.cast<StatusBarNotification>()
?: ExpandableNotificationRowClass
.method { name = "getStatusBarNotification" }
.get(this).invoke<StatusBarNotification>()
/**
* 根据当前 [ImageView] 的父布局克隆一个新的 [ImageView]
@@ -748,226 +836,218 @@ object SystemUIHooker : YukiBaseHooker() {
/** 缓存图标数据 */
cachingIconDatas()
/** 注入 MIUI 自己增加的一个工具类 */
NotificationUtilClass.hook {
NotificationUtilClass.apply {
/** 强制回写系统的状态栏图标样式为原生 */
injectMember {
method {
name { it == "shouldSubstituteSmallIcon" || it == "shouldSubstituteSmallIconForStatusBarNotification" }
param { it[0] extends StatusBarNotificationClass }
}.all()
replaceToFalse()
}
method {
name { it == "shouldSubstituteSmallIcon" || it == "shouldSubstituteSmallIconForStatusBarNotification" }
param { it[0] extends StatusBarNotificationClass }
}.hookAll().replaceToFalse()
var isUseLegacy = false
/** 强制回写系统的状态栏图标样式为原生 */
injectMember {
var isUseLegacy = false
method {
name = "getSmallIcon"
param { it[0] extends StatusBarNotificationClass && it[1] == IntType }
}.remedys {
method {
name = "getSmallIcon"
param { it[0] extends StatusBarNotificationClass && it[1] == IntType }
}.remedys {
method {
name = "getSmallIcon"
param(ExpandedNotificationClass)
}
method {
name = "getSmallIcon"
param(ContextClass, ExpandedNotificationClass)
}.onFind { isUseLegacy = true }
param(ExpandedNotificationClass)
}
afterHook {
(globalContext ?: args().first().cast())?.also { context ->
val expandedNf = args(if (isUseLegacy) 1 else 0).cast<StatusBarNotification?>()
/** Hook 状态栏小图标 */
compatStatusIcon(
context = context,
expandedNf,
result<Icon>()?.loadDrawable(context)
).also { pair -> if (pair.second) result = Icon.createWithBitmap(pair.first?.toBitmap()) }
}
}
}
}
/** 注入状态栏通知图标容器管理实例 */
NotificationIconAreaControllerClass.hook {
/** Hook 深色图标模式改变 */
injectMember {
method {
name = "onDarkChanged"
paramCount { it > 0 }
}
afterHook {
field { name = "mNotificationIcons" }.get(instance).cast<ViewGroup>()?.also {
/** 重新设置通知图标容器实例 */
notificationIconContainer = it
when (args(index = 1).float()) {
1.0f -> {
isDarkIconMode = true
updateStatusBarIconColor(it, isDarkIconMode = true)
}
0.0f -> {
isDarkIconMode = false
updateStatusBarIconColor(it, isDarkIconMode = false)
}
else -> updateStatusBarIconColor(it, isDarkIconMode = false, args(index = 2).int())
}
}
}
}
/** Hook 更新通知图标事件 */
injectMember {
method { name { it == "updateNotificationIcons" || it == "onChanged" } }.all()
afterHook {
field { name = "mNotificationIcons" }.get(instance).cast<ViewGroup>()?.also {
/** 重新设置通知图标容器实例 */
notificationIconContainer = it
updateStatusBarIconColor(it)
/** 延迟防止新添加的通知图标不刷新 */
delayedRun { updateStatusBarIconColor(it) }
}
name = "getSmallIcon"
param(ContextClass, ExpandedNotificationClass)
}.onFind { isUseLegacy = true }
}.hook().after {
(globalContext ?: args().first().cast())?.also { context ->
val expandedNf = args(if (isUseLegacy) 1 else 0).cast<StatusBarNotification?>()
/** Hook 状态栏小图标 */
compatStatusIcon(
context = context,
nf = expandedNf,
iconDrawable = result<Icon>()?.loadDrawable(context)
).also { pair -> if (pair.second) result = Icon.createWithBitmap(pair.first?.toBitmap()) }
}
}
}
/** 注入状态栏通知图标实例 */
StatusBarIconViewClass.hook {
/** 注册广播 */
injectMember {
method {
name = "setNotification"
param(StatusBarNotificationClass)
}.remedys {
method {
name = "setNotification"
param(ExpandedNotificationClass)
StatusBarIconViewClass.method {
name = "updateIconColor"
emptyParam()
}.ignored().hook().after {
val iconView = instance<ImageView>()
val expandedNf = iconView.current().field { name = "mNotification" }.cast<StatusBarNotification>()
/** Hook 状态栏小图标 */
compatStatusIcon(
context = iconView.context,
nf = expandedNf,
iconDrawable = expandedNf?.notification?.smallIcon?.loadDrawable(iconView.context)
).also { pair -> iconView.setImageDrawable(pair.first) }
updateStatusBarIconColor(iconView)
}
/** 注入状态栏通知图标容器管理实例 */
NotificationIconAreaControllerClass.apply {
/** Hook 深色图标模式改变 */
method {
name = "onDarkChanged"
paramCount { it > 0 }
}.hook().after {
field { name = "mNotificationIcons" }.get(instance).cast<ViewGroup>()?.also {
/** 重新设置通知图标容器实例 */
notificationIconContainer = it
when (args(index = 1).float()) {
1.0f -> {
isDarkIconMode = true
updateStatusBarIconsColor(it, isDarkIconMode = true)
}
0.0f -> {
isDarkIconMode = false
updateStatusBarIconsColor(it, isDarkIconMode = false)
}
else -> updateStatusBarIconsColor(it, isDarkIconMode = false, args(index = 2).int())
}
}
afterHook {
/** 注册壁纸颜色监听 */
if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) }
}
/** Hook 更新通知图标事件 */
method {
name { it == "updateNotificationIcons" || it.startsWith("onChanged") }
}.hookAll().after {
field { name = "mNotificationIcons" }.get(instance).cast<ViewGroup>()?.also {
/** 重新设置通知图标容器实例 */
notificationIconContainer = it
updateStatusBarIconsColor(it)
/** 延迟防止新添加的通知图标不刷新 */
delayedRun { updateStatusBarIconsColor(it) }
}
}
}
/** 注入状态栏通知图标实例 */
StatusBarIconViewClass.method {
name = "setNotification"
param(StatusBarNotificationClass)
}.remedys {
method {
name = "setNotification"
param(ExpandedNotificationClass)
}
}.hook().after {
/** 注册壁纸颜色监听 */
if (args().first().any() != null) instance<ImageView>().also { registerWallpaperColorChanged(it) }
}
/** 注入设置管理器实例 */
SettingsManagerClass?.constructor()?.hookAll()?.after { settingsManager = instance }
/** 注入通知控制器实例 */
StatusBarNotificationPresenterClass.hook {
injectMember {
allMembers(MembersType.CONSTRUCTOR)
afterHook { notificationPresenter = instance }
}
}
StatusBarNotificationPresenterClass.constructor().hookAll().after { notificationPresenter = instance }
/** 注入状态栏通知图标容器实例 */
NotificationIconContainerClass.hook {
injectMember {
method { name = "applyIconStates" }
afterHook { updateStatusBarIconAlpha(instance()) }
}
injectMember {
method { name = "resetViewStates" }
afterHook { updateStatusBarIconAlpha(instance()) }
}
injectMember {
method { name = "calculateIconTranslations" }
afterHook {
/** 缓存实例 */
notificationIconContainer = instance<ViewGroup>()
/** 修复部分开发版状态栏图标只能显示一个的问题 */
when (miuiIncrementalVersion.lowercase()) {
"22.3.14", "22.3.15", "22.3.16", "v13.0.1.1.16.dev", "22.3.18" ->
instance<ViewGroup>().layoutParams.width = 9999
}
NotificationIconContainerClass.apply {
method {
name = "applyIconStates"
}.hook().after { updateStatusBarIconsAlpha(instance()) }
method {
name = "resetViewStates"
}.hook().after { updateStatusBarIconsAlpha(instance()) }
method {
name { it == "calculateIconTranslations" || it == "calculateIconXTranslations" }
}.hook().after {
/** 缓存实例 */
notificationIconContainer = instance<ViewGroup>()
/** 修复部分开发版状态栏图标只能显示一个的问题 */
when (miuiIncrementalVersion.lowercase()) {
"22.3.14", "22.3.15", "22.3.16", "v13.0.1.1.16.dev", "22.3.18" ->
instance<ViewGroup>().layoutParams.width = 9999
}
}
injectMember {
method { name = "updateState" }
beforeHook {
val maxStaticIconsField = field { name = "MAX_STATIC_ICONS" }.get(instance)
if (statusBarMaxStaticIcons == -1) statusBarMaxStaticIcons = maxStaticIconsField.int()
/** 解除状态栏通知图标个数限制 */
if (isShowNotificationIcons && ConfigData.isEnableLiftedStatusIconCount)
maxStaticIconsField.set(ConfigData.liftedStatusIconCount.let { if (it in 0..100) it else 5 })
else maxStaticIconsField.set(if (isShowNotificationIcons) statusBarMaxStaticIcons else 0)
}
}.by { NotificationIconContainerClass.toClassOrNull()?.hasField { name = "MAX_STATIC_ICONS" } ?: false }
/** 旧版方法 A13MIUI - 新版不存在 */
method {
name = "updateState"
}.ignored().hook().before { hookStatusBarMaxStaticIcons("MAX_STATIC_ICONS", instance) }
/** 新版方法 (A14 MIUI14 / A14 HyperOS) - 旧版不存在 */
method {
name = "onMeasure"
}.ignored().hook().before { hookStatusBarMaxStaticIcons("mMaxStaticIcons", instance) }
/** 旧版方法 - 新版不存在 */
injectMember {
method {
name = "setMaxStaticIcons"
param(IntType)
}
beforeHook { isShowNotificationIcons = args().first().int() > 0 }
}.ignoredNoSuchMemberFailure()
method {
name = "setMaxStaticIcons"
param(IntType)
}.ignored().hook().before { isShowNotificationIcons = args().first().int() > 0 }
/** 新版方法 - 旧版不存在 */
injectMember {
method {
name = "miuiShowNotificationIcons"
param(BooleanType)
}
beforeHook { isShowNotificationIcons = args().first().boolean() }
}.ignoredNoSuchMemberFailure()
method {
name = "miuiShowNotificationIcons"
param(BooleanType)
}.ignored().hook().before { isShowNotificationIcons = args().first().boolean() }
}
/** 注入原生通知包装纸实例 */
NotificationHeaderViewWrapperClass.hook {
injectMember {
method { name { it == "resolveHeaderViews" || it == "handleHeaderViews" || it == "resolveViews" } }
afterHook { hookNotificationViewWrapper(instance) }
}
injectMember {
method { name = "onContentUpdated" }
afterHook { hookNotificationViewWrapper(instance) }
}
NotificationHeaderViewWrapperClass.apply {
method {
name { it == "resolveHeaderViews" || it == "handleHeaderViews" || it == "resolveViews" }
}.hook().after { hookNotificationViewWrapper(instance) }
method {
name = "onContentUpdated"
}.hook().after { hookNotificationViewWrapper(instance) }
}
/** 修改 MIUI 风格通知栏的通知图标 */
MiuiNotificationViewWrapperClass.hook {
/** 替换通知小图标 */
injectMember {
method { name = "handleAppIcon" }
replaceUnit {
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.clone {
compatNotifyIcon(
context = context,
nf = instance.getRowPair().second.getSbn(),
iconView = this,
isUseMaterial3Style = true
)
}
MiuiNotificationViewWrapperClass?.apply {
constructor().hook().after {
val nf = instance.getRowPair().second.getSbn() ?: return@after
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.clone {
if (ConfigData.isEnableReplaceMiuiStyleNotifyIcon || ConfigData.isEnableNotifyIconForceAppIcon)
compatNotifyIcon(context, nf, iconView = this, isUseMaterial3Style = true, isMiuiPanel = true)
else setImageDrawable(nf.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(nf.packageName))
}
}
}.ignoredHookClassNotFoundFailure()
}
/** 修改 MIUI 风格通知栏的通知图标 - 折叠通知 */
MiuiNotificationChildrenContainerClass.hook {
MiuiNotificationChildrenContainerClass?.apply {
/** 替换通知小图标 */
injectMember {
method {
name = "updateAppIcon"
param(BooleanType)
}
afterHook {
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply {
compatNotifyIcon(context, NotificationChildrenContainerClass.toClassOrNull()?.field {
name = "mContainingNotification"
}?.get(instance)?.any()?.getSbn(), iconView = this, isUseMaterial3Style = true)
}
method {
name = "updateAppIcon"
param(BooleanType)
}.hook().after {
field { name = "mAppIcon" }.get(instance).cast<ImageView>()?.apply {
val nf = NotificationChildrenContainerClass.field {
name = "mContainingNotification"
}.get(instance).any()?.getSbn() ?: return@after
if (ConfigData.isEnableReplaceMiuiStyleNotifyIcon || ConfigData.isEnableNotifyIconForceAppIcon)
compatNotifyIcon(context, nf, iconView = this, isUseMaterial3Style = true, isMiuiPanel = true)
else setImageDrawable(nf.miuiAppIcon?.loadDrawable(context) ?: context.appIconOf(nf.packageName))
}
}
}.ignoredHookClassNotFoundFailure()
}
/** 干掉下拉通知图标自动设置回 APP 图标的方法 */
NotificationHeaderViewWrapperInjectorClass.hook {
injectMember {
NotificationHeaderViewWrapperInjectorClass?.apply {
method {
name = "setAppIcon"
param(ContextClass, ImageViewClass, ExpandedNotificationClass)
}.remedys {
method {
name = "setAppIcon"
param(ContextClass, ImageViewClass, ExpandedNotificationClass)
}.remedys {
method {
name = "setAppIcon"
param(ImageViewClass, ExpandedNotificationClass)
}
}
intercept()
}.ignoredNoSuchMemberFailure()
injectMember {
method {
name = "resetIconBgAndPaddings"
param(ImageViewClass, ExpandedNotificationClass)
}
intercept()
}.ignoredNoSuchMemberFailure()
}.ignoredHookClassNotFoundFailure()
}.ignored().hook().intercept()
method {
name = "resetIconBgAndPaddings"
param(ImageViewClass, ExpandedNotificationClass)
}.ignored().hook().intercept()
}
/**
* 尝试修复从 MIUI 14 开始出现的一个崩溃问题
* 由于模块注入推送的通知没有对 [StatusBarNotification] 设置 TAG 会导致其空指针
* 直接替换掉它自己的实现方法 - 使用自己的方式实现这个功能
* ```java
* public final boolean isUnimportantEntry(NotificationEntry notificationEntry) {
* return notificationEntry.getSbn().getPackageName().equals("com.android.systemui") &&
* notificationEntry.getSbn().getTag().equals("UNIMPORTANT");
* }
* ```
*/
NotificationStatClass?.method {
name = "isUnimportantEntry"
paramCount = 1
}?.ignored()?.hook()?.replaceAny {
args().first().current(ignored = true).method {
name = "getSbn"
superClass()
}.invoke<StatusBarNotification>()?.let { sbn ->
sbn.packageName == PackageName.SYSTEMUI && sbn.tag == "UNIMPORTANT"
} ?: false
}
}
}

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/24.
* This file is created by fankes on 2022/1/24.
*/
@file:Suppress("MemberVisibilityCanBePrivate")
@@ -28,7 +28,11 @@ import android.content.Context
import android.graphics.Color
import com.fankes.miui.notify.bean.IconDataBean
import com.fankes.miui.notify.data.ConfigData
import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.factory.bitmap
import com.fankes.miui.notify.utils.factory.safeOf
import com.fankes.miui.notify.utils.factory.safeOfNan
import com.fankes.miui.notify.utils.factory.safeOfNull
import com.fankes.miui.notify.utils.factory.snake
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.param.PackageParam
import org.json.JSONArray
@@ -135,4 +139,4 @@ class IconPackParams(private val context: Context? = null, private val param: Pa
* @param dataJson 图标数据 JSON
*/
fun save(dataJson: String) = context?.prefs()?.edit { put(ConfigData.NOTIFY_ICONS_DATA, dataJson) }
}
}

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/2/15.
* This file is created by fankes on 2022/2/15.
* This file is Modified by fankes on 2023/2/3.
*/
package com.fankes.miui.notify.params.factory

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/26.
* This file is created by fankes on 2022/3/26.
*/
package com.fankes.miui.notify.service

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/30.
* This file is created by fankes on 2022/1/30.
*/
@file:Suppress("SetTextI18n", "InflateParams")
@@ -37,7 +37,16 @@ import com.fankes.miui.notify.params.factory.isAppNotifyHookOf
import com.fankes.miui.notify.params.factory.putAppNotifyHookAllOf
import com.fankes.miui.notify.params.factory.putAppNotifyHookOf
import com.fankes.miui.notify.ui.activity.base.BaseActivity
import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.factory.addOnBackPressedEvent
import com.fankes.miui.notify.utils.factory.bindAdapter
import com.fankes.miui.notify.utils.factory.callOnBackPressed
import com.fankes.miui.notify.utils.factory.colorOf
import com.fankes.miui.notify.utils.factory.copyToClipboard
import com.fankes.miui.notify.utils.factory.navigate
import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.showDialog
import com.fankes.miui.notify.utils.factory.snake
import com.fankes.miui.notify.utils.factory.toast
import com.fankes.miui.notify.utils.tool.IconRuleManagerTool
import com.fankes.miui.notify.utils.tool.SystemUITool
import com.highcapable.yukihookapi.YukiHookAPI
@@ -145,8 +154,8 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
if (b) showDialog {
title = "全部替换"
msg = "此功能仅针对严重不遵守规范的 APP 通知图标才需要开启例如APP 推送通知后无法识别出现的黑白块图标。\n\n" +
"此功能在一般情况下请保持关闭并跟随在线规则的配置,并不要随意改变此配置," +
"开启后 APP 的通知图标可能会被规则破坏,你确定还要开启吗?"
"此功能在一般情况下请保持关闭并跟随在线规则的配置,并不要随意改变此配置," +
"开启后 APP 的通知图标可能会被规则破坏,你确定还要开启吗?"
confirmButton { saveState() }
cancelButton { btn.isChecked = btn.isChecked.not() }
noCancelable()
@@ -188,10 +197,10 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
val pkgName = intent?.getStringExtra("pkgName") ?: ""
title = "新安装应用通知图标适配"
msg = "你已安装 $appName($pkgName)\n\n" +
"此应用未在通知优化名单中发现适配数据,若此应用发送的通知为彩色图标," +
"可随时点击本页面下方的“贡献通知图标优化名单”按钮提交贡献或请求适配。\n\n" +
"若你已知晓此应用会遵守原生通知图标规范,可忽略此提示。\n\n" +
"你可以现在立即同步适配列表,以获取最新的适配数据。"
"此应用未在通知优化名单中发现适配数据,若此应用发送的通知为彩色图标," +
"可随时点击本页面下方的“贡献通知图标优化名单”按钮提交贡献或请求适配。\n\n" +
"若你已知晓此应用会遵守原生通知图标规范,可忽略此提示。\n\n" +
"你可以现在立即同步适配列表,以获取最新的适配数据。"
confirmButton(text = "同步列表") { onStartRefresh() }
cancelButton(text = "复制名称+包名") { copyToClipboard(content = "$appName($pkgName)") }
neutralButton(text = "取消")
@@ -250,7 +259,7 @@ class ConfigureActivity : BaseActivity<ActivityConfigBinding>() {
onChanged?.invoke()
binding.configTitleCountText.text =
if (filterText.isBlank()) "已适配 ${iconDatas.size} 个 APP 的通知图标"
else "${filterText}” 匹配到 ${iconDatas.size} 个结果"
else "$filterText” 匹配到 ${iconDatas.size} 个结果"
binding.configListNoDataView.apply {
text = if (iconAllDatas.isEmpty()) "噫,竟然什么都没有~\n请点击右上角同步按钮获取云端数据" else "噫,竟然什么都没找到~"
isVisible = iconDatas.isEmpty()

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/24.
* This file is created by fankes on 2022/1/24.
*/
@file:Suppress("SetTextI18n")
@@ -26,19 +26,36 @@ package com.fankes.miui.notify.ui.activity
import androidx.core.view.isGone
import androidx.core.view.isVisible
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.R
import com.fankes.miui.notify.const.ModuleVersion
import com.fankes.miui.notify.data.ConfigData
import com.fankes.miui.notify.data.factory.bind
import com.fankes.miui.notify.databinding.ActivityMainBinding
import com.fankes.miui.notify.databinding.DiaStatusIconCountBinding
import com.fankes.miui.notify.params.IconPackParams
import com.fankes.miui.notify.ui.activity.base.BaseActivity
import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.factory.androidVersionCodeName
import com.fankes.miui.notify.utils.factory.hideOrShowLauncherIcon
import com.fankes.miui.notify.utils.factory.isLauncherIconShowing
import com.fankes.miui.notify.utils.factory.isLowerAndroidP
import com.fankes.miui.notify.utils.factory.isLowerAndroidR
import com.fankes.miui.notify.utils.factory.isMIOS
import com.fankes.miui.notify.utils.factory.isNotMiSystem
import com.fankes.miui.notify.utils.factory.isNotNoificationEnabled
import com.fankes.miui.notify.utils.factory.isNotSupportMiSystemVersion
import com.fankes.miui.notify.utils.factory.miSystemVersion
import com.fankes.miui.notify.utils.factory.miuiVersionCode
import com.fankes.miui.notify.utils.factory.navigate
import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.openNotifySetting
import com.fankes.miui.notify.utils.factory.showDialog
import com.fankes.miui.notify.utils.factory.showTimePicker
import com.fankes.miui.notify.utils.factory.snake
import com.fankes.miui.notify.utils.factory.systemFullVersion
import com.fankes.miui.notify.utils.tool.GithubReleaseTool
import com.fankes.miui.notify.utils.tool.I18nWarnTool
import com.fankes.miui.notify.utils.tool.SystemUITool
import com.fankes.miui.notify.utils.tool.YukiPromoteTool
import com.fankes.projectpromote.ProjectPromote
import com.highcapable.yukihookapi.YukiHookAPI
class MainActivity : BaseActivity<ActivityMainBinding>() {
@@ -53,19 +70,13 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
/** 模块是否有效 */
internal var isModuleValied = false
/** 模块版本 */
private const val moduleVersion = BuildConfig.VERSION_NAME
/** 预发布的版本标识 */
private const val pendingFlag = ""
}
override fun onCreate() {
/** 设置可用性 */
isActivityLive = true
/** 检查更新 */
GithubReleaseTool.checkingForUpdate(context = this, moduleVersion) { version, function ->
GithubReleaseTool.checkingForUpdate(context = this, ModuleVersion.NAME) { version, function ->
binding.mainTextReleaseVersion.apply {
text = "点击更新 $version"
isVisible = true
@@ -73,11 +84,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
}
}
when {
/** 判断是否为 MIUI 系统 */
isNotMIUI ->
/** 判断是否为小米系统 */
isNotMiSystem ->
showDialog {
title = "不是 MIUI 系统"
msg = "此模块专为 MIUI 系统打造,当前无法识别你的系统为 MIUI,所以模块无法工作。"
title = "不是 MIUI 或 HyperOS 系统"
msg = "此模块专为 MIUI、HyperOS 系统打造,当前无法识别你的系统为其中任意之一,所以模块无法工作。"
confirmButton(text = "查看支持的模块") {
openBrowser(url = "https://github.com/fankes/AndroidNotifyIconAdapt")
finish()
@@ -90,7 +101,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
showDialog {
title = "Android 系统版本过低"
msg = "此模块最低支持基于 Android 9 的 MIUI 系统,你的系统版本过低不再进行适配。\n\n" +
"若有其它疑问,你可以点击下方按钮前往项目地址进行反馈。"
"若有其它疑问,你可以点击下方按钮前往项目地址进行反馈。"
confirmButton(text = "前往项目地址") {
openProjectUrl()
finish()
@@ -98,14 +109,14 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
cancelButton(text = "退出") { finish() }
noCancelable()
}
/** 判断支持的 MIUI 版本 */
isNotSupportMiuiVersion ->
/** 判断支持的系统版本 */
isNotSupportMiSystemVersion ->
showDialog {
title = "不支持的 MIUI 版本"
msg = (if (miuiVersion.isNotBlank())
"此模块目前支持 MIUI 11~14 系统,你的 MIUI 版本为 ${miuiVersion},暂不支持。\n\n" +
"如果你的 MIUI 版本识别有误,请检查是否有相关插件修改了系统版本。\n\n"
else "无法获取 MIUI 版本,请检查你是否修改了系统参数或使用非官方系统。\n\n") + "若有其它疑问,你可以点击下方按钮前往项目地址进行反馈。"
title = "不支持的系统版本"
msg = (if (miSystemVersion.isNotBlank())
"此模块目前支持 MIUI 11~14 和 HyperOS 1.0 系统,你的系统版本为 $miSystemVersion,暂不支持。\n\n" +
"如果你的系统版本识别有误,请检查是否有相关插件修改了系统版本。\n\n"
else "无法获取系统版本,请检查你是否修改了系统参数或使用非官方系统。\n\n") + "若有其它疑问,你可以点击下方按钮前往项目地址进行反馈。"
confirmButton(text = "前往项目地址") {
openProjectUrl()
finish()
@@ -119,7 +130,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
showDialog {
title = "配置通知图标优化名单"
msg = "模块需要获取在线规则以更新“通知图标优化名单”,它现在是空的,这看起来是你第一次使用模块,请首先进行配置才可以使用相关功能。\n" +
"你可以随时在本页面下方找到“配置通知图标优化名单”手动前往。"
"你可以随时在本页面下方找到“配置通知图标优化名单”手动前往。"
confirmButton(text = "前往") { navigate<ConfigureActivity>() }
cancelButton()
noCancelable()
@@ -136,27 +147,46 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
showDialog {
title = "Android 版本过低"
msg = "你当前使用的 Android 版本过低,模块的部分功能可能会发生问题," +
"由于设备有限,无法逐一调试,若有好的建议可向我们贡献代码提交适配请求,建议在 Android 11 及以上版本中使用效果最佳。"
"由于设备有限,无法逐一调试,若有好的建议可向我们贡献代码提交适配请求,建议在 Android 11 及以上版本中使用效果最佳。"
confirmButton(text = "我知道了") { ConfigData.isIgnoredAndroidVersionToLow = true }
noCancelable()
}
/** 推广、恰饭 */
YukiPromoteTool.promote(context = this)
ProjectPromote.show(activity = this, ModuleVersion.toString())
}
else ->
showDialog {
title = "模块没有激活"
msg = "检测到模块没有激活,模块需要 Xposed 环境依赖," +
"同时需要系统拥有 Root 权限," +
"请自行查看本页面使用帮助与说明第二条。\n" +
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
"同时需要系统拥有 Root 权限," +
"请自行查看本页面使用帮助与说明第二条。\n" +
"由于需要修改系统应用达到效果,模块不支持太极阴、应用转生。"
confirmButton(text = "我知道了")
noCancelable()
}
}
I18nWarnTool.checkingOrShowing(context = this)
binding.mainTextVersion.text = "模块版本:$moduleVersion $pendingFlag"
binding.mainTextMiuiVersion.text = "系统版本:[$androidVersionCodeName] $miuiFullVersion"
if (isMIOS) binding.mainTitle.text = binding.mainTitle.text.toString().replace("MIUI", "HyperOS")
binding.mainTextVersion.text = "模块版本:${ModuleVersion.NAME}"
/** 设置 CI 自动构建标识 */
if (ModuleVersion.isCiMode)
binding.mainTextReleaseVersion.apply {
text = "CI ${ModuleVersion.GITHUB_COMMIT_ID}"
isVisible = true
setOnClickListener {
showDialog {
title = "CI 自动构建说明"
msg = """
你正在使用的是 CI 自动构建版本Commit ID 为 ${ModuleVersion.GITHUB_COMMIT_ID}
它是由代码提交后自动触发并构建、自动编译发布的,并未经任何稳定性测试,使用风险自负。
""".trimIndent()
confirmButton(text = "我知道了")
noCancelable()
}
}
}
binding.mainTextMiuiVersion.text = "系统版本:[$androidVersionCodeName] $systemFullVersion"
binding.warnSCountDisTip.isGone = miuiVersionCode > 12.5
binding.warnMiuiNotifyStyleTip.isGone = miuiVersionCode > 11
binding.statusIconCountText.text = ConfigData.liftedStatusIconCount.toString()
@@ -200,14 +230,17 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (it) showDialog {
title = "启用兼容模式"
msg = "启用兼容模式可修复部分系统版本可能出现无法判定通知图标反色的问题," +
"但是这也可能会导致新的问题,一般情况下不建议开启,确定要继续吗?\n\n" +
"如果系统界面刷新后通知图标颜色发生错误,请尝试重启一次系统界面。"
"但是这也可能会导致新的问题,一般情况下不建议开启,确定要继续吗?\n\n" +
"如果系统界面刷新后通知图标颜色发生错误,请尝试重启一次系统界面。"
confirmButton { applyChangesAndRefresh() }
cancelButton { cancelChanges() }
noCancelable()
} else applyChangesAndRefresh()
}
}
binding.miuiNotifyIconReplacementSwitch.bind(ConfigData.ENABLE_REPLACE_MIUI_STYLE_NOTIFY_ICON) {
onChanged { SystemUITool.refreshSystemUI(context = this@MainActivity) }
}
binding.notifyIconForceSystemColorSwitch.bind(ConfigData.ENABLE_NOTIFY_ICON_FORCE_SYSTEM_COLOR) {
isAutoApplyChanges = false
onChanged {
@@ -219,7 +252,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (it) showDialog {
title = "破坏性功能警告"
msg = "开启这个功能后,任何通知栏中的通知图标都会忽略图标自身的着色属性,全部使用系统默认颜色 (系统提供的统一色调) 着色。\n\n" +
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
confirmButton { applyChangesAndRefresh() }
cancelButton { cancelChanges() }
noCancelable()
@@ -233,6 +266,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.notifyIconCustomCornerItem,
binding.notifyIconForceSystemColorItem
).forEach { e -> e.isVisible = isLowerAndroidR.not() && it.not() }
binding.miuiNotifyIconReplacementItem.isVisible = it.not()
}
onChanged {
/** 应用更改并刷新系统界面 */
@@ -243,8 +277,8 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (it) showDialog {
title = "破坏性功能警告"
msg = "开启这个功能后,任何通知栏中的通知图标都会被强制替换为当前推送通知的 APP 的图标," +
"某些系统级别的 APP 通知图标可能会显示异常或发生图标丢失。\n\n" +
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
"某些系统级别的 APP 通知图标可能会显示异常或发生图标丢失。\n\n" +
"此功能仅面向一些追求图标美观度的用户,我们不推荐开启这个功能,且发生任何 BUG 都不会去修复,仍然继续开启吗?"
confirmButton { applyChangesAndRefresh() }
cancelButton { cancelChanges() }
noCancelable()
@@ -274,9 +308,9 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
if (it) showDialog {
title = "注意"
msg = "开启这个功能后,当发现未适配的彩色通知图标时," +
"状态栏中显示的通知图标将会使用预置的占位符图标进行修补," +
"通知栏中显示的通知图标保持原始图标不变。\n\n" +
"此功能的作用仅为临时修复破坏规范的通知图标,仍然继续开启吗?"
"状态栏中显示的通知图标将会使用预置的占位符图标进行修补," +
"通知栏中显示的通知图标保持原始图标不变。\n\n" +
"此功能的作用仅为临时修复破坏规范的通知图标,仍然继续开启吗?"
confirmButton { applyChangesAndRefresh() }
cancelButton { cancelChanges() }
noCancelable()
@@ -321,7 +355,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
confirmButton {
when {
(runCatching { binding.iconCountEdit.text.toString().toInt() }.getOrNull() ?: -1)
!in 0..100 -> snake(msg = "请输入有效数值")
!in 0..100 -> snake(msg = "请输入有效数值")
binding.iconCountEdit.text.toString().isNotBlank() -> runCatching {
ConfigData.liftedStatusIconCount = binding.iconCountEdit.text.toString().trim().toInt()
this@MainActivity.binding.statusIconCountText.text = ConfigData.liftedStatusIconCount.toString()
@@ -339,11 +373,11 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
showDialog {
title = "每天 $it 自动更新"
msg = "设置保存后将在每天 $it 自动同步名单到最新云端数据,若数据已是最新则不会显示任何提示,否则会发送一条通知。\n\n" +
"请确保:\n\n" +
"1.模块没有被禁止前台以及后台联网权限\n" +
"2.模块没有被禁止被其它 APP 关联唤醒\n" +
"3.模块的系统通知权限已开启\n\n" +
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
"请确保:\n\n" +
"1.模块没有被禁止前台以及后台联网权限\n" +
"2.模块没有被禁止被其它 APP 关联唤醒\n" +
"3.模块的系统通知权限已开启\n\n" +
"模块无需保持在后台运行,到达同步时间后会自动启动,如果到达时间后模块正在运行则会自动取消本次计划任务。"
confirmButton(text = "保存设置") {
ConfigData.notifyIconFixAutoTime = it
this@MainActivity.binding.notifyIconAutoSyncText.text = it
@@ -382,7 +416,7 @@ class MainActivity : BaseActivity<ActivityMainBinding>() {
binding.mainLinStatus.setBackgroundResource(
when {
YukiHookAPI.Status.isXposedModuleActive &&
(isModuleRegular.not() || isModuleValied.not() || ConfigData.isEnableModule.not()) -> R.drawable.bg_yellow_round
(isModuleRegular.not() || isModuleValied.not() || ConfigData.isEnableModule.not()) -> R.drawable.bg_yellow_round
YukiHookAPI.Status.isXposedModuleActive -> R.drawable.bg_green_round
else -> R.drawable.bg_dark_round
}

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/26.
* This file is created by fankes on 2022/3/26.
*/
@file:Suppress("DEPRECATION")

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/30.
* This file is created by fankes on 2022/1/30.
*/
@file:Suppress("UNCHECKED_CAST")

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/8.
* This file is created by fankes on 2022/1/8.
*/
@file:Suppress("SameParameterValue")

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/10/6.
* This file is created by fankes on 2022/10/6.
*/
package com.fankes.miui.notify.utils.factory

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/6/3.
* This file is created by fankes on 2022/6/3.
*/
package com.fankes.miui.notify.utils.factory

View File

@@ -18,9 +18,9 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/7.
* This file is created by fankes on 2022/1/7.
*/
@file:Suppress("unused", "OPT_IN_USAGE", "EXPERIMENTAL_API_USAGE")
@file:Suppress("unused")
package com.fankes.miui.notify.utils.factory
@@ -38,7 +38,6 @@ import androidx.viewbinding.ViewBinding
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.progressindicator.CircularProgressIndicator
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.annotation.CauseProblemsApi
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.type.android.LayoutInflaterClass
@@ -181,7 +180,6 @@ class DialogBuilder<VB : ViewBinding>(val context: Context, private val bindingC
fun cancel() = dialogInstance?.cancel()
/** 显示对话框 */
@CauseProblemsApi
fun show() = runInSafe {
/** 若当前自定义 View 的对话框没有调用 [binding] 将会对其手动调用一次以确保显示布局 */
if (bindingClass != null) binding

View File

@@ -18,13 +18,13 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/13.
* This file is created by fankes on 2022/3/13.
*/
@file:Suppress("unused")
package com.fankes.miui.notify.utils.factory
import com.highcapable.yukihookapi.hook.log.loggerE
import com.highcapable.yukihookapi.hook.log.YLog
/**
* 忽略异常返回值
@@ -79,5 +79,5 @@ inline fun <T> safeOf(default: T, result: () -> T) = try {
* @param block 正常回调
*/
inline fun <T> T.runInSafe(msg: String = "", block: () -> Unit) {
runCatching(block).onFailure { if (msg.isNotBlank()) loggerE(msg = msg, e = it) }
runCatching(block).onFailure { if (msg.isNotBlank()) YLog.error(msg, it) }
}

View File

@@ -18,24 +18,37 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/1/7.
* This file is created by fankes on 2022/1/7.
*/
@file:Suppress("unused", "ObsoleteSdkInt")
package com.fankes.miui.notify.utils.factory
import android.annotation.SuppressLint
import android.app.Activity
import android.app.Notification
import android.app.Service
import android.app.WallpaperManager
import android.content.*
import android.content.ClipData
import android.content.ClipboardManager
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.content.pm.ApplicationInfo
import android.content.pm.PackageInfo
import android.content.pm.PackageManager
import android.content.pm.PackageManager.PackageInfoFlags
import android.content.res.Configuration
import android.content.res.Resources
import android.graphics.*
import android.graphics.Bitmap
import android.graphics.BitmapFactory
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.PorterDuffXfermode
import android.graphics.Rect
import android.graphics.RectF
import android.graphics.drawable.Drawable
import android.net.ConnectivityManager
import android.net.Uri
@@ -50,17 +63,20 @@ import androidx.core.app.NotificationManagerCompat
import androidx.core.content.getSystemService
import androidx.core.content.pm.PackageInfoCompat
import androidx.core.content.res.ResourcesCompat
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.hook.factory.hasClass
import com.highcapable.yukihookapi.hook.factory.method
import com.highcapable.yukihookapi.hook.factory.toClassOrNull
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.type.java.StringClass
import com.highcapable.yukihookapi.hook.xposed.application.ModuleApplication.Companion.appContext
import com.topjohnwu.superuser.Shell
import java.io.ByteArrayOutputStream
import java.text.SimpleDateFormat
import java.util.*
import java.util.Calendar
import java.util.Date
import java.util.Locale
/**
* 系统深色模式是否开启
@@ -86,17 +102,23 @@ val Context.isSystemInDarkMode get() = (resources.configuration.uiMode and Confi
*/
inline val Context.isNotSystemInDarkMode get() = !isSystemInDarkMode
/**
* 系统版本是否高于或等于 Android 14
* @return [Boolean] 是否符合条件
*/
inline val isUpperOfAndroidU get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE
/**
* 系统版本是否高于或等于 Android 13
* @return [Boolean] 是否符合条件
*/
inline val isUpperOfAndroidT get() = Build.VERSION.SDK_INT > Build.VERSION_CODES.S
inline val isUpperOfAndroidT get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU
/**
* 系统版本是否高于或等于 Android 12
* @return [Boolean] 是否符合条件
*/
inline val isUpperOfAndroidS get() = Build.VERSION.SDK_INT > Build.VERSION_CODES.R
inline val isUpperOfAndroidS get() = Build.VERSION.SDK_INT >= Build.VERSION_CODES.S
/**
* 系统版本是否低于 Android 9
@@ -110,12 +132,30 @@ inline val isLowerAndroidP get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.P
*/
inline val isLowerAndroidR get() = Build.VERSION.SDK_INT < Build.VERSION_CODES.R
/**
* 当前设备是否是 MIUI、HyperOS 定制 Android 系统
* @return [Boolean] 是否符合条件
*/
val isMiSystem get() = isMIUI || isMIOS
/**
* 当前设备是否不是 MIUI、HyperOS 定制 Android 系统
* @return [Boolean] 是否符合条件
*/
val isNotMiSystem get() = !isMiSystem
/**
* 当前设备是否是 MIUI 定制 Android 系统
* @return [Boolean] 是否符合条件
*/
val isMIUI by lazy { "android.miui.R".hasClass() }
/**
* 当前设备是否是 HyperOS 定制 Android 系统
* @return [Boolean] 是否符合条件
*/
val isMIOS get() = isMIUI && miuiVersion == "816"
/**
* 当前设备是否不是 MIUI 定制 Android 系统
* @return [Boolean] 是否符合条件
@@ -123,20 +163,33 @@ val isMIUI by lazy { "android.miui.R".hasClass() }
inline val isNotMIUI get() = !isMIUI
/**
* 是否为支持的 MIUI 版本
* 当前设备是否不是 HyperOS 定制 Android 系统
* @return [Boolean] 是否符合条件
*/
inline val isNotMIOS get() = !isMIOS
/**
* 是否为支持的 MIUI、HyperOS 版本
* @return [Boolean]
*/
val isSupportMiuiVersion
get() = when (miuiVersion) {
"11", "12", "12.5", "13", "14" -> true
val isSupportMiSystemVersion
get() = when {
isMIOS -> when (miosVersion) {
"1.0" -> true
else -> false
}
isMIUI -> when (miuiVersion) {
"11", "12", "12.5", "13", "14" -> true
else -> false
}
else -> false
}
/**
* 是否不为支持的 MIUI 版本
* 是否不为支持的 MIUI、HyperOS 版本
* @return [Boolean]
*/
inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
inline val isNotSupportMiSystemVersion get() = !isSupportMiSystemVersion
/**
* 获取 Android 版本代号
@@ -144,6 +197,7 @@ inline val isNotSupportMiuiVersion get() = !isSupportMiuiVersion
*/
val androidVersionCodeName
get() = when (Build.VERSION.SDK_INT) {
34 -> "U"
33 -> "T"
32 -> "S_V2"
31 -> "S"
@@ -157,9 +211,31 @@ val androidVersionCodeName
23 -> "M"
22 -> "L_MR1"
21 -> "L"
else -> "?"
}
/**
* 获取 MIUI、HyperOS 版本
* @return [String]
*/
val miSystemVersion
get() = when {
isMIOS -> miosVersion
isMIUI -> miuiVersion
else -> ""
}
/**
* 获取 MIUI、HyperOS 版本号
* @return [Float]
*/
val miSystemVersionCode
get() = when {
isMIOS -> miosVersionCode
isMIUI -> miuiVersionCode
else -> 0f
}
/**
* 获取 MIUI 版本
* @return [String]
@@ -178,11 +254,28 @@ val miuiVersion
}.trim()
else ""
/**
* 获取 HyperOS 版本
* @return [String]
*/
val miosVersion
get() = if (isMIOS)
findPropString("ro.mi.os.version.name").let {
if (it.startsWith("OS")) it.replaceFirst("OS", "") else it
}.trim()
else ""
/**
* 获取 MIUI 版本号
* @return [Float]
*/
val miuiVersionCode get() = safeOf(default = 0f) { miuiVersion.toFloat() }
val miuiVersionCode get() = miuiVersion.toFloatOrNull() ?: 0f
/**
* 获取 HyperOS 版本号
* @return [Float]
*/
val miosVersionCode get() = findPropString("ro.mi.os.version.code").toFloatOrNull() ?: 0f
/**
* 获取 MIUI 次版本号
@@ -191,18 +284,35 @@ val miuiVersionCode get() = safeOf(default = 0f) { miuiVersion.toFloat() }
val miuiIncrementalVersion get() = findPropString("ro.system.build.version.incremental").trim()
/**
* 获取 MIUI 完全版本
* 获取 HyperOS 次版本
* @return [String]
*/
val miuiFullVersion
get() = if (isMIUI) miuiIncrementalVersion.let {
if (it.lowercase().endsWith(".dev").not() && it.lowercase().any { e -> e.code in 97..122 })
"$it 稳定版"
else when {
it.lowercase().endsWith(".dev") -> "$it 开发版"
else -> "V$miuiVersion $it 开发版"
val miosIncrementalVersion get() = findPropString("ro.mi.os.version.incremental").trim()
/**
* 获取 MIUI、HyperOS 完全版本
* @return [String]
*/
val systemFullVersion
get() = when {
isMIOS -> "HyperOS " + miosIncrementalVersion.let {
if (it.lowercase().endsWith(".dev").not() && it.lowercase().any { e -> e.code in 97..122 })
"${it.replaceFirst("OS", "")} 稳定版"
else when {
it.lowercase().endsWith(".dev") -> "${it.replaceFirst("OS", "")} 开发版"
else -> "$miosVersion $it 开发版"
}
}
} else "不是 MIUI 系统"
isMIUI -> miuiIncrementalVersion.let {
if (it.lowercase().endsWith(".dev").not() && it.lowercase().any { e -> e.code in 97..122 })
"$it 稳定版"
else when {
it.lowercase().endsWith(".dev") -> "$it 开发版"
else -> "V$miuiVersion $it 开发版"
}
}
else -> "不是 MIUI 或 HyperOS 系统"
}
/**
* 获取 [Drawable]
@@ -225,7 +335,7 @@ fun Resources.colorOf(@ColorRes resId: Int) = ResourcesCompat.getColor(this, res
* @return [PackageInfo] or null
*/
private fun Context.getPackageInfoCompat(packageName: String, flag: Number = 0) = runCatching {
@Suppress("DEPRECATION")
@Suppress("DEPRECATION", "KotlinRedundantDiagnosticSuppress")
if (Build.VERSION.SDK_INT >= 33)
packageManager?.getPackageInfo(packageName, PackageInfoFlags.of(flag.toLong()))
else packageManager?.getPackageInfo(packageName, flag.toInt())
@@ -350,6 +460,7 @@ fun Number.dpFloat(context: Context) = toFloat() * context.resources.displayMetr
* @return [Int] Android < 12 返回 [wallpaperColor]
*/
val Context.systemAccentColor
@SuppressLint("InlinedApi")
get() = safeOf(wallpaperColor) {
if (isUpperOfAndroidS) resources.colorOf(android.R.color.system_accent1_600) else wallpaperColor
}
@@ -460,7 +571,10 @@ fun findPropString(key: String, default: String = "") = safeOf(default) {
* 是否有 Root 权限
* @return [Boolean]
*/
val isRootAccess get() = safeOfFalse { Shell.rootAccess() }
val isRootAccess get() = safeOfFalse {
@Suppress("DEPRECATION")
Shell.rootAccess()
}
/**
* 执行命令
@@ -469,6 +583,7 @@ val isRootAccess get() = safeOfFalse { Shell.rootAccess() }
* @return [String] 执行结果
*/
fun execShell(cmd: String, isSu: Boolean = true) = safeOfNothing {
@Suppress("DEPRECATION")
(if (isSu) Shell.su(cmd) else Shell.sh(cmd)).exec().out.let {
if (it.isNotEmpty()) it[0].trim() else ""
}
@@ -478,7 +593,11 @@ fun execShell(cmd: String, isSu: Boolean = true) = safeOfNothing {
* 弹出 [Toast]
* @param msg 提示内容
*/
fun toast(msg: String) = Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).show()
fun toast(msg: String) {
runCatching {
Toast.makeText(appContext, msg, Toast.LENGTH_SHORT).show()
}.onFailure { YLog.warn(msg) }
}
/**
* 跳转到指定页面
@@ -587,7 +706,7 @@ fun Any?.delayedRun(ms: Long = 150, it: () -> Unit) = runInSafe {
*/
fun Context.hideOrShowLauncherIcon(isShow: Boolean) {
packageManager?.setComponentEnabledSetting(
ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home"),
ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home"),
if (isShow) PackageManager.COMPONENT_ENABLED_STATE_DISABLED else PackageManager.COMPONENT_ENABLED_STATE_ENABLED,
PackageManager.DONT_KILL_APP
)
@@ -599,5 +718,5 @@ fun Context.hideOrShowLauncherIcon(isShow: Boolean) {
*/
val Context.isLauncherIconShowing
get() = packageManager?.getComponentEnabledSetting(
ComponentName(packageName, "${BuildConfig.APPLICATION_ID}.Home")
ComponentName(packageName, "${BuildConfigWrapper.APPLICATION_ID}.Home")
) != PackageManager.COMPONENT_ENABLED_STATE_DISABLED

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/4/17.
* This file is created by fankes on 2023/4/17.
*/
package com.fankes.miui.notify.utils.tool
@@ -32,9 +32,9 @@ import android.content.Intent
import android.graphics.drawable.Icon
import android.os.Build
import androidx.core.graphics.drawable.toBitmap
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.R
import com.fankes.miui.notify.utils.factory.appIconOf
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
/**
* 模块更新激活提醒通知工具类
@@ -42,7 +42,7 @@ import com.fankes.miui.notify.utils.factory.appIconOf
object ActivationPromptTool {
/** 当前模块的包名 */
private const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
private const val MODULE_PACKAGE_NAME = BuildConfigWrapper.APPLICATION_ID
/** 推送通知的渠道名称 */
private const val NOTIFY_CHANNEL = "activationPromptId"
@@ -53,7 +53,7 @@ object ActivationPromptTool {
* @param packageName 当前 APP 包名
*/
fun prompt(context: Context, packageName: String) {
if (packageName != BuildConfig.APPLICATION_ID) return
if (packageName != BuildConfigWrapper.APPLICATION_ID) return
context.getSystemService(NotificationManager::class.java)?.apply {
createNotificationChannel(
NotificationChannel(
@@ -73,7 +73,7 @@ object ActivationPromptTool {
PendingIntent.getActivity(
context, packageName.hashCode(),
Intent().apply {
component = ComponentName(MODULE_PACKAGE_NAME, "${MODULE_PACKAGE_NAME}.ui.activity.MainActivity")
component = ComponentName(MODULE_PACKAGE_NAME, "$MODULE_PACKAGE_NAME.ui.activity.MainActivity")
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}, if (Build.VERSION.SDK_INT < 31) PendingIntent.FLAG_UPDATE_CURRENT else PendingIntent.FLAG_IMMUTABLE
)

View File

@@ -18,11 +18,15 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/2/19.
* This file is created by fankes on 2022/2/19.
*/
package com.fankes.miui.notify.utils.tool
import android.graphics.*
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Matrix
import android.graphics.Paint
import android.graphics.PorterDuff
import android.graphics.drawable.AnimationDrawable
import android.graphics.drawable.BitmapDrawable
import android.graphics.drawable.Drawable

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/20.
* This file is created by fankes on 2022/3/20.
*/
package com.fankes.miui.notify.utils.tool
@@ -27,12 +27,20 @@ import android.content.Context
import android.icu.text.SimpleDateFormat
import android.icu.util.Calendar
import android.icu.util.TimeZone
import com.fankes.miui.notify.utils.factory.*
import okhttp3.*
import com.fankes.miui.notify.utils.factory.isNetWorkSuccess
import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.openSelfSetting
import com.fankes.miui.notify.utils.factory.runInSafe
import com.fankes.miui.notify.utils.factory.showDialog
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import org.json.JSONObject
import java.io.IOException
import java.io.Serializable
import java.util.*
import java.util.Locale
/**
* 获取 GitHub Release 最新版本工具类
@@ -71,7 +79,7 @@ object GithubReleaseTool {
fun showUpdate() = context.showDialog {
title = "最新版本 $name"
msg = "发布于 $date\n\n" +
"更新日志\n\n" + content
"更新日志\n\n" + content
confirmButton(text = "更新") { context.openBrowser(htmlUrl) }
cancelButton()
}

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2023/2/3.
* This file is created by fankes on 2023/2/3.
*/
package com.fankes.miui.notify.utils.tool
@@ -26,7 +26,7 @@ import android.content.Context
import com.fankes.miui.notify.utils.factory.showDialog
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
import java.util.*
import java.util.Locale
/**
* I18n 适配警告提示工具类
@@ -46,8 +46,8 @@ object I18nWarnTool {
context.showDialog {
title = "Notice of I18n Support"
msg = "This Xposed Module is only for Chinese and the Chinese region.\n\n" +
"Currently, there will be no internationalization adaptation.\n\n" +
"There may be plans for internationalization adaptation in the future, so stay tuned."
"Currently, there will be no internationalization adaptation.\n\n" +
"There may be plans for internationalization adaptation in the future, so stay tuned."
confirmButton(text = "Got It") { saveReaded() }
noCancelable()
}

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/3/21.
* This file is created by fankes on 2022/3/21.
*/
package com.fankes.miui.notify.utils.tool
@@ -32,10 +32,15 @@ import android.content.Intent
import android.graphics.drawable.Icon
import android.os.Build
import androidx.core.graphics.drawable.toBitmap
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.R
import com.fankes.miui.notify.hook.HookEntry
import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.factory.appIconOf
import com.fankes.miui.notify.utils.factory.appNameOf
import com.fankes.miui.notify.utils.factory.isDebugApp
import com.fankes.miui.notify.utils.factory.isSystemApp
import com.fankes.miui.notify.utils.factory.runInSafe
import com.fankes.miui.notify.utils.factory.stampToDate
import com.fankes.miui.notify.wrapper.BuildConfigWrapper
/**
* 通知图标适配推送通知类
@@ -45,7 +50,7 @@ import com.fankes.miui.notify.utils.factory.*
object IconAdaptationTool {
/** 当前模块的包名 */
private const val MODULE_PACKAGE_NAME = BuildConfig.APPLICATION_ID
private const val MODULE_PACKAGE_NAME = BuildConfigWrapper.APPLICATION_ID
/** 推送通知的渠道名称 */
private const val NOTIFY_CHANNEL = "notifyRuleSupportId"
@@ -82,7 +87,7 @@ object IconAdaptationTool {
Intent().apply {
component = ComponentName(
MODULE_PACKAGE_NAME,
"${MODULE_PACKAGE_NAME}.ui.activity.ConfigureActivity"
"$MODULE_PACKAGE_NAME.ui.activity.ConfigureActivity"
)
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}.apply {
@@ -117,7 +122,7 @@ object IconAdaptationTool {
outTimeLimits.add(nowTime)
context.startActivity(
Intent().apply {
component = ComponentName(MODULE_PACKAGE_NAME, "${MODULE_PACKAGE_NAME}.ui.activity.auto.NotifyIconRuleUpdateActivity")
component = ComponentName(MODULE_PACKAGE_NAME, "$MODULE_PACKAGE_NAME.ui.activity.auto.NotifyIconRuleUpdateActivity")
flags = Intent.FLAG_ACTIVITY_NEW_TASK
}
)

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/2/25.
* This file is created by fankes on 2022/2/25.
*/
@file:Suppress("TrustAllX509TrustManager", "CustomX509TrustManager", "IMPLICIT_CAST_TO_ANY")
@@ -45,13 +45,25 @@ import com.fankes.miui.notify.databinding.DiaSourceFromBinding
import com.fankes.miui.notify.databinding.DiaSourceFromStringBinding
import com.fankes.miui.notify.params.IconPackParams
import com.fankes.miui.notify.ui.activity.ConfigureActivity
import com.fankes.miui.notify.utils.factory.*
import com.highcapable.yukihookapi.hook.log.loggerD
import okhttp3.*
import com.fankes.miui.notify.utils.factory.delayedRun
import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.safeOfNull
import com.fankes.miui.notify.utils.factory.showDialog
import com.fankes.miui.notify.utils.factory.snake
import com.highcapable.yukihookapi.hook.log.YLog
import okhttp3.Call
import okhttp3.Callback
import okhttp3.OkHttpClient
import okhttp3.Request
import okhttp3.Response
import java.io.IOException
import java.security.SecureRandom
import java.security.cert.X509Certificate
import javax.net.ssl.*
import javax.net.ssl.HostnameVerifier
import javax.net.ssl.SSLContext
import javax.net.ssl.SSLSocketFactory
import javax.net.ssl.TrustManager
import javax.net.ssl.X509TrustManager
/**
* 通知图标在线规则管理类
@@ -465,11 +477,11 @@ object IconRuleManagerTool {
get() = object : X509TrustManager {
override fun checkClientTrusted(chain: Array<X509Certificate?>?, authType: String?) {
loggerD(msg = "TrustX509 --> $authType")
YLog.debug("TrustX509 --> $authType")
}
override fun checkServerTrusted(chain: Array<X509Certificate?>?, authType: String?) {
loggerD(msg = "TrustX509 --> $authType")
YLog.debug("TrustX509 --> $authType")
}
override fun getAcceptedIssuers() = arrayOf<X509Certificate>()

View File

@@ -18,7 +18,7 @@
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/2/8.
* This file is created by fankes on 2022/2/8.
*/
package com.fankes.miui.notify.utils.tool
@@ -32,15 +32,20 @@ import androidx.appcompat.app.AppCompatActivity
import com.fankes.miui.notify.const.PackageName
import com.fankes.miui.notify.data.ConfigData
import com.fankes.miui.notify.ui.activity.MainActivity
import com.fankes.miui.notify.utils.factory.*
import com.fankes.miui.notify.utils.factory.delayedRun
import com.fankes.miui.notify.utils.factory.execShell
import com.fankes.miui.notify.utils.factory.isMIOS
import com.fankes.miui.notify.utils.factory.showDialog
import com.fankes.miui.notify.utils.factory.snake
import com.fankes.miui.notify.utils.factory.systemFullVersion
import com.google.android.material.snackbar.Snackbar
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.dataChannel
import com.highcapable.yukihookapi.hook.log.YukiHookLogger
import com.highcapable.yukihookapi.hook.log.YukiLoggerData
import com.highcapable.yukihookapi.hook.log.YLog
import com.highcapable.yukihookapi.hook.log.data.YLogData
import com.highcapable.yukihookapi.hook.param.PackageParam
import com.highcapable.yukihookapi.hook.xposed.channel.data.ChannelData
import java.util.*
import java.util.Locale
/**
* 系统界面工具
@@ -51,7 +56,7 @@ object SystemUITool {
private val CALL_MODULE_REFRESH_RESULT = ChannelData("call_module_refresh_result", false)
/** 当前全部调试日志 */
private var debugLogs = ArrayList<YukiLoggerData>()
private var debugLogs = listOf<YLogData>()
/** 当前启动器实例 */
private var launcher: ActivityResultLauncher<String>? = null
@@ -88,17 +93,17 @@ object SystemUITool {
runCatching {
result?.let { e ->
val content = "" +
"================================================================\n" +
" Generated by MIUINativeNotifyIcon\n" +
" Project Url: https://github.com/fankes/MIUINativeNotifyIcon\n" +
"================================================================\n\n" +
"[Device Brand]: ${Build.BRAND}\n" +
"[Device Model]: ${Build.MODEL}\n" +
"[Display]: ${Build.DISPLAY}\n" +
"[Android Version]: ${Build.VERSION.RELEASE}\n" +
"[Android API Level]: ${Build.VERSION.SDK_INT}\n" +
"[MIUI Version]: $miuiFullVersion\n" +
"[System Locale]: ${Locale.getDefault()}\n\n" + YukiHookLogger.contents(debugLogs).trim()
"================================================================\n" +
" Generated by MIUINativeNotifyIcon\n" +
" Project Url: https://github.com/fankes/MIUINativeNotifyIcon\n" +
"================================================================\n\n" +
"[Device Brand]: ${Build.BRAND}\n" +
"[Device Model]: ${Build.MODEL}\n" +
"[Display]: ${Build.DISPLAY}\n" +
"[Android Version]: ${Build.VERSION.RELEASE}\n" +
"[Android API Level]: ${Build.VERSION.SDK_INT}\n" +
"[${if (isMIOS) "HyperOS" else "MIUI"} Version]: $systemFullVersion\n" +
"[System Locale]: ${Locale.getDefault()}\n\n" + YLog.contents(debugLogs).trim()
activity.contentResolver?.openOutputStream(e)?.apply { write(content.toByteArray()) }?.close()
activity.snake(msg = "导出完成")
} ?: activity.snake(msg = "已取消操作")
@@ -125,9 +130,9 @@ object SystemUITool {
context.showDialog {
title = "导出全部调试日志"
msg = "调试日志中会包含当前系统推送的全部通知内容,其中可能包含你的个人隐私," +
"你可以在导出后的日志文件中选择将这些敏感信息模糊化处理再进行共享," +
"开发者使用并查看你导出的调试日志仅为排查与修复问题,并且在之后会及时销毁这些日志。\n\n" +
"继续导出即代表你已阅读并知悉上述内容。"
"你可以在导出后的日志文件中选择将这些敏感信息模糊化处理再进行共享," +
"开发者使用并查看你导出的调试日志仅为排查与修复问题,并且在之后会及时销毁这些日志。\n\n" +
"继续导出即代表你已阅读并知悉上述内容。"
confirmButton(text = "继续") { doExport() }
cancelButton()
}
@@ -139,8 +144,8 @@ object SystemUITool {
showDialog {
title = "获取 Root 权限失败"
msg = "当前无法获取 Root 权限,请确认你的设备已经被 Root 且同意授予 Root 权限。\n" +
"如果你正在使用 Magisk 并安装了 Shamiko 模块," +
"请确认当前是否正处于白名单模式。 (白名单模式将导致无法申请 Root 权限)"
"如果你正在使用 Magisk 并安装了 Shamiko 模块," +
"请确认当前是否正处于白名单模式。 (白名单模式将导致无法申请 Root 权限)"
confirmButton(text = "我知道了")
}
@@ -160,8 +165,8 @@ object SystemUITool {
}.onFailure {
execShell(
cmd = "am start -a" +
"com.miui.notification " +
"com.miui.notification/miui.notification.management.activity.NotificationDisplaySettingsActivity"
"com.miui.notification " +
"com.miui.notification/miui.notification.management.activity.NotificationDisplaySettingsActivity"
).also {
when {
it.isBlank() -> context.showWhenAccessRootFail()
@@ -181,9 +186,9 @@ object SystemUITool {
context.showDialog {
title = "重启系统界面"
msg = "你确定要立即重启系统界面吗?\n\n" +
"部分 MIUI 内测和开发版中使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。\n\n" +
"重启过程会黑屏并等待进入锁屏重新解锁。" + (if (isDynamicAvailable)
"\n\n你也可以选择“立即生效”来动态刷新系统界面并生效当前模块设置。" else "")
"部分 MIUI 内测和开发版中使用了状态栏主题可能会发生主题失效的情况,这种情况请再重启一次即可。\n\n" +
"重启过程会黑屏并等待进入锁屏重新解锁。" + (if (isDynamicAvailable)
"\n\n你也可以选择“立即生效”来动态刷新系统界面并生效当前模块设置。" else "")
confirmButton {
execShell(cmd = "pgrep systemui").also { pid ->
if (pid.isNotBlank())

View File

@@ -1,60 +0,0 @@
/*
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/MIUINativeNotifyIcon
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is Created by fankes on 2022/5/30.
*/
package com.fankes.miui.notify.utils.tool
import android.content.Context
import com.fankes.miui.notify.BuildConfig
import com.fankes.miui.notify.utils.factory.openBrowser
import com.fankes.miui.notify.utils.factory.showDialog
import com.highcapable.yukihookapi.YukiHookAPI
import com.highcapable.yukihookapi.hook.factory.prefs
import com.highcapable.yukihookapi.hook.xposed.prefs.data.PrefsData
/**
* [YukiHookAPI] 的自动推广工具类
*/
object YukiPromoteTool {
/** 推广已读存储键值 */
private val YUKI_PROMOTE_READED = PrefsData("yuki_promote_readed_${BuildConfig.VERSION_NAME}", false)
/**
* 显示推广对话框
* @param context 实例
*/
fun promote(context: Context) {
fun saveReaded() = context.prefs().edit { put(YUKI_PROMOTE_READED, value = true) }
if (context.prefs().get(YUKI_PROMOTE_READED).not())
context.showDialog {
title = "面向开发者的推广"
msg = "你想快速拥有一个自己的 Xposed 模块吗,你只需要拥有基础的 Android 开发经验以及使用 Kotlin 编程语言即可。\n\n" +
"快来体验 YukiHookAPI这是一个使用 Kotlin 构建的高效 Hook API 与 Xposed 模块解决方案,助你的开发变得更轻松。"
confirmButton(text = "去看看") {
context.openBrowser(url = "https://github.com/fankes/YukiHookAPI")
saveReaded()
}
cancelButton(text = "我不是开发者") { saveReaded() }
noCancelable()
}
}
}

View File

@@ -0,0 +1,37 @@
/*
* MIUINativeNotifyIcon - Fix the native notification bar icon function abandoned by the MIUI development team.
* Copyright (C) 2017-2023 Fankes Studio(qzmmcn@163.com)
* https://github.com/fankes/MIUINativeNotifyIcon
*
* This software is non-free but opensource software: you can redistribute it
* and/or modify it under the terms of the GNU Affero General Public License
* as published by the Free Software Foundation; either
* version 3 of the License, or any later version.
* <p>
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Affero General Public License for more details.
*
* You should have received a copy of the GNU Affero General Public License
* and eula along with this software. If not, see
* <https://www.gnu.org/licenses/>
*
* This file is created by fankes on 2023/9/17.
*/
@file:Suppress("unused")
package com.fankes.miui.notify.wrapper
import com.fankes.miui.notify.BuildConfig
/**
* 对 [BuildConfig] 的包装
*/
object BuildConfigWrapper {
const val APPLICATION_ID = BuildConfig.APPLICATION_ID
const val VERSION_NAME = BuildConfig.VERSION_NAME
const val VERSION_CODE = BuildConfig.VERSION_CODE
val isDebug = BuildConfig.DEBUG
}

View File

@@ -20,6 +20,7 @@
android:paddingBottom="5dp">
<TextView
android:id="@+id/main_title"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
@@ -377,7 +378,7 @@
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此选项默认开启MIUI 默认最多只能显示 3 个图标,其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。"
android:text="此选项默认开启MIUI 默认最多只能显示 3 个图标 (HyperOS 是 1 个),其余图标将变成省略号,你可以在下方自定义最多显示的图标个数,修改为 0 则只会显示省略号代表图标个数,为防止发生异常,最大限制 100 个,超出的图标可能会被信号或网速指示器遮挡。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
@@ -387,7 +388,7 @@
android:layout_marginBottom="10dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此功能针对不同类型的异形屏设备所搭载的 MIUI 会有不同的效果,如果你正在使用的是中置挖孔屏设备,那么通知图标的个数无论多少都不会超过挖孔区域,如果是居左或居右挖孔屏设备则通知图标的个数不会超过右侧信号图标区域。"
android:text="此功能针对不同类型的异形屏设备所搭载的 MIUI、HyperOS 会有不同的效果,如果你正在使用的是中置挖孔屏设备,那么通知图标的个数无论多少都不会超过挖孔区域,如果是居左或居右挖孔屏设备则通知图标的个数不会超过右侧信号图标区域。"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
@@ -763,7 +764,7 @@
android:gravity="center"
android:padding="10dp"
android:singleLine="true"
android:text="打开 MIUI 通知显示设置"
android:text="打开系统通知显示设置"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
@@ -774,7 +775,7 @@
android:layout_marginRight="15dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="点击上方按钮可以直接打开 MIUI 的通知显示设置界面,可以调整当前通知栏显示的通知样式为 MIUI 经典样式或原生样式,如果无法打开则是当前系统不支持此功能。"
android:text="点击上方按钮可以直接打开系统的通知显示设置界面,可以调整当前通知栏显示的通知样式为 MIUI 经典样式或原生样式,如果无法打开则是当前系统不支持此功能。"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
@@ -876,12 +877,40 @@
android:layout_marginRight="15dp"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:text="此功能仅支持 Android 12 及以上系统的 Material 3 通知图标风格以及 MIUI 后期的经典样式通知图标风格。"
android:text="此功能仅支持 Android 12 及以上系统的 Material 3 通知图标风格以及 MIUI、HyperOS 后期的经典样式通知图标风格。"
android:textColor="@color/colorTextDark"
android:textSize="12sp"
android:textStyle="bold" />
</LinearLayout>
<LinearLayout
android:id="@+id/miui_notify_icon_replacement_item"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<com.fankes.miui.notify.ui.widget.MaterialSwitch
android:id="@+id/miui_notify_icon_replacement_switch"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="替换经典样式通知栏的通知图标"
android:textColor="@color/colorTextGray"
android:textSize="15sp" />
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:alpha="0.6"
android:lineSpacingExtra="6dp"
android:paddingLeft="15dp"
android:paddingRight="15dp"
android:text="此选项默认开启,开启后经典 (MIUI) 样式的下拉通知栏中的通知图标将同样应用替换后的通知图标,否则将保持系统自己设置的图标。(此功能无法对所有系统版本兼容)"
android:textColor="@color/colorTextDark"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/notify_icon_force_system_color_item"
android:layout_width="match_parent"
@@ -1385,7 +1414,8 @@
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@mipmap/bg_qr_pay" />
android:adjustViewBounds="true"
android:src="@mipmap/bg_payment_code" />
</androidx.cardview.widget.CardView>
<TextView
@@ -1423,7 +1453,7 @@
android:ellipsize="end"
android:lineSpacingExtra="6dp"
android:maxLines="2"
android:text="此模块使用 YukiHookAPI 构建。\n了解更多 https://github.com/fankes/YukiHookAPI"
android:text="此模块使用 YukiHookAPI 构建。\n了解更多 https://github.com/HighCapable/YukiHookAPI"
android:textColor="@color/colorTextGray"
android:textSize="11sp" />
</LinearLayout>

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 201 KiB

View File

@@ -1,26 +0,0 @@
plugins {
id 'com.android.application' version '7.4.1' apply false
id 'com.android.library' version '7.4.1' apply false
id 'org.jetbrains.kotlin.android' version '1.8.20' apply false
id 'com.google.devtools.ksp' version '1.8.20-1.0.10' apply false
}
ext {
android = [
compileSdk: 33,
minSdk : 28,
targetSdk : 33
]
app = [
versionName : '2.101',
versionCode : 41,
signingConfigs: [
secretConfigsDirPath : "${projectDir.getAbsolutePath()}/.secret",
secretConfigsFileName: "key_store_secret.json"
]
]
}
task clean(type: Delete) {
delete rootProject.buildDir
}

5
build.gradle.kts Normal file
View File

@@ -0,0 +1,5 @@
plugins {
autowire(libs.plugins.android.application) apply false
autowire(libs.plugins.kotlin.android) apply false
autowire(libs.plugins.kotlin.ksp) apply false
}

View File

@@ -1,23 +1,18 @@
# Project-wide Gradle settings.
# IDE (e.g. Android Studio) users:
# Gradle settings configured through the IDE *will override*
# any settings specified in this file.
# For more details on how to configure your build environment visit
# http://www.gradle.org/docs/current/userguide/build_environment.html
# Specifies the JVM arguments used for the daemon process.
# The setting is particularly useful for tweaking memory settings.
org.gradle.jvmargs=-XX:+UseParallelGC
# When configured, Gradle will run in incubating parallel mode.
# This option should only be used with decoupled projects. More details, visit
# http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects
# org.gradle.parallel=true
# AndroidX package structure to make it clearer which packages are bundled with the
# Android operating system, and which are packaged with your app"s APK
# https://developer.android.com/topic/libraries/support-library/androidx-rn
# Compiler Configuration
org.gradle.jvmargs=-Xmx2048m -Dfile.encoding=UTF-8
android.useAndroidX=true
# Automatically convert third-party libraries to use AndroidX
android.enableJetifier=true
# Kotlin code style for this project: "official" or "obsolete":
android.nonTransitiveRClass=true
kotlin.code.style=official
# Incremental
kotlin.incremental.useClasspathSnapshot=true
kotlin.incremental.useClasspathSnapshot=true
# Project Configuration
project.name=MIUINativeNotifyIcon
project.android.compileSdk=34
project.android.minSdk=28
project.android.targetSdk=34
project.app.packageName=com.fankes.miui.notify
project.app.versionName="2.110"
project.app.versionCode=42
project.app.signing.keyAlias=public
project.app.signing.keyPassword="123456"
project.app.signing.storePassword="123456"
project.app.signing.storeFilePath=.secret/universal.p12

View File

@@ -0,0 +1,78 @@
preferences:
autowire-on-sync-mode: UPDATE_OPTIONAL_DEPENDENCIES
repositories-mode: FAIL_ON_PROJECT_REPOS
repositories:
gradle-plugin-portal:
scope: PLUGINS
google:
maven-central:
jit-pack:
sonatype-oss-releases:
rovo89-xposed-api:
scope: LIBRARIES
url: https://api.xposed.info/
content:
include:
group:
de.robv.android.xposed
fankes-maven-releases:
url: https://raw.githubusercontent.com/fankes/maven-repository/main/repository/releases
plugins:
com.android.application:
alias: android-application
version: 8.1.2
org.jetbrains.kotlin.android:
alias: kotlin-android
version: 1.9.10
com.google.devtools.ksp:
alias: kotlin-ksp
version: 1.9.10-1.0.13
libraries:
com.fankes.projectpromote:
project-promote:
version: 1.0.0
repositories:
fankes-maven-releases
de.robv.android.xposed:
api:
version: 82
repositories:
rovo89-xposed-api
com.highcapable.yukihookapi:
api:
version: 1.2.0
ksp-xposed:
version-ref: <this>::api
com.github.topjohnwu.libsu:
core:
version: 5.2.1
com.github.duanhong169:
drawabletoolbox:
version: 1.0.7
com.squareup.okhttp3:
okhttp:
version: 5.0.0-alpha.11
androidx.core:
core-ktx:
version: 1.12.0
androidx.appcompat:
appcompat:
version: 1.6.1
com.google.android.material:
material:
version: 1.10.0
androidx.constraintlayout:
constraintlayout:
version: 2.1.4
androidx.test.ext:
junit:
version: 1.1.5
androidx.test.espresso:
espresso-core:
version: 3.5.1
junit:
junit:
version: 4.13.2

View File

@@ -1,6 +1,5 @@
#Wed May 25 04:36:53 CST 2022
distributionBase=GRADLE_USER_HOME
distributionUrl=https\://services.gradle.org/distributions/gradle-8.0.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.3-bin.zip
distributionPath=wrapper/dists
zipStorePath=wrapper/dists
zipStoreBase=GRADLE_USER_HOME
zipStoreBase=GRADLE_USER_HOME

BIN
img-src/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 9.8 KiB

After

Width:  |  Height:  |  Size: 9.8 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

View File

Before

Width:  |  Height:  |  Size: 9.1 KiB

After

Width:  |  Height:  |  Size: 9.1 KiB

View File

Before

Width:  |  Height:  |  Size: 35 KiB

After

Width:  |  Height:  |  Size: 35 KiB

View File

Before

Width:  |  Height:  |  Size: 41 KiB

After

Width:  |  Height:  |  Size: 41 KiB

View File

Before

Width:  |  Height:  |  Size: 72 KiB

After

Width:  |  Height:  |  Size: 72 KiB

View File

@@ -1,19 +0,0 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
dependencyResolutionManagement {
repositoriesMode.set(RepositoriesMode.FAIL_ON_PROJECT_REPOS)
repositories {
google()
maven { url "https://api.xposed.info/" }
maven { url "https://www.jitpack.io" }
maven { url "https://s01.oss.sonatype.org/content/repositories/releases" }
mavenCentral()
}
}
rootProject.name = "MIUINativeNotifyIcon"
include ':app'

23
settings.gradle.kts Normal file
View File

@@ -0,0 +1,23 @@
pluginManagement {
repositories {
gradlePluginPortal()
google()
mavenCentral()
}
}
plugins {
id("com.highcapable.sweetdependency") version "1.0.2"
id("com.highcapable.sweetproperty") version "1.0.3"
}
sweetProperty {
global {
all {
permanentKeyValues("GITHUB_CI_COMMIT_ID" to "")
generateFrom(ROOT_PROJECT, SYSTEM_ENV)
}
sourcesCode { includeKeys("GITHUB_CI_COMMIT_ID") }
}
rootProject { all { isEnable = false } }
}
rootProject.name = "MIUINativeNotifyIcon"
include(":app")