├── .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 | ![Total Downloads](https://img.shields.io/github/downloads/tianma8023/XposedSmsCode/total) ![Total Stars](https://img.shields.io/github/stars/tianma8023/XposedSmsCode?style=social) [![Latest Release](https://img.shields.io/github/v/release/tianma8023/XposedSmsCode?label=Latest%20Release)](https://github.com/tianma8023/XposedSmsCode/releases) 3 | 4 | ![Star History Chart](https://api.star-history.com/svg?repos=tianma8023/XposedSmsCode&type=Date) 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 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 androidInjector; 21 | 22 | @Override 23 | protected void onCreate(@Nullable Bundle savedInstanceState) { 24 | AndroidInjection.inject(this); 25 | super.onCreate(savedInstanceState); 26 | } 27 | 28 | @Override 29 | public AndroidInjector androidInjector() { 30 | return androidInjector; 31 | } 32 | 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/app/base/BasePreferenceFragment.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.app.base; 2 | 3 | import android.os.Bundle; 4 | 5 | import androidx.annotation.NonNull; 6 | import androidx.preference.Preference; 7 | import androidx.preference.PreferenceFragmentCompat; 8 | import androidx.preference.PreferenceManager; 9 | 10 | import com.tianma.xsmscode.common.constant.PrefConst; 11 | 12 | import java.util.Objects; 13 | 14 | /** 15 | * Base Preferences Fragment 16 | */ 17 | public abstract class BasePreferenceFragment extends PreferenceFragmentCompat { 18 | 19 | @Override 20 | public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { 21 | PreferenceManager manager = getPreferenceManager(); 22 | manager.setSharedPreferencesName(PrefConst.PREF_NAME); 23 | 24 | doOnCreatePreferences(savedInstanceState, rootKey); 25 | } 26 | 27 | abstract protected void doOnCreatePreferences(Bundle savedInstanceState, String rootKey); 28 | 29 | @NonNull 30 | @Override 31 | public T findPreference(@NonNull CharSequence key) { 32 | return Objects.requireNonNull(super.findPreference(key)); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/app/base/DaggerBackPressFragment.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.app.base; 2 | 3 | import android.content.Context; 4 | 5 | import com.tianma.xsmscode.common.fragment.backpress.BackPressFragment; 6 | 7 | import javax.inject.Inject; 8 | 9 | import dagger.android.AndroidInjector; 10 | import dagger.android.DispatchingAndroidInjector; 11 | import dagger.android.HasAndroidInjector; 12 | import dagger.android.support.AndroidSupportInjection; 13 | 14 | public class DaggerBackPressFragment extends BackPressFragment implements HasAndroidInjector { 15 | 16 | @Inject 17 | DispatchingAndroidInjector androidInjector; 18 | 19 | @Override 20 | public void onAttach(Context context) { 21 | AndroidSupportInjection.inject(this); 22 | super.onAttach(context); 23 | } 24 | 25 | @Override 26 | public AndroidInjector androidInjector() { 27 | return androidInjector; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/block/AppBlockActivity.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.block; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import com.github.tianma8023.xposed.smscode.R; 8 | import com.tianma.xsmscode.ui.app.base.BaseActivity; 9 | 10 | import androidx.annotation.Nullable; 11 | import androidx.appcompat.app.ActionBar; 12 | import androidx.appcompat.widget.Toolbar; 13 | import butterknife.BindView; 14 | import butterknife.ButterKnife; 15 | 16 | /** 17 | * Activity for choosing apps where auto-input is banned. 18 | */ 19 | public class AppBlockActivity extends BaseActivity { 20 | 21 | @BindView(R.id.toolbar) 22 | Toolbar mToolbar; 23 | 24 | public static void startMe(Context context) { 25 | context.startActivity(new Intent(context, AppBlockActivity.class)); 26 | } 27 | 28 | @Override 29 | protected void onCreate(@Nullable Bundle savedInstanceState) { 30 | super.onCreate(savedInstanceState); 31 | setContentView(R.layout.activity_app_block); 32 | ButterKnife.bind(this); 33 | 34 | setupToolbar(); 35 | 36 | getSupportFragmentManager() 37 | .beginTransaction() 38 | .replace(R.id.app_block_main_content, AppBlockFragment.newInstance()) 39 | .commit(); 40 | } 41 | 42 | private void setupToolbar() { 43 | setSupportActionBar(mToolbar); 44 | ActionBar actionBar = getSupportActionBar(); 45 | if (actionBar != null) { 46 | actionBar.setHomeButtonEnabled(true); 47 | actionBar.setDisplayHomeAsUpEnabled(true); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/block/AppBlockContract.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.block; 2 | 3 | import com.tianma.xsmscode.common.mvp.BasePresenter; 4 | import com.tianma.xsmscode.common.mvp.BaseView; 5 | import com.tianma.xsmscode.data.db.entity.AppInfo; 6 | 7 | import java.util.List; 8 | 9 | interface AppBlockContract { 10 | 11 | interface View extends BaseView { 12 | 13 | void showData(List appInfoList); 14 | 15 | void showError(Throwable t); 16 | 17 | void showProgress(); 18 | 19 | void cancelProgress(); 20 | 21 | void onSaveSuccess(); 22 | 23 | void onSaveFailed(); 24 | } 25 | 26 | interface Presenter extends BasePresenter { 27 | 28 | void refreshData(); 29 | 30 | void doFilter(String filter); 31 | 32 | void doSort(SortType sortType); 33 | 34 | void doItemClicked(AppInfo item); 35 | 36 | void saveData(); 37 | } 38 | 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/block/AppBlockModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.block; 2 | 3 | import com.tianma.xsmscode.ui.app.FragmentScope; 4 | 5 | import dagger.Binds; 6 | import dagger.Module; 7 | 8 | @Module 9 | public abstract class AppBlockModule { 10 | 11 | @FragmentScope 12 | @Binds 13 | abstract AppBlockContract.View bindView(AppBlockFragment view); 14 | 15 | 16 | @FragmentScope 17 | @Binds 18 | abstract AppBlockContract.Presenter bindPresenter(AppBlockPresenter presenter); 19 | 20 | } 21 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/block/AppInfoHelper.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.block; 2 | 3 | import android.content.pm.ApplicationInfo; 4 | import android.content.pm.PackageInfo; 5 | import android.content.pm.PackageManager; 6 | 7 | import com.tianma.xsmscode.data.db.entity.AppInfo; 8 | 9 | public class AppInfoHelper { 10 | 11 | private AppInfoHelper() { 12 | } 13 | 14 | public static AppInfo getAppInfo(PackageManager pm, PackageInfo packageInfo) { 15 | String label = pm.getApplicationLabel(packageInfo.applicationInfo).toString(); 16 | String packageName = packageInfo.packageName; 17 | return new AppInfo(label, packageName); 18 | } 19 | 20 | public static AppInfo getAppInfo(PackageManager pm, ApplicationInfo applicationInfo) { 21 | String label = pm.getApplicationLabel(applicationInfo).toString(); 22 | String packageName = applicationInfo.packageName; 23 | return new AppInfo(label, packageName); 24 | } 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/block/SortType.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.block; 2 | 3 | /** 4 | * Sort Order Type 5 | */ 6 | public enum SortType { 7 | LABEL_ASC, 8 | PACKAGE_ASC, 9 | LABEL_DESC, 10 | PACKAGE_DESC, 11 | } 12 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/faq/FaqFragment.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.faq; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.view.LayoutInflater; 6 | import android.view.View; 7 | import android.view.ViewGroup; 8 | 9 | import com.github.tianma8023.xposed.smscode.R; 10 | 11 | import java.util.List; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.fragment.app.Fragment; 15 | import androidx.recyclerview.widget.LinearLayoutManager; 16 | import androidx.recyclerview.widget.RecyclerView; 17 | 18 | /** 19 | * FAQ fragment 20 | */ 21 | public class FaqFragment extends Fragment { 22 | 23 | private Context mContext; 24 | 25 | public FaqFragment() { 26 | } 27 | 28 | public static FaqFragment newInstance() { 29 | return new FaqFragment(); 30 | } 31 | 32 | @Override 33 | public void onAttach(Context context) { 34 | super.onAttach(context); 35 | mContext = context; 36 | } 37 | 38 | @Override 39 | public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, 40 | Bundle savedInstanceState) { 41 | View view = inflater.inflate(R.layout.fragment_faq, container, false); 42 | 43 | // Set the adapter 44 | if (view instanceof RecyclerView) { 45 | Context context = view.getContext(); 46 | RecyclerView recyclerView = (RecyclerView) view; 47 | recyclerView.setLayoutManager(new LinearLayoutManager(context)); 48 | List items = new FaqItemContainer(context).getFaqItems(); 49 | recyclerView.setAdapter(new FaqItemAdapter(mContext, items)); 50 | } 51 | return view; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/faq/FaqItem.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.faq; 2 | 3 | public class FaqItem { 4 | private String question; 5 | private String answer; 6 | 7 | public FaqItem(String question, String answer) { 8 | this.question = question; 9 | this.answer = answer; 10 | } 11 | 12 | public String getQuestion() { 13 | return question; 14 | } 15 | 16 | public String getAnswer() { 17 | return answer; 18 | } 19 | 20 | @Override 21 | public String toString() { 22 | return "FaqItem{" + 23 | "question='" + question + '\'' + 24 | ", answer='" + answer + '\'' + 25 | '}'; 26 | } 27 | } -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/faq/FaqItemAdapter.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.faq; 2 | 3 | import android.content.Context; 4 | import android.view.LayoutInflater; 5 | import android.view.View; 6 | import android.view.ViewGroup; 7 | import android.widget.TextView; 8 | 9 | import com.github.tianma8023.xposed.smscode.R; 10 | 11 | import java.util.List; 12 | 13 | import androidx.annotation.NonNull; 14 | import androidx.recyclerview.widget.RecyclerView; 15 | 16 | public class FaqItemAdapter extends RecyclerView.Adapter { 17 | 18 | private final List mFaqItems; 19 | 20 | private final String mQuestionPrefix; 21 | private final String mAnswerPrefix; 22 | 23 | FaqItemAdapter(Context context, List items) { 24 | mFaqItems = items; 25 | mQuestionPrefix = context.getString(R.string.simplified_question); 26 | mAnswerPrefix = context.getString(R.string.simplified_answer); 27 | } 28 | 29 | @NonNull 30 | @Override 31 | public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { 32 | View view = LayoutInflater.from(parent.getContext()) 33 | .inflate(R.layout.item_faq, parent, false); 34 | return new ViewHolder(view); 35 | } 36 | 37 | @Override 38 | public void onBindViewHolder(@NonNull final ViewHolder holder, int position) { 39 | FaqItem item = mFaqItems.get(position); 40 | holder.bindData(item); 41 | } 42 | 43 | @Override 44 | public int getItemCount() { 45 | return mFaqItems.size(); 46 | } 47 | 48 | class ViewHolder extends RecyclerView.ViewHolder { 49 | final View mView; 50 | final TextView mQuestionView; 51 | final TextView mAnswerView; 52 | FaqItem mItem; 53 | 54 | ViewHolder(View view) { 55 | super(view); 56 | mView = view; 57 | mQuestionView = view.findViewById(R.id.item_question); 58 | mAnswerView = view.findViewById(R.id.item_answer); 59 | } 60 | 61 | void bindData(FaqItem item) { 62 | mItem = item; 63 | String question = mQuestionPrefix + item.getQuestion(); 64 | mQuestionView.setText(question); 65 | String answer = mAnswerPrefix + item.getAnswer(); 66 | mAnswerView.setText(answer); 67 | } 68 | 69 | @Override 70 | public String toString() { 71 | return super.toString() + " '" + mAnswerView.getText() + "'"; 72 | } 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/faq/FaqItemContainer.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.faq; 2 | 3 | import android.content.Context; 4 | import android.content.res.Resources; 5 | 6 | import com.github.tianma8023.xposed.smscode.R; 7 | 8 | import java.util.ArrayList; 9 | import java.util.List; 10 | 11 | 12 | public class FaqItemContainer { 13 | 14 | private List mFaqItems = new ArrayList<>(); 15 | 16 | public FaqItemContainer(Context context) { 17 | loadItems(context); 18 | } 19 | 20 | private void loadItems(Context context) { 21 | Resources res = context.getResources(); 22 | String[] questionArr = res.getStringArray(R.array.question_list); 23 | String[] answerArr = res.getStringArray(R.array.answer_list); 24 | for (int i = 0; i < questionArr.length; i++) { 25 | if ("empty".equals(questionArr[i])) { 26 | continue; 27 | } 28 | mFaqItems.add(new FaqItem(questionArr[i], answerArr[i])); 29 | } 30 | } 31 | 32 | public List getFaqItems() { 33 | return mFaqItems; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/home/SettingsContract.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.home; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.tianma.xsmscode.common.mvp.BasePresenter; 6 | import com.tianma.xsmscode.common.mvp.BaseView; 7 | import com.tianma.xsmscode.data.db.entity.ApkVersion; 8 | 9 | public interface SettingsContract { 10 | 11 | interface View extends BaseView { 12 | 13 | void showGetAlipayPacketDialog(); 14 | 15 | void showSmsCodeTestResult(String code); 16 | 17 | void showCheckError(Throwable t); 18 | 19 | void showUpdateDialog(ApkVersion latestVersion); 20 | 21 | void showAppAlreadyNewest(); 22 | 23 | void showPrivacyPolicy(); 24 | } 25 | 26 | interface Presenter extends BasePresenter { 27 | 28 | void handleArguments(Bundle args); 29 | 30 | void setPreferenceWorldWritable(String preferencesName); 31 | 32 | void hideOrShowLauncherIcon(boolean hide); 33 | 34 | void performSmsCodeTest(String msgBody); 35 | 36 | void joinQQGroup(); 37 | 38 | void showSourceProject(); 39 | 40 | void setInternalFilesWritable(); 41 | 42 | void checkUpdate(); 43 | 44 | void updateFromGithub(); 45 | 46 | void updateFromCoolApk(); 47 | } 48 | 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/home/SettingsModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.home; 2 | 3 | import com.tianma.xsmscode.ui.app.FragmentScope; 4 | 5 | import dagger.Binds; 6 | import dagger.Module; 7 | 8 | @Module 9 | public abstract class SettingsModule { 10 | 11 | @FragmentScope 12 | @Binds 13 | abstract SettingsContract.View bindView(SettingsFragment view); 14 | 15 | @FragmentScope 16 | @Binds 17 | abstract SettingsContract.Presenter bindPresenter(SettingsPresenter presenter); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/record/CodeRecordActivity.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.record; 2 | 3 | import android.content.Context; 4 | import android.content.Intent; 5 | import android.os.Bundle; 6 | 7 | import androidx.appcompat.app.ActionBar; 8 | import androidx.appcompat.widget.Toolbar; 9 | 10 | import com.github.tianma8023.xposed.smscode.R; 11 | import com.tianma.xsmscode.common.fragment.backpress.BackPressEventDispatchHelper; 12 | import com.tianma.xsmscode.ui.app.base.BaseActivity; 13 | 14 | import butterknife.BindView; 15 | import butterknife.ButterKnife; 16 | 17 | /** 18 | * Sms Code Records 19 | */ 20 | public class CodeRecordActivity extends BaseActivity { 21 | 22 | @BindView(R.id.toolbar) 23 | Toolbar mToolbar; 24 | 25 | public static void startToMe(Context context) { 26 | Intent intent = new Intent(context, CodeRecordActivity.class); 27 | context.startActivity(intent); 28 | } 29 | 30 | @Override 31 | protected void onCreate(Bundle savedInstanceState) { 32 | super.onCreate(savedInstanceState); 33 | setContentView(R.layout.activity_code_records); 34 | ButterKnife.bind(this); 35 | 36 | setupToolbar(); 37 | 38 | getSupportFragmentManager() 39 | .beginTransaction() 40 | .replace(R.id.code_records_main_content, CodeRecordFragment.newInstance()) 41 | .commit(); 42 | } 43 | 44 | private void setupToolbar() { 45 | setSupportActionBar(mToolbar); 46 | ActionBar actionBar = getSupportActionBar(); 47 | if (actionBar != null) { 48 | actionBar.setHomeButtonEnabled(true); 49 | actionBar.setDisplayHomeAsUpEnabled(true); 50 | } 51 | } 52 | 53 | @Override 54 | public void onBackPressed() { 55 | if (!BackPressEventDispatchHelper.dispatchBackPressedEvent(this)) { 56 | super.onBackPressed(); 57 | } 58 | } 59 | } 60 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/record/CodeRecordActivityModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.record; 2 | 3 | import com.tianma.xsmscode.ui.app.FragmentScope; 4 | 5 | import dagger.Module; 6 | import dagger.android.ContributesAndroidInjector; 7 | 8 | @Module 9 | public abstract class CodeRecordActivityModule { 10 | 11 | @FragmentScope 12 | @ContributesAndroidInjector(modules = CodeRecordFragmentModule.class) 13 | abstract CodeRecordFragment contributeCodeRecordFragment(); 14 | 15 | } 16 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/record/CodeRecordContract.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.record; 2 | 3 | import com.tianma.xsmscode.common.mvp.BasePresenter; 4 | import com.tianma.xsmscode.common.mvp.BaseView; 5 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 6 | 7 | import java.util.List; 8 | 9 | interface CodeRecordContract { 10 | 11 | interface View extends BaseView { 12 | 13 | void showRefreshing(); 14 | 15 | void stopRefresh(); 16 | 17 | void displayData(List smsMsgList); 18 | 19 | } 20 | 21 | interface Presenter extends BasePresenter { 22 | 23 | void loadData(); 24 | 25 | void removeSmsMsg(List smsMsgList); 26 | } 27 | 28 | } 29 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/record/CodeRecordFragmentModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.record; 2 | 3 | import com.tianma.xsmscode.ui.app.FragmentScope; 4 | 5 | import dagger.Binds; 6 | import dagger.Module; 7 | 8 | @Module 9 | public abstract class CodeRecordFragmentModule { 10 | 11 | @FragmentScope 12 | @Binds 13 | public abstract CodeRecordContract.View bindView(CodeRecordFragment view); 14 | 15 | @FragmentScope 16 | @Binds 17 | public abstract CodeRecordContract.Presenter bindPresenter(CodeRecordPresenter presenter); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/record/CodeRecordPresenter.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.record; 2 | 3 | import android.content.Context; 4 | 5 | import com.tianma.xsmscode.common.utils.XLog; 6 | import com.tianma.xsmscode.data.db.DBManager; 7 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 8 | 9 | import java.util.List; 10 | 11 | import javax.inject.Inject; 12 | 13 | import io.reactivex.android.schedulers.AndroidSchedulers; 14 | import io.reactivex.disposables.CompositeDisposable; 15 | import io.reactivex.disposables.Disposable; 16 | import io.reactivex.schedulers.Schedulers; 17 | 18 | public class CodeRecordPresenter implements CodeRecordContract.Presenter { 19 | 20 | private CodeRecordContract.View mView; 21 | private Context mContext; 22 | private CompositeDisposable mCompositeDisposable; 23 | 24 | @Inject 25 | public CodeRecordPresenter() { 26 | mCompositeDisposable = new CompositeDisposable(); 27 | } 28 | 29 | @Inject 30 | @Override 31 | public void onAttach(Context context, CodeRecordContract.View view) { 32 | mContext = context; 33 | mView = view; 34 | } 35 | 36 | @Override 37 | public void onDetach() { 38 | mView = null; 39 | if (mCompositeDisposable.size() > 0) { 40 | mCompositeDisposable.clear(); 41 | } 42 | } 43 | 44 | @Override 45 | public void loadData() { 46 | Disposable disposable = DBManager.get(mContext) 47 | .queryAllSmsMsgRx() 48 | .subscribeOn(Schedulers.io()) 49 | .observeOn(AndroidSchedulers.mainThread()) 50 | .doOnSubscribe(dis -> mView.showRefreshing()) 51 | .subscribe(smsMsgList -> { 52 | mView.displayData(smsMsgList); 53 | mView.stopRefresh(); 54 | }, throwable -> { 55 | // ignore 56 | XLog.e("", throwable); 57 | }); 58 | mCompositeDisposable.add(disposable); 59 | } 60 | 61 | @Override 62 | public void removeSmsMsg(List smsMsgList) { 63 | Disposable disposable = DBManager.get(mContext) 64 | .removeSmsMsgListRx(smsMsgList) 65 | .subscribeOn(Schedulers.io()) 66 | .observeOn(AndroidSchedulers.mainThread()) 67 | .subscribe(list -> { 68 | // ignore 69 | }, throwable -> { 70 | XLog.e("Error occurs when remove SMS records", throwable); 71 | }); 72 | mCompositeDisposable.add(disposable); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/record/RecordItem.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.record; 2 | 3 | 4 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 5 | 6 | import java.util.Objects; 7 | 8 | public class RecordItem { 9 | 10 | private SmsMsg smsMsg; 11 | private boolean mSelected; 12 | 13 | RecordItem(SmsMsg smsMsg) { 14 | this.smsMsg = smsMsg; 15 | } 16 | 17 | public SmsMsg getSmsMsg() { 18 | return smsMsg; 19 | } 20 | 21 | public boolean isSelected() { 22 | return mSelected; 23 | } 24 | 25 | public void setSelected(boolean selected) { 26 | this.mSelected = selected; 27 | } 28 | 29 | @Override 30 | public String toString() { 31 | return "RecordItem{" + 32 | "smsMsg=" + smsMsg + 33 | ", selected=" + mSelected + 34 | '}'; 35 | } 36 | 37 | @Override 38 | public boolean equals(Object o) { 39 | if (this == o) return true; 40 | if (!(o instanceof RecordItem)) return false; 41 | RecordItem item = (RecordItem) o; 42 | return Objects.equals(smsMsg, item.smsMsg); 43 | } 44 | 45 | @Override 46 | public int hashCode() { 47 | return Objects.hash(smsMsg); 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/rule/CodeRulesModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.rule; 2 | 3 | 4 | import com.tianma.xsmscode.ui.app.FragmentScope; 5 | import com.tianma.xsmscode.ui.rule.edit.RuleEditFragment; 6 | import com.tianma.xsmscode.ui.rule.edit.RuleEditModule; 7 | import com.tianma.xsmscode.ui.rule.list.RuleListFragment; 8 | import com.tianma.xsmscode.ui.rule.list.RuleListModule; 9 | 10 | import dagger.Module; 11 | import dagger.android.ContributesAndroidInjector; 12 | 13 | @Module 14 | public abstract class CodeRulesModule { 15 | 16 | @FragmentScope 17 | @ContributesAndroidInjector(modules = RuleListModule.class) 18 | abstract RuleListFragment contributeRuleListFragment(); 19 | 20 | 21 | @FragmentScope 22 | @ContributesAndroidInjector(modules = RuleEditModule.class) 23 | abstract RuleEditFragment contributeRuleEditFragment(); 24 | 25 | } 26 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/rule/edit/RuleEditContract.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.rule.edit; 2 | 3 | import android.os.Bundle; 4 | 5 | import com.tianma.xsmscode.common.mvp.BasePresenter; 6 | import com.tianma.xsmscode.common.mvp.BaseView; 7 | import com.tianma.xsmscode.data.db.entity.SmsCodeRule; 8 | 9 | interface RuleEditContract { 10 | 11 | interface View extends BaseView { 12 | 13 | void displayCodeRule(SmsCodeRule codeRule); 14 | 15 | void clearAllErrorInfo(); 16 | 17 | void onTemplateSaved(boolean success); 18 | 19 | void showErrorInfo(boolean companyValid, boolean keywordValid, boolean codeRegexValid); 20 | 21 | void hideSoftInput(); 22 | 23 | void onCodeRuleSaved(boolean success); 24 | } 25 | 26 | interface Presenter extends BasePresenter { 27 | 28 | void handleArguments(Bundle args); 29 | 30 | void saveAsTemplate(SmsCodeRule template); 31 | 32 | void saveIfValid(SmsCodeRule codeRule); 33 | 34 | } 35 | 36 | } 37 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/rule/edit/RuleEditModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.rule.edit; 2 | 3 | import com.tianma.xsmscode.ui.app.FragmentScope; 4 | 5 | import dagger.Binds; 6 | import dagger.Module; 7 | 8 | @Module 9 | public abstract class RuleEditModule { 10 | 11 | @FragmentScope 12 | @Binds 13 | abstract RuleEditContract.View bindView(RuleEditFragment view); 14 | 15 | @FragmentScope 16 | @Binds 17 | abstract RuleEditContract.Presenter bindPresenter(RuleEditPresenter presenter); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/rule/list/RuleListContract.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.rule.list; 2 | 3 | import android.content.Context; 4 | import android.net.Uri; 5 | import android.os.Bundle; 6 | 7 | import com.tianma.xsmscode.common.mvp.BasePresenter; 8 | import com.tianma.xsmscode.common.mvp.BaseView; 9 | import com.tianma.xsmscode.data.db.entity.SmsCodeRule; 10 | import com.tianma.xsmscode.feature.backup.ImportResult; 11 | 12 | import java.io.File; 13 | import java.util.List; 14 | 15 | interface RuleListContract { 16 | 17 | interface View extends BaseView { 18 | 19 | void displayRules(List rules); 20 | 21 | void attemptImportRuleListDirectly(Uri importUri); 22 | 23 | void showImportDialogConfirm(Uri importUri); 24 | 25 | void showProgress(String progressMsg); 26 | 27 | void cancelProgress(); 28 | 29 | void onExportCompletedBelowQ(boolean success, File file); 30 | 31 | void onExportCompletedAboveQ(boolean success); 32 | 33 | void onImportComplete(ImportResult importResult); 34 | } 35 | 36 | interface Presenter extends BasePresenter { 37 | 38 | void loadAllRules(); 39 | 40 | void handleArguments(Bundle args); 41 | 42 | void removeRule(SmsCodeRule codeRule); 43 | 44 | void exportRulesBelowQ(List rules, File file, String progressMsg); 45 | 46 | void exportRulesAboveQ(List rules, Context context, Uri uri, String progressMsg); 47 | 48 | void importRules(Uri uri, boolean retain, String progressMsg); 49 | 50 | void saveRulesToFile(List rules); 51 | } 52 | 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/ui/rule/list/RuleListModule.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.ui.rule.list; 2 | 3 | import com.tianma.xsmscode.ui.app.FragmentScope; 4 | 5 | import dagger.Binds; 6 | import dagger.Module; 7 | 8 | @Module 9 | public abstract class RuleListModule { 10 | 11 | @FragmentScope 12 | @Binds 13 | abstract RuleListContract.View bindView(RuleListFragment view); 14 | 15 | @FragmentScope 16 | @Binds 17 | abstract RuleListContract.Presenter bindPresenter(RuleListPresenter presenter); 18 | 19 | } 20 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/HookEntry.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp; 2 | 3 | import android.util.Log; 4 | 5 | import com.github.tianma8023.xposed.smscode.BuildConfig; 6 | import com.tianma.xsmscode.common.constant.PrefConst; 7 | import com.tianma.xsmscode.common.utils.XLog; 8 | import com.tianma.xsmscode.common.utils.XSPUtils; 9 | import com.tianma.xsmscode.xp.hook.BaseHook; 10 | import com.tianma.xsmscode.xp.hook.me.ModuleUtilsHook; 11 | import com.tianma.xsmscode.xp.hook.permission.PermissionGranterHook; 12 | import com.tianma.xsmscode.xp.hook.code.SmsHandlerHook; 13 | 14 | import java.util.ArrayList; 15 | import java.util.List; 16 | 17 | import de.robv.android.xposed.IXposedHookLoadPackage; 18 | import de.robv.android.xposed.IXposedHookZygoteInit; 19 | import de.robv.android.xposed.XSharedPreferences; 20 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 21 | 22 | public class HookEntry implements IXposedHookLoadPackage, IXposedHookZygoteInit { 23 | 24 | private List mHookList; 25 | 26 | { 27 | mHookList = new ArrayList<>(); 28 | mHookList.add(new SmsHandlerHook()); // InBoundsSmsHandler Hook 29 | mHookList.add(new ModuleUtilsHook()); // ModuleUtils Hook 30 | mHookList.add(new PermissionGranterHook()); // PackageManagerService Hook 31 | } 32 | 33 | @Override 34 | public void initZygote(StartupParam startupParam) throws Throwable { 35 | for (BaseHook hook : mHookList) { 36 | if (hook.hookInitZygote()) { 37 | hook.initZygote(startupParam); 38 | } 39 | } 40 | 41 | try { 42 | XSharedPreferences xsp = new XSharedPreferences(BuildConfig.APPLICATION_ID, PrefConst.PREF_NAME); 43 | if (XSPUtils.isVerboseLogMode(xsp)) { 44 | XLog.setLogLevel(Log.VERBOSE); 45 | } else { 46 | XLog.setLogLevel(BuildConfig.LOG_LEVEL); 47 | } 48 | } catch (Throwable t) { 49 | XLog.e("", t); 50 | } 51 | } 52 | 53 | @Override 54 | public void handleLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 55 | for (BaseHook hook : mHookList) { 56 | if (hook.hookOnLoadPackage()) { 57 | hook.onLoadPackage(lpparam); 58 | } 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/helper/MethodHookWrapper.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.helper; 2 | 3 | 4 | import com.tianma.xsmscode.common.utils.XLog; 5 | 6 | import de.robv.android.xposed.XC_MethodHook; 7 | 8 | public abstract class MethodHookWrapper extends XC_MethodHook { 9 | 10 | @Override 11 | final protected void beforeHookedMethod(MethodHookParam param) throws Throwable { 12 | try { 13 | before(param); 14 | } catch (Throwable t) { 15 | XLog.d("Error in hook %s", param.method.getName(), t); 16 | } 17 | } 18 | 19 | protected void before(MethodHookParam param) throws Throwable { 20 | } 21 | 22 | @Override 23 | final protected void afterHookedMethod(MethodHookParam param) throws Throwable { 24 | try { 25 | after(param); 26 | } catch (Throwable t) { 27 | XLog.e("Error in hook %s", param.method.getName(), t); 28 | } 29 | } 30 | 31 | protected void after(MethodHookParam param) throws Throwable { 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/helper/XposedWrapper.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.helper; 2 | 3 | 4 | import com.tianma.xsmscode.common.utils.XLog; 5 | 6 | import java.lang.reflect.Member; 7 | import java.util.Set; 8 | 9 | import de.robv.android.xposed.XC_MethodHook; 10 | import de.robv.android.xposed.XposedBridge; 11 | import de.robv.android.xposed.XposedHelpers; 12 | 13 | /** 14 | * Xposed Wrapper Utils 15 | */ 16 | public class XposedWrapper { 17 | 18 | private XposedWrapper() { 19 | } 20 | 21 | public static Class findClass(String className, ClassLoader classLoader) { 22 | try { 23 | return XposedHelpers.findClass(className, classLoader); 24 | } catch (Throwable t) { 25 | XLog.e("Class not found: %s", className); 26 | return null; 27 | } 28 | } 29 | 30 | public static XC_MethodHook.Unhook findAndHookMethod(String className, ClassLoader classLoader, String methodName, Object... parameterTypesAndCallback) { 31 | try { 32 | return XposedHelpers.findAndHookMethod(className, classLoader, methodName, parameterTypesAndCallback); 33 | } catch (Throwable t) { 34 | XLog.e("Error in hook %s#%s", className, methodName, t); 35 | return null; 36 | } 37 | } 38 | 39 | public static XC_MethodHook.Unhook findAndHookMethod(Class clazz, String methodName, Object... parameterTypesAndCallback) { 40 | try { 41 | return XposedHelpers.findAndHookMethod(clazz, methodName, parameterTypesAndCallback); 42 | } catch (Throwable t) { 43 | XLog.e("Error in hook %s#%s", clazz.getName(), methodName, t); 44 | return null; 45 | } 46 | } 47 | 48 | public static XC_MethodHook.Unhook hookMethod(Member hookMethod, XC_MethodHook callback) { 49 | try { 50 | return XposedBridge.hookMethod(hookMethod, callback); 51 | } catch (Throwable t) { 52 | XLog.e("Error in hookMethod: %s", hookMethod.getName(), t); 53 | return null; 54 | } 55 | } 56 | 57 | public static Set hookAllConstructors(Class hookClass, XC_MethodHook callback) { 58 | try { 59 | return XposedBridge.hookAllConstructors(hookClass, callback); 60 | } catch (Throwable t) { 61 | XLog.e("Error in hookAllConstructors: %s", hookClass.getName(), t); 62 | return null; 63 | } 64 | } 65 | 66 | public static Set hookAllMethods(Class hookClass, String methodName, XC_MethodHook callback) { 67 | try { 68 | return XposedBridge.hookAllMethods(hookClass, methodName, callback); 69 | } catch (Throwable t) { 70 | XLog.e("Error in hookAllMethods: %s", hookClass.getName(), t); 71 | return null; 72 | } 73 | } 74 | 75 | } 76 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/BaseHook.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook; 2 | 3 | import de.robv.android.xposed.IXposedHookZygoteInit; 4 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 5 | 6 | public class BaseHook implements IHook { 7 | 8 | @Override 9 | public void initZygote(IXposedHookZygoteInit.StartupParam startupParam) throws Throwable { 10 | } 11 | 12 | public boolean hookInitZygote() { 13 | return false; 14 | } 15 | 16 | @Override 17 | public void onLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 18 | 19 | } 20 | 21 | public boolean hookOnLoadPackage() { 22 | return true; 23 | } 24 | 25 | 26 | } 27 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/BaseSubHook.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook; 2 | 3 | public abstract class BaseSubHook { 4 | 5 | protected ClassLoader mClassLoader; 6 | 7 | public BaseSubHook(ClassLoader classLoader) { 8 | mClassLoader = classLoader; 9 | } 10 | 11 | public abstract void startHook(); 12 | 13 | } 14 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/IHook.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook; 2 | 3 | import de.robv.android.xposed.IXposedHookZygoteInit; 4 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 5 | 6 | public interface IHook { 7 | 8 | void initZygote(IXposedHookZygoteInit.StartupParam startupParam) throws Throwable; 9 | 10 | void onLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/ParseResult.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code; 2 | 3 | class ParseResult { 4 | 5 | private boolean blockSms; 6 | 7 | ParseResult() { 8 | 9 | } 10 | 11 | boolean isBlockSms() { 12 | return blockSms; 13 | } 14 | 15 | void setBlockSms(boolean blockSms) { 16 | this.blockSms = blockSms; 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/Action.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action; 2 | 3 | public interface Action { 4 | 5 | T action(); 6 | 7 | } 8 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/CallableAction.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | 6 | import com.tianma.xsmscode.common.utils.XLog; 7 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 8 | 9 | import java.util.concurrent.Callable; 10 | 11 | import de.robv.android.xposed.XSharedPreferences; 12 | 13 | /** 14 | * Action + Callable 15 | */ 16 | public abstract class CallableAction implements Action, Callable { 17 | 18 | protected Context mPluginContext; 19 | protected Context mPhoneContext; 20 | protected SmsMsg mSmsMsg; 21 | protected XSharedPreferences xsp; 22 | 23 | public CallableAction(Context pluginContext, Context phoneContext, SmsMsg smsMsg, XSharedPreferences xsp) { 24 | mPluginContext = pluginContext; 25 | mPhoneContext = phoneContext; 26 | mSmsMsg = smsMsg; 27 | this.xsp = xsp; 28 | } 29 | 30 | @Override 31 | public Bundle call() { 32 | try { 33 | return action(); 34 | } catch (Throwable t) { 35 | XLog.e("Error in CallableAction#call()", t); 36 | return null; 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/RunnableAction.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action; 2 | 3 | import android.content.Context; 4 | 5 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 6 | 7 | import de.robv.android.xposed.XSharedPreferences; 8 | 9 | /** 10 | * Runnable + Action + Callable 11 | */ 12 | public abstract class RunnableAction extends CallableAction implements Runnable { 13 | 14 | public RunnableAction(Context pluginContext, Context phoneContext, SmsMsg smsMsg, XSharedPreferences xsp) { 15 | super(pluginContext, phoneContext, smsMsg, xsp); 16 | } 17 | 18 | @Override 19 | public void run() { 20 | call(); 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/impl/CancelNotifyAction.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action.impl; 2 | 3 | import android.app.NotificationManager; 4 | import android.content.Context; 5 | import android.os.Bundle; 6 | 7 | import com.tianma.xsmscode.common.utils.XLog; 8 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 9 | import com.tianma.xsmscode.xp.hook.code.action.CallableAction; 10 | 11 | import de.robv.android.xposed.XSharedPreferences; 12 | 13 | public class CancelNotifyAction extends CallableAction { 14 | 15 | private static final int NOTIFICATION_NONE = -0xff; 16 | 17 | private int mNotificationId = NOTIFICATION_NONE; 18 | 19 | public CancelNotifyAction(Context pluginContext, Context phoneContext, SmsMsg smsMsg, XSharedPreferences xsp) { 20 | super(pluginContext, phoneContext, smsMsg, xsp); 21 | } 22 | 23 | public void setNotificationId(int notificationId) { 24 | mNotificationId = notificationId; 25 | } 26 | 27 | @Override 28 | public Bundle action() { 29 | cancelNotification(); 30 | return null; 31 | } 32 | 33 | private void cancelNotification() { 34 | if (mNotificationId != NOTIFICATION_NONE) { 35 | NotificationManager manager = (NotificationManager) mPhoneContext.getSystemService(Context.NOTIFICATION_SERVICE); 36 | if (manager == null) { 37 | return; 38 | } 39 | manager.cancel(mNotificationId); 40 | XLog.d("Notification auto cancelled"); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/impl/CopyToClipboardAction.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action.impl; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | 6 | import com.tianma.xsmscode.common.utils.ClipboardUtils; 7 | import com.tianma.xsmscode.common.utils.XSPUtils; 8 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 9 | import com.tianma.xsmscode.xp.hook.code.action.RunnableAction; 10 | 11 | import de.robv.android.xposed.XSharedPreferences; 12 | 13 | /** 14 | * 将验证码复制到剪切板 15 | */ 16 | public class CopyToClipboardAction extends RunnableAction { 17 | 18 | public CopyToClipboardAction(Context pluginContext, Context phoneContext, SmsMsg smsMsg, XSharedPreferences xsp) { 19 | super(pluginContext, phoneContext, smsMsg, xsp); 20 | } 21 | 22 | @Override 23 | public Bundle action() { 24 | if (XSPUtils.copyToClipboardEnabled(xsp)) { 25 | copyToClipboard(); 26 | } 27 | return null; 28 | } 29 | 30 | private void copyToClipboard() { 31 | ClipboardUtils.copyToClipboard(mPluginContext, mSmsMsg.getSmsCode()); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/impl/KillMeAction.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action.impl; 2 | 3 | import android.annotation.SuppressLint; 4 | import android.app.ActivityManager; 5 | import android.content.Context; 6 | import android.os.Bundle; 7 | 8 | import com.github.tianma8023.xposed.smscode.BuildConfig; 9 | import com.tianma.xsmscode.common.utils.XLog; 10 | import com.tianma.xsmscode.common.utils.XSPUtils; 11 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 12 | import com.tianma.xsmscode.xp.hook.code.action.CallableAction; 13 | 14 | import de.robv.android.xposed.XSharedPreferences; 15 | 16 | public class KillMeAction extends CallableAction { 17 | 18 | public KillMeAction(Context pluginContext, Context phoneContext, SmsMsg smsMsg, XSharedPreferences xsp) { 19 | super(pluginContext, phoneContext, smsMsg, xsp); 20 | } 21 | 22 | @Override 23 | public Bundle action() { 24 | killMe(); 25 | return null; 26 | } 27 | 28 | private void killMe() { 29 | if (XSPUtils.killMeEnabled(xsp)) { 30 | killBackgroundProcess(BuildConfig.APPLICATION_ID); 31 | } 32 | } 33 | 34 | /** 35 | * android.app.ActivityManager#killBackgroundProcess() 36 | */ 37 | @SuppressLint("MissingPermission") 38 | private void killBackgroundProcess(String packageName) { 39 | try { 40 | ActivityManager activityManager = (ActivityManager) mPluginContext.getSystemService(Context.ACTIVITY_SERVICE); 41 | 42 | if (activityManager != null) { 43 | activityManager.killBackgroundProcesses(packageName); 44 | XLog.d("Kill %s background process succeed", packageName); 45 | } 46 | } catch (Throwable e) { 47 | XLog.e("Error occurs when kill background process %s", packageName, e); 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/code/action/impl/ToastAction.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.code.action.impl; 2 | 3 | import android.content.Context; 4 | import android.os.Bundle; 5 | import android.widget.Toast; 6 | 7 | import com.github.tianma8023.xposed.smscode.R; 8 | import com.tianma.xsmscode.common.utils.XSPUtils; 9 | import com.tianma.xsmscode.data.db.entity.SmsMsg; 10 | import com.tianma.xsmscode.xp.hook.code.action.RunnableAction; 11 | 12 | import de.robv.android.xposed.XSharedPreferences; 13 | 14 | /** 15 | * 显示验证码Toast 16 | */ 17 | public class ToastAction extends RunnableAction { 18 | 19 | public ToastAction(Context pluginContext, Context phoneContext, SmsMsg smsMsg, XSharedPreferences xsp) { 20 | super(pluginContext, phoneContext, smsMsg, xsp); 21 | } 22 | 23 | @Override 24 | public Bundle action() { 25 | if (XSPUtils.shouldShowToast(xsp)) { 26 | showCodeToast(); 27 | } 28 | return null; 29 | } 30 | 31 | private void showCodeToast() { 32 | String text = mPluginContext.getString(R.string.current_sms_code, mSmsMsg.getSmsCode()); 33 | if (mPhoneContext != null) { 34 | Toast.makeText(mPhoneContext, text, Toast.LENGTH_LONG).show(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/me/ModuleUtilsHook.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.me; 2 | 3 | import com.github.tianma8023.xposed.smscode.BuildConfig; 4 | import com.tianma.xsmscode.common.utils.ModuleUtils; 5 | import com.tianma.xsmscode.common.utils.XLog; 6 | import com.tianma.xsmscode.xp.hook.BaseHook; 7 | 8 | import de.robv.android.xposed.XC_MethodReplacement; 9 | import de.robv.android.xposed.XposedHelpers; 10 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 11 | 12 | /** 13 | * Hook class ModuleUtils 14 | */ 15 | public class ModuleUtilsHook extends BaseHook { 16 | 17 | private static final String SMSCODE_PACKAGE = BuildConfig.APPLICATION_ID; 18 | private static final int MODULE_VERSION = BuildConfig.MODULE_VERSION; 19 | 20 | @Override 21 | public void onLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 22 | 23 | if (SMSCODE_PACKAGE.equals(lpparam.packageName)) { 24 | try { 25 | XLog.i("Hooking current Xposed module status..."); 26 | hookModuleUtils(lpparam); 27 | } catch (Throwable e) { 28 | XLog.e("Failed to hook current Xposed module status."); 29 | } 30 | } 31 | 32 | } 33 | 34 | private void hookModuleUtils(XC_LoadPackage.LoadPackageParam lpparam) throws Throwable { 35 | String className = ModuleUtils.class.getName(); 36 | 37 | XposedHelpers.findAndHookMethod(className, lpparam.classLoader, 38 | "getModuleVersion", 39 | XC_MethodReplacement.returnConstant(MODULE_VERSION)); 40 | } 41 | 42 | } 43 | -------------------------------------------------------------------------------- /app/src/main/java/com/tianma/xsmscode/xp/hook/permission/PermissionGranterHook.java: -------------------------------------------------------------------------------- 1 | package com.tianma.xsmscode.xp.hook.permission; 2 | 3 | import android.os.Build; 4 | 5 | import com.tianma.xsmscode.xp.hook.BaseHook; 6 | 7 | import de.robv.android.xposed.callbacks.XC_LoadPackage; 8 | 9 | /** 10 | * Hook com.android.server.pm.PackageManagerService to grant permissions. 11 | */ 12 | public class PermissionGranterHook extends BaseHook { 13 | 14 | public static final String ANDROID_PACKAGE = "android"; 15 | 16 | @Override 17 | public void onLoadPackage(XC_LoadPackage.LoadPackageParam lpparam) { 18 | if (ANDROID_PACKAGE.equals(lpparam.packageName) && ANDROID_PACKAGE.equals(lpparam.processName)) { 19 | ClassLoader classLoader = lpparam.classLoader; 20 | 21 | final int sdkInt = Build.VERSION.SDK_INT; 22 | if (sdkInt >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) { 23 | new PermissionManagerServiceHook34(classLoader).startHook(); 24 | } else if (sdkInt >= Build.VERSION_CODES.TIRAMISU){ // Android 13+ 25 | new PermissionManagerServiceHook33(classLoader).startHook(); 26 | } else if (sdkInt >= Build.VERSION_CODES.S) { // Android 12~12L 27 | new PermissionManagerServiceHook31(classLoader).startHook(); 28 | } else if (sdkInt >= Build.VERSION_CODES.R){ // Android 11 29 | new PermissionManagerServiceHook30(classLoader).startHook(); 30 | } else if (sdkInt >= Build.VERSION_CODES.P) { // Android 9.0~10 31 | new PermissionManagerServiceHook(classLoader).startHook(); 32 | } else { // Android 5.0 ~ 8.1 33 | new PackageManagerServiceHook(classLoader).startHook(); 34 | } 35 | } 36 | } 37 | 38 | } 39 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/code_rule_quick_choose_bg.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_add.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_alipay.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_app_icon.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_automatic.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 19 | 22 | 23 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_baseline_timer.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_block.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_clear.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_copy.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_delete_normal.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_done.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_export.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_filter.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_help.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_hide.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_import.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_info.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_intercept.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_key_words.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_kill.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_lock_open.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_log.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_mark_as_read.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_notification.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_palette.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_privacy_tip.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 10 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_qq_group.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_records.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_rules.xml: -------------------------------------------------------------------------------- 1 | 6 | 9 | 12 | 13 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_search.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_select_all.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_sort.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_source_code.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_test.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_time.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/ic_toast.xml: -------------------------------------------------------------------------------- 1 | 7 | 10 | 11 | -------------------------------------------------------------------------------- /app/src/main/res/drawable/selectable_item_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_app_block.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 16 | 17 | 18 | 19 | 20 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_code_records.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_code_rules.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 15 | 16 | 17 | 18 | 19 | 28 | 29 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 17 | 18 | 20 | 21 | 22 | 23 | 32 | -------------------------------------------------------------------------------- /app/src/main/res/layout/dialog_code_regex_quick_chcoose.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 33 | 34 | 42 | 43 | 44 | 45 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_app_block.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | 14 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_code_records.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 11 | 12 | 16 | 17 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_faq.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/layout/fragment_rule_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 6 | 7 | 11 | 12 | 19 | 20 | 29 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_app_info.xml: -------------------------------------------------------------------------------- 1 | 2 | 9 | 10 | 16 | 17 | 26 | 27 | 35 | 36 | 43 | 44 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_code_record.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 22 | 23 | 31 | 32 | 40 | 41 | 50 | 51 | 56 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_faq.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 19 | 20 | 30 | 31 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_rule.xml: -------------------------------------------------------------------------------- 1 | 2 | 13 | 14 | 26 | 27 | 40 | 41 | 53 | -------------------------------------------------------------------------------- /app/src/main/res/layout/item_theme.xml: -------------------------------------------------------------------------------- 1 | 2 | 10 | 11 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/layout/preference_category.xml: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /app/src/main/res/layout/toolbar.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /app/src/main/res/menu/context_rule_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 7 | 8 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_app_block.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 11 | 12 | 16 | 17 | 20 | 23 | 26 | 29 | 30 | 31 | 32 | 37 | 38 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_edit_code_record.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 17 | 18 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_edit_rule.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | 21 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_home.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 15 | 16 | 20 | -------------------------------------------------------------------------------- /app/src/main/res/menu/menu_rule_list.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 10 | 11 | 16 | 17 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-hdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-mdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_foreground.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values-sw360dp-v13/values-preference.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | false 5 | 0dp 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/array.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | android 5 | com.android.phone 6 | 7 | -------------------------------------------------------------------------------- /app/src/main/res/values/attrs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | 7 | #F44336 8 | #F44336 9 | #FF4D3E 10 | 11 | #FB7299 12 | #FB7299 13 | #FF83AF 14 | 15 | #ffb300 16 | #ffb300 17 | #ffc107 18 | 19 | #4CAF50 20 | #4CAF50 21 | #66bb6a 22 | 23 | #00796b 24 | #00796b 25 | #00897b 26 | 27 | #2196F3 28 | #2196F3 29 | #25ACFF 30 | 31 | #9C27B0 32 | #9C27B0 33 | #B32CCA 34 | 35 | #212121 36 | #212121 37 | 38 | #f0f0f0 39 | #6f6f6f 40 | 41 | #202020 42 | #818181 43 | 44 | #FFFFFF 45 | #353535 46 | 47 | #DDDDDD 48 | #454545 49 | 50 | #008577 51 | #D81B60 52 | 53 | 54 | -------------------------------------------------------------------------------- /app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 0dp 4 | 2dp 5 | 4dp 6 | 6dp 7 | 8dp 8 | 10dp 9 | 12dp 10 | 16dp 11 | 20dp 12 | 24dp 13 | -------------------------------------------------------------------------------- /app/src/main/res/values/ic_launcher_background.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #00BCD4 4 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 9 | 10 | 15 | 16 | 19 | 20 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/res/xml/files.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /app/src/main/res/xml/network_security_config.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /app/src/main/res/xml/shortcuts.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 8 | 12 | 14 | 15 | 16 | 21 | 25 | 27 | 28 | 29 | 34 | 38 | 39 | 40 | 42 | 43 | -------------------------------------------------------------------------------- /art/cn/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/art/cn/01.png -------------------------------------------------------------------------------- /art/cn/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/art/cn/02.png -------------------------------------------------------------------------------- /art/cn/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/art/cn/03.png -------------------------------------------------------------------------------- /art/en/01.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/art/en/01.png -------------------------------------------------------------------------------- /art/en/02.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/art/en/02.png -------------------------------------------------------------------------------- /art/en/03.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/art/en/03.png -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | 5 | repositories { 6 | maven { 7 | url "https://maven.aliyun.com/repository/public/" 8 | } 9 | google() 10 | mavenCentral() // add repository 11 | } 12 | dependencies { 13 | classpath 'com.android.tools.build:gradle:7.4.2' 14 | 15 | 16 | // NOTE: Do not place your application dependencies here; they belong 17 | // in the individual module build.gradle files 18 | classpath 'org.greenrobot:greendao-gradle-plugin:3.3.0' // greenDao plugin 19 | 20 | classpath 'io.github.leon406:AndResGuard-gradle-plugin:1.2.23' // AndResGuard 21 | } 22 | } 23 | 24 | allprojects { 25 | repositories { 26 | maven { 27 | url "https://maven.aliyun.com/repository/public/" 28 | } 29 | google() 30 | mavenCentral() 31 | maven { 32 | url "https://jitpack.io" 33 | } 34 | maven { 35 | url "https://s01.oss.sonatype.org/content/repositories/snapshots/" 36 | } 37 | } 38 | } 39 | 40 | task clean(type: Delete) { 41 | delete rootProject.buildDir 42 | } 43 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx1536m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # R8 Android code shrinker 15 | # android.enableR8=true 16 | android.useAndroidX=true 17 | android.enableJetifier=true 18 | 19 | # Custom Properties start 20 | tianma.keystore.path=/Users/tianma/Codes/Keystore/tianma.jks 21 | tianma.signature.path=/Users/tianma/Codes/Keystore/signature.properties 22 | # Custom Properties end 23 | 24 | android.enableResourceOptimizations=false 25 | 26 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/tianma8023/XposedSmsCode/7be0a27e9d171352f17edc6095929896797a7bd1/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Sat Aug 24 13:29:23 CST 2019 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-7.5-all.zip 7 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | set DIRNAME=%~dp0 12 | if "%DIRNAME%" == "" set DIRNAME=. 13 | set APP_BASE_NAME=%~n0 14 | set APP_HOME=%DIRNAME% 15 | 16 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 17 | set DEFAULT_JVM_OPTS= 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windows variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | 53 | :win9xME_args 54 | @rem Slurp the command line arguments. 55 | set CMD_LINE_ARGS= 56 | set _SKIP=2 57 | 58 | :win9xME_args_slurp 59 | if "x%~1" == "x" goto execute 60 | 61 | set CMD_LINE_ARGS=%* 62 | 63 | :execute 64 | @rem Setup the command line 65 | 66 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 67 | 68 | @rem Execute Gradle 69 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 70 | 71 | :end 72 | @rem End local scope for the variables with windows NT shell 73 | if "%ERRORLEVEL%"=="0" goto mainEnd 74 | 75 | :fail 76 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 77 | rem the _cmd.exe /c_ return code! 78 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 79 | exit /b 1 80 | 81 | :mainEnd 82 | if "%OS%"=="Windows_NT" endlocal 83 | 84 | :omega 85 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':app' 2 | --------------------------------------------------------------------------------