├── .gitignore
├── LICENSE
├── LOG-CN.md
├── LOG-EN.md
├── README-CN.md
├── README.md
├── app
├── .gitignore
├── and-res-guard.gradle
├── build.gradle
├── proguard-rules.pro
└── src
│ └── main
│ ├── AndroidManifest.xml
│ ├── assets
│ └── xposed_init
│ ├── ic_launcher-web.png
│ ├── java
│ └── com
│ │ └── tianma
│ │ └── xsmscode
│ │ ├── common
│ │ ├── TextWatcherAdapter.java
│ │ ├── adapter
│ │ │ ├── BaseItemCallback.java
│ │ │ ├── ItemCallback.java
│ │ │ └── ItemChildCallback.java
│ │ ├── constant
│ │ │ ├── Const.java
│ │ │ ├── NotificationConst.java
│ │ │ ├── PermConst.java
│ │ │ ├── PrefConst.java
│ │ │ └── SmsCodeConst.java
│ │ ├── fragment
│ │ │ └── backpress
│ │ │ │ ├── BackPressEventDispatchHelper.java
│ │ │ │ ├── BackPressFragment.java
│ │ │ │ └── BackPressedListener.java
│ │ ├── mvp
│ │ │ ├── BasePresenter.java
│ │ │ └── BaseView.java
│ │ ├── preference
│ │ │ ├── ResetEditPreference.java
│ │ │ └── ResetEditPreferenceDialogFragCompat.java
│ │ ├── utils
│ │ │ ├── ClipboardUtils.java
│ │ │ ├── ColorUtils.java
│ │ │ ├── DebugHelper.java
│ │ │ ├── JsonUtils.java
│ │ │ ├── ModuleUtils.java
│ │ │ ├── NotificationUtils.java
│ │ │ ├── PackageUtils.java
│ │ │ ├── PreferencesUtils.java
│ │ │ ├── ReflectionUtils.java
│ │ │ ├── SPUtils.java
│ │ │ ├── SettingsUtils.java
│ │ │ ├── SmsCodeUtils.java
│ │ │ ├── SmsMessageUtils.java
│ │ │ ├── SnackbarHelper.java
│ │ │ ├── StorageUtils.java
│ │ │ ├── StringUtils.java
│ │ │ ├── Utils.java
│ │ │ ├── XLog.java
│ │ │ └── XSPUtils.java
│ │ └── widget
│ │ │ ├── DialogAsyncTask.java
│ │ │ └── FabScrollBehavior.java
│ │ ├── data
│ │ ├── db
│ │ │ ├── DBManager.java
│ │ │ ├── DBProvider.java
│ │ │ ├── TSQLiteOpenHelper.java
│ │ │ └── entity
│ │ │ │ ├── ApkVersion.java
│ │ │ │ ├── AppInfo.java
│ │ │ │ ├── SmsCodeRule.java
│ │ │ │ └── SmsMsg.java
│ │ ├── eventbus
│ │ │ ├── Event.java
│ │ │ └── XEventBus.java
│ │ ├── http
│ │ │ ├── ApiConst.java
│ │ │ ├── entity
│ │ │ │ └── GithubRelease.java
│ │ │ └── service
│ │ │ │ ├── CoolApkService.java
│ │ │ │ ├── GithubService.java
│ │ │ │ └── ServiceGenerator.java
│ │ └── repository
│ │ │ ├── ApkVersionHelper.java
│ │ │ └── DataRepository.java
│ │ ├── feature
│ │ ├── backup
│ │ │ ├── BackupConst.java
│ │ │ ├── BackupManager.java
│ │ │ ├── ExportResult.java
│ │ │ ├── ImportResult.java
│ │ │ ├── RuleExporter.java
│ │ │ ├── RuleImporter.java
│ │ │ └── exception
│ │ │ │ ├── BackupInvalidException.java
│ │ │ │ ├── VersionInvalidException.java
│ │ │ │ └── VersionMissedException.java
│ │ ├── migrate
│ │ │ ├── ITransition.java
│ │ │ ├── TransitionTask.java
│ │ │ ├── db
│ │ │ │ └── DBTransition.java
│ │ │ └── sp
│ │ │ │ └── PreferencesTransition.java
│ │ └── store
│ │ │ ├── EntityStoreManager.java
│ │ │ └── EntityType.java
│ │ ├── ui
│ │ ├── app
│ │ │ ├── ActivityBindingModule.java
│ │ │ ├── ActivityScope.java
│ │ │ ├── ApplicationComponent.java
│ │ │ ├── ApplicationModule.java
│ │ │ ├── FragmentBindingModule.java
│ │ │ ├── FragmentScope.java
│ │ │ ├── SmsCodeApplication.java
│ │ │ └── base
│ │ │ │ ├── BaseActivity.java
│ │ │ │ ├── BaseDaggerActivity.java
│ │ │ │ ├── BasePreferenceFragment.java
│ │ │ │ └── DaggerBackPressFragment.java
│ │ ├── block
│ │ │ ├── AppBlockActivity.java
│ │ │ ├── AppBlockContract.java
│ │ │ ├── AppBlockFragment.java
│ │ │ ├── AppBlockModule.java
│ │ │ ├── AppBlockPresenter.java
│ │ │ ├── AppInfoAdapter.java
│ │ │ ├── AppInfoHelper.java
│ │ │ └── SortType.java
│ │ ├── faq
│ │ │ ├── FaqFragment.java
│ │ │ ├── FaqItem.java
│ │ │ ├── FaqItemAdapter.java
│ │ │ └── FaqItemContainer.java
│ │ ├── home
│ │ │ ├── HomeActivity.java
│ │ │ ├── SettingsContract.java
│ │ │ ├── SettingsFragment.java
│ │ │ ├── SettingsModule.java
│ │ │ └── SettingsPresenter.java
│ │ ├── record
│ │ │ ├── CodeRecordActivity.java
│ │ │ ├── CodeRecordActivityModule.java
│ │ │ ├── CodeRecordAdapter.java
│ │ │ ├── CodeRecordContract.java
│ │ │ ├── CodeRecordFragment.java
│ │ │ ├── CodeRecordFragmentModule.java
│ │ │ ├── CodeRecordPresenter.java
│ │ │ ├── CodeRecordRestoreManager.java
│ │ │ └── RecordItem.java
│ │ └── rule
│ │ │ ├── CodeRulesActivity.java
│ │ │ ├── CodeRulesModule.java
│ │ │ ├── edit
│ │ │ ├── RuleEditContract.java
│ │ │ ├── RuleEditFragment.java
│ │ │ ├── RuleEditModule.java
│ │ │ └── RuleEditPresenter.java
│ │ │ └── list
│ │ │ ├── RuleAdapter.java
│ │ │ ├── RuleListContract.java
│ │ │ ├── RuleListFragment.java
│ │ │ ├── RuleListModule.java
│ │ │ └── RuleListPresenter.java
│ │ └── xp
│ │ ├── HookEntry.java
│ │ ├── helper
│ │ ├── MethodHookWrapper.java
│ │ └── XposedWrapper.java
│ │ └── hook
│ │ ├── BaseHook.java
│ │ ├── BaseSubHook.java
│ │ ├── IHook.java
│ │ ├── code
│ │ ├── CodeWorker.java
│ │ ├── CopyCodeReceiver.java
│ │ ├── ParseResult.java
│ │ ├── SmsHandlerHook.java
│ │ ├── action
│ │ │ ├── Action.java
│ │ │ ├── CallableAction.java
│ │ │ ├── RunnableAction.java
│ │ │ └── impl
│ │ │ │ ├── AutoInputAction.java
│ │ │ │ ├── CancelNotifyAction.java
│ │ │ │ ├── CopyToClipboardAction.java
│ │ │ │ ├── KillMeAction.java
│ │ │ │ ├── NotifyAction.java
│ │ │ │ ├── OperateSmsAction.java
│ │ │ │ ├── RecordSmsAction.java
│ │ │ │ ├── SmsParseAction.java
│ │ │ │ └── ToastAction.java
│ │ └── helper
│ │ │ └── InputHelper.java
│ │ ├── me
│ │ └── ModuleUtilsHook.java
│ │ └── permission
│ │ ├── PackageManagerServiceHook.java
│ │ ├── PermissionGranterHook.java
│ │ ├── PermissionManagerServiceHook.java
│ │ ├── PermissionManagerServiceHook30.java
│ │ ├── PermissionManagerServiceHook31.java
│ │ ├── PermissionManagerServiceHook33.java
│ │ └── PermissionManagerServiceHook34.java
│ └── res
│ ├── drawable
│ ├── code_rule_quick_choose_bg.xml
│ ├── ic_add.xml
│ ├── ic_alipay.xml
│ ├── ic_alipay_red_packet.xml
│ ├── ic_app_icon.xml
│ ├── ic_automatic.xml
│ ├── ic_baseline_timer.xml
│ ├── ic_block.xml
│ ├── ic_clear.xml
│ ├── ic_copy.xml
│ ├── ic_delete.xml
│ ├── ic_delete_normal.xml
│ ├── ic_done.xml
│ ├── ic_export.xml
│ ├── ic_filter.xml
│ ├── ic_help.xml
│ ├── ic_hide.xml
│ ├── ic_import.xml
│ ├── ic_info.xml
│ ├── ic_intercept.xml
│ ├── ic_key_words.xml
│ ├── ic_kill.xml
│ ├── ic_lock_open.xml
│ ├── ic_log.xml
│ ├── ic_mark_as_read.xml
│ ├── ic_notification.xml
│ ├── ic_palette.xml
│ ├── ic_privacy_tip.xml
│ ├── ic_qq_group.xml
│ ├── ic_records.xml
│ ├── ic_rules.xml
│ ├── ic_search.xml
│ ├── ic_select_all.xml
│ ├── ic_sort.xml
│ ├── ic_source_code.xml
│ ├── ic_test.xml
│ ├── ic_time.xml
│ ├── ic_toast.xml
│ └── selectable_item_background.xml
│ ├── layout
│ ├── activity_app_block.xml
│ ├── activity_code_records.xml
│ ├── activity_code_rules.xml
│ ├── activity_home.xml
│ ├── dialog_code_regex_quick_chcoose.xml
│ ├── fragment_app_block.xml
│ ├── fragment_code_records.xml
│ ├── fragment_faq.xml
│ ├── fragment_rule_edit.xml
│ ├── fragment_rule_list.xml
│ ├── item_app_info.xml
│ ├── item_code_record.xml
│ ├── item_faq.xml
│ ├── item_rule.xml
│ ├── item_theme.xml
│ ├── preference_category.xml
│ └── toolbar.xml
│ ├── menu
│ ├── context_rule_list.xml
│ ├── menu_app_block.xml
│ ├── menu_edit_code_record.xml
│ ├── menu_edit_rule.xml
│ ├── menu_home.xml
│ └── menu_rule_list.xml
│ ├── mipmap-anydpi-v26
│ ├── ic_launcher.xml
│ └── ic_launcher_round.xml
│ ├── mipmap-hdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-mdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── mipmap-xxxhdpi
│ ├── ic_launcher.png
│ ├── ic_launcher_foreground.png
│ └── ic_launcher_round.png
│ ├── values-sw360dp-v13
│ └── values-preference.xml
│ ├── values-zh-rCN
│ └── strings.xml
│ ├── values-zh-rTW
│ └── strings.xml
│ ├── values
│ ├── array.xml
│ ├── attrs.xml
│ ├── colors.xml
│ ├── common_strings.xml
│ ├── dimens.xml
│ ├── ic_launcher_background.xml
│ ├── strings.xml
│ └── styles.xml
│ └── xml
│ ├── files.xml
│ ├── network_security_config.xml
│ ├── settings.xml
│ └── shortcuts.xml
├── art
├── cn
│ ├── 01.png
│ ├── 02.png
│ └── 03.png
└── en
│ ├── 01.png
│ ├── 02.png
│ └── 03.png
├── build.gradle
├── gradle.properties
├── gradle
└── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradlew
├── gradlew.bat
└── settings.gradle
/.gitignore:
--------------------------------------------------------------------------------
1 | *.iml
2 | .gradle
3 | /local.properties
4 | /.idea/libraries
5 | /.idea/modules.xml
6 | /.idea/workspace.xml
7 | .DS_Store
8 | /build
9 | /captures
10 | # External native build folder generated in Android Studio 2.2 and later
11 | .externalNativeBuild
12 |
13 | # Built application files
14 | *.apk
15 | *.ap_
16 |
17 | # Files for the ART/Dalvik VM
18 | *.dex
19 |
20 | # Java class files
21 | *.class
22 |
23 | # Generated files
24 | bin/
25 | gen/
26 | out/
27 |
28 | # Gradle files
29 | .gradle/
30 | build/
31 |
32 | # Local configuration file (sdk path, etc)
33 | local.properties
34 |
35 | # Proguard folder generated by Eclipse
36 | proguard/
37 |
38 | # Log Files
39 | *.log
40 |
41 | # Android Studio Navigation editor temp files
42 | .navigation/
43 |
44 | # Android Studio captures folder
45 | captures/
46 |
47 | # IntelliJ
48 | .idea/workspace.xml
49 | .idea/tasks.xml
50 | .idea/gradle.xml
51 | .idea/assetWizardSettings.xml
52 | .idea/dictionaries
53 | .idea/libraries
54 | .idea/caches
55 | .idea/*
56 |
57 | # Keystore files
58 | # Uncomment the following line if you do not want to check your keystore files in.
59 | *.jks
60 |
61 | # Google Services (e.g. APIs or Firebase)
62 | google-services.json
63 |
64 | # Freeline
65 | freeline.py
66 | freeline/
67 | freeline_project_description.json
68 |
69 | # fastlane
70 | fastlane/report.xml
71 | fastlane/Preview.html
72 | fastlane/screenshots
73 | fastlane/test_output
74 | fastlane/readme.md
75 |
76 | # signature
77 | app/signature.properties
78 |
79 | # eclipse
80 | .settings/
81 | *.project
82 | */.classpath
83 |
84 | # vscode
85 | .vscode/*
--------------------------------------------------------------------------------
/README-CN.md:
--------------------------------------------------------------------------------
1 | # XposedSmsCode
2 |   [](https://github.com/tianma8023/XposedSmsCode/releases)
3 |
4 | 
5 |
6 | 识别短信验证码的Xposed模块,并将验证码拷贝到剪切板,亦可以自动输入验证码。
7 |
8 | [English README](./README-EN.md)
9 |
10 | # 应用截图
11 | 

12 |
13 | # 下载
14 | 下载地址:
15 | - [GitHub Releases](https://github.com/tianma8023/XposedSmsCode/releases)
16 | - [LSPosed仓库](https://github.com/Xposed-Modules-Repo/com.github.tianma8023.xposed.smscode/releases/)
17 | - ~~[酷安](https://www.coolapk.com/apk/com.github.tianma8023.xposed.smscode)~~
18 | - ~~[Xposed仓库](http://repo.xposed.info/module/com.github.tianma8023.xposed.smscode)~~
19 |
20 | # 使用
21 | 1. Root你的设备,安装Xposed框架;
22 | 2. 安装本模块,激活并重启;
23 | 3. Enjoy it!
24 |
25 | 欢迎反馈,欢迎提出意见或建议。
26 |
27 | # 注意
28 | - **此模块适用于偏原生的系统,其他第三方定制Rom可能不适用。**
29 | - **兼容性:兼容 Android 6.0 及以上(api等级≥23)设备。**
30 | - **支持 Xposed、EdXposed、LSPosed 以及 太极·magisk**
31 | - **遇到问题请先阅读模块中的"常见问题"**
32 |
33 | # 功能
34 | - 收到验证码短信后将验证码复制到系统剪贴板
35 | - 收到验证码时显示Toast
36 | - 收到验证码时显示通知
37 | - 将验证码短信标记为已读(实验性)
38 | - 验证码提取成功后,删除验证码短信(实验性)
39 | - 拦截验证码短信
40 | - 自定义验证码短信关键字(正则表达式)
41 | - 自定义验证码匹配规则,并支持规则导入导出
42 | - 自动输入验证码
43 | - 主题换肤
44 |
45 | # 更新日志
46 | [更新日志](/LOG-CN.md)
47 |
48 | # 感谢
49 | - [Xposed](https://github.com/rovo89/Xposed)
50 | - [NekoSMS](https://github.com/apsun/NekoSMS)
51 | - [ButterKnife](https://github.com/JakeWharton/butterknife)
52 | - [Material Dialogs](https://github.com/afollestad/material-dialogs)
53 | - [EventBus](https://github.com/greenrobot/EventBus)
54 | - [GreenDao](https://github.com/greenrobot/greenDAO)
55 | - [GreenDaoUpgradeHelper](https://github.com/yuweiguocn/GreenDaoUpgradeHelper)
56 | - [Gson](https://github.com/google/gson)
57 | - [dagger](https://github.com/google/dagger)
58 | - [rxjava](https://github.com/ReactiveX/RxJava)
59 | - [rxandroid](https://github.com/ReactiveX/RxAndroid)
60 | - [Cyanea](https://github.com/jaredrummler/Cyanea)
61 |
62 |
63 | # 协议
64 | 所有的源码均遵循 [GPLv3](https://www.gnu.org/licenses/gpl-3.0.txt) 协议
--------------------------------------------------------------------------------
/app/.gitignore:
--------------------------------------------------------------------------------
1 | /build
2 | /release
3 |
--------------------------------------------------------------------------------
/app/and-res-guard.gradle:
--------------------------------------------------------------------------------
1 | apply plugin: 'AndResGuard'
2 |
3 | andResGuard {
4 | // mappingFile = file("./resource_mapping.txt")
5 | mappingFile = null
6 | use7zip = true
7 | useSign = true
8 | // 打开这个开关,会keep住所有资源的原始路径,只混淆资源的名字
9 | keepRoot = false
10 | whiteList = [
11 | // for your icon
12 | "R.mipmap.ic_launcher",
13 | "R.mipmap.ic_launcher_round",
14 | "R.mipmap.ic_launcher_foreground",
15 |
16 | // Umeng sdk
17 | "R.anim.umeng*",
18 | "R.string.umeng*",
19 | "R.string.UM*",
20 | "R.string.tb_*",
21 | "R.layout.umeng*",
22 | "R.layout.socialize_*",
23 | "R.layout.*messager*",
24 | "R.layout.tb_*",
25 | "R.color.umeng*",
26 | "R.color.tb_*",
27 | "R.style.*UM*",
28 | "R.style.umeng*",
29 | "R.drawable.umeng*",
30 | "R.drawable.tb_*",
31 | "R.drawable.sina*",
32 | "R.drawable.qq_*",
33 | "R.drawable.tb_*",
34 | "R.id.umeng*",
35 | "R.id.*messager*",
36 | "R.id.progress_bar_parent",
37 | "R.id.socialize_*",
38 | "R.id.webView",
39 |
40 | // Google service
41 | "R.string.google_app_id",
42 | "R.string.gcm_defaultSenderId",
43 | "R.string.default_web_client_id",
44 | "R.string.ga_trackingId",
45 | "R.string.firebase_database_url",
46 | "R.string.google_api_key",
47 | "R.string.google_crash_reporting_api_key",
48 |
49 | // getui
50 | "R.drawable.push",
51 | "R.drawable.push_small",
52 | "R.layout.getui_notification",
53 |
54 | // JPush
55 | "R.drawable.jpush_notification_icon",
56 |
57 | // GrowingIO
58 | "R.string.growingio_project_id",
59 | "R.string.growingio_url_scheme",
60 | "R.string.growingio_channel",
61 | ]
62 | compressFilePattern = [
63 | "*.png",
64 | "*.jpg",
65 | "*.jpeg",
66 | "*.gif",
67 | ]
68 | sevenzip {
69 | artifact = 'com.tencent.mm:SevenZip:1.2.21'
70 | //path = "/usr/local/bin/7za"
71 | }
72 |
73 | /**
74 | * 可选: 如果不设置则会默认覆盖assemble输出的apk
75 | **/
76 | // finalApkBackupPath = "${project.rootDir}/final.apk"
77 |
78 | /**
79 | * 可选: 指定v1签名时生成jar文件的摘要算法
80 | * 默认值为“SHA-1”
81 | **/
82 | // digestalg = "SHA-256"
83 | }
--------------------------------------------------------------------------------
/app/proguard-rules.pro:
--------------------------------------------------------------------------------
1 | -keepclasseswithmembers class * implements de.robv.android.xposed.IXposedHookLoadPackage {
2 | public void handleLoadPackage(...);
3 | }
4 |
5 | -keepclasseswithmembers class * implements de.robv.android.xposed.IXposedHookZygoteInit {
6 | public void initZygote(...);
7 | }
8 |
9 | -keep class com.tianma.xsmscode.common.utils.ModuleUtils {
10 | int getModuleVersion();
11 | }
12 |
13 |
14 | # ==========================
15 | # Umeng analyze proguard start
16 |
17 | #-keepclassmembers class * {
18 | # public (org.json.JSONObject);
19 | #}
20 | #
21 | #-keep public class com.github.tianma8023.xposed.smscode.R$*{
22 | #public static final int *;
23 | #}
24 | #
25 | #-keepclassmembers enum * {
26 | # public static **[] values();
27 | # public static ** valueOf(java.lang.String);
28 | #}
29 | #
30 | #-keep class com.umeng.** {*;}
31 |
32 | # Umeng analyze proguard end
33 | # ==========================
34 |
35 |
36 | # ==========================
37 | # event bus proguard start
38 |
39 | -keepattributes *Annotation*
40 | -keepclassmembers class * {
41 | @org.greenrobot.eventbus.Subscribe ;
42 | }
43 | -keep enum org.greenrobot.eventbus.ThreadMode { *; }
44 |
45 | # Only required if you use AsyncExecutor
46 | -keepclassmembers class * extends org.greenrobot.eventbus.util.ThrowableFailureEvent {
47 | (java.lang.Throwable);
48 | }
49 |
50 | # event bus proguard end
51 | # ==========================
52 |
53 |
54 | # ==========================
55 | # greenDAO 3 proguard start
56 | ### greenDAO 3
57 | ### GreenDaoUpgradeHelper
58 | -keepclassmembers class * extends org.greenrobot.greendao.AbstractDao {
59 | public static java.lang.String TABLENAME;
60 | public static void dropTable(org.greenrobot.greendao.database.Database, boolean);
61 | public static void createTable(org.greenrobot.greendao.database.Database, boolean);
62 | }
63 | -keep class **$Properties {*;}
64 |
65 | # If you do not use SQLCipher:
66 | -dontwarn org.greenrobot.greendao.database.**
67 | # If you do not use RxJava:
68 | -dontwarn rx.**
69 |
70 | # greenDAO 3 proguard end
71 | # ==========================
72 |
73 |
74 | # ==========================
75 | # bugly proguard start
76 |
77 | #-dontwarn com.tencent.bugly.**
78 | #-keep public class com.tencent.bugly.** {
79 | # *;
80 | #}
81 |
82 | # bugly proguard end
83 | # ==========================
84 |
85 |
86 | # ==========================
87 | # jsoup proguard start
88 | -keeppackagenames org.jsoup.nodes
89 | # jsoup proguard end
90 | # ==========================
91 |
92 |
93 | # ==========================
94 | # okhttp3 start
95 | # okhttp3 end
96 | # ==========================
97 |
98 |
99 | # ==========================
100 | # okio start
101 | # okio end
102 | # ==========================
--------------------------------------------------------------------------------
/app/src/main/assets/xposed_init:
--------------------------------------------------------------------------------
1 | com.tianma.xsmscode.xp.HookEntry
--------------------------------------------------------------------------------
/app/src/main/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/ic_launcher-web.png
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/TextWatcherAdapter.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common;
2 |
3 | import android.text.Editable;
4 | import android.text.TextWatcher;
5 |
6 | /**
7 | * Default text watcher implementation
8 | */
9 | public class TextWatcherAdapter implements TextWatcher{
10 |
11 | @Override
12 | public void beforeTextChanged(CharSequence s, int start, int count, int after) {
13 |
14 | }
15 |
16 | @Override
17 | public void onTextChanged(CharSequence s, int start, int before, int count) {
18 |
19 | }
20 |
21 | @Override
22 | public void afterTextChanged(Editable s) {
23 |
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/adapter/BaseItemCallback.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.adapter;
2 |
3 | import android.view.ContextMenu;
4 | import android.view.View;
5 |
6 | public class BaseItemCallback implements ItemCallback {
7 | @Override
8 | public void onItemClicked(View itemView, E item, int position) {
9 | onItemClicked(item, position);
10 | }
11 |
12 | protected void onItemClicked(E item, int position) {
13 |
14 | }
15 |
16 | @Override
17 | public boolean onItemLongClicked(View itemView, E item, int position) {
18 | return onItemLongClicked(item, position);
19 | }
20 |
21 |
22 | protected boolean onItemLongClicked(E item, int position) {
23 | return false;
24 | }
25 |
26 | @Override
27 | public void onCreateItemContextMenu(ContextMenu menu, View v,
28 | ContextMenu.ContextMenuInfo menuInfo,
29 | E item, int position) {
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/adapter/ItemCallback.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.adapter;
2 |
3 | import android.view.ContextMenu;
4 | import android.view.View;
5 |
6 | public interface ItemCallback {
7 |
8 | void onItemClicked(View itemView, E item, int position);
9 |
10 | boolean onItemLongClicked(View itemView, E item, int position);
11 |
12 | void onCreateItemContextMenu(ContextMenu menu, View v, ContextMenu.ContextMenuInfo menuInfo, E item, int position);
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/adapter/ItemChildCallback.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.adapter;
2 |
3 | import android.view.View;
4 |
5 | public interface ItemChildCallback {
6 |
7 | void onItemChildClicked(View childView, E item, int position);
8 |
9 | }
10 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/constant/Const.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.constant;
2 |
3 | import com.github.tianma8023.xposed.smscode.BuildConfig;
4 |
5 | /**
6 | * Constant about 3rd app
7 | */
8 | public interface Const {
9 |
10 | /* Alipay begin */
11 | String ALIPAY_PACKAGE_NAME = "com.eg.android.AlipayGphone";
12 | String ALIPAY_QRCODE_URI_PREFIX = "alipayqr://platformapi/startapp?saId=10000007&qrcode=";
13 | String ALIPAY_QRCODE_URL = "HTTPS://QR.ALIPAY.COM/FKX074142EKXD0OIMV8B60";
14 | /* Alipay end */
15 |
16 | /* QQ begin */
17 | String QQ_GROUP_KEY = "jWGrWgSGLGQ0NyyRsKqRlrApRCzecuNA";
18 | /* QQ end */
19 |
20 | /* Xposed SmsCode begin */
21 | String HOME_ACTIVITY_ALIAS = BuildConfig.APPLICATION_ID + ".HomeActivityAlias";
22 |
23 | String PROJECT_SOURCE_CODE_URL = "https://github.com/tianma8023/XposedSmsCode";
24 | String PROJECT_GITHUB_LATEST_RELEASE_URL = PROJECT_SOURCE_CODE_URL + "/releases/latest";
25 | String PROJECT_DOC_BASE_URL = "https://tianma8023.github.io/SmsCode";
26 | String DOC_SMS_CODE_RULE_HELP ="sms_code_rule_help";
27 | /* Xposed SmsCode end */
28 |
29 | /* Taichi begin */
30 | String TAICHI_PACKAGE_NAME = "me.weishu.exp";
31 | String TAICHI_MAIN_PAGE = "me.weishu.exp.ui.MainActivity";
32 | /* Taichi end */
33 |
34 | /* Xposed Installer begin */
35 | String XPOSED_PACKAGE = "de.robv.android.xposed.installer";
36 | // Old Xposed installer
37 | String XPOSED_OPEN_SECTION_ACTION = XPOSED_PACKAGE + ".OPEN_SECTION";
38 | String XPOSED_EXTRA_SECTION = "section";
39 | // New Xposed installer
40 | String XPOSED_ACTIVITY = XPOSED_PACKAGE + ".WelcomeActivity";
41 | String XPOSED_EXTRA_FRAGMENT = "fragment";
42 | /* Xposed Installer end */
43 |
44 | /* CoolApk */
45 | String COOL_MARKET_PACKAGE_NAME = "com.coolapk.market";
46 | /* CoolApk end */
47 | }
48 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/constant/NotificationConst.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.constant;
2 |
3 | /**
4 | * Notification Constants
5 | */
6 | public interface NotificationConst {
7 |
8 | String CHANNEL_ID_FOREGROUND_SERVICE = "foreground_service";
9 |
10 | String CHANNEL_ID_SMSCODE_NOTIFICATION = "smscode_notification";
11 | String GROUP_KEY_SMSCODE_NOTIFICATION = "group_key_smscode_notification";
12 |
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/constant/PermConst.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.constant;
2 |
3 | import android.Manifest;
4 | import android.os.Build;
5 |
6 | import com.github.tianma8023.xposed.smscode.BuildConfig;
7 | import com.tianma.xsmscode.xp.hook.code.SmsHandlerHook;
8 |
9 | import java.util.ArrayList;
10 | import java.util.HashMap;
11 | import java.util.List;
12 | import java.util.Map;
13 |
14 | /**
15 | * Permission Constants
16 | */
17 | public class PermConst {
18 |
19 | public final static Map> PACKAGE_PERMISSIONS;
20 |
21 | static {
22 | PACKAGE_PERMISSIONS = new HashMap<>();
23 |
24 | List smsCodePermissions = new ArrayList<>();
25 |
26 | // Backup import or export
27 | smsCodePermissions.add(Manifest.permission.READ_EXTERNAL_STORAGE);
28 | smsCodePermissions.add(Manifest.permission.WRITE_EXTERNAL_STORAGE);
29 |
30 | String smsCodePackage = BuildConfig.APPLICATION_ID;
31 | PACKAGE_PERMISSIONS.put(smsCodePackage, smsCodePermissions);
32 |
33 | List phonePermissions = new ArrayList<>();
34 | // permission for InputManager#injectInputEvent();
35 | phonePermissions.add("android.permission.INJECT_EVENTS");
36 |
37 | // permission for kill background process - ActivityManagerService#killBackgroundProcesses()
38 | phonePermissions.add(Manifest.permission.KILL_BACKGROUND_PROCESSES);
39 |
40 | // READ_SMS for Mark SMS as read & Delete extracted verification SMS
41 | phonePermissions.add(Manifest.permission.READ_SMS);
42 | // api version < android M
43 | phonePermissions.add("android.permission.WRITE_SMS");
44 |
45 | // Permission for grant AppOps permissions
46 | if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
47 | // Android P
48 | phonePermissions.add("android.permission.MANAGE_APP_OPS_MODES");
49 | } else {
50 | // android 4.4 ~ 8.1
51 | phonePermissions.add("android.permission.UPDATE_APP_OPS_STATS");
52 | }
53 |
54 | PACKAGE_PERMISSIONS.put(SmsHandlerHook.ANDROID_PHONE_PACKAGE, phonePermissions);
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/constant/PrefConst.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.constant;
2 |
3 | import com.github.tianma8023.xposed.smscode.BuildConfig;
4 |
5 | /**
6 | * Preference相关的常量
7 | */
8 | public interface PrefConst {
9 |
10 | String PREF_NAME = BuildConfig.APPLICATION_ID + "_preferences";
11 |
12 | // General
13 | String KEY_ENABLE = "pref_enable";
14 | String KEY_HIDE_LAUNCHER_ICON = "pref_hide_launcher_icon";
15 | String KEY_CHOOSE_THEME = "pref_choose_theme";
16 |
17 | // SMS Code
18 | String KEY_SHOW_TOAST = "pref_show_toast";
19 | String KEY_COPY_TO_CLIPBOARD = "pref_copy_to_clipboard";
20 | String KEY_ENABLE_AUTO_INPUT_CODE = "pref_enable_auto_input_code";
21 | String KEY_AUTO_INPUT_CODE_DELAY = "pref_auto_input_code_delay";
22 | String KEY_AUTO_INPUT_CODE_DELAY_DEFAULT = "0";
23 | String KEY_APP_BLOCK_ENTRY = "pref_app_block_entry";
24 | String KEY_BLOCK_SMS = "pref_block_sms";
25 | String KEY_DEDUPLICATE_SMS = "pref_deduplicate_sms";
26 |
27 |
28 | // Code Notification
29 | String KEY_SHOW_CODE_NOTIFICATION = "pref_show_code_notification";
30 | String KEY_AUTO_CANCEL_CODE_NOTIFICATION = "pref_auto_cancel_code_notification";
31 | String KEY_NOTIFICATION_RETENTION_TIME = "pref_notification_retention_time";
32 | String NOTIFICATION_RETENTION_TIME_DEFAULT = "5";
33 |
34 |
35 | // Code Record
36 | String KEY_ENABLE_CODE_RECORDS = "pref_enable_code_records";
37 | int MAX_SMS_RECORDS_COUNT_DEFAULT = 20;
38 | String KEY_ENTRY_CODE_RECORDS = "pref_entry_code_records";
39 |
40 | // Code Rules
41 | String KEY_SMSCODE_KEYWORDS = "pref_smscode_keywords";
42 | String SMSCODE_KEYWORDS_DEFAULT = SmsCodeConst.VERIFICATION_KEYWORDS_REGEX;
43 | String KEY_SMSCODE_TEST = "pref_smscode_test";
44 | String KEY_CODE_RULES = "pref_code_rules";
45 |
46 | // Experimental
47 | String KEY_MARK_AS_READ = "pref_mark_as_read";
48 | String KEY_DELETE_SMS = "pref_delete_sms";
49 | String KEY_KILL_ME = "pref_kill_me";
50 |
51 | // Others
52 | String KEY_VERBOSE_LOG_MODE = "pref_verbose_log_mode";
53 |
54 | // About
55 | String KEY_ABOUT = "pref_about";
56 | String KEY_VERSION = "pref_version";
57 | String KEY_JOIN_QQ_GROUP = "pref_join_qq_group";
58 | String KEY_SOURCE_CODE = "pref_source_code";
59 | String KEY_DONATE_BY_ALIPAY = "pref_donate_by_alipay";
60 | String KEY_PRIVACY_POLICY = "pref_privacy_policy";
61 | String KEY_PRIVACY_POLICY_ACCEPTED = "pref_privacy_policy_accepted";
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/constant/SmsCodeConst.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.constant;
2 |
3 | /**
4 | * SmsCode Constant
5 | */
6 | public interface SmsCodeConst {
7 |
8 | String[] VERIFICATION_KEY_WORDS_CN = {
9 | "验证码" /**/,
10 | "校验码" /**/,
11 | "检验码" /**/,
12 | "确认码" /**/,
13 | "激活码" /**/,
14 | "动态码" /**/,
15 |
16 | "验证代码" /**/,
17 | "校验代码" /**/,
18 | "检验代码" /**/,
19 | "激活代码" /**/,
20 | "确认代码" /**/,
21 | "动态代码" /**/,
22 |
23 | "短信口令" /**/,
24 | "动态密码" /**/,
25 | "交易码" /**/,
26 | "上网密码" /**/,
27 |
28 | "驗證碼" /**/,
29 | "校驗碼" /**/,
30 | "檢驗碼" /**/,
31 | "確認碼" /**/,
32 | "激活碼" /**/,
33 | "動態碼" /**/,
34 |
35 | "驗證代碼" /**/,
36 | "校驗代碼" /**/,
37 | "檢驗代碼" /**/,
38 | "確認代碼" /**/,
39 | "激活代碼" /**/,
40 | "動態代碼" /**/,
41 | };
42 |
43 | String VERIFICATION_KEYWORDS_REGEX =
44 | /**/ "验证码|校验码|检验码|确认码|激活码|动态码|安全码" +
45 | /**/ "|验证代码|校验代码|检验代码|激活代码|确认代码|动态代码|安全代码" +
46 | /**/ "|登入码|认证码|识别码" +
47 | /**/ "|短信口令|动态密码|交易码|上网密码|随机码|动态口令" +
48 | /**/ "|驗證碼|校驗碼|檢驗碼|確認碼|激活碼|動態碼" +
49 | /**/ "|驗證代碼|校驗代碼|檢驗代碼|確認代碼|激活代碼|動態代碼" +
50 | /**/ "|登入碼|認證碼|識別碼" +
51 | /*English*/ "|Code|code|CODE" +
52 | /*Russian*/ "|Код|код|КОД|Пароль|пароль|ПАРОЛЬ|Kod|kod|KOD" +
53 | /*Vietnamese*/ "|Ma|Mã|OTP";
54 |
55 | String[] VERIFICATION_KEY_WORDS_EN = {
56 | "Code",
57 | "code",
58 | "CODE",
59 | };
60 |
61 | String PHONE_NUMBER_KEYWORDS =
62 | /**/ "手机号|电话号" +
63 | /**/ "|手機號|電話號" +
64 | /*(?i) 表示忽略大小写*/ "|(?i)phone(?-i)" +
65 | /*(?i) 表示忽略大小写*/ "|(?i)number(?-i)";
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/fragment/backpress/BackPressEventDispatchHelper.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.fragment.backpress;
2 |
3 | import java.util.List;
4 |
5 | import androidx.fragment.app.Fragment;
6 | import androidx.fragment.app.FragmentActivity;
7 | import androidx.fragment.app.FragmentManager;
8 |
9 | /**
10 | * Helper for dispatching back-press event.
11 | */
12 | public class BackPressEventDispatchHelper {
13 |
14 | public static boolean dispatchBackPressedEvent(FragmentManager fragmentManager) {
15 | List fragments = fragmentManager.getFragments();
16 |
17 | if (fragments == null)
18 | return false;
19 |
20 | for (int i = fragments.size() - 1; i >= 0; i--) {
21 | Fragment fragment = fragments.get(i);
22 |
23 | if (isBackPressedIntercepted(fragment)) {
24 | ((BackPressedListener) fragment).onBackPressed();
25 | return true;
26 | }
27 | }
28 |
29 | if (fragmentManager.getBackStackEntryCount() > 0) {
30 | fragmentManager.popBackStack();
31 | return true;
32 | }
33 | return false;
34 | }
35 |
36 | public static boolean dispatchBackPressedEvent(Fragment fragment) {
37 | return dispatchBackPressedEvent(fragment.getChildFragmentManager());
38 | }
39 |
40 | public static boolean dispatchBackPressedEvent(FragmentActivity fragmentActivity) {
41 | return dispatchBackPressedEvent(fragmentActivity.getSupportFragmentManager());
42 | }
43 |
44 | private static boolean isBackPressedIntercepted(Fragment fragment) {
45 | return fragment != null &&
46 | fragment.isVisible() &&
47 | fragment.getUserVisibleHint() &&
48 | fragment instanceof BackPressedListener &&
49 | ((BackPressedListener) fragment).interceptBackPress();
50 | }
51 |
52 | }
53 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/fragment/backpress/BackPressFragment.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.fragment.backpress;
2 |
3 | import androidx.fragment.app.Fragment;
4 |
5 | /**
6 | * Fragment that handled back pressed event.
7 | */
8 | public class BackPressFragment extends Fragment implements BackPressedListener {
9 |
10 | @Override
11 | public boolean interceptBackPress() {
12 | return false;
13 | }
14 |
15 | @Override
16 | public void onBackPressed() {
17 | BackPressEventDispatchHelper.dispatchBackPressedEvent(this);
18 | }
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/fragment/backpress/BackPressedListener.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.fragment.backpress;
2 |
3 | /**
4 | * Listener for handling back-press event.
5 | */
6 | public interface BackPressedListener {
7 |
8 | /**
9 | * Whether current fragment should intercept back-press event.
10 | *
11 | * @return true if back-press event should be intercepted, false if not.
12 | */
13 | boolean interceptBackPress();
14 |
15 | /**
16 | * Callback on back-pressed.
17 | */
18 | void onBackPressed();
19 |
20 | }
21 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/mvp/BasePresenter.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.mvp;
2 |
3 | import android.content.Context;
4 |
5 | /**
6 | * Base Presenter
7 | *
8 | * @param View extends BaseView
9 | */
10 | public interface BasePresenter {
11 |
12 | /**
13 | * on view attach
14 | *
15 | * @param context context
16 | * @param view view
17 | */
18 | void onAttach(Context context, T view);
19 |
20 | /**
21 | * on view detach
22 | */
23 | void onDetach();
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/mvp/BaseView.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.mvp;
2 |
3 | /**
4 | * Base View
5 | */
6 | public interface BaseView {
7 | }
8 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/preference/ResetEditPreference.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.preference;
2 |
3 | import android.annotation.TargetApi;
4 | import android.content.Context;
5 | import android.content.res.TypedArray;
6 | import android.os.Build;
7 | import android.util.AttributeSet;
8 |
9 | import com.github.tianma8023.xposed.smscode.R;
10 |
11 | import androidx.preference.EditTextPreference;
12 |
13 | public class ResetEditPreference extends EditTextPreference {
14 |
15 | private String mDefaultValue;
16 |
17 | @TargetApi(Build.VERSION_CODES.LOLLIPOP)
18 | public ResetEditPreference(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
19 | super(context, attrs, defStyleAttr, defStyleRes);
20 | init();
21 | }
22 |
23 | public ResetEditPreference(Context context, AttributeSet attrs, int defStyleAttr) {
24 | super(context, attrs, defStyleAttr);
25 | init();
26 | }
27 |
28 | public ResetEditPreference(Context context, AttributeSet attrs) {
29 | super(context, attrs);
30 | init();
31 | }
32 |
33 | public ResetEditPreference(Context context) {
34 | super(context);
35 | init();
36 | }
37 |
38 | private void init() {
39 | setNegativeButtonText(R.string.reset);
40 | }
41 |
42 | @Override
43 | public void setDefaultValue(Object value) {
44 | super.setDefaultValue(value);
45 | mDefaultValue = (String) value;
46 | }
47 |
48 | @Override
49 | protected Object onGetDefaultValue(TypedArray a, int index) {
50 | Object result = super.onGetDefaultValue(a, index);
51 | mDefaultValue = (String) result;
52 | return result;
53 | }
54 |
55 | public String getDefaultValue() {
56 | return mDefaultValue;
57 | }
58 | }
59 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/ClipboardUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.content.ClipData;
4 | import android.content.ClipDescription;
5 | import android.content.ClipboardManager;
6 | import android.content.Context;
7 |
8 | public class ClipboardUtils {
9 |
10 | private ClipboardUtils() {
11 | }
12 |
13 | public static void copyToClipboard(Context context, String text) {
14 | ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
15 | if (cm == null) {
16 | XLog.e("Copy failed, clipboard manager is null");
17 | return;
18 | }
19 | ClipData clipData = ClipData.newPlainText("Copy text", text);
20 | cm.setPrimaryClip(clipData);
21 | XLog.i("Copy to clipboard succeed");
22 | }
23 |
24 | public static void clearClipboard(Context context) {
25 | ClipboardManager cm = (ClipboardManager) context.getSystemService(Context.CLIPBOARD_SERVICE);
26 | if (cm == null) {
27 | XLog.e("Clear failed, clipboard manager is null");
28 | return;
29 | }
30 | if(cm.hasPrimaryClip()) {
31 | ClipDescription cd = cm.getPrimaryClipDescription();
32 | if (cd != null) {
33 | if (cd.hasMimeType(ClipDescription.MIMETYPE_TEXT_PLAIN)) {
34 | cm.setPrimaryClip(ClipData.newPlainText("Copy text", ""));
35 | XLog.i("Clear clipboard succeed");
36 | }
37 | }
38 | }
39 | }
40 |
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/ColorUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import androidx.annotation.ColorInt;
4 |
5 | public class ColorUtils {
6 |
7 | private ColorUtils() {
8 | }
9 |
10 | /**
11 | * Darken or lighten a specific color.
12 | * Calculate an new color according to originColor and factor. Dark color returned if factor < 1.0f, light color returned if factor > 1.0f
13 | *
14 | * @param originColor The specific color value.
15 | * @param factor The factor that can influence the color returned.
16 | * @return Dark color returned if factor < 1.0f, light color returned if factor > 1.0f
17 | */
18 | public static int gradientColor(@ColorInt int originColor, float factor) {
19 | if (factor == 1.0f) {
20 | return originColor;
21 | }
22 | int a = originColor >> 24;
23 | int r = (int) (((originColor >> 16) & 0xff) * factor);
24 | r = Math.min(r, 0xff);
25 | int g = (int) (((originColor >> 8) & 0xff) * factor);
26 | g = Math.min(g, 0xff);
27 | int b = (int) ((originColor & 0xff) * factor);
28 | b = Math.min(b, 0xff);
29 | return (a << 24) | (r << 16) | (g << 8) | b;
30 | }
31 |
32 | }
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/DebugHelper.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import com.jaredrummler.cyanea.Cyanea;
4 | import com.jaredrummler.cyanea.CyaneaThemes;
5 |
6 | import java.lang.reflect.Method;
7 |
8 | public class DebugHelper {
9 |
10 | private DebugHelper() {
11 |
12 | }
13 |
14 | public static void printCyanea() {
15 | XLog.d("------------------------");
16 |
17 | Cyanea cyanea = Cyanea.getInstance();
18 |
19 | Method[] methods = Cyanea.class.getDeclaredMethods();
20 | for (Method method : methods) {
21 | String methodName = method.getName();
22 | try {
23 | if (methodName.startsWith("is") || methodName.startsWith("get")) {
24 | method.setAccessible(true);
25 | Object object = method.invoke(cyanea);
26 | if (object instanceof Integer) {
27 | String hexColor = String.format("#%06X", (0xFFFFFF & (int) object));
28 | XLog.d("%s: %s", methodName, hexColor);
29 | } else {
30 | XLog.d("%s: %s", methodName, object == null ? "null" : object.toString());
31 | }
32 | }
33 | } catch (Exception e) {
34 | // ignore
35 | }
36 | }
37 |
38 | CyaneaThemes themes = cyanea.getThemes();
39 |
40 |
41 | // XLog.d("------------------------");
42 | //
43 | // Field[] fields = Cyanea.class.getDeclaredFields();
44 | // for (Field field : fields) {
45 | // try {
46 | // String fieldName = field.getName();
47 | // field.setAccessible(true);
48 | // Object object = field.get(cyanea);
49 | // XLog.d("%s: %s", fieldName, object == null ? "null" : object.toString());
50 | // } catch (Exception e) {
51 | // // ignore
52 | // }
53 | // }
54 |
55 | }
56 |
57 | }
58 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/JsonUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import com.google.gson.Gson;
4 | import com.google.gson.GsonBuilder;
5 |
6 | import org.jetbrains.annotations.NotNull;
7 |
8 | import java.io.Reader;
9 | import java.lang.reflect.ParameterizedType;
10 | import java.lang.reflect.Type;
11 | import java.util.List;
12 |
13 | /**
14 | * Gson utils
15 | */
16 | public class JsonUtils {
17 |
18 | private JsonUtils() {
19 | }
20 |
21 | private static Gson createGson(boolean excludeExposeAnnotation) {
22 | Gson gson;
23 | if (excludeExposeAnnotation) {
24 | gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
25 | } else {
26 | gson = new Gson();
27 | }
28 | return gson;
29 | }
30 |
31 | public static String toJson(Object object, boolean excludeExposeAnnotation) {
32 | return createGson(excludeExposeAnnotation).toJson(object);
33 | }
34 |
35 | public static void toJson(Object object, Appendable writer, boolean excludeExposeAnnotation) {
36 | createGson(excludeExposeAnnotation).toJson(object, writer);
37 | }
38 |
39 | public static T entityFromJson(String json, Class typeClass, boolean excludeExposeAnnotation) {
40 | return createGson(excludeExposeAnnotation).fromJson(json, typeClass);
41 | }
42 |
43 | public static T entityFromJson(Reader json, Class typeClass, boolean excludeExposeAnnotation) {
44 | return createGson(excludeExposeAnnotation).fromJson(json, typeClass);
45 | }
46 |
47 | public static List listFromJson(String json, Class typeClass, boolean excludeExposeAnnotation) {
48 | return createGson(excludeExposeAnnotation).fromJson(json, new ListOfJson(typeClass));
49 | }
50 |
51 | public static List listFromJson(Reader json, Class typeClass, boolean excludeExposeAnnotation) {
52 | Gson gson;
53 | if (excludeExposeAnnotation) {
54 | gson = new GsonBuilder().excludeFieldsWithoutExposeAnnotation().create();
55 | } else {
56 | gson = new Gson();
57 | }
58 | return gson.fromJson(json, new ListOfJson(typeClass));
59 | }
60 |
61 | public static class ListOfJson implements ParameterizedType {
62 | private Class> wrapped;
63 |
64 | private ListOfJson(Class wrapper) {
65 | this.wrapped = wrapper;
66 | }
67 |
68 | @NotNull
69 | @Override
70 | public Type[] getActualTypeArguments() {
71 | return new Type[]{wrapped};
72 | }
73 |
74 | @NotNull
75 | @Override
76 | public Type getRawType() {
77 | return List.class;
78 | }
79 |
80 | @Override
81 | public Type getOwnerType() {
82 | return null;
83 | }
84 | }
85 |
86 | }
87 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/ModuleUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | /**
4 | * 当前Xposed模块相关工具类
5 | */
6 | public class ModuleUtils {
7 |
8 | private ModuleUtils() {
9 | }
10 |
11 | /**
12 | * 返回模块版本
13 | * 注意:该方法被本模块Hook住,返回的值是 BuildConfig.MODULE_VERSION,如果没被Hook则返回-1
14 | */
15 | public static int getModuleVersion() {
16 | XLog.d("getModuleVersion()");
17 | return -1;
18 | }
19 |
20 | /**
21 | * 当前模块是否在XposedInstaller中被启用
22 | */
23 | public static boolean isModuleEnabled() {
24 | return getModuleVersion() > 0;
25 | }
26 | }
27 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/NotificationUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.app.NotificationChannel;
4 | import android.app.NotificationManager;
5 | import android.content.Context;
6 | import android.os.Build;
7 | import androidx.annotation.RequiresApi;
8 |
9 | public class NotificationUtils {
10 |
11 | private NotificationUtils() {
12 | }
13 |
14 | @RequiresApi(api = Build.VERSION_CODES.O)
15 | public static void createNotificationChannel(Context context, String channelId,
16 | String channelName, int importance) {
17 | NotificationChannel channel = new NotificationChannel(channelId, channelName, importance);
18 | NotificationManager manager = (NotificationManager)
19 | context.getSystemService(Context.NOTIFICATION_SERVICE);
20 | if (manager != null) {
21 | manager.createNotificationChannel(channel);
22 | }
23 | }
24 |
25 | }
26 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/PreferencesUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.content.Context;
4 | import android.content.SharedPreferences;
5 |
6 | import com.tianma.xsmscode.common.constant.PrefConst;
7 |
8 |
9 | /**
10 | * Common Shared preferences utils.
11 | */
12 | public class PreferencesUtils {
13 |
14 | private PreferencesUtils() {
15 |
16 | }
17 |
18 | private static SharedPreferences getPreferences(Context context) {
19 | return context.getSharedPreferences(PrefConst.PREF_NAME, Context.MODE_PRIVATE);
20 | }
21 |
22 | public static boolean contains(Context context, String key) {
23 | return getPreferences(context).contains(key);
24 | }
25 |
26 | public static String getString(Context context, String key, String defValue) {
27 | return getPreferences(context).getString(key, defValue);
28 | }
29 |
30 | public static void putString(Context context, String key, String value) {
31 | getPreferences(context).edit().putString(key, value).apply();
32 | }
33 |
34 | public static boolean getBoolean(Context context, String key, boolean defValue) {
35 | return getPreferences(context).getBoolean(key, defValue);
36 | }
37 |
38 | public static void putBoolean(Context context, String key, boolean value) {
39 | getPreferences(context).edit().putBoolean(key, value).apply();
40 | }
41 |
42 | public static int getInt(Context context, String key, int defValue) {
43 | return getPreferences(context).getInt(key, defValue);
44 | }
45 |
46 | public static void putInt(Context context, String key, int value) {
47 | getPreferences(context).edit().putInt(key, value).apply();
48 | }
49 |
50 | public static float getFloat(Context context, String key, float defValue) {
51 | return getPreferences(context).getFloat(key, defValue);
52 | }
53 |
54 | public static void putFloat(Context context, String key, float value) {
55 | getPreferences(context).edit().putFloat(key, value).apply();
56 | }
57 |
58 | public static long getLong(Context context, String key, long defValue) {
59 | return getPreferences(context).getLong(key, defValue);
60 | }
61 |
62 | public static void putLong(Context context, String key, long value) {
63 | getPreferences(context).edit().putLong(key, value).apply();
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/SPUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.content.Context;
4 |
5 | import com.tianma.xsmscode.common.constant.PrefConst;
6 |
7 | public class SPUtils {
8 |
9 | // 本地的版本号
10 | private static final String LOCAL_VERSION_CODE = "local_version_code";
11 | private static final int LOCAL_VERSION_CODE_DEFAULT = 16;
12 |
13 | private SPUtils() {
14 |
15 | }
16 |
17 | /**
18 | * 获取本地记录的版本号
19 | */
20 | public static int getLocalVersionCode(Context context) {
21 | // 如果不存在,则默认返回16,即v1.4.5版本
22 | return PreferencesUtils.getInt(context,
23 | LOCAL_VERSION_CODE, LOCAL_VERSION_CODE_DEFAULT);
24 | }
25 |
26 |
27 | /**
28 | * 设置当前版本号
29 | */
30 | public static void setLocalVersionCode(Context context, int versionCode) {
31 | PreferencesUtils.putInt(context, LOCAL_VERSION_CODE, versionCode);
32 | }
33 |
34 | /**
35 | * 获取短信验证码关键字
36 | */
37 | public static String getSMSCodeKeywords(Context context) {
38 | return PreferencesUtils.getString(context,
39 | PrefConst.KEY_SMSCODE_KEYWORDS, PrefConst.SMSCODE_KEYWORDS_DEFAULT);
40 | }
41 |
42 | /**
43 | * 是否同意隐私协议
44 | */
45 | public static boolean isPrivacyPolicyAccepted(Context context) {
46 | return PreferencesUtils.getBoolean(context, PrefConst.KEY_PRIVACY_POLICY_ACCEPTED, false);
47 | }
48 |
49 | /**
50 | * 设置是否同意隐私协议
51 | */
52 | public static void setPrivacyPolicyAccepted(Context context, boolean accepted) {
53 | PreferencesUtils.putBoolean(context, PrefConst.KEY_PRIVACY_POLICY_ACCEPTED, accepted);
54 | }
55 |
56 | }
57 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/SettingsUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.annotation.SuppressLint;
4 | import android.content.Context;
5 | import android.content.Intent;
6 | import android.net.Uri;
7 | import android.os.Build;
8 | import android.provider.Settings;
9 |
10 | import androidx.annotation.RequiresApi;
11 |
12 | import com.github.tianma8023.xposed.smscode.BuildConfig;
13 |
14 | /**
15 | * Utility for android.provider.Settings
16 | */
17 | public class SettingsUtils {
18 |
19 | private SettingsUtils() {
20 | }
21 |
22 | private static String getSecureString(Context context, String key) {
23 | return Settings.Secure.getString(context.getContentResolver(), key);
24 | }
25 |
26 | /**
27 | * Get system default SMS app package
28 | * @return package name of default sms app
29 | */
30 | public static String getDefaultSmsAppPackage(Context context) {
31 | String key = "sms_default_application";
32 | return getSecureString(context, key);
33 | }
34 |
35 | /**
36 | * Request ignore battery optimization
37 | */
38 | @RequiresApi(api = Build.VERSION_CODES.M)
39 | @SuppressLint("BatteryLife")
40 | public static void requestIgnoreBatteryOptimization(Context context) {
41 | Intent intent = new Intent(Settings.ACTION_REQUEST_IGNORE_BATTERY_OPTIMIZATIONS);
42 | intent.setData(Uri.parse("package:" + BuildConfig.APPLICATION_ID));
43 | context.startActivity(intent);
44 | }
45 |
46 | /**
47 | * Go to ignore battery optimization settings.
48 | */
49 | @RequiresApi(api = Build.VERSION_CODES.M)
50 | public static void gotoIgnoreBatteryOptimizationSettings(Context context) {
51 | Intent intent = new Intent(Settings.ACTION_IGNORE_BATTERY_OPTIMIZATION_SETTINGS);
52 | context.startActivity(intent);
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/SmsMessageUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.content.Intent;
4 | import android.provider.Telephony;
5 | import android.telephony.SmsMessage;
6 |
7 | public class SmsMessageUtils {
8 |
9 | private static final int SMS_CHARACTER_LIMIT = 160;
10 |
11 | private SmsMessageUtils() {
12 | }
13 |
14 | public static SmsMessage[] fromIntent(Intent intent) {
15 | return Telephony.Sms.Intents.getMessagesFromIntent(intent);
16 | }
17 |
18 | public static String getMessageBody(SmsMessage[] messageParts) {
19 | if (messageParts.length == 1) {
20 | return messageParts[0].getDisplayMessageBody();
21 | } else {
22 | StringBuilder sb = new StringBuilder(SMS_CHARACTER_LIMIT * messageParts.length);
23 | for (SmsMessage messagePart : messageParts) {
24 | sb.append(messagePart.getDisplayMessageBody());
25 | }
26 | return sb.toString();
27 | }
28 | }
29 |
30 | }
31 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/SnackbarHelper.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.view.View;
4 |
5 | import com.google.android.material.snackbar.Snackbar;
6 |
7 | import androidx.annotation.NonNull;
8 | import androidx.annotation.StringRes;
9 |
10 | public class SnackbarHelper {
11 |
12 | @NonNull
13 | public static Snackbar makeShort(@NonNull View view, @StringRes int resId) {
14 | return make(view, resId, Snackbar.LENGTH_SHORT);
15 | }
16 |
17 | @NonNull
18 | public static Snackbar makeShort(@NonNull View view, @NonNull CharSequence text) {
19 | return make(view, text, Snackbar.LENGTH_SHORT);
20 | }
21 |
22 | @NonNull
23 | public static Snackbar makeLong(@NonNull View view, @StringRes int resId) {
24 | return make(view, resId, Snackbar.LENGTH_LONG);
25 | }
26 |
27 | @NonNull
28 | public static Snackbar makeLong(@NonNull View view, @NonNull CharSequence text) {
29 | return make(view, text, Snackbar.LENGTH_LONG);
30 | }
31 |
32 | @NonNull
33 | private static Snackbar make(@NonNull View view, @StringRes int resId, int duration) {
34 | return make(view, view.getResources().getText(resId), duration);
35 | }
36 |
37 | @NonNull
38 | private static Snackbar make(@NonNull View view, @NonNull CharSequence text, int duration) {
39 | // View snackView = snackbar.getView();
40 | // TypedValue typedValue = new TypedValue();
41 | // Context context = view.getContext();
42 | // context.getTheme().resolveAttribute(R.attr.colorPrimary, typedValue, true);
43 | // @ColorInt int colorPrimary = typedValue.data;
44 | // colorPrimary = ColorUtils.gradientColor(colorPrimary, 1.2f);
45 | // snackView.setBackgroundColor(colorPrimary);
46 | return Snackbar.make(view, text, duration);
47 | }
48 |
49 | }
50 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/StringUtils.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | public class StringUtils {
4 |
5 | private StringUtils() {
6 | }
7 |
8 | public static String escape(String str) {
9 | if (str == null)
10 | return null;
11 |
12 | StringBuilder sb = new StringBuilder(str.length() + 2);
13 | sb.append('"');
14 | for (int i = 0; i < str.length(); ++i) {
15 | char c = str.charAt(i);
16 | switch (c) {
17 | case '\t':
18 | sb.append("\\t");
19 | break;
20 | case '\b':
21 | sb.append("\\b");
22 | break;
23 | case '\n':
24 | sb.append("\\n");
25 | break;
26 | case '\r':
27 | sb.append("\\r");
28 | break;
29 | case '\f':
30 | sb.append("\\f");
31 | break;
32 | case '\\':
33 | sb.append("\\\\");
34 | break;
35 | case '\'':
36 | sb.append("\\'");
37 | break;
38 | case '\"':
39 | sb.append("\\\"");
40 | break;
41 | default:
42 | if (c < 32 || c >= 127) {
43 | sb.append(String.format("\\u%04x", (int) c));
44 | } else {
45 | sb.append(c);
46 | }
47 | break;
48 | }
49 | }
50 | sb.append('"');
51 | return sb.toString();
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/utils/XLog.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.utils;
2 |
3 | import android.util.Log;
4 |
5 | import com.github.tianma8023.xposed.smscode.BuildConfig;
6 |
7 | import de.robv.android.xposed.XposedBridge;
8 |
9 | public class XLog {
10 |
11 | private static final String LOG_TAG = BuildConfig.LOG_TAG;
12 | private static int sLogLevel = BuildConfig.LOG_LEVEL;
13 | private static final boolean LOG_TO_XPOSED = BuildConfig.LOG_TO_XPOSED;
14 |
15 | private XLog() {
16 | }
17 |
18 | private static void log(int priority, String message, Object... args) {
19 | if (priority < sLogLevel)
20 | return;
21 |
22 | message = String.format(message, args);
23 |
24 | if (args.length > 0 && args[args.length - 1] instanceof Throwable) {
25 | Throwable throwable = (Throwable) args[args.length - 1];
26 | String stacktraceStr = Log.getStackTraceString(throwable);
27 | message += '\n' + stacktraceStr;
28 | }
29 |
30 | // Write to the default log tag
31 | Log.println(priority, LOG_TAG, message);
32 |
33 | // Duplicate to the Xposed log if enabled
34 | if (LOG_TO_XPOSED) {
35 | // only log to LSPosed
36 | Log.println(priority, "LSPosed-Bridge", LOG_TAG + ": " + message);
37 | }
38 | }
39 |
40 | public static void v(String message, Object... args) {
41 | log(Log.VERBOSE, message, args);
42 | }
43 |
44 | public static void d(String message, Object... args) {
45 | log(Log.DEBUG, message, args);
46 | }
47 |
48 | public static void i(String message, Object... args) {
49 | log(Log.INFO, message, args);
50 | }
51 |
52 | public static void w(String message, Object... args) {
53 | log(Log.WARN, message, args);
54 | }
55 |
56 | public static void e(String message, Object... args) {
57 | log(Log.ERROR, message, args);
58 | }
59 |
60 | public static void setLogLevel(int logLevel) {
61 | sLogLevel = logLevel;
62 | }
63 | }
64 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/widget/DialogAsyncTask.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.widget;
2 |
3 | import android.content.Context;
4 | import android.content.DialogInterface;
5 | import android.os.AsyncTask;
6 |
7 | import com.afollestad.materialdialogs.MaterialDialog;
8 |
9 | public abstract class DialogAsyncTask extends AsyncTask implements DialogInterface.OnCancelListener {
10 |
11 | private boolean mCancelable;
12 |
13 | private MaterialDialog mProgressDialog;
14 |
15 | public DialogAsyncTask(Context context, String progressMsg, boolean cancelable) {
16 | mProgressDialog = new MaterialDialog.Builder(context)
17 | .content(progressMsg)
18 | .progress(true, 100)
19 | .cancelable(mCancelable)
20 | .build();
21 | mCancelable = cancelable;
22 | }
23 |
24 | @Override
25 | protected void onPreExecute() {
26 | if (mCancelable) {
27 | mProgressDialog.setOnCancelListener(this);
28 | }
29 | mProgressDialog.show();
30 | }
31 |
32 | @Override
33 | public void onCancel(DialogInterface dialog) {
34 | cancel(true);
35 | }
36 |
37 | @Override
38 | protected void onPostExecute(Result result) {
39 | mProgressDialog.dismiss();
40 | }
41 |
42 | @Override
43 | protected void onCancelled() {
44 | mProgressDialog.dismiss();
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/common/widget/FabScrollBehavior.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.common.widget;
2 |
3 | import android.content.Context;
4 | import android.util.AttributeSet;
5 | import android.view.View;
6 | import android.view.animation.LinearInterpolator;
7 |
8 | import com.google.android.material.floatingactionbutton.FloatingActionButton;
9 |
10 | import androidx.annotation.NonNull;
11 | import androidx.coordinatorlayout.widget.CoordinatorLayout;
12 | import androidx.core.view.ViewCompat;
13 |
14 | /**
15 | * Floating Action Bar scroll behavior
16 | */
17 | public class FabScrollBehavior extends FloatingActionButton.Behavior {
18 |
19 | public FabScrollBehavior() {
20 | }
21 |
22 | public FabScrollBehavior(Context context, AttributeSet attrs) {
23 | super(context, attrs);
24 | }
25 |
26 | @Override
27 | public boolean onStartNestedScroll(@NonNull CoordinatorLayout coordinatorLayout,
28 | @NonNull FloatingActionButton child,
29 | @NonNull View directTargetChild,
30 | @NonNull View target, int axes, int type) {
31 | // Ensure we react to vertical scrolling
32 | return type == ViewCompat.TYPE_TOUCH && axes == ViewCompat.SCROLL_AXIS_VERTICAL;
33 | }
34 |
35 | @Override
36 | public boolean onNestedFling(@NonNull CoordinatorLayout coordinatorLayout,
37 | @NonNull FloatingActionButton child,
38 | @NonNull View target, float velocityX,
39 | float velocityY, boolean consumed) {
40 | if (velocityY > 500) {
41 | animateOut(child);
42 | return true;
43 | } else if (velocityY < -500) {
44 | animateIn(child);
45 | return true;
46 | }
47 | return super.onNestedFling(coordinatorLayout, child, target, velocityX, velocityY, consumed);
48 | }
49 |
50 | private void animateOut(FloatingActionButton fab) {
51 | CoordinatorLayout.LayoutParams layoutParams = (CoordinatorLayout.LayoutParams) fab.getLayoutParams();
52 | int bottomMargin = layoutParams.bottomMargin;
53 | fab.animate().translationY(fab.getHeight() + bottomMargin).setInterpolator(new LinearInterpolator()).start();
54 | }
55 |
56 | private void animateIn(FloatingActionButton fab) {
57 | fab.animate().translationY(0).setInterpolator(new LinearInterpolator()).start();
58 | }
59 | }
60 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/db/TSQLiteOpenHelper.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.db;
2 |
3 | import android.content.Context;
4 | import android.database.sqlite.SQLiteDatabase;
5 |
6 | import com.github.yuweiguocn.library.greendao.MigrationHelper;
7 | import com.tianma.xsmscode.data.db.entity.AppInfoDao;
8 | import com.tianma.xsmscode.data.db.entity.DaoMaster;
9 | import com.tianma.xsmscode.data.db.entity.SmsCodeRuleDao;
10 | import com.tianma.xsmscode.data.db.entity.SmsMsgDao;
11 |
12 | import org.greenrobot.greendao.database.Database;
13 |
14 | public class TSQLiteOpenHelper extends DaoMaster.OpenHelper{
15 |
16 | public TSQLiteOpenHelper(Context context, String name) {
17 | super(context, name);
18 | }
19 |
20 | public TSQLiteOpenHelper(Context context, String name, SQLiteDatabase.CursorFactory factory) {
21 | super(context, name, factory);
22 | }
23 |
24 | @SuppressWarnings("unchecked")
25 | @Override
26 | public void onUpgrade(Database db, int oldVersion, int newVersion) {
27 | super.onUpgrade(db, oldVersion, newVersion);
28 |
29 | MigrationHelper.migrate(db, new MigrationHelper.ReCreateAllTableListener() {
30 | @Override
31 | public void onCreateAllTables(Database db, boolean ifNotExists) {
32 | DaoMaster.createAllTables(db, ifNotExists);
33 | }
34 |
35 | @Override
36 | public void onDropAllTables(Database db, boolean ifExists) {
37 | DaoMaster.dropAllTables(db, ifExists);
38 | }
39 | }, SmsCodeRuleDao.class, SmsMsgDao.class, AppInfoDao.class);
40 | }
41 | }
42 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/db/entity/ApkVersion.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.db.entity;
2 |
3 | /**
4 | * Apk version info
5 | */
6 | public class ApkVersion implements Comparable {
7 |
8 | private final String mVersionName;
9 | private final String mVersionInfo;
10 |
11 | public ApkVersion(String versionName, String versionInfo) {
12 | mVersionName = versionName;
13 | mVersionInfo = versionInfo;
14 | }
15 |
16 | public String getVersionInfo() {
17 | return mVersionInfo;
18 | }
19 |
20 | public String getVersionName() {
21 | return mVersionName;
22 | }
23 |
24 | @Override
25 | public String toString() {
26 | return "ApkVersion{" +
27 | "mVersionName='" + mVersionName + '\'' +
28 | ", mVersionInfo='" + mVersionInfo + '\'' +
29 | '}';
30 | }
31 |
32 | @Override
33 | public int compareTo(ApkVersion that) {
34 | if (that == null) {
35 | return 1;
36 | }
37 |
38 | String[] thisParts = this.getVersionName().split("\\.");
39 | String[] thatParts = that.getVersionName().split("\\.");
40 |
41 | int maxLength = Math.max(thisParts.length, thatParts.length);
42 | for (int i = 0; i < maxLength; i++) {
43 | int thisPart = i < thisParts.length ? Integer.parseInt(thisParts[i]) : 0;
44 | int thatPart = i < thatParts.length ? Integer.parseInt(thatParts[i]) : 0;
45 | if (thisPart < thatPart) {
46 | return -1;
47 | } else if (thisPart > thatPart) {
48 | return 1;
49 | }
50 | }
51 | return 0;
52 | }
53 | }
54 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/eventbus/Event.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.eventbus;
2 |
3 | import com.tianma.xsmscode.ui.rule.edit.RuleEditFragment;
4 | import com.tianma.xsmscode.feature.backup.ExportResult;
5 | import com.tianma.xsmscode.data.db.entity.SmsCodeRule;
6 |
7 | import java.io.File;
8 |
9 | public class Event {
10 |
11 | private Event() {
12 | }
13 | /**
14 | * Start to edit codeRule event
15 | */
16 | public static class StartRuleEditEvent {
17 | public @RuleEditFragment.RuleEditType int type;
18 | public SmsCodeRule codeRule;
19 | public StartRuleEditEvent(@RuleEditFragment.RuleEditType int type, SmsCodeRule codeRule) {
20 | this.type = type;
21 | this.codeRule = codeRule;
22 | }
23 | }
24 |
25 | /**
26 | * Rule create or update event
27 | */
28 | public static class OnRuleCreateOrUpdate {
29 | public SmsCodeRule codeRule;
30 | public @RuleEditFragment.RuleEditType int type;
31 | public OnRuleCreateOrUpdate(@RuleEditFragment.RuleEditType int type, SmsCodeRule rule) {
32 | this.codeRule = rule;
33 | this.type = type;
34 | }
35 | }
36 |
37 | /**
38 | * Save template rule event
39 | */
40 | public static class TemplateSaveEvent {
41 | public boolean success;
42 | public TemplateSaveEvent(boolean success) {
43 | this.success = success;
44 | }
45 | }
46 |
47 | /**
48 | * Load template rule event
49 | */
50 | public static class TemplateLoadEvent {
51 | public SmsCodeRule template;
52 | public TemplateLoadEvent(SmsCodeRule template) {
53 | this.template = template;
54 | }
55 | }
56 |
57 | public static class ExportEvent {
58 | public ExportResult result;
59 | public File file;
60 | public ExportEvent(ExportResult result, File file) {
61 | this.result = result;
62 | this.file = file;
63 | }
64 | }
65 |
66 | }
67 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/eventbus/XEventBus.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.eventbus;
2 |
3 | import org.greenrobot.eventbus.EventBus;
4 |
5 | /**
6 | * Event bus utils
7 | */
8 | public class XEventBus {
9 |
10 | private XEventBus() {
11 | }
12 |
13 | private static EventBus get() {
14 | return EventBus.getDefault();
15 | }
16 |
17 | public static void post(Object event) {
18 | get().post(event);
19 | }
20 |
21 | public static void register(Object subscriber) {
22 | get().register(subscriber);
23 | }
24 |
25 | public static void unregister(Object subscriber) {
26 | get().unregister(subscriber);
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/http/ApiConst.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.http;
2 |
3 | public class ApiConst {
4 |
5 | public static final String GITHUB_BASE_URL = "https://api.github.com/";
6 | public static final String GITHUB_USERNAME = "tianma8023";
7 | public static final String GITHUB_REPO_NAME = "XposedSmsCode";
8 |
9 | public static final String COOLAPK_BASE_URL = "https://www.coolapk.com/";
10 |
11 | }
12 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/http/service/CoolApkService.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.http.service;
2 |
3 | import io.reactivex.Observable;
4 | import retrofit2.http.GET;
5 | import retrofit2.http.Path;
6 |
7 | /**
8 | * retrofit service for coolapk.com
9 | */
10 | public interface CoolApkService {
11 |
12 | @GET("/apk/{packageName}")
13 | Observable getLatestRelease(@Path("packageName") String packageName);
14 |
15 | }
16 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/http/service/GithubService.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.http.service;
2 |
3 | import com.tianma.xsmscode.data.http.entity.GithubRelease;
4 |
5 | import io.reactivex.Observable;
6 | import retrofit2.http.GET;
7 | import retrofit2.http.Path;
8 |
9 | /**
10 | * Retrofit Service for GitHub
11 | */
12 | public interface GithubService {
13 |
14 | @GET("/repos/{username}/{repoName}/releases/latest")
15 | Observable getLatestRelease(@Path("username") String username,
16 | @Path("repoName") String repoName);
17 |
18 | }
19 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/http/service/ServiceGenerator.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.http.service;
2 |
3 | import android.util.ArrayMap;
4 |
5 | import java.util.Map;
6 |
7 | import okhttp3.OkHttpClient;
8 | import retrofit2.Retrofit;
9 | import retrofit2.adapter.rxjava2.RxJava2CallAdapterFactory;
10 | import retrofit2.converter.gson.GsonConverterFactory;
11 | import retrofit2.converter.scalars.ScalarsConverterFactory;
12 |
13 | public class ServiceGenerator {
14 |
15 | private Map mRetrofitMap;
16 |
17 | private OkHttpClient mOkHttpClient;
18 |
19 | private static class InstanceHolder {
20 | private static final ServiceGenerator INSTANCE = new ServiceGenerator();
21 | }
22 |
23 | private ServiceGenerator() {
24 | mRetrofitMap = new ArrayMap<>();
25 | mOkHttpClient = new OkHttpClient.Builder().build();
26 | }
27 |
28 | public static ServiceGenerator getInstance() {
29 | return InstanceHolder.INSTANCE;
30 | }
31 |
32 | public T createService(String baseUrl, Class serviceClass) {
33 | Retrofit retrofit = mRetrofitMap.get(baseUrl);
34 | if (retrofit == null) {
35 | retrofit = new Retrofit.Builder()
36 | .baseUrl(baseUrl)
37 | .client(mOkHttpClient)
38 | .addConverterFactory(ScalarsConverterFactory.create())
39 | .addConverterFactory(GsonConverterFactory.create())
40 | .addCallAdapterFactory(RxJava2CallAdapterFactory.create())
41 | .build();
42 | mRetrofitMap.put(baseUrl, retrofit);
43 | }
44 | return retrofit.create(serviceClass);
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/repository/ApkVersionHelper.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.repository;
2 |
3 | import com.tianma.xsmscode.data.db.entity.ApkVersion;
4 |
5 | import org.jsoup.Jsoup;
6 | import org.jsoup.nodes.Document;
7 | import org.jsoup.nodes.Element;
8 |
9 | import java.util.regex.Matcher;
10 | import java.util.regex.Pattern;
11 |
12 | import androidx.core.text.HtmlCompat;
13 |
14 | class ApkVersionHelper {
15 |
16 | private ApkVersionHelper() {
17 | }
18 |
19 | static ApkVersion parseFromCoolApk(String html) {
20 | Document document = Jsoup.parse(html);
21 | String versionName = "-1";
22 | String versionInfo = null;
23 | if (document != null) {
24 | // version name
25 | Element element = document.selectFirst("title");
26 | if (element != null) {
27 | String text = element.text();
28 | Pattern p = Pattern.compile("\\d(\\.\\d)+");
29 | Matcher m = p.matcher(text);
30 | if (m.find()) {
31 | versionName = m.group();
32 | }
33 | }
34 |
35 | // version info
36 | Element rootInfoEle = document.selectFirst(".apk_left_title:contains(新版特性)");
37 | if (rootInfoEle != null) {
38 | Element infoEle = rootInfoEle.selectFirst(".apk_left_title_info");
39 | if (infoEle != null) {
40 | versionInfo = HtmlCompat.fromHtml(infoEle.toString(), HtmlCompat.FROM_HTML_MODE_COMPACT)
41 | .toString().trim();
42 | }
43 | }
44 | }
45 | return new ApkVersion(versionName, versionInfo);
46 | }
47 |
48 | }
49 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/data/repository/DataRepository.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.data.repository;
2 |
3 | import com.github.tianma8023.xposed.smscode.BuildConfig;
4 | import com.tianma.xsmscode.data.db.entity.ApkVersion;
5 | import com.tianma.xsmscode.data.http.ApiConst;
6 | import com.tianma.xsmscode.data.http.service.CoolApkService;
7 | import com.tianma.xsmscode.data.http.service.GithubService;
8 | import com.tianma.xsmscode.data.http.service.ServiceGenerator;
9 |
10 | import java.util.Locale;
11 |
12 | import io.reactivex.Observable;
13 |
14 | public class DataRepository {
15 |
16 | private DataRepository() {
17 | }
18 |
19 | private static boolean isInChina() {
20 | Locale locale = Locale.getDefault();
21 | String language = locale.getLanguage();
22 | return "zh".equalsIgnoreCase(language);
23 | }
24 |
25 | public static Observable getLatestVersion() {
26 | boolean isInChina = isInChina();
27 |
28 | CoolApkService coolApkService = ServiceGenerator.getInstance()
29 | .createService(ApiConst.COOLAPK_BASE_URL, CoolApkService.class);
30 | Observable dataFromCoolApk = coolApkService.getLatestRelease(BuildConfig.APPLICATION_ID)
31 | .map(ApkVersionHelper::parseFromCoolApk);
32 |
33 | GithubService githubService = ServiceGenerator.getInstance()
34 | .createService(ApiConst.GITHUB_BASE_URL, GithubService.class);
35 | Observable dataFromGithub = githubService.getLatestRelease(ApiConst.GITHUB_USERNAME, ApiConst.GITHUB_REPO_NAME)
36 | .map(githubRelease -> {
37 | String regex = "
|
";
38 | String[] arr = githubRelease.getBody().split(regex);
39 | String versionInfo;
40 | if (arr.length >= 2) {
41 | versionInfo = isInChina ? arr[1].trim() : arr[0].trim();
42 | } else {
43 | versionInfo = githubRelease.getBody().replaceAll(regex, "");
44 | }
45 | return new ApkVersion(githubRelease.getName(), versionInfo);
46 | });
47 |
48 | if (isInChina) {
49 | // In China region
50 | // Firstly, request data from coolapk.
51 | // If error throws, then request data from github.
52 | return dataFromCoolApk.onErrorResumeNext(throwable -> dataFromGithub);
53 | } else {
54 | // In other regions
55 | // Firstly, request data from GitHub.
56 | // If error throws, then request data from coolapk.
57 | return dataFromGithub.onErrorResumeNext(throwable -> dataFromCoolApk);
58 | }
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/BackupConst.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup;
2 |
3 | public class BackupConst {
4 |
5 | public static final String KEY_VERSION = "version";
6 | public static final int BACKUP_VERSION = 1;
7 |
8 | public static final String KEY_RULES = "rules";
9 |
10 | public static final String KEY_COMPANY = "company";
11 | public static final String KEY_CODE_KEYWORD = "code_keyword";
12 | public static final String KEY_CODE_REGEX = "code_regex";
13 | }
14 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/ExportResult.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup;
2 |
3 | public enum ExportResult {
4 | SUCCESS,
5 | FAILED
6 | }
7 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/ImportResult.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup;
2 |
3 | public enum ImportResult {
4 | /**
5 | * Success
6 | */
7 | SUCCESS,
8 | /**
9 | * Backup version missed
10 | */
11 | VERSION_MISSED,
12 | /**
13 | * Backup version unknown
14 | */
15 | VERSION_UNKNOWN,
16 | /**
17 | * Backup invalid
18 | */
19 | BACKUP_INVALID,
20 | /**
21 | * Read error
22 | */
23 | READ_FAILED,
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/RuleExporter.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup;
2 |
3 | import com.tianma.xsmscode.data.db.entity.SmsCodeRule;
4 | import com.google.gson.stream.JsonWriter;
5 |
6 | import java.io.Closeable;
7 | import java.io.File;
8 | import java.io.FileNotFoundException;
9 | import java.io.FileOutputStream;
10 | import java.io.IOException;
11 | import java.io.OutputStream;
12 | import java.io.OutputStreamWriter;
13 | import java.nio.charset.StandardCharsets;
14 | import java.util.List;
15 |
16 | /**
17 | * SmsCode rules exporter
18 | */
19 | public class RuleExporter implements Closeable{
20 |
21 | private JsonWriter mJsonWriter;
22 |
23 | public RuleExporter(OutputStream out) {
24 | OutputStreamWriter osw;
25 | osw = new OutputStreamWriter(out, StandardCharsets.UTF_8);
26 | mJsonWriter = new JsonWriter(osw);
27 | mJsonWriter.setIndent("\t"); // pretty print
28 | }
29 |
30 | public RuleExporter(File file) throws FileNotFoundException {
31 | this(new FileOutputStream(file));
32 | }
33 |
34 | public void doExport(List ruleList) throws IOException {
35 | begin();
36 | exportRuleList(ruleList);
37 | end();
38 | }
39 |
40 | private void begin() throws IOException {
41 | mJsonWriter.beginObject();
42 | mJsonWriter.name(BackupConst.KEY_VERSION)
43 | .value(BackupConst.BACKUP_VERSION);
44 | }
45 |
46 | private void exportRuleList(List ruleList) throws IOException {
47 | mJsonWriter.name(BackupConst.KEY_RULES)
48 | .beginArray();
49 | for(SmsCodeRule rule : ruleList) {
50 | exportRule(rule);
51 | }
52 | mJsonWriter.endArray();
53 | }
54 |
55 | private void exportRule(SmsCodeRule rule) throws IOException {
56 | mJsonWriter.beginObject();
57 | mJsonWriter.name(BackupConst.KEY_COMPANY).value(rule.getCompany());
58 | mJsonWriter.name(BackupConst.KEY_CODE_KEYWORD).value(rule.getCodeKeyword());
59 | mJsonWriter.name(BackupConst.KEY_CODE_REGEX).value(rule.getCodeRegex());
60 | mJsonWriter.endObject();
61 | }
62 |
63 | private void end() throws IOException {
64 | mJsonWriter.endObject();
65 | }
66 |
67 | @Override
68 | public void close() {
69 | if (mJsonWriter != null) {
70 | try {
71 | mJsonWriter.close();
72 | } catch (IOException e) {
73 | e.printStackTrace();
74 | }
75 | }
76 | }
77 | }
78 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/exception/BackupInvalidException.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup.exception;
2 |
3 | /**
4 | * Backup invalid exception
5 | */
6 | public class BackupInvalidException extends Exception {
7 |
8 | public BackupInvalidException() {
9 | }
10 |
11 | public BackupInvalidException(String message) {
12 | super(message);
13 | }
14 |
15 | public BackupInvalidException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | public BackupInvalidException(Throwable cause) {
20 | super(cause);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/exception/VersionInvalidException.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup.exception;
2 |
3 | /**
4 | * Version invalid exception
5 | */
6 | public class VersionInvalidException extends BackupInvalidException {
7 |
8 | public VersionInvalidException() {
9 | }
10 |
11 | public VersionInvalidException(String message) {
12 | super(message);
13 | }
14 |
15 | public VersionInvalidException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | public VersionInvalidException(Throwable cause) {
20 | super(cause);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/backup/exception/VersionMissedException.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.backup.exception;
2 |
3 | /**
4 | * version missed exception
5 | */
6 | public class VersionMissedException extends VersionInvalidException {
7 |
8 | public VersionMissedException() {
9 | }
10 |
11 | public VersionMissedException(String message) {
12 | super(message);
13 | }
14 |
15 | public VersionMissedException(String message, Throwable cause) {
16 | super(message, cause);
17 | }
18 |
19 | public VersionMissedException(Throwable cause) {
20 | super(cause);
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/migrate/ITransition.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.migrate;
2 |
3 | /**
4 | * 数据迁移过渡接口(版本更新不免遇到旧数据被弃用之类的,兼容旧版本的话就需要进行数据迁移)
5 | */
6 | public interface ITransition {
7 |
8 | /**
9 | * 是否需要迁移过渡数据
10 | */
11 | boolean shouldTransit();
12 |
13 | /**
14 | * 执行数据迁移兼容过渡逻辑
15 | * @return 是否执行成功,是则返回true
16 | */
17 | boolean doTransition();
18 |
19 | }
20 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/migrate/TransitionTask.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.migrate;
2 |
3 | import android.content.Context;
4 |
5 | import com.tianma.xsmscode.feature.migrate.db.DBTransition;
6 |
7 | import java.util.ArrayList;
8 | import java.util.List;
9 |
10 | /**
11 | * 执行数据迁移过渡的Task
12 | */
13 | public class TransitionTask implements Runnable {
14 |
15 | private List mTransitionList;
16 |
17 | public TransitionTask(Context context) {
18 | init(context);
19 | }
20 |
21 | private void init(Context context) {
22 | mTransitionList = new ArrayList<>();
23 | // mTransitionList.add(new PreferencesTransition(context));
24 | mTransitionList.add(new DBTransition(context));
25 | }
26 |
27 | @Override
28 | public void run() {
29 | for (ITransition transition : mTransitionList) {
30 | if (transition.shouldTransit()) {
31 | transition.doTransition();
32 | }
33 | }
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/migrate/db/DBTransition.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.migrate.db;
2 |
3 | import android.content.Context;
4 |
5 | import com.tianma.xsmscode.ui.record.CodeRecordRestoreManager;
6 | import com.tianma.xsmscode.feature.migrate.ITransition;
7 |
8 | import java.io.File;
9 |
10 | public class DBTransition implements ITransition {
11 |
12 | private Context mContext;
13 |
14 | public DBTransition(Context context) {
15 | mContext = context;
16 | }
17 |
18 | @Override
19 | public boolean shouldTransit() {
20 | File[] recordFiles = CodeRecordRestoreManager.getRecordFiles();
21 | return recordFiles != null && recordFiles.length > 0;
22 | }
23 |
24 | @Override
25 | public boolean doTransition() {
26 | return CodeRecordRestoreManager.importToDatabase(mContext);
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/migrate/sp/PreferencesTransition.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.migrate.sp;
2 |
3 | import android.content.Context;
4 |
5 | import com.tianma.xsmscode.feature.migrate.ITransition;
6 | import com.tianma.xsmscode.common.utils.SPUtils;
7 |
8 | /**
9 | * SharedPreferences 相关数据迁移
10 | */
11 | public class PreferencesTransition implements ITransition {
12 |
13 | private Context mContext;
14 | private int mLocalVersionCode;
15 |
16 | private static final int VERSION_CODE_16 = 16;
17 |
18 | public PreferencesTransition(Context context) {
19 | mContext = context;
20 | mLocalVersionCode = SPUtils.getLocalVersionCode(mContext);
21 | }
22 |
23 | @Override
24 | public boolean shouldTransit() {
25 | return false;
26 | }
27 |
28 | @Override
29 | public boolean doTransition() {
30 | return false;
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/feature/store/EntityType.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.feature.store;
2 |
3 | public enum EntityType {
4 | BLOCKED_APP,
5 | CODE_RULES,
6 | CODE_RULE_TEMPLATE,
7 | PREV_SMS_MSG,
8 | }
9 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/ActivityBindingModule.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import com.tianma.xsmscode.ui.rule.CodeRulesActivity;
4 | import com.tianma.xsmscode.ui.rule.CodeRulesModule;
5 |
6 | import dagger.Module;
7 | import dagger.android.ContributesAndroidInjector;
8 |
9 | /**
10 | * Dagger Module for binding Activity
11 | */
12 | @Module
13 | public abstract class ActivityBindingModule {
14 |
15 | @ActivityScope
16 | @ContributesAndroidInjector(modules = CodeRulesModule.class)
17 | abstract CodeRulesActivity contributeCodeRulesActivity();
18 |
19 | // CodeRecordActivity 其实并没有注入依赖。
20 | // 所以可以绕开 CodeRecordActivity 而直接对 CodeRecordFragment 进行注入
21 | // @ActivityScope
22 | // @ContributesAndroidInjector(modules = CodeRecordActivityModule.class)
23 | // abstract CodeRecordActivity contributeCodeRecordActivity();
24 | }
25 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/ActivityScope.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 |
7 | import javax.inject.Scope;
8 |
9 | /**
10 | * Activity Scope
11 | */
12 | @Scope
13 | @Documented
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface ActivityScope {
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/ApplicationComponent.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import javax.inject.Singleton;
4 |
5 | import dagger.Component;
6 | import dagger.android.AndroidInjector;
7 | import dagger.android.support.AndroidSupportInjectionModule;
8 |
9 | @Singleton
10 | @Component(modules = {
11 | AndroidSupportInjectionModule.class,
12 | ApplicationModule.class,
13 | ActivityBindingModule.class,
14 | FragmentBindingModule.class,
15 | })
16 | public interface ApplicationComponent extends AndroidInjector {
17 |
18 | @Component.Factory
19 | interface Factory extends AndroidInjector.Factory {
20 |
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/ApplicationModule.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import android.content.Context;
4 |
5 | import javax.inject.Singleton;
6 |
7 | import dagger.Binds;
8 | import dagger.Module;
9 |
10 | @Module
11 | public abstract class ApplicationModule {
12 |
13 | @Singleton
14 | @Binds
15 | abstract Context provideContext(SmsCodeApplication application);
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/FragmentBindingModule.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import com.tianma.xsmscode.ui.block.AppBlockFragment;
4 | import com.tianma.xsmscode.ui.block.AppBlockModule;
5 | import com.tianma.xsmscode.ui.home.SettingsFragment;
6 | import com.tianma.xsmscode.ui.home.SettingsModule;
7 | import com.tianma.xsmscode.ui.record.CodeRecordFragment;
8 | import com.tianma.xsmscode.ui.record.CodeRecordFragmentModule;
9 |
10 | import dagger.Module;
11 | import dagger.android.ContributesAndroidInjector;
12 |
13 | /**
14 | * Dagger Module for binding Fragment.
15 | */
16 | @Module
17 | public abstract class FragmentBindingModule {
18 |
19 |
20 | // CodeRecordActivity 其实并没有注入依赖。
21 | // 所以可以绕开 CodeRecordActivity 而直接对 CodeRecordFragment 进行注入
22 | @FragmentScope
23 | @ContributesAndroidInjector(modules = CodeRecordFragmentModule.class)
24 | abstract CodeRecordFragment contributeCodeRecordFragment();
25 |
26 | @FragmentScope
27 | @ContributesAndroidInjector(modules = AppBlockModule.class)
28 | abstract AppBlockFragment contributeAppBlockFragment();
29 |
30 | @FragmentScope
31 | @ContributesAndroidInjector(modules = SettingsModule.class)
32 | abstract SettingsFragment contributeSettingsFragment();
33 | }
34 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/FragmentScope.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import java.lang.annotation.Documented;
4 | import java.lang.annotation.Retention;
5 | import java.lang.annotation.RetentionPolicy;
6 |
7 | import javax.inject.Scope;
8 |
9 | /**
10 | * Fragment Scope
11 | */
12 | @Scope
13 | @Documented
14 | @Retention(RetentionPolicy.RUNTIME)
15 | public @interface FragmentScope {
16 | }
17 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/SmsCodeApplication.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app;
2 |
3 | import android.content.res.Resources;
4 |
5 | import com.jaredrummler.cyanea.Cyanea;
6 | import com.jaredrummler.cyanea.CyaneaResources;
7 | import com.tianma.xsmscode.data.eventbus.MyEventBusIndex;
8 | import com.tianma.xsmscode.feature.migrate.TransitionTask;
9 |
10 | import org.greenrobot.eventbus.EventBus;
11 |
12 | import java.util.concurrent.Executor;
13 | import java.util.concurrent.Executors;
14 |
15 | import dagger.android.AndroidInjector;
16 | import dagger.android.DaggerApplication;
17 |
18 | public class SmsCodeApplication extends DaggerApplication {
19 |
20 | private CyaneaResources mResources = null;
21 |
22 | @Override
23 | protected AndroidInjector extends DaggerApplication> applicationInjector() {
24 | return DaggerApplicationComponent.factory().create(this);
25 | }
26 |
27 | @Override
28 | public void onCreate() {
29 | super.onCreate();
30 | Cyanea.init(this, super.getResources());
31 | if (!Cyanea.getInstance().isThemeModified()) {
32 | Cyanea.getInstance().edit()
33 | .baseTheme(Cyanea.BaseTheme.LIGHT)
34 | .apply();
35 | }
36 |
37 | installDefaultEventBus();
38 | performTransitionTask();
39 | }
40 |
41 | @Override
42 | public Resources getResources() {
43 | if (Cyanea.isInitialized()) {
44 | if (mResources == null) {
45 | mResources = new CyaneaResources(super.getResources(), Cyanea.getInstance());
46 | }
47 | return mResources;
48 | }
49 | return super.getResources();
50 | }
51 |
52 | private void installDefaultEventBus() {
53 | EventBus.builder().addIndex(new MyEventBusIndex()).installDefaultEventBus();
54 | }
55 |
56 | // data transition task
57 | private void performTransitionTask() {
58 | Executor singlePool = Executors.newSingleThreadExecutor();
59 | singlePool.execute(new TransitionTask(this));
60 | }
61 |
62 | }
63 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/base/BaseActivity.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app.base;
2 |
3 | import android.view.MenuItem;
4 |
5 | import androidx.annotation.NonNull;
6 |
7 | import com.jaredrummler.cyanea.app.CyaneaAppCompatActivity;
8 |
9 | /**
10 | * base activity
11 | */
12 | public abstract class BaseActivity extends CyaneaAppCompatActivity {
13 |
14 | @Override
15 | public boolean onOptionsItemSelected(@NonNull MenuItem item) {
16 | if (item.getItemId() == android.R.id.home) {
17 | onBackPressed();
18 | return true;
19 | }
20 | return super.onOptionsItemSelected(item);
21 | }
22 |
23 | }
24 |
--------------------------------------------------------------------------------
/app/src/main/java/com/tianma/xsmscode/ui/app/base/BaseDaggerActivity.java:
--------------------------------------------------------------------------------
1 | package com.tianma.xsmscode.ui.app.base;
2 |
3 | import android.os.Bundle;
4 |
5 | import androidx.annotation.Nullable;
6 |
7 | import javax.inject.Inject;
8 |
9 | import dagger.android.AndroidInjection;
10 | import dagger.android.AndroidInjector;
11 | import dagger.android.DispatchingAndroidInjector;
12 | import dagger.android.HasAndroidInjector;
13 |
14 | /**
15 | * Base Dagger Activity
16 | */
17 | public abstract class BaseDaggerActivity extends BaseActivity implements HasAndroidInjector {
18 |
19 | @Inject
20 | DispatchingAndroidInjector