diff --git a/.github/FUNDING.yml b/.github/FUNDING.yml
new file mode 100644
index 00000000..b84ee7d2
--- /dev/null
+++ b/.github/FUNDING.yml
@@ -0,0 +1,3 @@
+# These are supported funding model platforms
+
+custom: https://gitee.com/pp/SmsForwarder/wikis/pages?sort_id=4912193&doc_id=1821427
diff --git a/.github/workflows/issue_check.yml b/.github/workflows/issue_check.yml
new file mode 100644
index 00000000..e36da2f4
--- /dev/null
+++ b/.github/workflows/issue_check.yml
@@ -0,0 +1,18 @@
+name: No Free usage issue checker # Action名字。可以自定义
+
+on:
+ issues:
+ types: [ opened, reopened ] # 在issue打开和重新打开时调用
+
+jobs:
+ build:
+ runs-on: ubuntu-latest
+
+ steps:
+ - uses: actions/checkout@v2
+ - name: Check issue actor # 步骤名字。可以自定义。
+ uses: fluttercandies/no-free-usage-action@v1.0.1
+ with:
+ token: ${{ secrets.GITHUB_TOKEN }} # 由GitHub提供的临时Token,必须在此处进行传递,且必须为这个值。
+ forked: '--no-forked'
+ words: To support our project, please file the issue after you starred the repo. Thanks! 🙂
diff --git a/.gitignore b/.gitignore
index 0c6511e8..bccd1136 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,10 +1,19 @@
-.idea/
-.gradle
-.git
-build
-local.properties
-gradle.properties
*.iml
+.gradle
+/LocalRepository
+/keystores
+/local.properties
+/.idea/caches
+/.idea/codeStyles
+/.idea/inspectionProfiles
+/.idea/libraries
+/.idea/dictionaries
+/.idea/markdown-navigator
+/.idea/*.xml
+.DS_Store
+/build
+/captures
+.externalNativeBuild
*.project
*/*.project
*.classpath
@@ -21,3 +30,7 @@ gradle.properties
*.bak
/pic/working_principle.drawio
/app/debug
+/.idea
+/app/mapping.txt
+/app/seeds.txt
+/app/unused.txt
diff --git a/.gitmodules b/.gitmodules
deleted file mode 100644
index f074c9fa..00000000
--- a/.gitmodules
+++ /dev/null
@@ -1,3 +0,0 @@
-[submodule "keystore"]
- path = keystore
- url = https://github.com/pppscn/keystore.git
diff --git a/PRIVACY b/PRIVACY
new file mode 100644
index 00000000..e1a86b9f
--- /dev/null
+++ b/PRIVACY
@@ -0,0 +1,25 @@
+BSD 2-Clause License
+
+Copyright (c) 2021, pppscn
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions are met:
+
+1. Redistributions of source code must retain the above copyright notice, this
+ list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
+OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/README.md b/README.md
index b1da7e58..f4db97ae 100644
--- a/README.md
+++ b/README.md
@@ -6,23 +6,19 @@
[![GitHub release](https://img.shields.io/github/release/pppscn/SmsForwarder.svg)](https://github.com/pppscn/SmsForwarder/releases) [![GitHub stars](https://img.shields.io/github/stars/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/stargazers) [![GitHub forks](https://img.shields.io/github/forks/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/network/members) [![GitHub issues](https://img.shields.io/github/issues/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/issues) [![GitHub license](https://img.shields.io/github/license/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/blob/main/LICENSE)
-短信转发器——监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。
+--------
-### 下载地址
+短信转发器——不仅只转发短信,备用机必备神器!
-> ⚠ 首发地址:https://github.com/pppscn/SmsForwarder/releases
+监控Android手机短信、来电、APP通知,并根据指定规则转发到其他手机:钉钉机器人、企业微信群机器人、飞书机器人、企业微信应用消息、邮箱、bark、webhook、Telegram机器人、Server酱、PushPlus、手机短信等。
-> ⚠ 国内镜像:https://gitee.com/pp/SmsForwarder/releases
+包括主动控制服务端与客户端,让你轻松远程发短信、查短信、查通话、查话簿、查电量等。(V3.0 新增)
-> ⚠ 网盘下载:https://wws.lanzoui.com/b025yl86h 访问密码:`pppscn`
+> 注意:从`2022-06-06`开始,原`Java版`的代码归档到`v2.x`分支,不再更新!
-> ⚠ 酷安应用市场:https://www.coolapk.com/apk/com.idormy.sms.forwarder
+> 1、从`v2.x`到`v3.x`不是简单的功能迭代,采用`kotlin`全新重构了(不是单纯的迁移代码,起初我也是这么认为的),由于我是第一次使用`kotlin`开发(Java版也是第一次),到处踩坑,每一行代码都是度娘手把手教会我的,所以`v3.x`版本可能一开始并不稳定。另外,眼睛葡萄膜炎还没好,晚上不敢肝,中间停摆了个把月,进度缓慢,历时2个月终于让`V3.x`顺产了!
-### 使用文档
-
-> ⚠ 首发地址:https://github.com/pppscn/SmsForwarder/wiki
-
-> ⚠ 国内镜像:https://gitee.com/pp/SmsForwarder/wikis/pages
+> 2、如果目前`v2.x`用的好好的没必要升级(之前也是这么建议大家的,没必要每版必跟,除非你急需新功能)
--------
@@ -38,75 +34,39 @@
--------
-## 特点和准则:
+## 工作流程:
-**简单** 只做两件事:监听手机短信/来电/APP通知 --> 根据指定规则转发
-
-由此带来的好处:
-
-* 简洁:(当时用Pad的时候,看手机验证码各种不方便,网上搜了好久也没有理想的解决方案)
- > + AirDroid:手机管理工具功能太多,看着都耗电,权限太多,数据经过三方,账号分级
- > + IFTTT:功能太多,看着耗电,权限太多,数据经过三方,收费
- > + 还有一些其他的APP(例如:Tasker)也是这些毛病
-* 省电:运行时只监听广播,有短信才执行转发,并记录最近n条的转发内容和转发状态
-* 健壮:越简单越不会出错(UNIX设计哲学),就越少崩溃,运行越稳定持久
-
-### 工作流程:
-
-![工作流程](pic/working_principle.png "工作流程")
-
-### 功能列表:
-
-- [x] 监听短信,按规则转发(规则:什么短信内容/来源转发到哪里)
-- [x] 转发到钉钉机器人(支持:单个钉钉群,@某人)
-- [x] 转发到邮箱(支持:SMTP)
-- [x] 转发到Bark(支持:验证码/动态密码自动复制)
-- [x] 转发到webhook(支持:单个web页面([向设置的url发送POST/GET请求](doc/POST_WEB.md)))
-- [x] 转发到企业微信群机器人
-- [x] 转发到企业微信应用消息
-- [x] 转发到ServerChan(Server酱·Turbo版)
-- [x] 转发到Telegram机器人(支持设置Socks5/Http代理、POST/GET、[CloudFlare反向代理](doc/TGBOT_cfwork_reverse_proxy.md))
-- [x] 转发到其他手机短信【注意:非免费的,转发短信运营商有收费的,建议没有网络时启用,并设置好内容过滤规则】
-- [x] 在线检测新版本、升级
-- [x] 清理缓存
-- [x] 兼容 Android 5.xx、6.xx、7.xx、8.xx、9.xx、10.xx、11.xx、12.xx
-- [x] 支持双卡手机,增加卡槽标识/运营商/手机号(如果能获取的话)
-- [x] 支持多重匹配规则
-- [x] 支持标注卡槽号码(优先使用)、设备信息;自定义转发信息模版
-- [x] 支持正则匹配规则
-- [x] 支持卡槽匹配规则
-- [x] 转发未接来电提醒(固定sim1卡发出提醒)
-- [x] 接口请求失败后延时重试5次(可配置间隔时间,成功一次则终止重试)
-- [x] 转发到飞书机器人
-- [x] 自定义 Scheme(forwarder://main)用于唤起App
-- [x] 电池电量、状态变化预警
-- [x] 多语言支持(目前:中文、英文)
-- [x] 增加配置导出导入功能(一键克隆)
-- [x] 监听其他APP通知信息并转发(可自动消除)
-- [x] 转发到PushPlus
-- [x] 转发规则上允许自定义模板(留空则取全局设置)
-- [x] 转发规则上支持配置正则替换内容
-- [x] 转发到 Gotify发送通道(自主推送通知服务)
-- [x] 被动接收本地 HttpServer
-- [x] 主动轮询远程 SmsHub Api(v2.5.0+已删除)
-- [x] 适配暗夜模式
+![工作流程](https://images.gitee.com/uploads/images/2022/0126/133916_ca965452_16273.png "working_principle.png")
--------
-### 应用截图:
+## 界面预览:
-| 前台服务常驻状态栏 | 应用主界面 | 发送通道 | 转发规则 |
-| :--: | :--: | :--: | :--: |
-| ![前台服务常驻状态栏](pic/taskbar.jpg "前台服务常驻状态栏") | ![应用主界面](pic/main.jpg "应用主界面") | ![发送通道](pic/sender.png "发送通道") | ![转发规则](pic/rule.jpg "转发规则") |
-| 转发规则--短信转发 | 转发规则--通话记录 | 转发规则--APP通知 | 转发日志详情 |
-| ![短信转发](pic/rule_sms.jpg "短信转发") | ![通话转发](pic/rule_call.jpg "通话转发") | ![通知转发](pic/rule_app.jpg "通知转发") | ![转发日志详情](pic/maindetail.jpg "转发日志详情") |
-| 设置界面--总开关 | 设置界面--电量监控&保活措施 | 设置界面--个性设置 | 一键克隆(配置导出导入) |
-| ![设置界面--总开关](pic/setting_1.jpg "设置界面--总开关") | ![设置界面--电量监控&保活措施](pic/setting_2.jpg "设置界面--电量监控&保活措施") | ![设置界面--个性设置](pic/setting_3.jpg "设置界面--个性设置") | ![配置导出导入功能(一键克隆)](pic/clone.jpg "配置导出导入功能(一键克隆)") |
+![界面预览](https://images.gitee.com/uploads/images/2022/0606/133422_808b4589_16273.png "界面预览.png")
更多截图参见 https://github.com/pppscn/SmsForwarder/wiki
--------
+## 下载地址
+
+> ⚠ 首发地址:https://github.com/pppscn/SmsForwarder/releases
+
+> ⚠ 国内镜像:https://gitee.com/pp/SmsForwarder/releases
+
+> ⚠ 网盘下载:https://wws.lanzoui.com/b025yl86h 访问密码:`pppscn`
+
+> ⚠ 酷安应用市场:https://www.coolapk.com/apk/com.idormy.sms.forwarder
+
+--------
+
+## 使用文档【新用户必看!】
+
+> ⚠ GitHub Wiki:https://github.com/pppscn/SmsForwarder/wiki
+
+> ⚠ Gitee Wiki:https://gitee.com/pp/SmsForwarder/wikis/pages
+--------
+
## 反馈与建议:
+ 提交issues 或 pr
@@ -116,18 +76,16 @@
| ---- | ---- | ---- | ---- |
| ![钉钉客户群](pic/dingtalk.png "钉钉客户群") | ![QQ交流群:562854376](pic/qqgroup_1.jpg "QQ交流群:562854376") | ![QQ交流群:31330492](pic/qqgroup_2.jpg "QQ交流群:31330492") | ![企业微信群](pic/qywechat.png "企业微信群") |
+PS.如果QQ群已满员,请看群简介加入其他群
+
## 感谢
> 本项目得到以下项目的支持与帮助,在此表示衷心的感谢!
-+ https://github.com/xiaoyuanhost/TranspondSms (基于此项目优化改造)
-+ https://github.com/square/okhttp (网络请求)
++ https://github.com/xiaoyuanhost/TranspondSms (项目原型)
++ https://github.com/xuexiangjys/XUI (UI框架)
+ https://github.com/xuexiangjys/XUpdateAPI (在线升级)
-+ https://github.com/mailhu/emailkit (邮件发送)
-+ https://github.com/alibaba/fastjson (Json解析)
+ https://github.com/getActivity/XXPermissions (权限请求框架)
-+ https://github.com/Xcreen/RestSMS (被动接收本地API方案)
-+ ~~https://github.com/juancrescente/SMSHub (主动轮询远程API方案,v2.5.0+删除)~~
+ https://github.com/mainfunx/frpc_android (内网穿透)
+ [](https://jb.gg/OpenSourceSupport) (License Certificate for JetBrains All Products Pack)
diff --git a/README_en.md b/README_en.md
index 91474ed4..372bd839 100644
--- a/README_en.md
+++ b/README_en.md
@@ -6,23 +6,13 @@
[![GitHub release](https://img.shields.io/github/release/pppscn/SmsForwarder.svg)](https://github.com/pppscn/SmsForwarder/releases) [![GitHub stars](https://img.shields.io/github/stars/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/stargazers) [![GitHub forks](https://img.shields.io/github/forks/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/network/members) [![GitHub issues](https://img.shields.io/github/issues/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/issues) [![GitHub license](https://img.shields.io/github/license/pppscn/SmsForwarder)](https://github.com/pppscn/SmsForwarder/blob/main/LICENSE)
-SmsForwarder - listens to SMS, incoming calls, and App notifications on Android mobile devices, and forward according to user defined rules to another App/device, including DingTalk, WeCom and WeCom Group Bot, Feishi Bot, E-mail, Bark, Webhook, Telegram Bot, ServerChan, PushPlus, SMS, etc.
+--------
-### Download
+SmsForwarder - Not only forwarding text messages, but also a must-have for backup devices!
-> ⚠ Repo address: https://github.com/pppscn/SmsForwarder/releases
+listens to SMS, incoming calls, and App notifications on Android mobile devices, and forward according to user defined rules to another App/device, including DingTalk, WeCom and WeCom Group Bot, Feishi Bot, E-mail, Bark, Webhook, Telegram Bot, ServerChan, PushPlus, SMS, etc.
-> ⚠ Repo mirror in China: https://gitee.com/pp/SmsForwarder/releases
-
-> ⚠ Internet storage: https://wws.lanzoui.com/b025yl86h, access password: `pppscn`
-
-> ⚠ CoolAPK.com: https://www.coolapk.com/apk/com.idormy.sms.forwarder
-
-### Manual
-
-> ⚠ GitHub: https://github.com/pppscn/SmsForwarder/wiki
-
-> ⚠ Gitee: https://gitee.com/pp/SmsForwarder/wikis/pages
+Including active control of the server and client, allowing you to easily and remotely send text messages, check text messages, check calls, check the phone book, check the battery, etc.
--------
@@ -38,74 +28,35 @@ SmsForwarder - listens to SMS, incoming calls, and App notifications on Android
--------
-## Features and standards
-
-**Simplicity** - `SmsForwarder` does two things only: Listen to "SMS service/Incoming calls/App notifications", and forward according to rules specified by user.
-
-Benefit by simplicity:
-
-* **E**fficient: (It's inconvenient to read the security codes such as OTP on a mobile phone, when you are using another device; and no solution satisfices our needs)
-
- > + AirDroid: Too many functionalities, power consuming, requiring to many permissions, data relayed by a 3rd party, paid premium service...
- > + IFTTT: Too many functionalities, power consuming, requiring to many permissions, data relayed by a 3rd party, paid premium service...
- > + And other Apps (e.g. Tasker) with similar features.
-
-* **E**nergy friendly: listens to broadcast only when running, and forwards message only when texts are received and logs recent forwarding contents and status.
-* **E**ndurance: "Simplicity is the Ultimate Sophistication." The simpler the code is, the less it errs or crashes; that is what make the app runs longer.
-
-### Workflow:
+## Workflow:
![Workflow](pic/working_principle_en.png "Workflow")
-### Features:
+--------
-- [x] Listen to SMS service, and forward according to user-defined rules (SMS contents to destination);
-- [x] Forward to DingTalk Bot (to a group chat and @SOMBODY);
-- [x] Forward to E-mail (SMTP with SSL encryption);
-- [x] Forward to Bark;
-- [x] Forward to webhook (a single web page [sending POST/GET requests to a designated URL](doc/POST_WEB.md));
-- [x] Forward to WeCom Bots;
-- [x] Forward to WeCom enterprise channels;
-- [x] Forward to ServerChan·Turbo;
-- [x] Forward to Telegram Bots (Proxy support ready);
-- [x] Forward to another mobile phone via SMS [Note: Paid service, carriers may charge for SMS forwarding. SMS forwarding should apply with filtered rules when device has no Internet access.]
-- [x] Check for new version and upgrade;
-- [x] Cache purge;
-- [x] Compatible with Android 5.xx, 6.xx, 7.xx, 8.xx, 9.xx, and 10.xx;
-- [x] Support for dual SIM slots smartphones and label different slots/carrier/phone number (if available);
-- [x] Support for multi-level rules;
-- [x] Support for customized labeling of SIM slots and device, and customized forwarding templates;
-- [x] Support for rules with regular expression
-- [x] Support for rules for different SIM slots;
-- [x] Forward missed call information (forwarded by SIM1 slot by default);
-- [x] Retry 5 times after a failed request (customized interval time, stop retrying once successfully request);
-- [x] Forward to FeiShu Bot;
-- [x] Customized scheme (forwarder://main) wake up other Apps;
-- [x] Monitor of battery status changes;
-- [x] I18n support (Chinese and English currently);
-- [x] Support for setting import and export functions (One-key cloning);
-- [x] Listen to notifications of other Apps and forward;
-- [x] Forward to PushPlus;
-- [x] Support for customized template of forwarding rules (default template overrides if left blank);
-- [x] Support for variables in regular expression of forwarding rules;
-- [x] 转发到 Gotify发送通道(自主推送通知服务)
-- [x] 被动接收本地 HttpServer
-- [x] 主动轮询远程 SmsHub Api(v2.5.0+已删除)
-- [x] 适配暗夜模式
+## Screenshots :
+
+![界面预览](https://images.gitee.com/uploads/images/2022/0606/133422_808b4589_16273.png "界面预览.png")
+
+See more screenshots:https://github.com/pppscn/SmsForwarder/wiki
--------
-### Screenshots :
+## Download
-| 前台服务常驻状态栏 | 应用主界面 | 发送通道 | 转发规则 |
-| :--: | :--: | :--: | :--: |
-| ![前台服务常驻状态栏](pic/taskbar.jpg "前台服务常驻状态栏") | ![应用主界面](pic/main.jpg "应用主界面") | ![发送通道](pic/sender.png "发送通道") | ![转发规则](pic/rule.jpg "转发规则") |
-| 转发规则--短信转发 | 转发规则--通话记录 | 转发规则--APP通知 | 转发日志详情 |
-| ![短信转发](pic/rule_sms.jpg "短信转发") | ![通话转发](pic/rule_call.jpg "通话转发") | ![通知转发](pic/rule_app.jpg "通知转发") | ![转发日志详情](pic/maindetail.jpg "转发日志详情") |
-| 设置界面--总开关 | 设置界面--电量监控&保活措施 | 设置界面--个性设置 | 一键克隆(配置导出导入) |
-| ![设置界面--总开关](pic/setting_1.jpg "设置界面--总开关") | ![设置界面--电量监控&保活措施](pic/setting_2.jpg "设置界面--电量监控&保活措施") | ![设置界面--个性设置](pic/setting_3.jpg "设置界面--个性设置") | ![配置导出导入功能(一键克隆)](pic/clone.jpg "配置导出导入功能(一键克隆)") |
+> ⚠ Repo address: https://github.com/pppscn/SmsForwarder/releases
-更多截图参见 https://github.com/pppscn/SmsForwarder/wiki
+> ⚠ Repo mirror in China: https://gitee.com/pp/SmsForwarder/releases
+
+> ⚠ Internet storage: https://wws.lanzoui.com/b025yl86h, access password: `pppscn`
+
+> ⚠ CoolAPK.com: https://www.coolapk.com/apk/com.idormy.sms.forwarder
+
+## Manual
+
+> ⚠ GitHub: https://github.com/pppscn/SmsForwarder/wiki
+
+> ⚠ Gitee: https://gitee.com/pp/SmsForwarder/wikis/pages
--------
@@ -118,18 +69,16 @@ Benefit by simplicity:
| ---- | ---- | ---- | ---- |
| ![钉钉客户群](pic/dingtalk.png "钉钉客户群") | ![QQ交流群:562854376](pic/qqgroup_1.jpg "QQ交流群:562854376") | ![QQ交流群:31330492](pic/qqgroup_2.jpg "QQ交流群:31330492") | ![企业微信群](pic/qywechat.png "企业微信群") |
+PS.If the QQ group is full, please see the group introduction to join other groups
+
## Acknowledgements
> Thanks to the projects below, `SmsForwarder` won't exists without them!
+ https://github.com/xiaoyuanhost/TranspondSms (Foundation of `SmsForwarder`)
-+ https://github.com/square/okhttp (http communications)
++ https://github.com/xuexiangjys/XUI (UI Framework)
+ https://github.com/xuexiangjys/XUpdateAPI (online update)
-+ https://github.com/mailhu/emailkit (email sending)
-+ https://github.com/alibaba/fastjson (json parsing)
+ https://github.com/getActivity/XXPermissions (permission requiring)
-+ https://github.com/Xcreen/RestSMS(被动接收本地API方案)
-+ ~~https://github.com/juancrescente/SMSHub(主动轮询远程API方案,v2.5.0+删除)~~
+ https://github.com/mainfunx/frpc_android (内网穿透)
+ [](https://jb.gg/OpenSourceSupport) (License Certificate for JetBrains All Products Pack)
diff --git a/_config.yml b/_config.yml
deleted file mode 100644
index c4192631..00000000
--- a/_config.yml
+++ /dev/null
@@ -1 +0,0 @@
-theme: jekyll-theme-cayman
\ No newline at end of file
diff --git a/app/.gitignore b/app/.gitignore
new file mode 100644
index 00000000..796b96d1
--- /dev/null
+++ b/app/.gitignore
@@ -0,0 +1 @@
+/build
diff --git a/app/build.gradle b/app/build.gradle
index f2b6276b..78e5b5fb 100644
--- a/app/build.gradle
+++ b/app/build.gradle
@@ -1,4 +1,11 @@
-apply plugin: 'com.android.application'
+plugins {
+ id 'com.android.application'
+ id 'kotlin-android'
+ id 'kotlin-kapt'
+ id 'kotlin-parcelize'
+ id 'img-optimizer'
+ id 'com.yanzhenjie.andserver'
+}
def keyProps = new Properties()
def keyPropsFile = rootProject.file('keystore/keystore.properties')
@@ -6,32 +13,47 @@ if (keyPropsFile.exists()) {
keyProps.load(new FileInputStream(keyPropsFile))
}
-// 读取version.properties
-def versionProps = new Properties()
-def versionPropsFile = rootProject.file('version.properties')
-if (versionPropsFile.exists()) {
- versionProps.load(new FileInputStream(versionPropsFile))
+//打包时,记得设置true启用
+if (isNeedPackage.toBoolean() && isUseBooster.toBoolean()) {
+ apply plugin: 'com.didiglobal.booster'
}
android {
//noinspection GradleDependency
- buildToolsVersion '32.0.0'
- compileSdkVersion 32
+ buildToolsVersion build_versions.build_tools
+ compileSdkVersion build_versions.target_sdk
+
compileOptions {
- sourceCompatibility 11
- targetCompatibility 11
+ sourceCompatibility JavaVersion.VERSION_1_8
+ targetCompatibility JavaVersion.VERSION_1_8
}
+
+ buildFeatures {
+ viewBinding true
+ }
+
defaultConfig {
applicationId "com.idormy.sms.forwarder"
- minSdkVersion 21
- targetSdkVersion 32
- versionCode versionProps['versionCode'].toInteger()
- versionName versionProps['versionName']
- testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
+ minSdkVersion build_versions.min_sdk
+ targetSdkVersion build_versions.target_sdk
+ versionCode build_versions.version_code
+ versionName build_versions.version_name
+ testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
+
+ multiDexEnabled true
+ vectorDrawables.useSupportLibrary = true
+
+ javaCompileOptions {
+ annotationProcessorOptions {
+ arguments = [moduleName: project.getName()]
+ }
+ }
+
ndk {
- abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86'//, 'x86_64'
+ abiFilters 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
}
}
+
signingConfigs {
release {
keyAlias keyProps['keyAlias']
@@ -46,31 +68,81 @@ android {
storePassword keyProps['storePassword']
}
}
+
buildTypes {
release {
- minifyEnabled false
- //shrinkResources true
+ minifyEnabled true
+ shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- signingConfig signingConfigs.release
+ if (isNeedPackage.toBoolean()) {
+ signingConfig signingConfigs.release
+ if (file('local.properties').exists()) {
+ Properties properties = new Properties()
+ properties.load(project.rootProject.file('local.properties').newDataInputStream())
+ def appID = properties.getProperty("APP_ID_UMENG")
+ if (appID != null) {
+ buildConfigField "String", "APP_ID_UMENG", appID
+ } else {
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }
+ } else {
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }
+ } else {
+ signingConfig signingConfigs.debug
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }
}
debug {
- minifyEnabled false
- //shrinkResources true
+ minifyEnabled true
+ shrinkResources true
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
- signingConfig signingConfigs.debug
+ if (isNeedPackage.toBoolean()) {
+ signingConfig signingConfigs.release
+ if (file('local.properties').exists()) {
+ Properties properties = new Properties()
+ properties.load(project.rootProject.file('local.properties').newDataInputStream())
+ def appID = properties.getProperty("APP_ID_UMENG")
+ if (appID != null) {
+ buildConfigField "String", "APP_ID_UMENG", appID
+ } else {
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }
+ } else {
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }
+ } else {
+ signingConfig signingConfigs.debug
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }
}
+ /*debug {
+ debuggable true
+ minifyEnabled false
+
+ signingConfig signingConfigs.debug
+ buildConfigField "String", "APP_ID_UMENG", '"60254fc7425ec25f10f4293e"'
+ }*/
}
+
//ABI配置——按CPU架构分别打包
splits {
abi {
enable true
reset()
- include 'armeabi-v7a', 'arm64-v8a', 'x86'//, 'x86_64'
+ include 'armeabi-v7a', 'arm64-v8a', 'x86', 'x86_64'
universalApk true
}
}
def abiCodes = ['universal': 1, 'armeabi-v7a': 2, 'arm64-v8a': 3, 'x86': 4, 'x86_64': 5]
packagingOptions {
+ //去除FrpcLib的so,用时下载并动态加载
+ if (isNeedPackage.toBoolean()) {
+ exclude 'lib/armeabi-v7a/libgojni.so'
+ exclude 'lib/arm64-v8a/libgojni.so'
+ exclude 'lib/x86/libgojni.so'
+ exclude 'lib/x86_64/libgojni.so'
+ }
resources {
pickFirst 'META-INF/LICENSE.md'
pickFirst 'META-INF/NOTICE.md'
@@ -82,6 +154,7 @@ android {
variant.outputs.each {
output ->
def date = new Date().format("yyyyMMdd", TimeZone.getTimeZone("GMT+08"))
+ //noinspection GrDeprecatedAPIUsage
def abiName = output.getFilter(com.android.build.OutputFile.ABI)
if (abiName == null) abiName = "universal"
output.versionCodeOverride = abiCodes.get(abiName, 0) * 100000 + variant.versionCode
@@ -89,8 +162,8 @@ android {
}
}
- lint {
- checkReleaseBuilds false
+ lintOptions {
+ abortOnError false
}
sourceSets {
@@ -101,110 +174,97 @@ android {
}
-
-task upgradeVersion {
- group 'help'
- description '构建新版本'
- doLast {
- println("---自动升级版本号---\n")
- String oldVersionCode = versionProps['versionCode']
- String oldVersionName = versionProps['versionName']
- if (oldVersionCode == null || oldVersionName == null ||
- oldVersionCode.isEmpty() || oldVersionName.isEmpty()) {
- println("error:版本号不能为空")
- return
- }
- versionProps['versionCode'] = String.valueOf(versionProps['versionCode'].toInteger() + 1)
- String str = versionProps['versionName'].toString()
- versionProps['versionName'] = str.substring(0, str.lastIndexOf('.') + 1) +
- (str.substring(str.lastIndexOf('.') + 1).toInteger() + 1)
- String tip =
- "版本号从$oldVersionName($oldVersionCode)升级到${versionProps['versionName']}(${versionProps['versionCode']})"
- println(tip)
-
- def writer = new FileWriter(versionPropsFile)
- versionProps.store(writer, null)
- writer.flush()
- writer.close()
- def tag = "v${versionProps['versionName']}"
- cmdExecute("git pull")
- cmdExecute("git add version.properties")
- cmdExecute("git commit -m \"版本号升级为:$tag\"")
- cmdExecute("git push origin")
- cmdExecute("git tag $tag")
- cmdExecute("git push origin $tag")
- }
-}
-
-void cmdExecute(String cmd) {
- println "\n执行$cmd"
- println cmd.execute().text
-}
-
dependencies {
- implementation fileTree(include: ['*.jar'], dir: 'libs')
- //noinspection GradleDependency
- implementation 'androidx.appcompat:appcompat:1.4.1'
- implementation 'androidx.constraintlayout:constraintlayout:2.1.3'
- implementation 'com.google.android.material:material:1.5.0'
- testImplementation 'junit:junit:4.13.2'
- androidTestImplementation 'androidx.test.ext:junit:1.1.3'
- androidTestImplementation 'androidx.test.espresso:espresso-core:3.4.0'
-
- //okhttp
- //noinspection GradleDependency
- implementation 'com.squareup.okhttp3:okhttp:4.9.3'
- implementation 'com.squareup.okio:okio:3.0.0'
-
- //fastjson
- implementation "com.alibaba:fastjson:1.2.80"
-
- //XUpdate
- implementation 'com.github.xuexiangjys:XUpdate:2.1.1'
- implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-easy:1.0.1'
- implementation 'com.github.xuexiangjys.XUpdateAPI:xupdate-downloader-aria:1.0.1'
-
- //EmailKit
- implementation 'com.github.mailhu:emailkit:4.2.2'
- implementation 'com.sun.mail:android-mail:1.6.7'
- implementation 'com.sun.mail:android-activation:1.6.7'
-
- //Lombok
- //noinspection AnnotationProcessorOnCompilePath
- compileOnly 'org.projectlombok:lombok:1.18.22'
- annotationProcessor 'org.projectlombok:lombok:1.18.22'
-
- //RxJava
- //implementation 'io.reactivex.rxjava3:rxjava:3.1.3'
-
- //AndroidAsync
- implementation 'com.koushikdutta.async:androidasync:3.1.0'
-
- //吐司框架:https://github.com/getActivity/ToastUtils
- implementation 'com.github.getActivity:ToastUtils:10.3'
- //权限请求框架:https://github.com/getActivity/XXPermissions
- implementation 'com.github.getActivity:XXPermissions:13.2'
-
- //jetty
- def jetty_version = '9.2.30.v20200428'
- //noinspection GradleDependency
- implementation "org.eclipse.jetty:jetty-server:$jetty_version"
- //noinspection GradleDependency
- implementation "org.eclipse.jetty:jetty-servlet:$jetty_version"
-
- //友盟统计SDK
- implementation 'com.umeng.umsdk:common:9.4.7'// (必选)
- implementation 'com.umeng.umsdk:asms:1.6.0'// 必选
-
+ implementation fileTree(dir: 'libs', include: ['*.jar'])
//frpc
- //implementation(name: 'frpclib', ext: 'aar')
implementation files('libs/frpclib.aar')
- implementation 'io.github.jeremyliao:live-event-bus-x:1.8.0'
- implementation 'io.reactivex.rxjava2:rxandroid:2.1.1'
- implementation 'io.reactivex.rxjava2:rxjava:2.2.21'
- def room_version = "2.4.2"
+ testImplementation deps.junit
+ androidTestImplementation 'androidx.test.ext:junit:1.1.3'
+ androidTestImplementation deps.espresso.core
+
+ implementation 'androidx.core:core-ktx:1.8.0'
+ implementation "androidx.activity:activity-ktx:1.4.0"
+ implementation "androidx.fragment:fragment-ktx:1.4.1"
+ implementation "androidx.cardview:cardview:1.0.0"
+ implementation 'androidx.appcompat:appcompat:1.4.2'
+ implementation 'androidx.preference:preference-ktx:1.2.0'
+
+ //分包
+ implementation deps.androidx.multidex
+
+ implementation 'com.alibaba.android:vlayout:1.3.0'
+ //下拉刷新
+ implementation 'com.github.xuexiangjys.SmartRefreshLayout:refresh-header:1.1.5'
+ implementation 'com.github.xuexiangjys.SmartRefreshLayout:refresh-layout:1.1.5'
+ //WebView
+ implementation 'com.github.xuexiangjys.AgentWeb:agentweb-core:1.0.0'
+ implementation 'com.github.xuexiangjys.AgentWeb:agentweb-download:1.0.0'//选填
+ //腾讯的键值对存储mmkv
+ implementation 'com.tencent:mmkv:1.2.13'
+ //屏幕适配AutoSize
+ implementation 'me.jessyan:autosize:1.2.1'
+ //umeng统计
+ implementation 'com.umeng.umsdk:common:9.5.0'
+ implementation 'com.umeng.umsdk:asms:1.6.3'
+
+ //预加载占位控件
+ implementation 'me.samlss:broccoli:1.0.0'
+
+ implementation 'com.zzhoujay.richtext:richtext:3.0.8'
+ implementation 'com.squareup.retrofit2:retrofit:2.9.0'
+
+ //ANR异常捕获
+ implementation 'com.github.anrwatchdog:anrwatchdog:1.4.0'
+
+ //美团多渠道打包
+ implementation 'com.meituan.android.walle:library:1.1.6'
+
+ api("androidx.work:work-multiprocess:2.7.1")
+ api("androidx.work:work-runtime-ktx:2.7.1")
+
+ //Android Room
+ def room_version = '2.4.2'
+ implementation "androidx.room:room-ktx:$room_version"
implementation "androidx.room:room-runtime:$room_version"
- annotationProcessor "androidx.room:room-compiler:$room_version"
+ implementation "androidx.room:room-paging:$room_version"
implementation "androidx.room:room-rxjava2:$room_version"
-}
\ No newline at end of file
+ kapt "androidx.room:room-compiler:$room_version"
+
+ implementation 'com.github.AmrDeveloper:CodeView:1.3.4'
+ implementation 'io.github.jeremyliao:live-event-bus-x:1.8.0'
+
+ implementation 'com.github.tiagohm.MarkdownView:library:0.19.0'
+ implementation 'com.github.tiagohm.MarkdownView:emoji:0.19.0'
+
+ def retrofit2_version = '2.9.0'
+ implementation "com.squareup.retrofit2:retrofit:$retrofit2_version"
+ implementation "com.squareup.retrofit2:converter-gson:$retrofit2_version"
+ implementation "com.squareup.retrofit2:adapter-rxjava2:$retrofit2_version"
+
+ def paging_version = "3.1.1"
+ implementation "androidx.paging:paging-runtime-ktx:$paging_version"
+ // alternatively - without Android dependencies for tests
+ testImplementation "androidx.paging:paging-common-ktx:$paging_version"
+
+ //权限请求框架:https://github.com/getActivity/XXPermissions
+ implementation 'com.github.getActivity:XXPermissions:13.6'
+
+ def mail_version = '1.6.7'
+ implementation "com.sun.mail:android-mail:$mail_version"
+ implementation "com.sun.mail:android-activation:$mail_version"
+
+ //Android Keep Alive(安卓保活),Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
+ //https://github.com/gyf-dev/Cactus
+ implementation 'com.gyf.cactus:cactus:1.1.3-beta13'
+
+ //HTTP服务器:https://github.com/yanzhenjie/AndServer
+ implementation 'com.yanzhenjie.andserver:api:2.1.10'
+ kapt 'com.yanzhenjie.andserver:processor:2.1.10'
+}
+//自动添加X-Library依赖
+apply from: 'x-library.gradle'
+//walle多渠道打包
+apply from: 'multiple-channel.gradle'
+
+
diff --git a/app/channel b/app/channel
new file mode 100644
index 00000000..10c8afd1
--- /dev/null
+++ b/app/channel
@@ -0,0 +1,25 @@
+# 美团
+meituan
+# 三星
+samsungapps
+# 小米
+xiaomi
+# 91助手
+91com
+# 魅族
+meizu
+# 豌豆荚
+wandou
+# Google Play
+googleplay
+# 百度
+baidu
+# 360
+360cn
+# 应用宝
+myapp
+# 华为
+huawei
+# 蒲公英
+pgyer
+github
\ No newline at end of file
diff --git a/app/libs/frpclib-sources.jar b/app/libs/frpclib-sources.jar
index 4d6800cc..68d672b9 100644
Binary files a/app/libs/frpclib-sources.jar and b/app/libs/frpclib-sources.jar differ
diff --git a/app/libs/frpclib.aar b/app/libs/frpclib.aar
index fc6dd286..a3eaa0e8 100644
Binary files a/app/libs/frpclib.aar and b/app/libs/frpclib.aar differ
diff --git a/app/lint.xml b/app/lint.xml
new file mode 100644
index 00000000..04f82282
--- /dev/null
+++ b/app/lint.xml
@@ -0,0 +1,9 @@
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/multiple-channel.gradle b/app/multiple-channel.gradle
new file mode 100644
index 00000000..5dc6dbf1
--- /dev/null
+++ b/app/multiple-channel.gradle
@@ -0,0 +1,10 @@
+apply plugin: 'walle'
+
+walle {
+ // 指定渠道包的输出路径
+ apkOutputFolder = new File("${project.buildDir}/outputs/channels")
+ // 定制渠道包的APK的文件名称
+ apkFileNameFormat = '${appName}-${packageName}-${channel}-${buildType}-v${versionName}-${versionCode}-${buildTime}.apk'
+ // 渠道配置文件
+ channelFile = new File("${project.getProjectDir()}/channel")
+}
\ No newline at end of file
diff --git a/app/proguard-rules.pro b/app/proguard-rules.pro
index 110d973b..d2a696ec 100644
--- a/app/proguard-rules.pro
+++ b/app/proguard-rules.pro
@@ -1,28 +1,283 @@
-# Add project specific ProGuard rules here.
-# You can control the set of applied configuration files using the
-# proguardFiles setting in build.gradle.
-#
-# For more details, see
-# http://developer.android.com/guide/developing/tools/proguard.html
+#=========================================基础不变的混淆配置=========================================##
+#指定代码的压缩级别
+-optimizationpasses 5
+#包名不混合大小写
+-dontusemixedcaseclassnames
+#不去忽略非公共的库类
+-dontskipnonpubliclibraryclasses
+# 指定不去忽略非公共的库的类的成员
+-dontskipnonpubliclibraryclassmembers
+#优化 不优化输入的类文件
+-dontoptimize
+#预校验
+-dontpreverify
+#混淆时是否记录日志
+-verbose
+# 混淆时所采用的算法
+-optimizations !code/simplification/arithmetic,!field/*,!class/merging/*
+#保护注解
+-keepattributes *Annotation*
+#忽略警告
+-ignorewarnings
-# If your project uses WebView with JS, uncomment the following
-# and specify the fully qualified class name to the JavaScript interface
-# class:
-#-keepclassmembers class fqcn.of.javascript.interface.for.webview {
-# public *;
+##记录生成的日志数据,gradle build时在本项目根目录输出##
+#apk 包内所有 class 的内部结构
+-dump class_files.txt
+#未混淆的类和成员
+-printseeds seeds.txt
+#列出从 apk 中删除的代码
+-printusage unused.txt
+#混淆前后的映射
+-printmapping mapping.txt
+# 并保留源文件名为"Proguard"字符串,而非原始的类名 并保留行号
+-keepattributes SourceFile,LineNumberTable
+########记录生成的日志数据,gradle build时 在本项目根目录输出-end#####
+
+#需要保留的东西
+# 保持哪些类不被混淆
+-keep public class * extends android.app.Fragment
+-keep public class * extends android.app.Activity
+-keep public class * extends android.app.Application
+-keep public class * extends android.app.Service
+-keep public class * extends android.content.BroadcastReceiver
+-keep public class * extends android.content.ContentProvider
+-keep public class * extends android.app.backup.BackupAgentHelper
+-keep public class * extends android.preference.Preference
+-keep public class * extends android.support.v4.**
+#-keep public class com.android.vending.licensing.ILicensingService
+
+#如果有引用v4包可以添加下面这行
+#-keep public class * extends android.support.v4.app.Fragment
+
+##########JS接口类不混淆,否则执行不了
+-dontwarn com.android.JsInterface.**
+-keep class com.android.JsInterface.** {*; }
+
+#极光推送和百度lbs android sdk一起使用proguard 混淆的问题#http的类被混淆后,导致apk定位失败,保持apache 的http类不被混淆就好了
+-dontwarn org.apache.**
+-keep class org.apache.**{ *; }
+
+-keep public class * extends android.view.View {
+ public (android.content.Context);
+ public (android.content.Context, android.util.AttributeSet);
+ public (android.content.Context, android.util.AttributeSet, int);
+ public void set*(...);
+ }
+
+#保持 native 方法不被混淆
+-keepclasseswithmembernames class * {
+ native ;
+}
+
+#保持自定义控件类不被混淆
+-keepclasseswithmembers class * {
+ public (android.content.Context, android.util.AttributeSet);
+}
+
+#保持自定义控件类不被混淆
+-keepclassmembers class * extends android.app.Activity {
+ public void *(android.view.View);
+}
+
+#保持 Parcelable 不被混淆
+-keep class * implements android.os.Parcelable {
+ public static final android.os.Parcelable$Creator *;
+}
+
+#保持 Serializable 不被混淆
+-keepnames class * implements java.io.Serializable
+
+#保持 Serializable 不被混淆并且enum 类也不被混淆
+-keepclassmembers class * implements java.io.Serializable {
+ static final long serialVersionUID;
+ private static final java.io.ObjectStreamField[] serialPersistentFields;
+ !static !transient ;
+ !private ;
+ !private ;
+ private void writeObject(java.io.ObjectOutputStream);
+ private void readObject(java.io.ObjectInputStream);
+ java.lang.Object writeReplace();
+ java.lang.Object readResolve();
+}
+
+#保持枚举 enum 类不被混淆 如果混淆报错,建议直接使用上面的 -keepclassmembers class * implements java.io.Serializable即可
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keepclassmembers class * {
+ public void *ButtonClicked(android.view.View);
+}
+
+#不混淆资源类
+-keep class **.R$* {*;}
+
+#===================================混淆保护自己项目的部分代码以及引用的第三方jar包library=============================#######
+#如果引用了v4或者v7包
+-dontwarn android.support.**
+
+
+# AndroidX 防止混淆
+-dontwarn com.google.android.material.**
+-dontnote com.google.android.material.**
+-dontwarn androidx.**
+-keep class com.google.android.material.** {*;}
+-keep class androidx.** {*;}
+-keep public class * extends androidx.**
+-keep interface androidx.** {*;}
+-keepclassmembers class * {
+ @androidx.annotation.Keep *;
+}
+
+# zxing
+-dontwarn com.google.zxing.**
+-keep class com.google.zxing.**{*;}
+
+#SignalR推送
+-keep class microsoft.aspnet.signalr.** { *; }
+
+# 极光推送混淆
+-dontoptimize
+-dontpreverify
+-dontwarn cn.jpush.**
+-keep class cn.jpush.** { *; }
+-dontwarn cn.jiguang.**
+-keep class cn.jiguang.** { *; }
+
+# 数据库框架OrmLite
+-keepattributes *DatabaseField*
+-keepattributes *DatabaseTable*
+-keepattributes *SerializedName*
+-keep class com.j256.**
+-keepclassmembers class com.j256.** { *; }
+-keep enum com.j256.**
+-keepclassmembers enum com.j256.** { *; }
+-keep interface com.j256.**
+-keepclassmembers interface com.j256.** { *; }
+
+#XHttp2
+-keep class com.xuexiang.xhttp2.model.** { *; }
+-keep class com.xuexiang.xhttp2.cache.model.** { *; }
+-keep class com.xuexiang.xhttp2.cache.stategy.**{*;}
+-keep class com.xuexiang.xhttp2.annotation.** { *; }
+
+#okhttp
+-dontwarn com.squareup.okhttp3.**
+-keep class com.squareup.okhttp3.** { *;}
+-dontwarn okio.**
+-dontwarn javax.annotation.Nullable
+-dontwarn javax.annotation.ParametersAreNonnullByDefault
+-dontwarn javax.annotation.**
+
+#如果用到Gson解析包的,直接添加下面这几行就能成功混淆,不然会报错
+-keepattributes Signature
+-keep class com.google.gson.stream.** { *; }
+-keepattributes EnclosingMethod
+-keep class org.xz_sale.entity.**{*;}
+-keep class com.google.gson.** {*;}
+-keep class com.google.**{*;}
+#-keep class sun.misc.Unsafe { *; }
+-keep class com.google.gson.stream.** { *; }
+-keep class com.google.gson.examples.android.model.** { *; }
+
+# Glide
+-keep public class * implements com.bumptech.glide.module.GlideModule
+-keep public class * extends com.bumptech.glide.module.AppGlideModule
+-keep public enum com.bumptech.glide.load.ImageHeaderParser$** {
+ **[] $VALUES;
+ public *;
+}
+
+# Retrofit
+-dontwarn retrofit2.**
+-keep class retrofit2.** { *; }
+-keepattributes Exceptions
+
+# RxJava RxAndroid
+-dontwarn sun.misc.**
+-keepclassmembers class rx.internal.util.unsafe.*ArrayQueue*Field* {
+ long producerIndex;
+ long consumerIndex;
+}
+#-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueProducerNodeRef {
+# rx.internal.util.atomic.LinkedQueueNode producerNode;
+#}
+#-keepclassmembers class rx.internal.util.unsafe.BaseLinkedQueueConsumerNodeRef {
+# rx.internal.util.atomic.LinkedQueueNode consumerNode;
#}
-# Uncomment this to preserve the line number information for
-# debugging stack traces.
-#-keepattributes SourceFile,LineNumberTable
+-dontwarn okio.**
+-dontwarn javax.annotation.Nullable
+-dontwarn javax.annotation.ParametersAreNonnullByDefault
+-dontwarn javax.annotation.**
-# If you keep the line number information, uncomment this to
-# hide the original source file name.
-#-renamesourcefileattribute SourceFile
+# fastjson
+-dontwarn com.alibaba.fastjson.**
+-keep class com.alibaba.fastjson.** { *; }
+-keepattributes Signature
--keep class com.idormy.**{*;}
+# xpage
+-keep class com.xuexiang.xpage.annotation.** { *; }
+-keep class com.xuexiang.xpage.config.** { *; }
-#emailkit
+# xaop
+-keep @com.xuexiang.xaop.annotation.* class * {*;}
+-keep @org.aspectj.lang.annotation.* class * {*;}
+-keep class * {
+ @com.xuexiang.xaop.annotation.* ;
+ @org.aspectj.lang.annotation.* ;
+}
+-keepclassmembers class * {
+ @com.xuexiang.xaop.annotation.* ;
+ @org.aspectj.lang.annotation.* ;
+}
+
+# xrouter
+-keep public class com.xuexiang.xrouter.routes.**{*;}
+-keep class * implements com.xuexiang.xrouter.facade.template.ISyringe{*;}
+# 如果使用了 byType 的方式获取 Service,需添加下面规则,保护接口
+-keep interface * implements com.xuexiang.xrouter.facade.template.IProvider
+# 如果使用了 单类注入,即不定义接口实现 IProvider,需添加下面规则,保护实现
+-keep class * implements com.xuexiang.xrouter.facade.template.IProvider
+
+# xupdate
+-keep class com.xuexiang.xupdate.entity.** { *; }
+
+# xvideo
+-keep class com.xuexiang.xvideo.jniinterface.** { *; }
+
+# xipc
+-keep @com.xuexiang.xipc.annotation.* class * {*;}
+-keep class * {
+ @com.xuexiang.xipc.annotation.* ;
+}
+-keepclassmembers class * {
+ @com.xuexiang.xipc.annotation.* ;
+}
+
+# umeng统计
+-keep class com.umeng.** {*;}
+-keepclassmembers class * {
+ public (org.json.JSONObject);
+}
+-keepclassmembers enum * {
+ public static **[] values();
+ public static ** valueOf(java.lang.String);
+}
+
+-keep class com.xuexiang.xui.widget.edittext.materialedittext.** { *; }
+
+# Android Keep Alive(安卓保活),Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
+-keep class com.gyf.cactus.entity.* {*;}
+
+# 排除实体类
+-keep class com.idormy.sms.forwarder.core.http.entity.** {*;}
+-keep class com.idormy.sms.forwarder.database.entity.** {*;}
+-keep class com.idormy.sms.forwarder.entity.** {*;}
+-keep class com.idormy.sms.forwarder.server.model.** {*;}
+
+# javax.mail
-dontwarn com.sun.**
-dontwarn javax.mail.**
-dontwarn javax.activation.**
@@ -30,48 +285,4 @@
-keep class javax.mail.** { *;}
-keep class javax.activation.** { *;}
-keep class com.smailnet.emailkit.** { *;}
-
-#xupdate
--keep class com.xuexiang.xupdate.entity.** { *; }
--dontwarn com.arialyy.aria.**
--keep class com.arialyy.aria.**{*;}
--keep class **$$DownloadListenerProxy{ *; }
--keep class **$$UploadListenerProxy{ *; }
--keep class **$$DownloadGroupListenerProxy{ *; }
--keep class **$$DGSubListenerProxy{ *; }
--keepclasseswithmembernames class * {
- @Download.* ;
- @Upload.* ;
- @DownloadGroup.* ;
-}
-
-#友盟统计SDK
--dontwarn com.umeng.**
--dontwarn com.taobao.**
--dontwarn anet.channel.**
--dontwarn anetwork.channel.**
--dontwarn org.android.**
--dontwarn org.apache.thrift.**
--dontwarn com.xiaomi.**
--dontwarn com.huawei.**
--dontwarn com.meizu.**
-
--keepattributes *Annotation*
-
--keep class com.taobao.** {*;}
--keep class org.android.** {*;}
--keep class anet.channel.** {*;}
--keep class com.umeng.** {*;}
--keep class com.xiaomi.** {*;}
--keep class com.huawei.** {*;}
--keep class com.meizu.** {*;}
--keep class org.apache.thrift.** {*;}
-
--keep class com.alibaba.sdk.android.** {*;}
--keep class com.ut.** {*;}
--keep class com.uc.** {*;}
--keep class com.ta.** {*;}
-
--keep public class **.R$* {
- public static final int *;
-}
\ No newline at end of file
+-keep class com.idormy.sms.forwarder.utils.mail.** {*;}
\ No newline at end of file
diff --git a/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt b/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt
index f6b7d657..02b5e3a6 100644
--- a/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt
+++ b/app/src/androidTest/java/com/idormy/sms/forwarder/ExampleInstrumentedTest.kt
@@ -1,15 +1,32 @@
+/*
+ * Copyright (C) 2022 xuexiangjys(xuexiangjys@163.com)
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
package com.idormy.sms.forwarder
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
-import org.junit.Assert.assertEquals
+import org.junit.Assert
import org.junit.Test
import org.junit.runner.RunWith
/**
* Instrumented test, which will execute on an Android device.
*
- * See [testing documentation](http://d.android.com/tools/testing).
+ * @see [Testing documentation](http://d.android.com/tools/testing)
*/
@RunWith(AndroidJUnit4::class)
class ExampleInstrumentedTest {
@@ -17,6 +34,6 @@ class ExampleInstrumentedTest {
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getInstrumentation().targetContext
- assertEquals("com.idormy.sms.forwarder", appContext.packageName)
+ Assert.assertEquals("com.idormy.sms.forwarder", appContext.packageName)
}
-}
+}
\ No newline at end of file
diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 3a307982..b86a8d5d 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -7,6 +7,9 @@
+
+
+
@@ -16,9 +19,8 @@
tools:ignore="ProtectedPermissions" />
-
+
+
@@ -28,6 +30,8 @@
+
+
@@ -44,10 +48,16 @@
+
+
+
+ android:windowSoftInputMode="adjustPan|stateHidden"
+ tools:ignore="DataExtractionRules,LockedOrientationActivity,UnusedAttribute"
+ tools:replace="android:allowBackup">
+ android:screenOrientation="portrait"
+ android:taskAffinity=":splash"
+ android:theme="@style/AppTheme.Launch.App"
+ android:windowSoftInputMode="adjustPan|stateHidden"
+ tools:ignore="TranslucentOrientation">
+
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
+ android:screenOrientation="portrait"
+ android:windowSoftInputMode="adjustPan|stateHidden" />
-
-
-
-
-
-
+ android:screenOrientation="portrait"
+ android:windowSoftInputMode="adjustPan|stateHidden" />
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -163,30 +247,6 @@
-
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/app/src/main/assets/protocol/account_protocol.txt b/app/src/main/assets/protocol/account_protocol.txt
new file mode 100644
index 00000000..376a6323
--- /dev/null
+++ b/app/src/main/assets/protocol/account_protocol.txt
@@ -0,0 +1,107 @@
+软件许可及服务协议
+【重要须知】
+
+【福州多米信息科技有限公司】(如下简称“多米科技”)在此特别提醒用户认真阅读、充分理解本《软件许可及服务协议》(下称“本协议”)。用户应认真阅读、充分理解本协议中各条款,特别涉及免除或者限制多米科技责任、争议解决和法律适用的条款。免除或者限制责任的条款将以粗体标识,您需要重点阅读。请您审慎阅读并选择接受或不接受本协议(未成年人应在法定监护人陪同下阅读)。您的下载、安装、使用本软件以及账号获取和登录等行为将视为对本协议的接受,并同意接受本协议各项条款的约束。
+
+多米科技有权修订本协议,更新后的协议条款将公布于官网或软件,自公布之日起生效。用户可重新下载安装本软件或网站查阅最新版协议条款。在多米科技修改本协议条款后,如果用户不接受修改后的条款,请立即停止使用多米科技提供的“多米科技”软件和服务,用户继续使用多米科技提供的“多米科技”软件和服务将被视为已接受了修改后的协议。
+
+一、总则
+
+1.1. 本协议是您(如下也称“用户”)与多米科技及其运营合作单位(如下简称“合作单位”)之间关于用户下载、安装、使用多米科技“多米科技”软件(下称“本软件”)以及使用多米科技相关服务所订立的协议。
+
+1.2. 本软件及服务是多米科技提供的安装在包括但不限于移动智能终端设备上的软件和服务,为使用该智能终端的用户提供绑定、操作智能产品等服务等。
+
+1.3. 本软件及服务的所有权和运营权均归多米科技所有。
+
+二、软件授权范围
+
+2.1. 多米科技就本软件给予用户一项个人的、不可转让、不可转授权以及非独占性的许可。
+
+2.2. 用户可以为非商业目的在单一台移动终端设备上安装、使用、显示、运行本软件。但用户不得为商业运营目的安装、使用、运行本软件,不可以对本软件或者本软件运行过程中释放到任何终端设备内存中的数据及本软件运行过程中客户端与服务器端的交互数据进行复制、更改、修改、挂接运行或创作任何衍生作品,形式包括但不限于使用插件、外挂或非经授权的第三方工具/服务接入本软件和相关系统。如果需要进行商业性的销售、复制和散发,例如软件预装和捆绑,必须获得多米科技的书面授权和许可。
+
+2.3. 用户不得未经多米科技许可,将本软件安装在未经多米科技明示许可的其他终端设备上,包括但不限于机顶盒、游戏机、电视机、DVD机等。
+
+2.4. 用户可以为使用本软件及服务的目的复制本软件的一个副本,仅用作备份。备份副本必须包含原软件中含有的所有著作权信息。
+
+2.5. 除本《协议》明示授权外,多米科技未授权给用户其他权利,若用户使用其他权利时须另外取得多米科技的书面同意。
+
+三、软件的获取、安装、升级
+
+3.1. 用户应当按照多米科技的指定网站或指定方式下载安装本软件产品。谨防在非指定网站下载本软件,以免移动终端设备感染能破坏用户数据和获取用户隐私信息的恶意程序。如果用户从未经多米科技授权的第三方获取本软件或与本软件名称相同的安装程序,多米科技无法保证该软件能够正常使用,并对因此给您造成的损失不予负责。
+
+3.2. 用户必须选择与所安装终端设备相匹配的本软件版本,否则,由于软件与设备型号不相匹配所导致的任何软件问题、设备问题或损害,均由用户自行承担。
+
+3.3. 为了改善用户体验、完善服务内容,多米科技有权不时地为您提供本软件替换、修改、升级版本,也有权为替换、修改或升级收取费用,但将收费提前征得您的同意。本软件为用户默认开通“升级提示”功能,视用户使用的软件版本差异,多米科技提供给用户自行选择是否需要开通此功能。软件新版本发布后,多米科技不保证旧版本软件的继续可用。
+
+四、使用规范
+
+4.1. 用户在遵守法律及本《协议》的前提下可依本《协议》使用本软件及服务,用户不得实施如下行为:
+
+4.1.1. 删除本软件及其他副本上一切关于版权的信息,以及修改、删除或避开本软件为保护知识产权而设置的技术措施;
+4.1.2. 对本软件进行反向工程,如反汇编、反编译或者其他试图获得本软件的源代码;
+4.1.3. 通过修改或伪造软件运行中的指令、数据,增加、删减、变动软件的功能或运行效果,或者将用于上述用途的软件、方法进行运营或向公众传播,无论这些行为是否为商业目的;
+4.1.4. 使用本软件进行任何危害网络安全的行为,包括但不限于:使用未经许可的数据或进入未经许可的服务器/账户;未经允许进入公众网络或者他人操作系统并删除、修改、增加存储信息;未经许可企图探查、扫描、测试本软件的系统或网络的弱点或其它实施破坏网络安全的行为; 企图干涉、破坏本软件系统或网站的正常运行,故意传播恶意程序或病毒以及其他破坏干扰正常网络信息服务的行为;伪造TCP/IP数据包名称或部分名称;
+4.1.5. 用户通过非多米科技公司开发、授权或认可的第三方兼容软件、系统登录或使用本软件及服务,或制作、发布、传播上述工具;
+4.1.6. 未经多米科技书面同意,用户对软件及其中的信息擅自实施包括但不限于下列行为:使用、出租、出借、复制、修改、链接、转载、汇编、发表、出版,建立镜像站点、擅自借助本软件发展与之有关的衍生产品、作品、服务、插件、外挂、兼容、互联等;
+4.1.7. 利用本软件发表、传送、传播、储存违反当地法律法规的内容;
+4.1.8. 利用本软件发表、传送、传播、储存侵害他人知识产权、商业秘密等合法权利的内容;
+4.1.9. 利用本软件批量发表、传送、传播广告信息及垃圾信息;
+4.1.10. 其他以任何不合法的方式、为任何不合法的目的、或以任何与本协议许可使用不一致的方式使用本软件和多米科技提供的其他服务;
+4.2. 信息发布规范
+
+4.2.1.您可使用本软件发表属于您原创或您有权发表的观点看法、数据、文字、信息、用户名、图片、照片、个人信息、音频、视频文件、链接等信息内容。您必须保证,您拥有您所上传信息内容的知识产权或已获得合法授权,您使用本软件及服务的任何行为未侵犯任何第三方之合法权益。
+4.2.2.您在使用本软件时需遵守当地法律法规要求。
+4.2.3.您在使用本软件时不得利用本软件从事以下行为,包括但不限于:
+
+4.2.3.1.制作、复制、发布、传播、储存违反当地法律法规的内容;
+
+4.2.3.2.发布、传送、传播、储存侵害他人名誉权、肖像权、知识产权、商业秘密等合法权利的内容;
+
+4.2.3.3.虚构事实、隐瞒真相以误导、欺骗他人;
+
+4.2.3.4.发表、传送、传播广告信息及垃圾信息;
+
+4.2.3.5.从事其他违反当地法律法规的行为。
+
+4.2.4. 未经多米科技许可,您不得在本软件中进行任何诸如发布广告、销售商品的商业行为。
+
+4.3.您理解并同意:
+
+4.3.1. 多米科技会对用户是否涉嫌违反上述使用规范做出认定,并根据认定结果中止、终止对您的使用许可或采取其他依本约定可采取的限制措施;
+4.3.2. 对于用户使用许可软件时发布的涉嫌违法或涉嫌侵犯他人合法权利或违反本协议的信息,多米科技会直接删除;
+4.3.3. 对于用户违反上述使用规范的行为对第三方造成损害的,您需要以自己的名义独立承担法律责任,并应确保多米科技免于因此产生损失或增加费用;
+4.3.4.若用户违反有关法律规定或协议约定,使多米科技遭受损失,或受到第三方的索赔,或受到行政管理机关的处罚,用户应当赔偿多米科技因此造成的损失和(或)发生的费用,包括合理的律师费、调查取证费用。
+五、服务风险及免责声明
+
+5.1. 用户必须自行配备移动终端设备上网和使用电信增值业务所需的设备,自行负担个人移动终端设备上网或第三方(包括但不限于电信或移动通信提供商)收取的通讯费、信息费等有关费用。如涉及电信增值服务的,我们建议您与您的电信增值服务提供商确认相关的费用问题。
+
+5.2. 用户因第三方如通讯线路故障、技术问题、网络、移动终端设备故障、系统不稳定性及其他各种不可抗力原因而遭受的一切损失,多米科技及合作单位不承担责任。
+
+5.3. 本软件同大多数互联网软件一样,受包括但不限于用户原因、网络服务质量、社会环境等因素的差异影响,可能受到各种安全问题的侵扰,如他人利用用户的资料,造成现实生活中的骚扰;用户下载安装的其它软件或访问的其他网站中含有“特洛伊木马”等病毒,威胁到用户的终端设备信息和数据的安全,继而影响本软件的正常使用等等。用户应加强信息安全及使用者资料的保护意识,要注意加强密码保护,以免遭致损失和骚扰。
+
+5.4. 因用户使用本软件或要求多米科技提供特定服务时,本软件可能会调用第三方系统或第三方软件支持用户的使用或访问,使用或访问的结果由该第三方提供,多米科技不保证通过第三方系统或第三方软件支持实现的结果的安全性、准确性、有效性及其他不确定的风险,由此若引发的任何争议及损害,多米科技不承担任何责任。
+
+5.5. 多米科技特别提请用户注意,多米科技为了保障公司业务发展和调整的自主权,多米科技公司拥有随时修改或中断服务而不需通知用户的权利,多米科技行使修改或中断服务的权利不需对用户或任何第三方负责。
+
+5.6. 除法律法规有明确规定外,我们将尽最大努力确保软件及其所涉及的技术及信息安全、有效、准确、可靠,但受限于现有技术,用户理解多米科技不能对此进行担保。
+
+5.7. 由于用户因下述任一情况所引起或与此有关的人身伤害或附带的、间接的经济损害赔偿,包括但不限于利润损失、资料损失、业务中断的损害赔偿或其他商业损害赔偿或损失,需由用户自行承担:
+
+5.7.1.使用或未能使用许可软件;
+5.7.2.第三方未经许可的使用软件或更改用户的数据;
+5.7.3.用户使用软件进行的行为产生的费用及损失;
+5.7.4.用户对软件的误解;
+5.7.5.非因多米科技的原因引起的与软件有关的其他损失。
+5.8. 用户与其他使用软件的用户之间通过软件进行的行为,因您受误导或欺骗而导致或可能导致的任何人身或经济上的伤害或损失,均由过错方依法承担所有责任。
+
+六、知识产权声明
+
+6.1. 多米科技是本软件的知识产权权利人。本软件的一切著作权、商标权、专利权、商业秘密等知识产权,以及与本软件相关的所有信息内容(包括但不限于文字、图片、音 频、视频、图表、界面设计、版面框架、有关数据或电子文档等)均受您所在当地法律法规和相应的国际条约保护,多米科技享有上述知识产权。
+
+6.2 未经多米科技书面同意,用户不得为任何商业或非商业目的自行或许可任何第三方实施、利用、转让上述知识产权,多米科技保留追究上述行为法律责任的权利。
+
+七、协议变更
+
+7.1. 多米科技有权在必要时修改本协议条款,协议条款一旦发生变动,将会在相关页面上公布修改后的协议条款。如果不同意所改动的内容,用户应主动取消此项服务。如果用户继续使用服务,则视为接受协议条款的变动。
+
+7.2. 多米科技和合作公司有权按需要修改或变更所提供的收费服务、收费标准、收费方式、服务费及服务条款。多米科技在提供服务时,可能现在或日后对部分服务的用户开始收取一定的费用如用户拒绝支付该等费用,则不能在收费开始后继续使用相关的服务。多米科技和合作公司将尽最大努力通过电邮或其他方式通知用户有关的修改或变更。
diff --git a/app/src/main/assets/protocol/privacy_protocol.txt b/app/src/main/assets/protocol/privacy_protocol.txt
new file mode 100644
index 00000000..66850eac
--- /dev/null
+++ b/app/src/main/assets/protocol/privacy_protocol.txt
@@ -0,0 +1,70 @@
+SmsForwarder尊重并保护所有使用服务用户的个人隐私权。为了给您提供更准确、更有个性化的 服务,SmsForwarder会按照本隐私权政策的规定使用和披露您的个人信息。但SmsForwarder将以高 度的勤勉、审慎义务对待这些信息。除本隐私权政策另有规定外,在未征得您事先许可的情况下 ,SmsForwarder不会将这些信息对外披露或向第三方提供。SmsForwarder会不时更新本隐私权政策 。 您在同意SmsForwarder服务使用协议之时,即视为您已经同意本隐私权政策全部内容。本隐私 权政策属于SmsForwarder服务使用协议不可分割的一部分。
+
+
+1. 适用范围
+
+a) 在您注册SmsForwarder帐号时,您根据SmsForwarder要求提供的个人注册信息;
+
+b) 在您使用SmsForwarder网络服务,或访问SmsForwarder平台网页时,SmsForwarder自动接收并记 录的您的浏览器和计算机上的信息,包括但不限于您的IP地址、浏览器的类型、使用的语言、访 问日期和时间、软硬件特征信息及您需求的网页记录等数据;
+
+c) SmsForwarder通过合法途径从商业伙伴处取得的用户个人数据。
+
+您了解并同意,以下信息不适用本隐私权政策:
+
+a) 您在使用SmsForwarder平台提供的搜索服务时输入的关键字信息;
+
+b) SmsForwarder收集到的您在SmsForwarder发布的有关信息数据,包括但不限于参与活动、成交 信息及评价详情;
+
+c) 违反法律规定或违反SmsForwarder规则行为及SmsForwarder已对您采取的措施。
+
+2. 信息使用
+
+a) SmsForwarder不会向任何无关第三方提供、出售、出租、分享或交易您的个人信息,除非事先 得到您的许可,或该第三方和SmsForwarder(含SmsForwarder关联公司)单独或共同为您提供服务 ,且在该服务结束后,其将被禁止访问包括其以前能够访问的所有这些资料。
+
+b) SmsForwarder亦不允许任何第三方以任何手段收集、编辑、出售或者无偿传播您的个人信息。 任何SmsForwarder平台用户如从事上述活动,一经发现,SmsForwarder有权立即终止与该用户的服 务协议。
+
+c) 为服务用户的目的,SmsForwarder可能通过使用您的个人信息,向您提供您感兴趣的信息,包 括但不限于向您发出产品和服务信息,或者与SmsForwarder合作伙伴共享信息以便他们向您发送 有关其产品和服务的信息(后者需要您的事先同意)。
+
+3. 信息披露 在如下情况下,SmsForwarder将依据您的个人意愿或法律的规定全部或部分的披露您的个人信息 :
+
+a) 经您事先同意,向第三方披露;
+
+b) 为提供您所要求的产品和服务,而必须和第三方分享您的个人信息;
+
+c) 根据法律的有关规定,或者行政或司法机构的要求,向第三方或者行政、司法机构披露;
+
+d) 如您出现违反中国有关法律、法规或者SmsForwarder服务协议或相关规则的情况,需要向第三 方披露;
+
+e) 如您是适格的知识产权投诉人并已提起投诉,应被投诉人要求,向被投诉人披露,以便双方 处理可能的权利纠纷;
+
+f) 在SmsForwarder平台上创建的某一交易中,如交易任何一方履行或部分履行了交易义务并提出 信息披露请求的,SmsForwarder有权决定向该用户提供其交易对方的联络方式等必要信息,以促 成交易的完成或纠纷的解决。
+
+g) 其它SmsForwarder根据法律、法规或者网站政策认为合适的披露。
+
+4. 信息存储和交换 SmsForwarder收集的有关您的信息和资料将保存在SmsForwarder及(或)其关联公司的服务器上, 这些信息和资料可能传送至您所在国家、地区或SmsForwarder收集信息和资料所在地的境外并在 境外被访问、存储和展示。
+
+5. Cookie的使用
+
+a) 在您未拒绝接受cookies的情况下,SmsForwarder会在您的计算机上设定或取用cookies ,以便您能登录或使用依赖于cookies的SmsForwarder平台服务或功能。SmsForwarder使用cookies 可为您提供更加周到的个性化服务,包括推广服务。
+
+b) 您有权选择接受或拒绝接受cookies。 您可以通过修改浏览器设置的方式拒绝接受cookies。但如果您选择拒绝接受cookies,则您可能 无法登录或使用依赖于cookies的SmsForwarder网络服务或功能。
+
+c) 通过SmsForwarder所设cookies所取得的有关信息,将适用本政策。
+
+6. 信息安全
+
+a) SmsForwarder帐号均有安全保护功能,请妥善保管您的用户名及密码信息。SmsForwarder将通 过对用户密码进行加密等安全措施确保您的信息不丢失,不被滥用和变造。尽管有前述安全措施 ,但同时也请您注意在信息网络上不存在“完善的安全措施”。
+
+b) 在使用SmsForwarder网络服务进行网上交易时,您不可避免的要向交易对方或潜在的交易对方 披露自己的个人信息,如联络方式或者邮政地址。请您妥善保护自己的个人信息,仅在必要的情 形下向他人提供。如您发现自己的个人信息泄密,尤其是SmsForwarder用户名及密码发生泄露, 请您立即联络SmsForwarder客服,以便SmsForwarder采取相应措施。
+
+7. 接入的第三方SDK说明
+
+a) 友盟统计SDK(com.umeng)
+ 使用目的: 统计应用运营数据
+ 使用范围: 应用运营数据统计
+
+8. 敏感信息收集说明
+ 我们的产品集成友盟+SDK,友盟+SDK需要收集您的设备Mac地址、唯一设备识别码(IMEI/android ID/IDFA/OPENUDID/GUID、SIM 卡 IMSI 信息)以提供统计分析服务,并通过地理位置校准报表数据准确性,提供基础反作弊能力。
+
+
+
diff --git a/app/src/main/assets/tips.json b/app/src/main/assets/tips.json
new file mode 100644
index 00000000..5a77023d
--- /dev/null
+++ b/app/src/main/assets/tips.json
@@ -0,0 +1,17 @@
+{
+ "Code": 0,
+ "Data": [
+ {
+ "title": "新用户必读",
+ "content": "开始设置之前,请您认真地看一遍 Wiki !
\n遇到问题,请按照 常见问题 章节进行排查!
\n没找到答案的,再加入QQ互助交流群里提问,请清楚地描述问题,并给出对应的配置截图与相关日志,方便大家直观的判断问题! "
+ },
+ {
+ "title": "QQ互助交流群",
+ "content": "QQ互助交流①群
QQ互助交流②群
QQ互助交流③群
QQ互助交流④群
QQ互助交流⑤群"
+ },
+ {
+ "title": "打赏名单",
+ "content": "感谢热心网友们对开源项目的喜爱和支持!查看赞助名单!"
+ }
+ ]
+}
diff --git a/app/src/main/assets/web/index.html b/app/src/main/assets/web/index.html
new file mode 100644
index 00000000..7a35b591
--- /dev/null
+++ b/app/src/main/assets/web/index.html
@@ -0,0 +1,3 @@
+
+Hello SmsForwarder!!!
+
\ No newline at end of file
diff --git a/app/src/main/assets/web/main.html b/app/src/main/assets/web/main.html
new file mode 100644
index 00000000..f4b8500c
--- /dev/null
+++ b/app/src/main/assets/web/main.html
@@ -0,0 +1,3 @@
+
+Welcome to Main Page!!!
+
\ No newline at end of file
diff --git a/app/src/main/ic_launcher-playstore.png b/app/src/main/ic_launcher-playstore.png
deleted file mode 100644
index 62cd18bb..00000000
Binary files a/app/src/main/ic_launcher-playstore.png and /dev/null differ
diff --git a/app/src/main/java/com/idormy/sms/forwarder/AboutActivity.java b/app/src/main/java/com/idormy/sms/forwarder/AboutActivity.java
deleted file mode 100644
index f1af88f8..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/AboutActivity.java
+++ /dev/null
@@ -1,146 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.content.Intent;
-import android.net.Uri;
-import android.os.Bundle;
-import android.util.Log;
-import android.widget.Button;
-import android.widget.TextView;
-
-import com.hjq.permissions.OnPermissionCallback;
-import com.hjq.permissions.Permission;
-import com.hjq.permissions.XXPermissions;
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.receiver.RebootBroadcastReceiver;
-import com.idormy.sms.forwarder.utils.CacheUtils;
-import com.idormy.sms.forwarder.utils.CommonUtils;
-import com.idormy.sms.forwarder.utils.SettingUtils;
-import com.xuexiang.xupdate.easy.EasyUpdate;
-import com.xuexiang.xupdate.proxy.impl.DefaultUpdateChecker;
-
-import java.util.List;
-
-public class AboutActivity extends BaseActivity {
-
- private final String TAG = "AboutActivity";
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_about);
- Log.d(TAG, "onCreate: " + RebootBroadcastReceiver.class.getName());
-
- XXPermissions.with(this)
- // 申请安装包权限
- .permission(Permission.REQUEST_INSTALL_PACKAGES)
- // 申请通知栏权限
- .permission(Permission.NOTIFICATION_SERVICE)
- .request(new OnPermissionCallback() {
-
- @Override
- public void onGranted(List permissions, boolean all) {
- if (all) {
- ToastUtils.show(R.string.toast_granted_all);
- } else {
- ToastUtils.show(R.string.toast_granted_part);
- }
- SettingUtils.switchEnableSms(true);
- }
-
- @Override
- public void onDenied(List permissions, boolean never) {
- if (never) {
- ToastUtils.show(R.string.toast_denied_never);
- // 如果是被永久拒绝就跳转到应用权限系统设置页面
- XXPermissions.startPermissionActivity(AboutActivity.this, permissions);
- } else {
- ToastUtils.show(R.string.toast_denied);
- }
- SettingUtils.switchEnableSms(false);
- }
- });
-
- final TextView version_now = findViewById(R.id.version_now);
- Button check_version_now = findViewById(R.id.check_version_now);
- try {
- version_now.setText(CommonUtils.getVersionName(AboutActivity.this));
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- check_version_now.setOnClickListener(v -> {
- try {
- String updateUrl = "https://xupdate.bms.ink/update/checkVersion?appKey=com.idormy.sms.forwarder&versionCode=";
- updateUrl += CommonUtils.getVersionCode(AboutActivity.this);
- Log.d(TAG, updateUrl);
-
- EasyUpdate.create(AboutActivity.this, updateUrl)
- .updateChecker(new DefaultUpdateChecker() {
- @Override
- public void onBeforeCheck() {
- super.onBeforeCheck();
- ToastUtils.delayedShow(R.string.checking, 3000);
- }
-
- @Override
- public void noNewVersion(Throwable throwable) {
- super.noNewVersion(throwable);
- // 没有最新版本的处理
- ToastUtils.delayedShow(R.string.up_to_date, 3000);
- }
- })
- .update();
- } catch (Exception e) {
- e.printStackTrace();
- }
-
- });
-
- final TextView cache_size = findViewById(R.id.cache_size);
- try {
- cache_size.setText(CacheUtils.getTotalCacheSize(AboutActivity.this));
- } catch (Exception e) {
- e.printStackTrace();
- }
- Button clear_all_cache = findViewById(R.id.clear_all_cache);
- clear_all_cache.setOnClickListener(v -> {
- CacheUtils.clearAllCache(AboutActivity.this);
- try {
- cache_size.setText(CacheUtils.getTotalCacheSize(AboutActivity.this));
- } catch (Exception e) {
- e.printStackTrace();
- }
- ToastUtils.delayedShow(R.string.cache_purged, 3000);
- });
-
- Button join_qq_group1 = findViewById(R.id.join_qq_group1);
- join_qq_group1.setOnClickListener(v -> {
- String key = "Mj5m39bqy6eodOImrFLI19Tdeqvv-9zf";
- joinQQGroup(key);
- });
-
- Button join_qq_group2 = findViewById(R.id.join_qq_group2);
- join_qq_group2.setOnClickListener(v -> {
- String key = "jPXy4YaUzA7Uo0yPPbZXdkb66NS1smU_";
- joinQQGroup(key);
- });
-
- }
-
- //发起添加群流程
- public void joinQQGroup(String key) {
- Intent intent = new Intent();
- intent.setData(Uri.parse("mqqopensdkapi://bizAgent/qm/qr?url=http%3A%2F%2Fqm.qq.com%2Fcgi-bin%2Fqm%2Fqr%3Ffrom%3Dapp%26p%3Dandroid%26jump_from%3Dwebapi%26k%3D" + key));
- // 此Flag可根据具体产品需要自定义,如设置,则在加群界面按返回,返回手Q主界面,不设置,按返回会返回到呼起产品界面
- //intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
- try {
- startActivity(intent);
- } catch (Exception e) {
- // 未安装手Q或安装的版本不支持
- ToastUtils.delayedShow(R.string.unknown_qq_version, 3000);
- }
- }
-
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/App.kt b/app/src/main/java/com/idormy/sms/forwarder/App.kt
new file mode 100644
index 00000000..56ad62ae
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/App.kt
@@ -0,0 +1,250 @@
+package com.idormy.sms.forwarder
+
+import android.annotation.SuppressLint
+import android.app.Application
+import android.app.PendingIntent
+import android.content.Context
+import android.content.Intent
+import android.content.IntentFilter
+import android.os.Build
+import android.util.Log
+import androidx.lifecycle.MutableLiveData
+import androidx.multidex.MultiDex
+import androidx.work.Configuration
+import com.gyf.cactus.Cactus
+import com.gyf.cactus.callback.CactusCallback
+import com.gyf.cactus.ext.cactus
+import com.idormy.sms.forwarder.activity.MainActivity
+import com.idormy.sms.forwarder.core.Core
+import com.idormy.sms.forwarder.database.AppDatabase
+import com.idormy.sms.forwarder.database.repository.FrpcRepository
+import com.idormy.sms.forwarder.database.repository.LogsRepository
+import com.idormy.sms.forwarder.database.repository.RuleRepository
+import com.idormy.sms.forwarder.database.repository.SenderRepository
+import com.idormy.sms.forwarder.entity.SimInfo
+import com.idormy.sms.forwarder.receiver.CactusReceiver
+import com.idormy.sms.forwarder.service.BatteryService
+import com.idormy.sms.forwarder.service.ForegroundService
+import com.idormy.sms.forwarder.service.HttpService
+import com.idormy.sms.forwarder.utils.*
+import com.idormy.sms.forwarder.utils.sdkinit.ANRWatchDogInit
+import com.idormy.sms.forwarder.utils.sdkinit.UMengInit
+import com.idormy.sms.forwarder.utils.sdkinit.XBasicLibInit
+import com.idormy.sms.forwarder.utils.sdkinit.XUpdateInit
+import com.idormy.sms.forwarder.utils.tinker.TinkerLoadLibrary
+import com.xuexiang.xutil.app.AppUtils
+import io.reactivex.Observable
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import kotlinx.coroutines.*
+import java.io.File
+import java.text.SimpleDateFormat
+import java.util.*
+import java.util.concurrent.TimeUnit
+
+@Suppress("PrivatePropertyName")
+class App : Application(), CactusCallback, Configuration.Provider by Core {
+
+ val applicationScope = CoroutineScope(SupervisorJob())
+ val database by lazy { AppDatabase.getInstance(this) }
+ val frpcRepository by lazy { FrpcRepository(database.frpcDao()) }
+ val logsRepository by lazy { LogsRepository(database.logsDao()) }
+ val ruleRepository by lazy { RuleRepository(database.ruleDao()) }
+ val senderRepository by lazy { SenderRepository(database.senderDao()) }
+
+ companion object {
+ const val TAG: String = "SmsForwarder"
+
+ @SuppressLint("StaticFieldLeak")
+ lateinit var context: Context
+
+ //已插入SIM卡信息
+ var SimInfoList: MutableMap = mutableMapOf()
+
+ //已安装App信息
+ var AppInfoList: List = arrayListOf()
+
+ /**
+ * @return 当前app是否是调试开发模式
+ */
+ val isDebug: Boolean
+ get() = BuildConfig.DEBUG
+
+ //Cactus结束时间
+ val mEndDate = MutableLiveData()
+
+ //Cactus上次存活时间
+ val mLastTimer = MutableLiveData()
+
+ //Cactus存活时间
+ val mTimer = MutableLiveData()
+
+ //Cactus运行状态
+ val mStatus = MutableLiveData().apply { value = true }
+ }
+
+ override fun attachBaseContext(base: Context) {
+ super.attachBaseContext(base)
+ //解决4.x运行崩溃的问题
+ MultiDex.install(this)
+ }
+
+ override fun onCreate() {
+ super.onCreate()
+ try {
+ //动态加载FrpcLib
+ val libPath = filesDir.absolutePath + "/libs"
+ val soFile = File(libPath)
+ try {
+ TinkerLoadLibrary.installNativeLibraryPath(classLoader, soFile)
+ } catch (throwable: Throwable) {
+ Log.e("APP", throwable.message!!)
+ }
+
+ context = applicationContext
+ initLibs()
+
+ //启动前台服务
+ val intent = Intent(this, ForegroundService::class.java)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ startForegroundService(intent)
+ } else {
+ startService(intent)
+ }
+
+ //电池状态监听
+ val batteryServiceIntent = Intent(this, BatteryService::class.java)
+ startService(batteryServiceIntent)
+
+ //异步获取所有已安装 App 信息
+ val get = GlobalScope.async(Dispatchers.IO) {
+ AppInfoList = AppUtils.getAppsInfo()
+ }
+ GlobalScope.launch(Dispatchers.Main) {
+ runCatching {
+ get.await()
+ Log.d("GlobalScope", "AppUtils.getAppsInfo() Done")
+ }.onFailure {
+ Log.e("GlobalScope", it.message.toString())
+ }
+ }
+
+ //启动HttpServer
+ if (HttpServerUtils.enableServerAutorun) {
+ startService(Intent(this, HttpService::class.java))
+ }
+
+ //Cactus 集成双进程前台服务,JobScheduler,onePix(一像素),WorkManager,无声音乐
+ if (!isDebug) {
+ //注册广播监听器
+ registerReceiver(CactusReceiver(), IntentFilter().apply {
+ addAction(Cactus.CACTUS_WORK)
+ addAction(Cactus.CACTUS_STOP)
+ addAction(Cactus.CACTUS_BACKGROUND)
+ addAction(Cactus.CACTUS_FOREGROUND)
+ })
+ //设置通知栏点击事件
+ val activityIntent = Intent(this, MainActivity::class.java)
+ val flags = if (Build.VERSION.SDK_INT >= 30) PendingIntent.FLAG_IMMUTABLE else PendingIntent.FLAG_UPDATE_CURRENT
+ val pendingIntent = PendingIntent.getActivity(this, 0, activityIntent, flags)
+ cactus {
+ setServiceId(FRONT_NOTIFY_ID) //服务Id
+ setChannelId(FRONT_CHANNEL_ID) //渠道Id
+ setChannelName(FRONT_CHANNEL_NAME) //渠道名
+ setTitle(getString(R.string.app_name))
+ setContent(SettingUtils.notifyContent.toString())
+ setSmallIcon(R.drawable.ic_forwarder)
+ setLargeIcon(R.mipmap.ic_launcher)
+ setPendingIntent(pendingIntent)
+ //无声音乐
+ if (SettingUtils.enablePlaySilenceMusic) {
+ setMusicEnabled(true)
+ setBackgroundMusicEnabled(true)
+ setMusicId(R.raw.silence)
+ //设置音乐间隔时间,时间间隔越长,越省电
+ setMusicInterval(10)
+ isDebug(true)
+ }
+ //是否可以使用一像素,默认可以使用,只有在android p以下可以使用
+ if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.P && SettingUtils.enableOnePixelActivity) {
+ setOnePixEnabled(true)
+ }
+ //奔溃是否可以重启用户界面
+ setCrashRestartUIEnabled(true)
+ addCallback({
+ Log.d(TAG, "Cactus保活:onStop回调")
+ }) {
+ Log.d(TAG, "Cactus保活:doWork回调")
+ }
+ //切后台切换回调
+ addBackgroundCallback {
+ Log.d(TAG, if (it) "SmsForwarder 切换到后台运行" else "SmsForwarder 切换到前台运行")
+ }
+ }
+ }
+
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+
+ /**
+ * 初始化基础库
+ */
+ private fun initLibs() {
+ Core.init(this)
+ // 转发历史工具类初始化
+ HistoryUtils.init(this)
+ // X系列基础库初始化
+ XBasicLibInit.init(this)
+ // 版本更新初始化
+ XUpdateInit.init(this)
+ // 运营统计数据
+ UMengInit.init(this)
+ // ANR监控
+ ANRWatchDogInit.init()
+ }
+
+ private var mDisposable: Disposable? = null
+
+ @SuppressLint("CheckResult")
+ override fun doWork(times: Int) {
+ Log.d(TAG, "doWork:$times")
+ mStatus.postValue(true)
+ val dateFormat = SimpleDateFormat("HH:mm:ss", Locale.getDefault())
+ dateFormat.timeZone = TimeZone.getTimeZone("GMT+00:00")
+ var oldTimer = CactusSave.timer
+ if (times == 1) {
+ CactusSave.lastTimer = oldTimer
+ CactusSave.endDate = CactusSave.date
+ oldTimer = 0L
+ }
+ mLastTimer.postValue(dateFormat.format(Date(CactusSave.lastTimer * 1000)))
+ mEndDate.postValue(CactusSave.endDate)
+ mDisposable = Observable.interval(1, TimeUnit.SECONDS)
+ .map {
+ oldTimer + it
+ }
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe { aLong ->
+ CactusSave.timer = aLong
+ CactusSave.date = SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()).run {
+ format(Date())
+ }
+ mTimer.value = dateFormat.format(Date(aLong * 1000))
+ }
+ }
+
+ override fun onStop() {
+ Log.d(TAG, "onStop")
+ mStatus.postValue(false)
+ mDisposable?.apply {
+ if (!isDisposed) {
+ dispose()
+ }
+ }
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java b/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java
deleted file mode 100644
index 894c13b3..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/AppListActivity.java
+++ /dev/null
@@ -1,151 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
-
-import android.annotation.SuppressLint;
-import android.content.ClipData;
-import android.content.ClipboardManager;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.ApplicationInfo;
-import android.content.pm.PackageInfo;
-import android.content.pm.PackageManager;
-import android.graphics.drawable.Drawable;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.view.View;
-import android.widget.ListView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.adapter.AppAdapter;
-import com.idormy.sms.forwarder.model.AppInfo;
-
-import java.util.ArrayList;
-import java.util.List;
-
-@SuppressWarnings("deprecation")
-public class AppListActivity extends BaseActivity {
-
- public static final int APP_LIST = 0x9731991;
- private final String TAG = "AppListActivity";
- private List appInfoList = new ArrayList<>();
- private ListView listView;
- private String currentType = "user";
-
- //消息处理者,创建一个Handler的子类对象,目的是重写Handler的处理消息的方法(handleMessage())
- @SuppressLint("HandlerLeak")
- private final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == NOTIFY) {
- ToastUtils.delayedShow(msg.getData().getString("DATA"), 3000);
- } else if (msg.what == APP_LIST) {
- AppAdapter adapter = new AppAdapter(AppListActivity.this, R.layout.item_app, appInfoList);
- listView.setAdapter(adapter);
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_applist);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
-
- //是否关闭页面提示
- TextView help_tip = findViewById(R.id.help_tip);
- help_tip.setVisibility(MyApplication.showHelpTip ? View.VISIBLE : View.GONE);
-
- //获取应用列表
- getAppList();
-
- //切换日志类别
- int typeCheckId = "user".equals(currentType) ? R.id.btnTypeUser : R.id.btnTypeSys;
- final RadioGroup radioGroupTypeCheck = findViewById(R.id.radioGroupTypeCheck);
- radioGroupTypeCheck.check(typeCheckId);
- radioGroupTypeCheck.setOnCheckedChangeListener((group, checkedId) -> {
- RadioButton rb = findViewById(checkedId);
- currentType = (String) rb.getTag();
- getAppList();
- });
-
- listView = findViewById(R.id.list_view_app);
- listView.setOnItemClickListener((parent, view, position, id) -> {
- AppInfo appInfo = appInfoList.get(position);
- Log.d(TAG, "onItemClick: " + appInfo.toString());
- //复制到剪贴板
- ClipboardManager cm = (ClipboardManager) getSystemService(Context.CLIPBOARD_SERVICE);
- ClipData mClipData = ClipData.newPlainText("pkgName", appInfo.getPkgName());
- cm.setPrimaryClip(mClipData);
-
- ToastUtils.delayedShow(getString(R.string.package_name_copied) + appInfo.getPkgName(), 3000);
- });
- listView.setOnItemLongClickListener((parent, view, position, id) -> {
- AppInfo appInfo = appInfoList.get(position);
- Log.d(TAG, "onItemClick: " + appInfo.toString());
- //启动应用
- Intent intent;
- intent = getPackageManager().getLaunchIntentForPackage(appInfo.getPkgName());
- startActivity(intent);
-
- return true;
- });
- }
-
- //获取应用列表
- private void getAppList() {
- new Thread(() -> {
- Message msg = new Message();
- msg.what = NOTIFY;
- Bundle bundle = new Bundle();
- bundle.putString("DATA", "user".equals(currentType) ? getString(R.string.loading_user_app) : getString(R.string.loading_system_app));
- msg.setData(bundle);
- handler.sendMessage(msg);
-
- appInfoList = new ArrayList<>();
- PackageManager pm = getApplication().getPackageManager();
- try {
- List packages = pm.getInstalledPackages(PackageManager.GET_ACTIVITIES | PackageManager.GET_SERVICES);
- for (PackageInfo packageInfo : packages) {
- //只取用户应用
- if ("user".equals(currentType) && isSystemApp(packageInfo)) continue;
- //只取系统应用
- if ("sys".equals(currentType) && !isSystemApp(packageInfo)) continue;
-
- String appName = packageInfo.applicationInfo.loadLabel(pm).toString();
- String packageName = packageInfo.packageName;
- Drawable drawable = packageInfo.applicationInfo.loadIcon(pm);
- String verName = packageInfo.versionName;
- int verCode = packageInfo.versionCode;
- AppInfo appInfo = new AppInfo(appName, packageName, drawable, verName, verCode);
- appInfoList.add(appInfo);
- Log.d(TAG, appInfo.toString());
- }
- } catch (Throwable t) {
- t.printStackTrace();
- }
-
- Message message = new Message();
- message.what = APP_LIST;
- message.obj = appInfoList;
- handler.sendMessage(message);
- }).start();
- }
-
- // 通过packName得到PackageInfo,作为参数传入即可
- private boolean isSystemApp(PackageInfo pi) {
- return (pi.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) == 1;
- }
-
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/BaseActivity.java b/app/src/main/java/com/idormy/sms/forwarder/BaseActivity.java
deleted file mode 100644
index dc168838..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/BaseActivity.java
+++ /dev/null
@@ -1,68 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.annotation.SuppressLint;
-import android.content.Intent;
-import android.util.Log;
-import android.view.Menu;
-import android.view.MenuItem;
-
-import androidx.appcompat.app.AppCompatActivity;
-
-import java.lang.reflect.Method;
-
-public class BaseActivity extends AppCompatActivity {
-
- //启用menu
- @Override
- public boolean onCreateOptionsMenu(Menu menu) {
- getMenuInflater().inflate(R.menu.menu_main, menu);
- return super.onCreateOptionsMenu(menu);
- }
-
- //menu点击事件
- @SuppressLint("NonConstantResourceId")
- @Override
- public boolean onOptionsItemSelected(MenuItem item) {
- Intent intent;
- switch (item.getItemId()) {
- case R.id.to_app_list:
- intent = new Intent(this, AppListActivity.class);
- break;
- case R.id.to_clone:
- intent = new Intent(this, CloneActivity.class);
- break;
- case R.id.to_about:
- intent = new Intent(this, AboutActivity.class);
- break;
- case R.id.to_help:
- intent = new Intent(this, HelpActivity.class);
- break;
- default:
- return super.onOptionsItemSelected(item);
- }
-
- startActivity(intent);
- return true;
- }
-
- //设置menu图标显示
- @Override
- public boolean onMenuOpened(int featureId, Menu menu) {
- String TAG = "BaseActivity";
- Log.d(TAG, "onMenuOpened, featureId=" + featureId);
- if (menu != null) {
- if (menu.getClass().getSimpleName().equals("MenuBuilder")) {
- try {
- Method m = menu.getClass().getDeclaredMethod("setOptionalIconsVisible", Boolean.TYPE);
- m.setAccessible(true);
- m.invoke(menu, true);
- } catch (NoSuchMethodException e) {
- Log.e(TAG, "onMenuOpened", e);
- } catch (Exception e) {
- throw new RuntimeException(e);
- }
- }
- }
- return super.onMenuOpened(featureId, menu);
- }
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/CloneActivity.java b/app/src/main/java/com/idormy/sms/forwarder/CloneActivity.java
deleted file mode 100644
index 8f150d1f..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/CloneActivity.java
+++ /dev/null
@@ -1,300 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.os.Bundle;
-import android.os.Environment;
-import android.text.TextUtils;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-import android.widget.LinearLayout;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-
-import com.alibaba.fastjson.JSON;
-import com.hjq.permissions.OnPermissionCallback;
-import com.hjq.permissions.Permission;
-import com.hjq.permissions.XXPermissions;
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.model.vo.CloneInfoVo;
-import com.idormy.sms.forwarder.receiver.BaseServlet;
-import com.idormy.sms.forwarder.receiver.RebootBroadcastReceiver;
-import com.idormy.sms.forwarder.sender.HttpServer;
-import com.idormy.sms.forwarder.utils.CloneUtils;
-import com.idormy.sms.forwarder.utils.Define;
-import com.idormy.sms.forwarder.utils.FileUtils;
-import com.idormy.sms.forwarder.utils.HttpUtils;
-import com.idormy.sms.forwarder.utils.NetUtils;
-import com.idormy.sms.forwarder.utils.SettingUtils;
-import com.idormy.sms.forwarder.view.IPEditText;
-
-import java.io.File;
-import java.io.IOException;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Objects;
-import java.util.concurrent.TimeUnit;
-
-import okhttp3.Call;
-import okhttp3.Callback;
-import okhttp3.MediaType;
-import okhttp3.OkHttpClient;
-import okhttp3.Request;
-import okhttp3.RequestBody;
-import okhttp3.Response;
-
-public class CloneActivity extends BaseActivity {
- private final String TAG = "CloneActivity";
- private Context context;
- private String serverIp;
- private String backupPath;
- private final String backupFile = "SmsForwarder.json";
- private IPEditText textServerIp;
- private TextView sendTxt;
- private TextView receiveTxt;
- private TextView backupPathTxt;
- private Button sendBtn;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
- super.onCreate(savedInstanceState);
-
- setContentView(R.layout.activity_clone);
- Log.d(TAG, "onCreate: " + RebootBroadcastReceiver.class.getName());
-
- HttpUtils.init(this);
- HttpServer.init(this);
- }
-
- @SuppressWarnings({"rawtypes", "unchecked", "deprecation"})
- @SuppressLint("SetTextI18n")
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
-
- backupPathTxt = findViewById(R.id.backupPathTxt);
- // 申请储存权限
- XXPermissions.with(this).permission(Permission.Group.STORAGE).request(new OnPermissionCallback() {
- @Override
- public void onGranted(List permissions, boolean all) {
- backupPath = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getPath();
- backupPathTxt.setText(backupPath + File.separator + backupFile);
- }
-
- @Override
- public void onDenied(List permissions, boolean never) {
- if (never) {
- ToastUtils.show(R.string.toast_denied_never);
- // 如果是被永久拒绝就跳转到应用权限系统设置页面
- XXPermissions.startPermissionActivity(CloneActivity.this, permissions);
- } else {
- ToastUtils.show(R.string.toast_denied);
- }
- backupPathTxt.setText("未授权储存权限,该功能无法使用!");
- }
- });
-
- LinearLayout layoutNetwork = findViewById(R.id.layoutNetwork);
- LinearLayout layoutOffline = findViewById(R.id.layoutOffline);
- final RadioGroup radioGroupTypeCheck = findViewById(R.id.radioGroupTypeCheck);
- radioGroupTypeCheck.setOnCheckedChangeListener((group, checkedId) -> {
- if (checkedId == R.id.btnTypeOffline) {
- layoutNetwork.setVisibility(View.GONE);
- layoutOffline.setVisibility(View.VISIBLE);
- } else {
- layoutNetwork.setVisibility(View.VISIBLE);
- layoutOffline.setVisibility(View.GONE);
- }
- });
-
- sendBtn = findViewById(R.id.sendBtn);
- sendTxt = findViewById(R.id.sendTxt);
- TextView ipText = findViewById(R.id.ipText);
- textServerIp = findViewById(R.id.textServerIp);
- receiveTxt = findViewById(R.id.receiveTxt);
- Button receiveBtn = findViewById(R.id.receiveBtn);
-
- serverIp = NetUtils.getLocalIp(CloneActivity.this);
- ipText.setText(serverIp);
-
- if (HttpServer.asRunning()) {
- sendBtn.setText(R.string.stop);
- sendTxt.setText(R.string.server_has_started);
- textServerIp.setIP(serverIp);
- } else {
- sendBtn.setText(R.string.send);
- sendTxt.setText(R.string.server_has_stopped);
- }
-
- //发送
- sendBtn.setOnClickListener(v -> {
- if (!HttpServer.asRunning() && NetUtils.NETWORK_WIFI != NetUtils.getNetWorkStatus()) {
- ToastUtils.show(getString(R.string.no_wifi_network));
- return;
- }
-
- SettingUtils.switchEnableHttpServer(!SettingUtils.getSwitchEnableHttpServer());
- if (!HttpServer.update()) {
- SettingUtils.switchEnableHttpServer(!SettingUtils.getSwitchEnableHttpServer());
- return;
- }
- if (!HttpServer.asRunning()) {
- sendTxt.setText(R.string.server_has_stopped);
- textServerIp.setIP("");
- sendBtn.setText(R.string.send);
- } else {
- sendTxt.setText(R.string.server_has_started);
- textServerIp.setIP(serverIp);
- sendBtn.setText(R.string.stop);
- }
- });
-
- //接收
- receiveBtn.setOnClickListener(v -> {
- if (HttpServer.asRunning()) {
- receiveTxt.setText(R.string.sender_cannot_receive);
- ToastUtils.show(getString(R.string.sender_cannot_receive));
- return;
- }
-
- if (NetUtils.NETWORK_WIFI != NetUtils.getNetWorkStatus()) {
- receiveTxt.setText(R.string.no_wifi_network);
- ToastUtils.show(getString(R.string.no_wifi_network));
- return;
- }
-
- serverIp = textServerIp.getIP();
- if (serverIp == null || serverIp.isEmpty()) {
- receiveTxt.setText(R.string.invalid_server_ip);
- ToastUtils.show(getString(R.string.invalid_server_ip));
- return;
- }
-
- OkHttpClient.Builder builder = new OkHttpClient.Builder();
- //设置读取超时时间
- OkHttpClient client = builder
- .readTimeout(Define.REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
- .writeTimeout(Define.REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
- .connectTimeout(Define.REQUEST_TIMEOUT_SECONDS, TimeUnit.SECONDS)
- .build();
-
- Map msgMap = new HashMap();
- msgMap.put("versionCode", SettingUtils.getVersionCode());
- msgMap.put("versionName", SettingUtils.getVersionName());
-
- String requestMsg = JSON.toJSONString(msgMap);
- Log.i(TAG, "requestMsg:" + requestMsg);
- RequestBody requestBody = RequestBody.create(MediaType.parse("application/json;charset=utf-8"), requestMsg);
-
- //请求链接:post 获取版本信息,get 下载备份文件
- final String requestUrl = "http://" + serverIp + ":" + Define.HTTP_SERVER_PORT + BaseServlet.CLONE_PATH + "?" + System.currentTimeMillis();
- Log.i(TAG, "requestUrl:" + requestUrl);
-
- //获取版本信息
- final Request request = new Request.Builder()
- .url(requestUrl)
- .addHeader("Content-Type", "application/json; charset=utf-8")
- .post(requestBody)
- .build();
- client.newCall(request).enqueue(new Callback() {
- @Override
- public void onFailure(@NonNull Call call, @NonNull final IOException e) {
- ToastUtils.show(getString(R.string.tips_get_info_failed));
- }
-
- @Override
- public void onResponse(@NonNull Call call, @NonNull Response response) throws IOException {
- final String responseStr = Objects.requireNonNull(response.body()).string();
- Log.d(TAG, "Response:" + response.code() + "," + responseStr);
-
- if (TextUtils.isEmpty(responseStr)) {
- ToastUtils.show(getString(R.string.tips_get_info_failed));
- return;
- }
-
- try {
- CloneInfoVo cloneInfoVo = JSON.parseObject(responseStr, CloneInfoVo.class);
- Log.d(TAG, cloneInfoVo.toString());
-
- if (!SettingUtils.getVersionName().equals(cloneInfoVo.getVersionName())) {
- ToastUtils.show(getString(R.string.tips_versions_inconsistent));
- return;
- }
-
- if (CloneUtils.restoreSettings(cloneInfoVo)) {
- ToastUtils.show(getString(R.string.tips_clone_done));
- } else {
- ToastUtils.show(getString(R.string.tips_clone_failed));
- }
-
- } catch (Exception e) {
- ToastUtils.show(getString(R.string.tips_clone_failed) + e.getMessage());
- }
- }
- });
-
- });
-
- Button exportBtn = findViewById(R.id.exportBtn);
- TextView exportTxt = findViewById(R.id.exportTxt);
- Button importBtn = findViewById(R.id.importBtn);
- TextView importTxt = findViewById(R.id.importTxt);
-
- //导出
- exportBtn.setOnClickListener(v -> {
- if (FileUtils.writeFileR(CloneUtils.exportSettings(), backupPath, backupFile, true)) {
- ToastUtils.show("导出配置成功!");
- } else {
- exportTxt.setText("导出失败,请检查写入权限!");
- ToastUtils.show("导出失败,请检查写入权限!");
- }
- });
-
- //导入
- importBtn.setOnClickListener(v -> {
- try {
- String responseStr = FileUtils.readFileI(backupPath, backupFile);
- if (TextUtils.isEmpty(responseStr)) {
- ToastUtils.show(getString(R.string.tips_get_info_failed));
- return;
- }
-
- CloneInfoVo cloneInfoVo = JSON.parseObject(responseStr, CloneInfoVo.class);
- Log.d(TAG, Objects.requireNonNull(cloneInfoVo).toString());
-
- if (!SettingUtils.getVersionName().equals(cloneInfoVo.getVersionName())) {
- ToastUtils.show(getString(R.string.tips_versions_inconsistent));
- return;
- }
-
- if (CloneUtils.restoreSettings(cloneInfoVo)) {
- ToastUtils.show(getString(R.string.tips_clone_done));
- } else {
- ToastUtils.show(getString(R.string.tips_clone_failed));
- }
-
- } catch (Exception e) {
- e.printStackTrace();
- importTxt.setText("还原失败:" + e.getMessage());
- }
- });
-
- }
-
- @SuppressLint("SetTextI18n")
- @Override
- protected void onResume() {
- super.onResume();
-
- serverIp = NetUtils.getLocalIp(CloneActivity.this);
- TextView ipText = findViewById(R.id.ipText);
- ipText.setText(getString(R.string.local_ip) + serverIp);
- }
-
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/HelpActivity.java b/app/src/main/java/com/idormy/sms/forwarder/HelpActivity.java
deleted file mode 100644
index 213492db..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/HelpActivity.java
+++ /dev/null
@@ -1,58 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.annotation.SuppressLint;
-import android.os.Build;
-import android.os.Bundle;
-import android.webkit.WebSettings;
-import android.webkit.WebView;
-import android.webkit.WebViewClient;
-
-@SuppressWarnings("deprecation")
-public class HelpActivity extends BaseActivity {
-
- @SuppressLint("SetJavaScriptEnabled")
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_help);
- //获得控件
- WebView webView = findViewById(R.id.wv_webview);
-
- //设置
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- webView.getSettings().setSafeBrowsingEnabled(false);
- }
- WebSettings webSetting = webView.getSettings();
- webSetting.setJavaScriptEnabled(true);
-
- webSetting.setBuiltInZoomControls(true);
- webSetting.setDisplayZoomControls(false);
- webSetting.setUseWideViewPort(true);
-
- webSetting.setBlockNetworkImage(false);
- //缓存模式
- webSetting.setCacheMode(WebSettings.LOAD_NO_CACHE);
- webSetting.setDatabaseEnabled(true);
- webSetting.setDomStorageEnabled(true);
- webSetting.setAppCacheMaxSize(1024 * 1024 * 8);
- webSetting.setAppCachePath(getFilesDir().getAbsolutePath());
- webSetting.setDatabasePath(getFilesDir().getAbsolutePath());
- webSetting.setAllowFileAccess(true);
- webSetting.setAppCacheEnabled(true);
- //webSetting.setTextZoom(100);
- webSetting.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
-
- //访问网页
- webView.loadUrl("https://gitee.com/pp/SmsForwarder/wikis/pages");
- //系统默认会通过手机浏览器打开网页,为了能够直接通过WebView显示网页,则必须设置
- webView.setWebViewClient(new WebViewClient() {
- @Override
- public boolean shouldOverrideUrlLoading(WebView view, String url) {
- //使用WebView加载显示url
- view.loadUrl(url);
- //返回true
- return true;
- }
- });
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java b/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java
deleted file mode 100644
index 6e11289d..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/MainActivity.java
+++ /dev/null
@@ -1,539 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.content.Context;
-import android.content.Intent;
-import android.content.pm.PackageManager;
-import android.os.Build;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Looper;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.Window;
-import android.view.WindowManager;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.TextView;
-
-import androidx.annotation.NonNull;
-import androidx.appcompat.app.AlertDialog;
-
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.hjq.permissions.OnPermissionCallback;
-import com.hjq.permissions.Permission;
-import com.hjq.permissions.XXPermissions;
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.adapter.LogAdapter;
-import com.idormy.sms.forwarder.model.vo.LogVo;
-import com.idormy.sms.forwarder.sender.BatteryReportCronTask;
-import com.idormy.sms.forwarder.sender.HttpServer;
-import com.idormy.sms.forwarder.sender.SendUtil;
-import com.idormy.sms.forwarder.sender.SenderUtil;
-import com.idormy.sms.forwarder.service.BatteryService;
-import com.idormy.sms.forwarder.service.FrontService;
-import com.idormy.sms.forwarder.service.MusicService;
-import com.idormy.sms.forwarder.utils.CommonUtils;
-import com.idormy.sms.forwarder.utils.HttpUtils;
-import com.idormy.sms.forwarder.utils.KeepAliveUtils;
-import com.idormy.sms.forwarder.utils.LogUtils;
-import com.idormy.sms.forwarder.utils.NetUtils;
-import com.idormy.sms.forwarder.utils.OnePixelManager;
-import com.idormy.sms.forwarder.utils.PhoneUtils;
-import com.idormy.sms.forwarder.utils.RuleUtils;
-import com.idormy.sms.forwarder.utils.SettingUtils;
-import com.idormy.sms.forwarder.utils.SharedPreferencesHelper;
-import com.idormy.sms.forwarder.utils.SmsUtils;
-import com.idormy.sms.forwarder.utils.TimeUtils;
-import com.idormy.sms.forwarder.utils.UmInitConfig;
-import com.idormy.sms.forwarder.view.RefreshListView;
-import com.idormy.sms.forwarder.view.StepBar;
-import com.umeng.commonsdk.UMConfigure;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class MainActivity extends BaseActivity implements RefreshListView.IRefreshListener {
-
- private final String TAG = "MainActivity";
- // logVoList用于存储数据
- private List logVos = new ArrayList<>();
- private LogAdapter adapter;
- private RefreshListView listView;
- private Intent serviceIntent;
- private String currentType = "sms";
- OnePixelManager onePixelManager;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
-
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
-
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) return;
-
- //短信&网络组件初始化
- SmsUtils.init(this);
- NetUtils.init(this);
-
- LogUtils.init(this);
- RuleUtils.init(this);
- SenderUtil.init(this);
-
- //前台服务
- try {
- serviceIntent = new Intent(MainActivity.this, FrontService.class);
- serviceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startService(serviceIntent);
- } catch (Exception e) {
- Log.e(TAG, "FrontService:", e);
- }
-
- //监听电池状态
- try {
- Intent batteryServiceIntent = new Intent(this, BatteryService.class);
- batteryServiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startService(batteryServiceIntent);
- } catch (Exception e) {
- Log.e(TAG, "BatteryService:", e);
- }
-
- //后台播放无声音乐
- if (SettingUtils.getPlaySilenceMusic()) {
- try {
- Intent musicServiceIntent = new Intent(this, MusicService.class);
- musicServiceIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- startService(musicServiceIntent);
- } catch (Exception e) {
- Log.e(TAG, "MusicService:", e);
- }
- }
-
- //1像素透明Activity保活 or 仅锁屏状态转发APP通知
- if (SettingUtils.getOnePixelActivity() || SettingUtils.getSwitchNotUserPresent()) {
- try {
- onePixelManager = new OnePixelManager();
- onePixelManager.registerOnePixelReceiver(this);//注册广播接收者
- } catch (Exception e) {
- Log.e(TAG, "OnePixelManager:", e);
- }
- }
-
- HttpUtils.init(this);
- //启用HttpServer
- if (SettingUtils.getSwitchEnableHttpServer()) {
- HttpServer.init(this);
- try {
- HttpServer.update();
- } catch (Exception e) {
- Log.e(TAG, "Start HttpServer:", e);
- }
- }
-
- //电池状态定时推送
- if (SettingUtils.getSwitchEnableBatteryCron()) {
- try {
- BatteryReportCronTask.getSingleton().updateTimer();
- } catch (Exception e) {
- Log.e(TAG, "BatteryReportCronTask:", e);
- }
- }
-
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
-
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) {
- dialog(this);
- return;
- }
-
- //检查权限是否获取
- PackageManager pm = getPackageManager();
- CommonUtils.CheckPermission(pm, this);
- XXPermissions.with(this)
- // 接收短信
- .permission(Permission.RECEIVE_SMS)
- // 发送短信
- //.permission(Permission.SEND_SMS)
- // 读取短信
- .permission(Permission.READ_SMS)
- // 读取电话状态
- .permission(Permission.READ_PHONE_STATE)
- // 读取手机号码
- .permission(Permission.READ_PHONE_NUMBERS)
- // 读取通话记录
- .permission(Permission.READ_CALL_LOG)
- // 读取联系人
- .permission(Permission.READ_CONTACTS)
- // 储存权限
- .permission(Permission.Group.STORAGE)
- // 申请安装包权限
- //.permission(Permission.REQUEST_INSTALL_PACKAGES)
- // 申请通知栏权限
- .permission(Permission.NOTIFICATION_SERVICE)
- // 申请系统设置权限
- //.permission(Permission.WRITE_SETTINGS)
- .request(new OnPermissionCallback() {
-
- @Override
- public void onGranted(List permissions, boolean all) {
- if (MyApplication.showHelpTip) {
- if (all) {
- ToastUtils.show(R.string.toast_granted_all);
- } else {
- ToastUtils.show(R.string.toast_granted_part);
- }
- }
- SettingUtils.switchEnableSms(true);
-
- //首次使用重要提醒
- final SharedPreferencesHelper sharedPreferencesHelper = new SharedPreferencesHelper(MainActivity.this, "umeng");
- boolean firstTime = sharedPreferencesHelper.getSharedPreference("firstTime", "true").equals("true");
- if (firstTime && LogUtils.countLog("2", null, null) == 0) {
- AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this)
- .setIcon(R.mipmap.ic_launcher)
- .setTitle("首次使用重要提醒")
- .setMessage(R.string.tips_first_time)
- .setCancelable(false)//点击对话框以外的区域是否让对话框消失
- .setPositiveButton("前往系统设置", (dialogInterface, i) -> {
- sharedPreferencesHelper.put("firstTime", "false");
- dialogInterface.dismiss();
- XXPermissions.startPermissionActivity(MainActivity.this);
- }).setNegativeButton("稍后自行处理", (dialogInterface, i) -> {
- sharedPreferencesHelper.put("firstTime", "false");
- dialogInterface.dismiss();
- });
- builder.create().show();
- }
- }
-
- @Override
- public void onDenied(List permissions, boolean never) {
- if (MyApplication.showHelpTip) {
- if (never) {
- ToastUtils.show(R.string.toast_denied_never);
- // 如果是被永久拒绝就跳转到应用权限系统设置页面
- XXPermissions.startPermissionActivity(MainActivity.this, permissions);
- } else {
- ToastUtils.show(R.string.toast_denied);
- }
- }
- SettingUtils.switchEnableSms(false);
- }
- });
-
- //计算浮动按钮位置
- FloatingActionButton btnFloat = findViewById(R.id.btnCleanLog);
- RefreshListView viewList = findViewById(R.id.list_view_log);
- CommonUtils.calcMarginBottom(this, btnFloat, viewList, null);
-
- //清空日志
- btnFloat.setOnClickListener(v -> {
- AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
- builder.setTitle(R.string.clear_logs_tips)
- .setPositiveButton(R.string.confirm, (dialog, which) -> {
- // TODO Auto-generated method stub
- LogUtils.delLog(null, null);
- initTLogs();
- adapter.add(logVos);
- });
- builder.show();
- });
-
- // 先拿到数据并放在适配器上
- initTLogs(); //初始化数据
- showList(logVos);
-
- //切换日志类别
- int typeCheckId = getTypeCheckId(currentType);
- final RadioGroup radioGroupTypeCheck = findViewById(R.id.radioGroupTypeCheck);
- radioGroupTypeCheck.check(typeCheckId);
- radioGroupTypeCheck.setOnCheckedChangeListener((group, checkedId) -> {
- RadioButton rb = findViewById(checkedId);
- currentType = (String) rb.getTag();
- initTLogs();
- showList(logVos);
- });
-
- // 为ListView注册一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick()方法
- // 在这个方法中可以通过position参数判断出用户点击的是那一个子项
- listView.setOnItemClickListener((parent, view, position, id) -> {
- if (position <= 0) return;
-
- LogVo logVo = logVos.get(position - 1);
- logDetail(logVo);
- });
-
- listView.setOnItemLongClickListener((parent, view, position, id) -> {
- if (position <= 0) return false;
-
- //定义AlertDialog.Builder对象,当长按列表项的时候弹出确认删除对话框
- AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
- builder.setTitle(R.string.delete_log_title);
- builder.setMessage(R.string.delete_log_tips);
-
- //添加AlertDialog.Builder对象的setPositiveButton()方法
- builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
- Long id1 = logVos.get(position - 1).getId();
- Log.d(TAG, "id = " + id1);
- LogUtils.delLog(id1, null);
- initTLogs(); //初始化数据
- showList(logVos);
- ToastUtils.show(R.string.delete_log_toast);
- });
-
- //添加AlertDialog.Builder对象的setNegativeButton()方法
- builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
- });
-
- builder.create().show();
- return true;
- });
-
- //步骤完成状态校验
- StepBar stepBar = findViewById(R.id.stepBar);
- stepBar.setHighlight();
- }
-
- private int getTypeCheckId(String currentType) {
- switch (currentType) {
- case "call":
- return R.id.btnTypeCall;
- case "app":
- return R.id.btnTypeApp;
- default:
- return R.id.btnTypeSms;
- }
- }
-
- @SuppressLint("ObsoleteSdkInt")
- @Override
- protected void onResume() {
- super.onResume();
-
- try {
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) return;
-
- //第一次打开,未授权无法获取SIM信息,尝试在此重新获取
- if (MyApplication.SimInfoList.isEmpty()) {
- MyApplication.SimInfoList = PhoneUtils.getSimMultiInfo();
- }
- Log.d(TAG, "SimInfoList = " + MyApplication.SimInfoList.size());
-
- //省电优化设置为无限制
- if (MyApplication.showHelpTip && Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
- if (!KeepAliveUtils.isIgnoreBatteryOptimization(this)) {
- ToastUtils.delayedShow(R.string.tips_battery_optimization, 3000);
- }
- }
-
- //开启读取通知栏权限
- if (SettingUtils.getSwitchEnableAppNotify() && !CommonUtils.isNotificationListenerServiceEnabled(this)) {
- CommonUtils.toggleNotificationListenerService(this);
- SettingUtils.switchEnableAppNotify(false);
- ToastUtils.delayedShow(R.string.tips_notification_listener, 3000);
- return;
- }
-
- if (serviceIntent != null) startService(serviceIntent);
- } catch (Exception e) {
- Log.e(TAG, "onResume:", e);
- }
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
-
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) return;
-
- try {
- if (serviceIntent != null) startService(serviceIntent);
- } catch (Exception e) {
- Log.e(TAG, "onDestroy:", e);
- }
-
- if (onePixelManager != null) onePixelManager.unregisterOnePixelReceiver(this);
- }
-
- @Override
- protected void onPause() {
- overridePendingTransition(0, 0);
- super.onPause();
-
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) return;
-
- try {
- if (serviceIntent != null) startService(serviceIntent);
- } catch (Exception e) {
- Log.e(TAG, "onPause:", e);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
-
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) return;
-
- if (requestCode == CommonUtils.NOTIFICATION_REQUEST_CODE) {
- if (CommonUtils.isNotificationListenerServiceEnabled(this)) {
- ToastUtils.show(R.string.notification_listener_service_enabled);
- CommonUtils.toggleNotificationListenerService(this);
- } else {
- ToastUtils.show(R.string.notification_listener_service_disabled);
- }
- }
- }
-
- // 权限判断相关
- @Override
- public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
- super.onRequestPermissionsResult(requestCode, permissions, grantResults);
- }
-
- // 初始化数据
- private void initTLogs() {
- logVos = LogUtils.getLog(null, null, currentType);
- }
-
- private void showList(List logVosN) {
- //Log.d(TAG, "showList: " + logVosN);
- if (adapter == null) {
- // 将适配器上的数据传递给listView
- listView = findViewById(R.id.list_view_log);
- listView.setInterface(this);
- adapter = new LogAdapter(MainActivity.this, R.layout.item_log, logVosN);
- listView.setAdapter(adapter);
- } else {
- adapter.onDateChange(logVosN);
- }
- }
-
- @Override
- public void onRefresh() {
- Handler handler = new Handler();
- handler.postDelayed(() -> {
- // TODO Auto-generated method stub
- //获取最新数据
- initTLogs();
- //通知界面显示
- showList(logVos);
- //通知listview 刷新数据完毕;
- listView.refreshComplete();
- }, 2000);
- }
-
- public void logDetail(LogVo logVo) {
- AlertDialog.Builder builder = new AlertDialog.Builder(MainActivity.this);
- builder.setTitle(R.string.details);
- String simInfo = logVo.getSimInfo();
- if (simInfo != null) {
- builder.setMessage(getString(R.string.from) + logVo.getFrom() + "\n\n" + getString(R.string.msg) + logVo.getContent() + "\n\n" + getString(R.string.slot) + logVo.getSimInfo() + "\n\n" + getString(R.string.rule) + logVo.getRule() + "\n\n" + getString(R.string.time) + TimeUtils.utc2Local(logVo.getTime()) + getString(R.string.result) + logVo.getForwardResponse());
- } else {
- builder.setMessage(getString(R.string.from) + logVo.getFrom() + "\n\n" + getString(R.string.msg) + logVo.getContent() + "\n\n" + getString(R.string.rule) + logVo.getRule() + "\n\n" + getString(R.string.time) + TimeUtils.utc2Local(logVo.getTime()) + getString(R.string.result) + logVo.getForwardResponse());
- }
- //删除
- builder.setNegativeButton(R.string.del, (dialog, which) -> {
- Long id = logVo.getId();
- Log.d(TAG, "id = " + id);
- LogUtils.delLog(id, null);
- initTLogs(); //初始化数据
- showList(logVos);
- ToastUtils.show(R.string.delete_log_toast);
- dialog.dismiss();
- });
- //取消
- builder.setPositiveButton(R.string.cancel, (dialog, which) -> dialog.dismiss());
-
- //重发消息回调,重发失败也会触发
- Handler handler = new Handler(Looper.myLooper(), msg -> {
- initTLogs();
- showList(logVos);
- return true;
- });
- //对于发送失败的消息添加重发按钮
- if (logVo.getForwardStatus() != 2) {
- builder.setNeutralButton(R.string.resend, (dialog, which) -> {
- ToastUtils.show(R.string.resend_toast);
- SendUtil.resendMsgByLog(MainActivity.this, handler, logVo);
- dialog.dismiss();
- });
- }
- builder.show();
- }
-
- //按返回键不退出回到桌面
- @Override
- public void onBackPressed() {
- Intent intent = new Intent(Intent.ACTION_MAIN);
- intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.addCategory(Intent.CATEGORY_HOME);
- startActivity(intent);
- }
-
- /*** 隐私协议授权弹窗*/
- public void dialog(Context context) {
- Dialog dialog = new Dialog(context, R.style.dialog);
- @SuppressLint("InflateParams") View inflate = LayoutInflater.from(context).inflate(R.layout.diaolog_privacy_policy, null);
- TextView succsebtn = inflate.findViewById(R.id.succsebtn);
- TextView canclebtn = inflate.findViewById(R.id.caclebtn);
-
- succsebtn.setOnClickListener(v -> {
- /* uminit为1时代表已经同意隐私协议,sp记录当前状态*/
- SharedPreferencesHelper sharedPreferencesHelper = new SharedPreferencesHelper(MainActivity.this, "umeng");
- sharedPreferencesHelper.put("uminit", "1");
- UMConfigure.submitPolicyGrantResult(getApplicationContext(), true);
- /* 友盟sdk正式初始化*/
- UmInitConfig umInitConfig = new UmInitConfig();
- umInitConfig.UMinit(getApplicationContext());
- //关闭弹窗
- dialog.dismiss();
-
- //跳转到HomeActivity
- final Intent intent = context.getPackageManager().getLaunchIntentForPackage(getPackageName());
- intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
- startActivity(intent);
-
- //杀掉以前进程
- android.os.Process.killProcess(android.os.Process.myPid());
- finish();
- });
-
- canclebtn.setOnClickListener(v -> {
- dialog.dismiss();
-
- UMConfigure.submitPolicyGrantResult(getApplicationContext(), false);
- //不同意隐私协议,退出app
- android.os.Process.killProcess(android.os.Process.myPid());
- finish();
- });
-
- dialog.setContentView(inflate);
- Window dialogWindow = dialog.getWindow();
- dialogWindow.setGravity(Gravity.CENTER);
-
- //自适应大小
- WindowManager.LayoutParams dialogParams = dialogWindow.getAttributes();
- dialogParams.width = (int) (context.getResources().getDisplayMetrics().widthPixels * 0.85);
- //dialogParams.height = (int) (context.getResources().getDisplayMetrics().heightPixels * 0.7);
- dialogWindow.setAttributes(dialogParams);
-
- dialog.setCancelable(false);
- dialog.show();
- }
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java b/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java
deleted file mode 100644
index 96411a22..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/MyApplication.java
+++ /dev/null
@@ -1,137 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.Application;
-import android.content.Context;
-import android.content.Intent;
-import android.content.IntentFilter;
-import android.content.SharedPreferences;
-import android.os.Build;
-import android.util.Log;
-
-import com.hjq.permissions.XXPermissions;
-import com.hjq.toast.ToastUtils;
-import com.hjq.toast.style.WhiteToastStyle;
-import com.idormy.sms.forwarder.receiver.SimStateReceiver;
-import com.idormy.sms.forwarder.sender.SendHistory;
-import com.idormy.sms.forwarder.service.BatteryService;
-import com.idormy.sms.forwarder.service.FrontService;
-import com.idormy.sms.forwarder.service.MusicService;
-import com.idormy.sms.forwarder.utils.CrashHandler;
-import com.idormy.sms.forwarder.utils.Define;
-import com.idormy.sms.forwarder.utils.PermissionInterceptor;
-import com.idormy.sms.forwarder.utils.PhoneUtils;
-import com.idormy.sms.forwarder.utils.SettingUtils;
-import com.idormy.sms.forwarder.utils.SharedPreferencesHelper;
-import com.idormy.sms.forwarder.utils.UmInitConfig;
-import com.smailnet.emailkit.EmailKit;
-import com.umeng.commonsdk.UMConfigure;
-
-import java.util.ArrayList;
-import java.util.List;
-
-public class MyApplication extends Application {
- private static final String TAG = "MyApplication";
- //SIM卡信息
- public static List SimInfoList = new ArrayList<>();
- //是否关闭页面提示
- public static boolean showHelpTip = true;
- SharedPreferencesHelper sharedPreferencesHelper;
- //是否同意隐私协议
- public static boolean allowPrivacyPolicy = false;
- @SuppressLint("StaticFieldLeak")
- private static Context context;
- //是否已解锁
- public static boolean isUserPresent = true;
-
- @Override
- protected void attachBaseContext(Context base) {
- super.attachBaseContext(base);
- }
-
- @Override
- public void onCreate() {
- Log.d(TAG, "onCreate");
- super.onCreate();
- context = getApplicationContext();
-
- try {
- //异常捕获类
- CrashHandler crashHandler = CrashHandler.getInstance();
- crashHandler.init(getApplicationContext());
-
- // 初始化吐司工具类
- ToastUtils.init(this, new WhiteToastStyle());
- // 设置权限申请拦截器(全局设置)
- XXPermissions.setInterceptor(new PermissionInterceptor());
-
- //友盟统计
- sharedPreferencesHelper = new SharedPreferencesHelper(this, "umeng");
- //设置LOG开关,默认为false
- //UMConfigure.setLogEnabled(true);
- //友盟预初始化
- UMConfigure.preInit(getApplicationContext(), "60254fc7425ec25f10f4293e", "Umeng");
-
- //判断是否同意隐私协议,uminit为1时为已经同意,直接初始化umsdk
- if (sharedPreferencesHelper.getSharedPreference("uminit", "").equals("1")) {
- allowPrivacyPolicy = true;
- //友盟正式初始化
- UmInitConfig umInitConfig = new UmInitConfig();
- umInitConfig.UMinit(getApplicationContext());
- }
-
- //是否同意隐私协议
- if (!MyApplication.allowPrivacyPolicy) return;
-
- //前台服务
- Intent intent = new Intent(this, FrontService.class);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
- startForegroundService(intent);
- } else {
- startService(intent);
- }
-
- SendHistory.init(this);
- SettingUtils.init(this);
- EmailKit.initialize(this);
-
- SharedPreferences sp = MyApplication.this.getSharedPreferences(Define.SP_CONFIG, Context.MODE_PRIVATE);
- showHelpTip = sp.getBoolean(Define.SP_CONFIG_SWITCH_HELP_TIP, true);
-
- if (SettingUtils.getExcludeFromRecents()) {
- ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
- if (am != null) {
- List appTasks = am.getAppTasks();
- if (appTasks != null && !appTasks.isEmpty()) {
- appTasks.get(0).setExcludeFromRecents(true);
- }
- }
- }
-
- //电池状态监听
- Intent batteryServiceIntent = new Intent(this, BatteryService.class);
- startService(batteryServiceIntent);
-
- //后台播放无声音乐
- if (SettingUtils.getPlaySilenceMusic()) {
- startService(new Intent(context, MusicService.class));
- }
-
- //SIM卡插拔状态广播监听
- PhoneUtils.init(this);
- IntentFilter simStateFilter = new IntentFilter(SimStateReceiver.ACTION_SIM_STATE_CHANGED);
- registerReceiver(new SimStateReceiver(), simStateFilter);
-
- } catch (Exception e) {
- Log.e(TAG, "onCreate:", e);
- }
- }
-
- /**
- * 获取全局上下文
- */
- public static Context getContext() {
- return context;
- }
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/OnePixelActivity.java b/app/src/main/java/com/idormy/sms/forwarder/OnePixelActivity.java
deleted file mode 100644
index 63e10ed9..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/OnePixelActivity.java
+++ /dev/null
@@ -1,65 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.app.Activity;
-import android.os.Bundle;
-import android.util.Log;
-import android.view.Gravity;
-import android.view.Window;
-import android.view.WindowManager;
-
-import androidx.annotation.Nullable;
-
-import com.idormy.sms.forwarder.utils.OnePixelManager;
-
-public class OnePixelActivity extends Activity {
- private static final String TAG = "OnePixelActivity";
-
- @Override
- protected void onCreate(@Nullable Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- Window window = getWindow();
- window.setGravity(Gravity.START | Gravity.TOP);
- WindowManager.LayoutParams params = window.getAttributes();
- params.x = 0;
- params.y = 0;
- params.height = 1;
- params.width = 1;
- window.setAttributes(params);
- OnePixelManager manager = new OnePixelManager();
- manager.setKeepAliveReference(this);//将引用传给OnePixelManager
-
- Log.e(TAG, "onCreate");
- }
-
- @Override
- protected void onDestroy() {
- super.onDestroy();
- Log.e(TAG, "onDestroy");
- }
-
- @Override
- protected void onStop() {
- super.onStop();
- Log.e(TAG, "onStop");
- }
-
- @Override
- protected void onPause() {
- super.onPause();
- Log.e(TAG, "onPause");
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.e(TAG, "onStart");
- }
-
- @Override
- protected void onResume() {
- super.onResume();
- Log.e(TAG, "onResume");
- }
-}
-
-
diff --git a/app/src/main/java/com/idormy/sms/forwarder/RuleActivity.java b/app/src/main/java/com/idormy/sms/forwarder/RuleActivity.java
deleted file mode 100644
index 5e4a3d5e..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/RuleActivity.java
+++ /dev/null
@@ -1,618 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import static com.idormy.sms.forwarder.SenderActivity.NOTIFY;
-import static com.idormy.sms.forwarder.model.RuleModel.STATUS_OFF;
-import static com.idormy.sms.forwarder.model.RuleModel.STATUS_ON;
-
-import android.annotation.SuppressLint;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.util.Log;
-import android.view.View;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.RadioButton;
-import android.widget.RadioGroup;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import androidx.appcompat.app.AlertDialog;
-
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.adapter.RuleAdapter;
-import com.idormy.sms.forwarder.model.RuleModel;
-import com.idormy.sms.forwarder.model.SenderModel;
-import com.idormy.sms.forwarder.model.vo.SmsVo;
-import com.idormy.sms.forwarder.sender.SendUtil;
-import com.idormy.sms.forwarder.sender.SenderUtil;
-import com.idormy.sms.forwarder.utils.CommonUtils;
-import com.idormy.sms.forwarder.utils.LogUtils;
-import com.idormy.sms.forwarder.utils.RuleUtils;
-import com.idormy.sms.forwarder.utils.SettingUtils;
-import com.idormy.sms.forwarder.view.StepBar;
-
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.List;
-
-@SuppressWarnings("deprecation")
-public class RuleActivity extends BaseActivity {
-
- private final String TAG = "RuleActivity";
- // 用于存储数据
- private List ruleModels = new ArrayList<>();
- private RuleAdapter adapter;
- private String currentType = "sms";
- private ListView listView;
-
- //消息处理者,创建一个Handler的子类对象,目的是重写Handler的处理消息的方法(handleMessage())
- @SuppressLint("HandlerLeak")
- private final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == NOTIFY) {
- ToastUtils.delayedShow(msg.getData().getString("DATA"), 3000);
- }
- }
- };
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_rule);
-
- LogUtils.init(this);
- RuleUtils.init(this);
- SenderUtil.init(this);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
-
- // 先拿到数据并放在适配器上
- initRules(); //初始化数据
- adapter = new RuleAdapter(RuleActivity.this, R.layout.item_rule, ruleModels);
-
- // 将适配器上的数据传递给listView
- listView = findViewById(R.id.list_view_rule);
- listView.setAdapter(adapter);
-
- // 为ListView注册一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick()方法
- // 在这个方法中可以通过position参数判断出用户点击的是那一个子项
- listView.setOnItemClickListener((parent, view, position, id) -> {
- RuleModel ruleModel = ruleModels.get(position);
- Log.d(TAG, "onItemClick: " + ruleModel);
- setRule(ruleModel, false);
- });
-
- listView.setOnItemLongClickListener((parent, view, position, id) -> {
- //定义AlertDialog.Builder对象,当长按列表项的时候弹出确认删除对话框
- AlertDialog.Builder builder = new AlertDialog.Builder(RuleActivity.this);
- builder.setTitle(R.string.delete_rule_title);
- builder.setMessage(R.string.delete_rule_tips);
-
- builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
- RuleUtils.delRule(ruleModels.get(position).getId());
- initRules();
- adapter.del(ruleModels);
- ToastUtils.show(R.string.delete_rule_toast);
- });
-
- builder.setNeutralButton(R.string.clone, (dialog, which) -> {
- RuleModel ruleModel = ruleModels.get(position);
- setRule(ruleModel, true);
- });
-
- builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
-
- });
-
- builder.create().show();
- return true;
- });
-
- //切换日志类别
- int typeCheckId = getTypeCheckId(currentType);
- final RadioGroup radioGroupTypeCheck = findViewById(R.id.radioGroupTypeCheck);
- radioGroupTypeCheck.check(typeCheckId);
- radioGroupTypeCheck.setOnCheckedChangeListener((group, checkedId) -> {
- RadioButton rb = findViewById(checkedId);
- currentType = (String) rb.getTag();
- initRules(); //初始化数据
- adapter = new RuleAdapter(RuleActivity.this, R.layout.item_rule, ruleModels);
- listView.setAdapter(adapter);
- });
-
-
- //计算浮动按钮位置
- FloatingActionButton btnAddRule = findViewById(R.id.btnAddRule);
- CommonUtils.calcMarginBottom(this, btnAddRule, listView, null);
-
- //添加规则
- btnAddRule.setOnClickListener(v -> setRule(null, false));
-
- //步骤完成状态校验
- StepBar stepBar = findViewById(R.id.stepBar);
- stepBar.setHighlight();
- }
-
- private int getTypeCheckId(String curType) {
- switch (curType) {
- case "call":
- return R.id.btnTypeCall;
- case "app":
- return R.id.btnTypeApp;
- default:
- return R.id.btnTypeSms;
- }
- }
-
- private int getDialogView(String curType) {
- switch (curType) {
- case "call":
- return R.layout.alert_dialog_setview_rule_call;
- case "app":
- return R.layout.alert_dialog_setview_rule_app;
- default:
- return R.layout.alert_dialog_setview_rule;
- }
- }
-
- private int getDialogTitle(String curType) {
- switch (curType) {
- case "call":
- return R.string.setrule_call;
- case "app":
- return R.string.setrule_app;
- default:
- return R.string.setrule;
- }
- }
-
- // 初始化数据
- private void initRules() {
- ruleModels = RuleUtils.getRule(null, null, currentType);
- }
-
- private void setRule(final RuleModel ruleModel, final boolean isClone) {
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(RuleActivity.this);
- final View view1 = View.inflate(RuleActivity.this, getDialogView(currentType), null);
-
- final RadioGroup radioGroupRuleFiled = view1.findViewById(R.id.radioGroupRuleFiled);
- if (ruleModel != null) radioGroupRuleFiled.check(ruleModel.getRuleFiledCheckId());
-
- final RadioGroup radioGroupRuleCheck = view1.findViewById(R.id.radioGroupRuleCheck);
- final RadioGroup radioGroupRuleCheck2 = view1.findViewById(R.id.radioGroupRuleCheck2);
- if (ruleModel != null) {
- int ruleCheckCheckId = ruleModel.getRuleCheckCheckId();
- if (ruleCheckCheckId == R.id.btnIs || ruleCheckCheckId == R.id.btnNotContain || ruleCheckCheckId == R.id.btnContain) {
- radioGroupRuleCheck.check(ruleCheckCheckId);
- } else {
- radioGroupRuleCheck2.check(ruleCheckCheckId);
- }
- } else {
- radioGroupRuleCheck.check(R.id.btnIs);
- }
-
- final RadioGroup radioGroupSimSlot = view1.findViewById(R.id.radioGroupSimSlot);
- if (ruleModel != null) radioGroupSimSlot.check(ruleModel.getRuleSimSlotCheckId());
-
- final TextView tv_mu_rule_tips = view1.findViewById(R.id.tv_mu_rule_tips);
- final TextView ruleSenderTv = view1.findViewById(R.id.ruleSenderTv);
- if (ruleModel != null && ruleModel.getSenderId() != null) {
- List getSenders = SenderUtil.getSender(ruleModel.getSenderId(), null);
- if (!getSenders.isEmpty()) {
- ruleSenderTv.setText(getSenders.get(0).getName());
- ruleSenderTv.setTag(getSenders.get(0).getId());
- }
- }
- final Button btSetRuleSender = view1.findViewById(R.id.btSetRuleSender);
- btSetRuleSender.setOnClickListener(view -> {
- //ToastUtils.show("selectSender", 3000);
- selectSender(ruleSenderTv);
- });
-
- final EditText editTextRuleValue = view1.findViewById(R.id.editTextRuleValue);
- if (ruleModel != null)
- editTextRuleValue.setText(ruleModel.getValue());
-
- //当更新选择的字段的时候,更新之下各个选项的状态
- final LinearLayout matchTypeLayout = view1.findViewById(R.id.matchTypeLayout);
- final LinearLayout matchValueLayout = view1.findViewById(R.id.matchValueLayout);
- refreshSelectRadioGroupRuleFiled(radioGroupRuleFiled, radioGroupRuleCheck, radioGroupRuleCheck2, editTextRuleValue, tv_mu_rule_tips, matchTypeLayout, matchValueLayout);
-
- //是否启用该规则
- @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switchRuleStatus = view1.findViewById(R.id.switch_rule_status);
- if (ruleModel != null) {
- switchRuleStatus.setChecked(ruleModel.getStatusChecked());
- }
- //自定义模板
- @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switchSmsTemplate = view1.findViewById(R.id.switch_sms_template);
- EditText textSmsTemplate = view1.findViewById(R.id.text_sms_template);
- if (ruleModel != null) {
- switchSmsTemplate.setChecked(ruleModel.getSwitchSmsTemplate());
- textSmsTemplate.setText(ruleModel.getSmsTemplate());
- }
-
- //正则替换
- @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switchRegexReplace = view1.findViewById(R.id.switch_regex_replace);
- EditText textRegexReplace = view1.findViewById(R.id.text_regex_replace);
- if (ruleModel != null) {
- switchRegexReplace.setChecked(ruleModel.getSwitchRegexReplace());
- textRegexReplace.setText(ruleModel.getRegexReplace());
- }
-
- Button buttonRuleOk = view1.findViewById(R.id.buttonRuleOk);
- Button buttonRuleDel = view1.findViewById(R.id.buttonRuleDel);
- buttonRuleDel.setText(ruleModel != null ? R.string.del : R.string.cancel);
- Button buttonRuleTest = view1.findViewById(R.id.buttonRuleTest);
- alertDialog71
- .setTitle(getDialogTitle(currentType))
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
- buttonRuleOk.setOnClickListener(view -> {
- Object senderId = ruleSenderTv.getTag();
- if (senderId == null) {
- ToastUtils.delayedShow(R.string.new_sender_first, 3000);
- return;
- }
-
- //检查正则替换填写是否正确
- String regexReplace = textRegexReplace.getText().toString().trim();
- int lineNum = checkRegexReplace(regexReplace);
- if (lineNum > 0) {
- ToastUtils.show("lineNum=" + lineNum);
- return;
- }
-
- int radioGroupRuleCheckId = Math.max(radioGroupRuleCheck.getCheckedRadioButtonId(), radioGroupRuleCheck2.getCheckedRadioButtonId());
- Log.d(TAG, radioGroupRuleCheck.getCheckedRadioButtonId() + " " + radioGroupRuleCheck2.getCheckedRadioButtonId() + " " + radioGroupRuleCheckId);
- if (isClone || ruleModel == null) {
- RuleModel newRuleModel = new RuleModel();
- newRuleModel.setType(currentType);
- newRuleModel.setFiled(RuleModel.getRuleFiledFromCheckId(radioGroupRuleFiled.getCheckedRadioButtonId()));
- newRuleModel.setCheck(RuleModel.getRuleCheckFromCheckId(radioGroupRuleCheckId));
- newRuleModel.setSimSlot(RuleModel.getRuleSimSlotFromCheckId(radioGroupSimSlot.getCheckedRadioButtonId()));
- newRuleModel.setValue(editTextRuleValue.getText().toString().trim());
- newRuleModel.setSwitchSmsTemplate(switchSmsTemplate.isChecked());
- newRuleModel.setSmsTemplate(textSmsTemplate.getText().toString().trim());
- newRuleModel.setSwitchRegexReplace(switchRegexReplace.isChecked());
- newRuleModel.setRegexReplace(regexReplace);
- newRuleModel.setSenderId(Long.valueOf(senderId.toString()));
- newRuleModel.setStatus(switchRuleStatus.isChecked() ? STATUS_ON : STATUS_OFF);
- RuleUtils.addRule(newRuleModel);
- initRules();
- adapter.add(ruleModels);
- } else {
- ruleModel.setFiled(RuleModel.getRuleFiledFromCheckId(radioGroupRuleFiled.getCheckedRadioButtonId()));
- ruleModel.setCheck(RuleModel.getRuleCheckFromCheckId(radioGroupRuleCheckId));
- ruleModel.setSimSlot(RuleModel.getRuleSimSlotFromCheckId(radioGroupSimSlot.getCheckedRadioButtonId()));
- ruleModel.setValue(editTextRuleValue.getText().toString().trim());
- ruleModel.setSwitchSmsTemplate(switchSmsTemplate.isChecked());
- ruleModel.setSmsTemplate(textSmsTemplate.getText().toString().trim());
- ruleModel.setSwitchRegexReplace(switchRegexReplace.isChecked());
- ruleModel.setRegexReplace(regexReplace);
- ruleModel.setSenderId(Long.valueOf(senderId.toString()));
- ruleModel.setStatus(switchRuleStatus.isChecked() ? STATUS_ON : STATUS_OFF);
- RuleUtils.updateRule(ruleModel);
- initRules();
- adapter.update(ruleModels);
- }
- show.dismiss();
- });
-
- buttonRuleDel.setOnClickListener(view -> {
- if (ruleModel != null) {
- RuleUtils.delRule(ruleModel.getId());
- initRules();
- adapter.del(ruleModels);
- }
- show.dismiss();
- });
-
- buttonRuleTest.setOnClickListener(view -> {
- Object senderId = ruleSenderTv.getTag();
- if (senderId == null) {
- ToastUtils.delayedShow(R.string.new_sender_first, 3000);
- return;
- }
-
- //检查正则替换填写是否正确
- String regexReplace = textRegexReplace.getText().toString().trim();
- int lineNum = checkRegexReplace(regexReplace);
- if (lineNum > 0) {
- ToastUtils.show("lineNum=" + lineNum);
- return;
- }
-
- int radioGroupRuleCheckId = Math.max(radioGroupRuleCheck.getCheckedRadioButtonId(), radioGroupRuleCheck2.getCheckedRadioButtonId());
- if (ruleModel == null) {
- RuleModel newRuleModel = new RuleModel();
- newRuleModel.setFiled(RuleModel.getRuleFiledFromCheckId(radioGroupRuleFiled.getCheckedRadioButtonId()));
- newRuleModel.setCheck(RuleModel.getRuleCheckFromCheckId(radioGroupRuleCheckId));
- newRuleModel.setSimSlot(RuleModel.getRuleSimSlotFromCheckId(radioGroupSimSlot.getCheckedRadioButtonId()));
- newRuleModel.setValue(editTextRuleValue.getText().toString().trim());
- newRuleModel.setSenderId(Long.valueOf(senderId.toString()));
- newRuleModel.setSwitchSmsTemplate(switchSmsTemplate.isChecked());
- newRuleModel.setSmsTemplate(textSmsTemplate.getText().toString().trim());
- newRuleModel.setSwitchRegexReplace(switchRegexReplace.isChecked());
- newRuleModel.setRegexReplace(regexReplace);
- newRuleModel.setStatus(switchRuleStatus.isChecked() ? STATUS_ON : STATUS_OFF);
-
- testRule(newRuleModel, Long.valueOf(senderId.toString()));
- } else {
- ruleModel.setFiled(RuleModel.getRuleFiledFromCheckId(radioGroupRuleFiled.getCheckedRadioButtonId()));
- ruleModel.setCheck(RuleModel.getRuleCheckFromCheckId(radioGroupRuleCheckId));
- ruleModel.setSimSlot(RuleModel.getRuleSimSlotFromCheckId(radioGroupSimSlot.getCheckedRadioButtonId()));
- ruleModel.setValue(editTextRuleValue.getText().toString().trim());
- ruleModel.setSenderId(Long.valueOf(senderId.toString()));
- ruleModel.setSwitchSmsTemplate(switchSmsTemplate.isChecked());
- ruleModel.setSmsTemplate(textSmsTemplate.getText().toString().trim());
- ruleModel.setSwitchRegexReplace(switchRegexReplace.isChecked());
- ruleModel.setRegexReplace(regexReplace);
- ruleModel.setStatus(switchRuleStatus.isChecked() ? STATUS_ON : STATUS_OFF);
-
- testRule(ruleModel, Long.valueOf(senderId.toString()));
- }
- });
-
- //自定义模板
- final LinearLayout layout_sms_template = view1.findViewById(R.id.layout_sms_template);
- if (ruleModel != null) {
- layout_sms_template.setVisibility(ruleModel.getSwitchSmsTemplate() ? View.VISIBLE : View.GONE);
- }
- switchSmsTemplate.setOnCheckedChangeListener((buttonView, isChecked) -> {
- layout_sms_template.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- if (!isChecked) {
- textSmsTemplate.setText("");
- }
- });
-
- Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
- buttonInsertSender.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_from));
- });
-
- Button buttonInsertContent = view1.findViewById(R.id.bt_insert_content);
- buttonInsertContent.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_sms));
- });
-
- Button buttonInsertSenderApp = view1.findViewById(R.id.bt_insert_sender_app);
- buttonInsertSenderApp.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_package_name));
- });
-
- Button buttonInsertContentApp = view1.findViewById(R.id.bt_insert_content_app);
- buttonInsertContentApp.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_msg));
- });
-
- Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
- buttonInsertExtra.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_card_slot));
- });
-
- Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
- buttonInsertTime.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_receive_time));
- });
-
- Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
- buttonInsertDeviceName.setOnClickListener(view -> {
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_device_name));
- });
-
- //正则替换
- final LinearLayout layout_regex_replace = view1.findViewById(R.id.layout_regex_replace);
- if (ruleModel != null) {
- layout_regex_replace.setVisibility(ruleModel.getSwitchRegexReplace() ? View.VISIBLE : View.GONE);
- }
- switchRegexReplace.setOnCheckedChangeListener((buttonView, isChecked) -> {
- layout_regex_replace.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- if (!isChecked) {
- textRegexReplace.setText("");
- }
- });
-
- }
-
- //当更新选择的字段的时候,更新之下各个选项的状态
- // 如果设置了转发全部,禁用选择模式和匹配值输入
- // 如果设置了多重规则,选择模式置为是
- private void refreshSelectRadioGroupRuleFiled(RadioGroup radioGroupRuleFiled, final RadioGroup radioGroupRuleCheck, final RadioGroup radioGroupRuleCheck2, final EditText editTextRuleValue, final TextView tv_mu_rule_tips, final LinearLayout matchTypeLayout, final LinearLayout matchValueLayout) {
- refreshSelectRadioGroupRuleFiledAction(radioGroupRuleFiled.getCheckedRadioButtonId(), radioGroupRuleCheck, radioGroupRuleCheck2, editTextRuleValue, tv_mu_rule_tips, matchTypeLayout, matchValueLayout);
-
- radioGroupRuleCheck.setOnCheckedChangeListener((group, checkedId) -> {
- Log.d(TAG, String.valueOf(group));
- Log.d(TAG, String.valueOf(checkedId));
- if (group != null && checkedId > 0) {
- if (group == radioGroupRuleCheck) {
- radioGroupRuleCheck2.clearCheck();
- } else if (group == radioGroupRuleCheck2) {
- radioGroupRuleCheck.clearCheck();
- }
- group.check(checkedId);
- }
- });
- radioGroupRuleCheck2.setOnCheckedChangeListener((group, checkedId) -> {
- Log.d(TAG, String.valueOf(group));
- Log.d(TAG, String.valueOf(checkedId));
- if (group != null && checkedId > 0) {
- if (group == radioGroupRuleCheck) {
- radioGroupRuleCheck2.clearCheck();
- } else if (group == radioGroupRuleCheck2) {
- radioGroupRuleCheck.clearCheck();
- }
- group.check(checkedId);
- }
- });
- radioGroupRuleFiled.setOnCheckedChangeListener((group, checkedId) -> {
- Log.d(TAG, String.valueOf(group));
- Log.d(TAG, String.valueOf(checkedId));
- if (group == radioGroupRuleCheck) {
- radioGroupRuleCheck2.clearCheck();
- } else if (group == radioGroupRuleCheck2) {
- radioGroupRuleCheck.clearCheck();
- }
- refreshSelectRadioGroupRuleFiledAction(checkedId, radioGroupRuleCheck, radioGroupRuleCheck2, editTextRuleValue, tv_mu_rule_tips, matchTypeLayout, matchValueLayout);
- });
- }
-
- @SuppressLint("NonConstantResourceId")
- private void refreshSelectRadioGroupRuleFiledAction(int checkedRuleFiledId, final RadioGroup radioGroupRuleCheck, final RadioGroup radioGroupRuleCheck2, final EditText editTextRuleValue, final TextView tv_mu_rule_tips, final LinearLayout matchTypeLayout, final LinearLayout matchValueLayout) {
- tv_mu_rule_tips.setVisibility(View.GONE);
- matchTypeLayout.setVisibility(View.VISIBLE);
- matchValueLayout.setVisibility(View.VISIBLE);
-
- switch (checkedRuleFiledId) {
- case R.id.btnTranspondAll:
- for (int i = 0; i < radioGroupRuleCheck.getChildCount(); i++) {
- radioGroupRuleCheck.getChildAt(i).setEnabled(false);
- }
- for (int i = 0; i < radioGroupRuleCheck2.getChildCount(); i++) {
- radioGroupRuleCheck2.getChildAt(i).setEnabled(false);
- }
- editTextRuleValue.setEnabled(false);
- matchTypeLayout.setVisibility(View.GONE);
- matchValueLayout.setVisibility(View.GONE);
- break;
- case R.id.btnMultiMatch:
- for (int i = 0; i < radioGroupRuleCheck.getChildCount(); i++) {
- radioGroupRuleCheck.getChildAt(i).setEnabled(false);
- }
- for (int i = 0; i < radioGroupRuleCheck2.getChildCount(); i++) {
- radioGroupRuleCheck2.getChildAt(i).setEnabled(false);
- }
- editTextRuleValue.setEnabled(true);
- matchTypeLayout.setVisibility(View.GONE);
- tv_mu_rule_tips.setVisibility(MyApplication.showHelpTip ? View.VISIBLE : View.GONE);
- break;
- default:
- for (int i = 0; i < radioGroupRuleCheck.getChildCount(); i++) {
- radioGroupRuleCheck.getChildAt(i).setEnabled(true);
- }
- for (int i = 0; i < radioGroupRuleCheck2.getChildCount(); i++) {
- radioGroupRuleCheck2.getChildAt(i).setEnabled(true);
- }
- editTextRuleValue.setEnabled(true);
- break;
- }
- }
-
- public void selectSender(final TextView showTv) {
- final List senderModels = SenderUtil.getSender(null, null);
- if (senderModels.isEmpty()) {
- ToastUtils.show(R.string.add_sender_first);
- return;
- }
- final CharSequence[] senderNames = new CharSequence[senderModels.size()];
- for (int i = 0; i < senderModels.size(); i++) {
- senderNames[i] = senderModels.get(i).getName();
- }
- AlertDialog.Builder builder = new AlertDialog.Builder(RuleActivity.this);
- builder.setTitle(R.string.select_sender);
- //添加列表
- builder.setItems(senderNames, (dialogInterface, which) -> {
- //ToastUtils.delayedShow(senderNames[which], 3000);
- showTv.setText(senderNames[which]);
- showTv.setTag(senderModels.get(which).getId());
- });
- builder.show();
- }
-
- public void testRule(final RuleModel ruleModel, final Long senderId) {
- final View view = View.inflate(RuleActivity.this, R.layout.alert_dialog_setview_rule_test, null);
- final TextView textTestSimSlot = view.findViewById(R.id.textTestSimSlot);
- final TextView textTestPhone = view.findViewById(R.id.textTestPhone);
- final TextView textTestContent = view.findViewById(R.id.textTestContent);
- final RadioGroup radioGroupTestSimSlot = view.findViewById(R.id.radioGroupTestSimSlot);
- final EditText editTextTestPhone = view.findViewById(R.id.editTextTestPhone);
- final EditText editTextTestMsgContent = view.findViewById(R.id.editTextTestMsgContent);
-
- if ("app".equals(currentType)) {
- textTestSimSlot.setVisibility(View.GONE);
- radioGroupTestSimSlot.setVisibility(View.GONE);
- textTestPhone.setText(R.string.test_package_name);
- textTestContent.setText(R.string.test_inform_content);
- } else if ("call".equals(currentType)) {
- textTestContent.setVisibility(View.GONE);
- editTextTestMsgContent.setVisibility(View.GONE);
- }
-
- Button buttonRuleTest = view.findViewById(R.id.buttonRuleTest);
- AlertDialog.Builder ad1 = new AlertDialog.Builder(RuleActivity.this);
- ad1.setTitle(R.string.rule_tester);
- ad1.setIcon(android.R.drawable.ic_dialog_email);
- ad1.setView(view);
- buttonRuleTest.setOnClickListener(v -> {
-
- Log.i("editTextTestPhone", editTextTestPhone.getText().toString().trim());
- Log.i("editTextTestMsgContent", editTextTestMsgContent.getText().toString().trim());
-
- try {
- String simSlot = RuleModel.getRuleSimSlotFromCheckId(radioGroupTestSimSlot.getCheckedRadioButtonId());
- String simInfo;
- if (simSlot.equals("SIM2")) {
- simInfo = simSlot + "_" + SettingUtils.getAddExtraSim2();
- } else {
- simInfo = simSlot + "_" + SettingUtils.getAddExtraSim1();
- }
- SmsVo testSmsVo = new SmsVo(editTextTestPhone.getText().toString().trim(), editTextTestMsgContent.getText().toString().trim(), new Date(), simInfo);
- SendUtil.sendMsgByRuleModelSenderId(handler, ruleModel, testSmsVo, senderId);
- } catch (Exception e) {
- ToastUtils.delayedShow(e.getMessage(), 3000);
- }
- });
- ad1.show();// 显示对话框
- }
-
- @Override
- protected void onDestroy() {
- Log.d(TAG, "onDestroy");
- super.onDestroy();
- }
-
- @Override
- protected void onPause() {
- overridePendingTransition(0, 0);
- super.onPause();
- }
-
- private int checkRegexReplace(String regexReplace) {
- if (regexReplace == null || regexReplace.isEmpty()) return 0;
-
- int lineNum = 1;
- String[] lineArray = regexReplace.split("\\n");
- for (String line : lineArray) {
- int position = line.indexOf("===");
- if (position < 1) return lineNum;
- lineNum++;
- }
-
- return 0;
- }
-
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java b/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java
deleted file mode 100644
index 967a28b1..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/SenderActivity.java
+++ /dev/null
@@ -1,2212 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import static com.idormy.sms.forwarder.model.SenderModel.STATUS_OFF;
-import static com.idormy.sms.forwarder.model.SenderModel.STATUS_ON;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_BARK;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_DINGDING;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_EMAIL;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_FEISHU;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_GOTIFY;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_PUSHPLUS;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_APP;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_QYWX_GROUP_ROBOT;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_SERVER_CHAN;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_SMS;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_TELEGRAM;
-import static com.idormy.sms.forwarder.model.SenderModel.TYPE_WEB_NOTIFY;
-
-import android.annotation.SuppressLint;
-import android.app.Dialog;
-import android.os.Bundle;
-import android.os.Handler;
-import android.os.Message;
-import android.text.SpannableString;
-import android.text.Spanned;
-import android.text.SpannedString;
-import android.text.TextUtils;
-import android.text.style.AbsoluteSizeSpan;
-import android.util.Log;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.widget.AdapterView;
-import android.widget.Button;
-import android.widget.EditText;
-import android.widget.GridView;
-import android.widget.ImageView;
-import android.widget.LinearLayout;
-import android.widget.ListView;
-import android.widget.RadioGroup;
-import android.widget.SimpleAdapter;
-import android.widget.Spinner;
-import android.widget.Switch;
-
-import androidx.appcompat.app.AlertDialog;
-
-import com.alibaba.fastjson.JSON;
-import com.google.android.material.floatingactionbutton.FloatingActionButton;
-import com.hjq.permissions.OnPermissionCallback;
-import com.hjq.permissions.Permission;
-import com.hjq.permissions.XXPermissions;
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.adapter.SenderAdapter;
-import com.idormy.sms.forwarder.model.SenderModel;
-import com.idormy.sms.forwarder.model.vo.BarkSettingVo;
-import com.idormy.sms.forwarder.model.vo.DingDingSettingVo;
-import com.idormy.sms.forwarder.model.vo.EmailSettingVo;
-import com.idormy.sms.forwarder.model.vo.FeiShuSettingVo;
-import com.idormy.sms.forwarder.model.vo.GotifySettingVo;
-import com.idormy.sms.forwarder.model.vo.PushPlusSettingVo;
-import com.idormy.sms.forwarder.model.vo.QYWXAppSettingVo;
-import com.idormy.sms.forwarder.model.vo.QYWXGroupRobotSettingVo;
-import com.idormy.sms.forwarder.model.vo.ServerChanSettingVo;
-import com.idormy.sms.forwarder.model.vo.SmsSettingVo;
-import com.idormy.sms.forwarder.model.vo.SmsVo;
-import com.idormy.sms.forwarder.model.vo.TelegramSettingVo;
-import com.idormy.sms.forwarder.model.vo.WebNotifySettingVo;
-import com.idormy.sms.forwarder.sender.SenderBarkMsg;
-import com.idormy.sms.forwarder.sender.SenderDingdingMsg;
-import com.idormy.sms.forwarder.sender.SenderFeishuMsg;
-import com.idormy.sms.forwarder.sender.SenderGotifyMsg;
-import com.idormy.sms.forwarder.sender.SenderMailMsg;
-import com.idormy.sms.forwarder.sender.SenderPushPlusMsg;
-import com.idormy.sms.forwarder.sender.SenderQyWxAppMsg;
-import com.idormy.sms.forwarder.sender.SenderQyWxGroupRobotMsg;
-import com.idormy.sms.forwarder.sender.SenderServerChanMsg;
-import com.idormy.sms.forwarder.sender.SenderSmsMsg;
-import com.idormy.sms.forwarder.sender.SenderTelegramMsg;
-import com.idormy.sms.forwarder.sender.SenderUtil;
-import com.idormy.sms.forwarder.sender.SenderWebNotifyMsg;
-import com.idormy.sms.forwarder.utils.CommonUtils;
-import com.idormy.sms.forwarder.utils.LogUtils;
-import com.idormy.sms.forwarder.utils.RuleUtils;
-import com.idormy.sms.forwarder.view.ClearEditText;
-import com.idormy.sms.forwarder.view.StepBar;
-
-import java.net.Proxy;
-import java.util.ArrayList;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-
-@SuppressWarnings("deprecation")
-public class SenderActivity extends BaseActivity {
-
- public static final int NOTIFY = 0x9731993;
- private final String TAG = "SenderActivity";
- //消息处理者,创建一个Handler的子类对象,目的是重写Handler的处理消息的方法(handleMessage())
- @SuppressLint("HandlerLeak")
- private final Handler handler = new Handler() {
- @Override
- public void handleMessage(Message msg) {
- if (msg.what == NOTIFY) {
- ToastUtils.delayedShow(msg.getData().getString("DATA"), 3000);
- }
- }
- };
- // 用于存储数据
- private List senderModels = new ArrayList<>();
- private SenderAdapter adapter;
-
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_sender);
-
- LogUtils.init(this);
- RuleUtils.init(this);
- SenderUtil.init(this);
- }
-
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
-
- // 先拿到数据并放在适配器上
- initSenders(); //初始化数据
- adapter = new SenderAdapter(SenderActivity.this, R.layout.item_sender, senderModels);
-
- // 将适配器上的数据传递给listView
- ListView listView = findViewById(R.id.list_view_sender);
- listView.setAdapter(adapter);
-
- // 为ListView注册一个监听器,当用户点击了ListView中的任何一个子项时,就会回调onItemClick()方法
- // 在这个方法中可以通过position参数判断出用户点击的是那一个子项
- listView.setOnItemClickListener((parent, view, position, id) -> {
- SenderModel senderModel = senderModels.get(position);
- Log.d(TAG, "onItemClick: " + senderModel);
-
- switch (senderModel.getType()) {
- case TYPE_DINGDING:
- setDingDing(senderModel, false);
- break;
- case TYPE_EMAIL:
- setEmail(senderModel, false);
- break;
- case TYPE_BARK:
- setBark(senderModel, false);
- break;
- case TYPE_WEB_NOTIFY:
- setWebNotify(senderModel, false);
- break;
- case TYPE_QYWX_GROUP_ROBOT:
- setQYWXGroupRobot(senderModel, false);
- break;
- case TYPE_QYWX_APP:
- setQYWXApp(senderModel, false);
- break;
- case TYPE_SERVER_CHAN:
- setServerChan(senderModel, false);
- break;
- case TYPE_TELEGRAM:
- setTelegram(senderModel, false);
- break;
- case TYPE_SMS:
- setSms(senderModel, false);
- break;
- case TYPE_FEISHU:
- setFeiShu(senderModel, false);
- break;
- case TYPE_PUSHPLUS:
- setPushPlus(senderModel, false);
- break;
- case TYPE_GOTIFY:
- setGotify(senderModel, false);
- break;
- default:
- ToastUtils.delayedShow(R.string.invalid_sender, 3000);
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- break;
- }
-
- });
-
- listView.setOnItemLongClickListener((parent, view, position, id) -> {
- //定义AlertDialog.Builder对象,当长按列表项的时候弹出确认删除对话框
- AlertDialog.Builder builder = new AlertDialog.Builder(SenderActivity.this);
- builder.setTitle(R.string.delete_sender_title);
- builder.setMessage(R.string.delete_sender_tips);
-
- //添加AlertDialog.Builder对象的setPositiveButton()方法
- builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
- SenderUtil.delSender(senderModels.get(position).getId());
- initSenders();
- adapter.del(senderModels);
- ToastUtils.show(R.string.delete_sender_toast);
- });
-
- builder.setNeutralButton(R.string.clone, (dialog, which) -> {
- SenderModel senderModel = senderModels.get(position);
- switch (senderModel.getType()) {
- case TYPE_DINGDING:
- setDingDing(senderModel, true);
- break;
- case TYPE_EMAIL:
- setEmail(senderModel, true);
- break;
- case TYPE_BARK:
- setBark(senderModel, true);
- break;
- case TYPE_WEB_NOTIFY:
- setWebNotify(senderModel, true);
- break;
- case TYPE_QYWX_GROUP_ROBOT:
- setQYWXGroupRobot(senderModel, true);
- break;
- case TYPE_QYWX_APP:
- setQYWXApp(senderModel, true);
- break;
- case TYPE_SERVER_CHAN:
- setServerChan(senderModel, true);
- break;
- case TYPE_TELEGRAM:
- setTelegram(senderModel, true);
- break;
- case TYPE_SMS:
- setSms(senderModel, true);
- break;
- case TYPE_FEISHU:
- setFeiShu(senderModel, true);
- break;
- case TYPE_PUSHPLUS:
- setPushPlus(senderModel, true);
- break;
- case TYPE_GOTIFY:
- setGotify(senderModel, true);
- break;
- default:
- ToastUtils.delayedShow(R.string.invalid_sender, 3000);
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- break;
- }
- });
-
- //添加AlertDialog.Builder对象的setNegativeButton()方法
- builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
-
- });
-
- builder.create().show();
- return true;
- });
-
-
- //计算浮动按钮位置
- FloatingActionButton btnFloat = findViewById(R.id.btnAddSender);
- CommonUtils.calcMarginBottom(this, btnFloat, listView, null);
-
- //添加发送通道
- btnFloat.setOnClickListener(v -> {
-
- @SuppressLint("InflateParams") View dialog_menu = LayoutInflater.from(SenderActivity.this).inflate(R.layout.alert_dialog_menu, null);
- // 设置style 控制默认dialog带来的边距问题
- final Dialog dialog = new Dialog(this, R.style.dialog_menu);
- dialog.setContentView(dialog_menu);
- dialog.show();
-
- GridView gridview = dialog.findViewById(R.id.MemuGridView);
- final List> item = getMenuData();
- SimpleAdapter simpleAdapter = new SimpleAdapter(this, item, R.layout.item_menu, new String[]{"ItemImageView", "ItemTextView"}, new int[]{R.id.ItemImageView, R.id.ItemTextView});
- gridview.setAdapter(simpleAdapter);
-
- // 添加点击事件
- gridview.setOnItemClickListener((arg0, arg1, position, arg3) -> {
- dialog.dismiss();
-
- switch (position) {
- case TYPE_DINGDING:
- setDingDing(null, false);
- break;
- case TYPE_EMAIL:
- setEmail(null, false);
- break;
- case TYPE_BARK:
- setBark(null, false);
- break;
- case TYPE_WEB_NOTIFY:
- setWebNotify(null, false);
- break;
- case TYPE_QYWX_GROUP_ROBOT:
- setQYWXGroupRobot(null, false);
- break;
- case TYPE_QYWX_APP:
- setQYWXApp(null, false);
- break;
- case TYPE_SERVER_CHAN:
- setServerChan(null, false);
- break;
- case TYPE_TELEGRAM:
- setTelegram(null, false);
- break;
- case TYPE_SMS:
- setSms(null, false);
- break;
- case TYPE_FEISHU:
- setFeiShu(null, false);
- break;
- case TYPE_PUSHPLUS:
- setPushPlus(null, false);
- break;
- case TYPE_GOTIFY:
- setGotify(null, false);
- break;
- default:
- ToastUtils.delayedShow(R.string.not_supported, 3000);
- break;
- }
- });
- });
-
- //步骤完成状态校验
- StepBar stepBar = findViewById(R.id.stepBar);
- stepBar.setHighlight();
- }
-
- @Override
- protected void onDestroy() {
- Log.d(TAG, "onDestroy");
- super.onDestroy();
- }
-
- @Override
- protected void onPause() {
- overridePendingTransition(0, 0);
- super.onPause();
- }
-
- // 初始化数据
- private void initSenders() {
- senderModels = SenderUtil.getSender(null, null);
- }
-
- // 获取发送通道菜单
- private List> getMenuData() {
- //定义图标数组
- int[] imageRes = {
- R.mipmap.dingding,
- R.mipmap.email,
- R.mipmap.bark,
- R.mipmap.webhook,
- R.mipmap.qywx,
- R.mipmap.qywxapp,
- R.mipmap.serverchan,
- R.mipmap.telegram,
- R.mipmap.sms,
- R.mipmap.feishu,
- R.mipmap.pushplus,
- R.mipmap.gotify,
- };
- //定义标题数组
- String[] itemName = {
- getString(R.string.dingding),
- getString(R.string.email),
- getString(R.string.bark),
- getString(R.string.webhook),
- getString(R.string.qywx),
- getString(R.string.qywxapp),
- getString(R.string.serverchan),
- getString(R.string.telegram),
- getString(R.string.sms_menu),
- getString(R.string.feishu),
- getString(R.string.pushplus),
- getString(R.string.gotify),
- };
- List> data = new ArrayList<>();
- int length = itemName.length;
- for (int i = 0; i < length; i++) {
- HashMap map = new HashMap<>();
- map.put("ItemImageView", imageRes[i]);
- map.put("ItemTextView", itemName[i]);
- data.add(map);
- }
- return data;
- }
-
- //钉钉机器人
- @SuppressLint({"SimpleDateFormat", "SetTextI18n"})
- private void setDingDing(final SenderModel senderModel, final boolean isClone) {
- DingDingSettingVo dingDingSettingVo = null;
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- dingDingSettingVo = JSON.parseObject(jsonSettingStr, DingDingSettingVo.class);
- }
- }
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_dingding, null);
-
- final EditText editTextDingdingName = view1.findViewById(R.id.editTextDingdingName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchDingdingEnable = view1.findViewById(R.id.switchDingdingEnable);
- if (senderModel != null) {
- editTextDingdingName.setText(senderModel.getName());
- switchDingdingEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextDingdingToken = view1.findViewById(R.id.editTextDingdingToken);
- final ClearEditText editTextDingdingSecret = view1.findViewById(R.id.editTextDingdingSecret);
- final EditText editTextDingdingAtMobiles = view1.findViewById(R.id.editTextDingdingAtMobiles);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchDingdingAtAll = view1.findViewById(R.id.switchDingdingAtAll);
- final LinearLayout linearLayoutDingdingAtMobiles = view1.findViewById(R.id.linearLayoutDingdingAtMobiles);
- if (dingDingSettingVo != null) {
- editTextDingdingToken.setText(dingDingSettingVo.getToken());
- editTextDingdingSecret.setText(dingDingSettingVo.getSecret());
- editTextDingdingAtMobiles.setText(dingDingSettingVo.getAtMobiles());
- if (dingDingSettingVo.getAtAll() != null) {
- switchDingdingAtAll.setChecked(dingDingSettingVo.getAtAll());
- linearLayoutDingdingAtMobiles.setVisibility(dingDingSettingVo.getAtAll() ? View.GONE : View.VISIBLE);
- }
- }
-
- switchDingdingAtAll.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (isChecked) {
- linearLayoutDingdingAtMobiles.setVisibility(View.GONE);
- editTextDingdingAtMobiles.setText("@all");
- } else {
- linearLayoutDingdingAtMobiles.setVisibility(View.VISIBLE);
- editTextDingdingAtMobiles.setText("");
- }
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- });
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setdingdingtitle)
- .setIcon(R.mipmap.dingding)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextDingdingName.getText().toString().trim();
- int senderStatus = switchDingdingEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- String token = editTextDingdingToken.getText().trim();
- String secret = editTextDingdingSecret.getText().trim();
- String atMobiles = editTextDingdingAtMobiles.getText().toString().trim();
- Boolean atAll = switchDingdingAtAll.isChecked();
-
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
- if (CommonUtils.checkUrl(token, true)) {
- ToastUtils.delayedShow(R.string.invalid_token, 3000);
- return;
- }
-
- DingDingSettingVo dingDingSettingVoNew = new DingDingSettingVo(token, secret, atMobiles, atAll);
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_DINGDING);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(dingDingSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_DINGDING);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(dingDingSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String token = editTextDingdingToken.getText().trim();
- if (CommonUtils.checkUrl(token, true)) {
- ToastUtils.delayedShow(R.string.invalid_token, 3000);
- return;
- }
-
- String secret = editTextDingdingSecret.getText().trim();
- String atMobiles = editTextDingdingAtMobiles.getText().toString().trim();
- Boolean atAll = switchDingdingAtAll.isChecked();
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderDingdingMsg.sendMsg(0, handler, null, token, secret, atMobiles, atAll, smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //邮箱
- @SuppressLint("SimpleDateFormat")
- private void setEmail(final SenderModel senderModel, final boolean isClone) {
- final String[] MAIL_TYPE = getResources().getStringArray(R.array.MailType);
-
- EmailSettingVo emailSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- emailSettingVo = JSON.parseObject(jsonSettingStr, EmailSettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_email, null);
-
- final EditText editTextEmailName = view1.findViewById(R.id.editTextEmailName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchEmailEnable = view1.findViewById(R.id.switchEmailEnable);
- if (senderModel != null) {
- editTextEmailName.setText(senderModel.getName());
- switchEmailEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final EditText editTextEmailHost = view1.findViewById(R.id.editTextEmailHost);
- final EditText editTextEmailPort = view1.findViewById(R.id.editTextEmailPort);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchEmailSSl = view1.findViewById(R.id.switchEmailSSl);
- final EditText editTextEmailFromAdd = view1.findViewById(R.id.editTextEmailFromAdd);
- final EditText editTextEmailNickname = view1.findViewById(R.id.editTextEmailNickname);
- final ClearEditText editTextEmailPsw = view1.findViewById(R.id.editTextEmailPsw);
- final EditText editTextEmailToAdd = view1.findViewById(R.id.editTextEmailToAdd);
- final EditText editTextEmailTitle = view1.findViewById(R.id.editTextEmailTitle);
- final Spinner spinnerEmailType = view1.findViewById(R.id.spinnerEmailType);
- final LinearLayout layoutServiceSetting = view1.findViewById(R.id.layoutServiceSetting);
- if (emailSettingVo != null) {
- String mailType = emailSettingVo.getMailType();
- if (!TextUtils.isEmpty(mailType)) {
- for (int i = 0; i < MAIL_TYPE.length; i++) {
- if (mailType.equals(MAIL_TYPE[i])) {
- spinnerEmailType.setSelection(i);
- break;
- }
- }
- } else {
- spinnerEmailType.setSelection(MAIL_TYPE.length - 1);
- }
- editTextEmailHost.setText(emailSettingVo.getHost());
- editTextEmailPort.setText(emailSettingVo.getPort());
- switchEmailSSl.setChecked(emailSettingVo.getSsl());
- editTextEmailFromAdd.setText(emailSettingVo.getFromEmail());
- editTextEmailNickname.setText(emailSettingVo.getNickname());
- editTextEmailPsw.setText(emailSettingVo.getPwd());
- editTextEmailToAdd.setText(emailSettingVo.getToEmail());
- editTextEmailTitle.setText(emailSettingVo.getTitle());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setemailtitle)
- .setIcon(R.mipmap.email)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- spinnerEmailType.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
-
- @Override
- public void onItemSelected(AdapterView> parent, View view, int position, long id) {
- String mailType = parent.getItemAtPosition(position).toString();
- //ToastUtils.show("选择的邮箱类型是:" + mailType);
-
- String hint;
- if (mailType.equals(getString(R.string.other_mail_type))) {
- hint = getString(R.string.hint_from_add_full);
- layoutServiceSetting.setVisibility(View.VISIBLE);
- ToastUtils.delayedShow(R.string.tips_other_mail_type, 3000);
- } else {
- hint = getString(R.string.hint_from_add);
- layoutServiceSetting.setVisibility(View.GONE);
- }
- SpannableString ss = new SpannableString(hint);//定义hint的值
- AbsoluteSizeSpan ass = new AbsoluteSizeSpan(13, true);//设置字体大小 true表示单位是sp
- ss.setSpan(ass, 0, ss.length(), Spanned.SPAN_EXCLUSIVE_EXCLUSIVE);
- editTextEmailFromAdd.setHint(new SpannedString(ss));
- }
-
- @Override
- public void onNothingSelected(AdapterView> parent) {
- // TODO Auto-generated method stub
- }
- });
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextEmailName.getText().toString().trim();
- int senderStatus = switchEmailEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String mailType = spinnerEmailType.getSelectedItem().toString();
- String host = editTextEmailHost.getText().toString().trim();
- String port = editTextEmailPort.getText().toString().trim();
- boolean ssl = switchEmailSSl.isChecked();
- String fromEmail = editTextEmailFromAdd.getText().toString().trim();
- String pwd = editTextEmailPsw.getText().trim();
- String toEmail = editTextEmailToAdd.getText().toString().trim();
-
- String title = editTextEmailTitle.getText().toString().trim();
- if (title.isEmpty()) title = "SmsForwarder Title";
-
- String nickname = editTextEmailNickname.getText().toString().trim();
- if (nickname.isEmpty()) nickname = "SmsForwarder";
- if (fromEmail.isEmpty() || pwd.isEmpty() || toEmail.isEmpty()) {
- ToastUtils.delayedShow(R.string.invalid_email, 3000);
- return;
- }
-
- if (mailType.equals(getString(R.string.other_mail_type)) && (host.isEmpty() || port.isEmpty())) {
- ToastUtils.delayedShow(R.string.tips_other_mail_type, 3000);
- return;
- }
-
- EmailSettingVo emailSettingVoNew = new EmailSettingVo(mailType, host, port, ssl, fromEmail, nickname, pwd, toEmail, title);
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_EMAIL);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(emailSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_EMAIL);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(emailSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String mailType = spinnerEmailType.getSelectedItem().toString();
- String host = editTextEmailHost.getText().toString().trim();
- String port = editTextEmailPort.getText().toString().trim();
- boolean ssl = switchEmailSSl.isChecked();
- String fromEmail = editTextEmailFromAdd.getText().toString().trim();
- String pwd = editTextEmailPsw.getText().trim();
- String toEmail = editTextEmailToAdd.getText().toString().trim();
-
- String title = editTextEmailTitle.getText().toString().trim();
- if (title.isEmpty()) title = "SmsForwarder Title";
-
- String nickname = editTextEmailNickname.getText().toString().trim();
- if (nickname.isEmpty()) nickname = "SmsForwarder";
-
- if (fromEmail.isEmpty() || pwd.isEmpty() || toEmail.isEmpty()) {
- ToastUtils.delayedShow(R.string.invalid_email, 3000);
- return;
- }
-
- if (mailType.equals(getString(R.string.other_mail_type)) && (host.isEmpty() || port.isEmpty())) {
- ToastUtils.delayedShow(R.string.tips_other_mail_type, 3000);
- return;
- }
-
- try {
- EmailSettingVo emailSettingVoNew = new EmailSettingVo(mailType, host, port, ssl, fromEmail, nickname, pwd, toEmail, title);
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderMailMsg.sendEmail(0, handler, emailSettingVoNew, smsVo.getTitleForSend(title), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
-
-
- Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
- buttonInsertSender.setOnClickListener(view -> {
- editTextEmailTitle.setFocusable(true);
- editTextEmailTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextEmailTitle, getString(R.string.tag_from));
- });
-
- Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
- buttonInsertExtra.setOnClickListener(view -> {
- editTextEmailTitle.setFocusable(true);
- editTextEmailTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextEmailTitle, getString(R.string.tag_card_slot));
- });
-
- Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
- buttonInsertTime.setOnClickListener(view -> {
- editTextEmailTitle.setFocusable(true);
- editTextEmailTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextEmailTitle, getString(R.string.tag_receive_time));
- });
-
- Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
- buttonInsertDeviceName.setOnClickListener(view -> {
- editTextEmailTitle.setFocusable(true);
- editTextEmailTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextEmailTitle, getString(R.string.tag_device_name));
- });
-
- }
-
- //Bark
- private void setBark(final SenderModel senderModel, final boolean isClone) {
- BarkSettingVo barkSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- barkSettingVo = JSON.parseObject(jsonSettingStr, BarkSettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_bark, null);
-
- final EditText editTextBarkName = view1.findViewById(R.id.editTextBarkName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchBarkEnable = view1.findViewById(R.id.switchBarkEnable);
- if (senderModel != null) {
- editTextBarkName.setText(senderModel.getName());
- switchBarkEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextBarkServer = view1.findViewById(R.id.editTextBarkServer);
- final EditText editTextBarkTitle = view1.findViewById(R.id.editTextBarkTitle);
- final EditText editTextBarkIcon = view1.findViewById(R.id.editTextBarkIcon);
- final EditText editTextBarkSound = view1.findViewById(R.id.editTextBarkSound);
- final EditText editTextBarkBadge = view1.findViewById(R.id.editTextBarkBadge);
- final EditText editTextBarkUrl = view1.findViewById(R.id.editTextBarkUrl);
- final RadioGroup radioGroupBarkLevel = view1.findViewById(R.id.radioGroupBarkLevel);
- if (barkSettingVo != null) {
- editTextBarkServer.setText(barkSettingVo.getServer());
- editTextBarkTitle.setText(barkSettingVo.getTitle());
- editTextBarkIcon.setText(barkSettingVo.getIcon());
- editTextBarkSound.setText(barkSettingVo.getSound());
- editTextBarkBadge.setText(barkSettingVo.getBadge());
- editTextBarkUrl.setText(barkSettingVo.getUrl());
- radioGroupBarkLevel.check(barkSettingVo.getLevelId());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setbarktitle)
- .setIcon(R.mipmap.bark)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextBarkName.getText().toString().trim();
- int senderStatus = switchBarkEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- //推送地址
- String barkServer = editTextBarkServer.getText().trim();
- if (!CommonUtils.checkUrl(barkServer, false)) {
- ToastUtils.delayedShow(R.string.invalid_bark_server, 3000);
- return;
- }
-
- String icon = editTextBarkIcon.getText().toString().trim(); //消息图标
- String title = editTextBarkTitle.getText().toString().trim(); //标题模板
- int levelId = radioGroupBarkLevel.getCheckedRadioButtonId(); //时效性
- String sound = editTextBarkSound.getText().toString().trim(); //声音
- String badge = editTextBarkBadge.getText().toString().trim(); //角标
- String url = editTextBarkUrl.getText().toString().trim(); //链接
- BarkSettingVo barkSettingVoNew = new BarkSettingVo(barkServer, icon, title, levelId, sound, badge, url);
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_BARK);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(barkSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_BARK);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(barkSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String barkServer = editTextBarkServer.getText().trim();
- String icon = editTextBarkIcon.getText().toString().trim(); //消息图标
- String title = editTextBarkTitle.getText().toString().trim(); //标题模板
- int levelId = radioGroupBarkLevel.getCheckedRadioButtonId(); //时效性
- String sound = editTextBarkSound.getText().toString().trim(); //声音
- String badge = editTextBarkBadge.getText().toString().trim(); //角标
- String url = editTextBarkUrl.getText().toString().trim(); //链接
- BarkSettingVo barkSettingVoNew = new BarkSettingVo(barkServer, icon, title, levelId, sound, badge, url);
- if (CommonUtils.checkUrl(barkServer, false)) {
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderBarkMsg.sendMsg(0, handler, null, barkSettingVoNew, smsVo.getTitleForSend(title), smsVo.getSmsVoForSend(), getString(R.string.test_group_name));
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- } else {
- ToastUtils.delayedShow(R.string.invalid_bark_server, 3000);
- }
- });
-
-
- Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
- buttonInsertSender.setOnClickListener(view -> {
- editTextBarkTitle.setFocusable(true);
- editTextBarkTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextBarkTitle, getString(R.string.tag_from));
- });
-
- Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
- buttonInsertExtra.setOnClickListener(view -> {
- editTextBarkTitle.setFocusable(true);
- editTextBarkTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextBarkTitle, getString(R.string.tag_card_slot));
- });
-
- Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
- buttonInsertTime.setOnClickListener(view -> {
- editTextBarkTitle.setFocusable(true);
- editTextBarkTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextBarkTitle, getString(R.string.tag_receive_time));
- });
-
- Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
- buttonInsertDeviceName.setOnClickListener(view -> {
- editTextBarkTitle.setFocusable(true);
- editTextBarkTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextBarkTitle, getString(R.string.tag_device_name));
- });
-
- }
-
- //header序号
- int headerItemId = 0;
-
- /**
- * 动态增删header
- *
- * @param headerItemMap 管理item的map,用于删除指定header
- * @param linearLayoutWebNotifyHeaders 需要挂载item的LinearLayout
- * @param key header的key,为空则不设置
- * @param value header的value,为空则不设置
- */
- private void addHeaderItemLinearLayout(Map headerItemMap, final LinearLayout linearLayoutWebNotifyHeaders, String key, String value) {
- LinearLayout linearLayoutItemAddHeader = (LinearLayout) View.inflate(this, R.layout.item_add_header, null);
- ImageView imageViewRemoveHeader = linearLayoutItemAddHeader.findViewById(R.id.imageViewRemoveHeader);
-
- if (key != null && value != null) {
- EditText editTextHeaderKey = linearLayoutItemAddHeader.findViewById(R.id.editTextHeaderKey);
- EditText editTextHeaderValue = linearLayoutItemAddHeader.findViewById(R.id.editTextHeaderValue);
- editTextHeaderKey.setText(key);
- editTextHeaderValue.setText(value);
- }
-
- imageViewRemoveHeader.setTag(headerItemId);
- imageViewRemoveHeader.setOnClickListener(view2 -> {
- int itemId = (int) view2.getTag();
- linearLayoutWebNotifyHeaders.removeView(headerItemMap.get(itemId));
- headerItemMap.remove(itemId);
- });
- linearLayoutWebNotifyHeaders.addView(linearLayoutItemAddHeader);
- headerItemMap.put(headerItemId, linearLayoutItemAddHeader);
- headerItemId++;
- }
-
- /**
- * 从EditText控件中获取全部headers
- *
- * @param headerItemMap 管理item的map
- * @return 全部headers
- */
- private Map getHeadersFromHeaderItemMap(Map headerItemMap) {
- Map headers = new HashMap<>();
- for (LinearLayout headerItem : headerItemMap.values()) {
- EditText editTextHeaderKey = headerItem.findViewById(R.id.editTextHeaderKey);
- EditText editTextHeaderValue = headerItem.findViewById(R.id.editTextHeaderValue);
- String key = editTextHeaderKey.getText().toString().trim();
- String value = editTextHeaderValue.getText().toString().trim();
- headers.put(key, value);
- }
- return headers;
- }
-
- //webhook
- @SuppressLint("SimpleDateFormat")
- private void setWebNotify(final SenderModel senderModel, final boolean isClone) {
- WebNotifySettingVo webNotifySettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- webNotifySettingVo = JSON.parseObject(jsonSettingStr, WebNotifySettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_webnotify, null);
-
- final EditText editTextWebNotifyName = view1.findViewById(R.id.editTextWebNotifyName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchWebNotifyEnable = view1.findViewById(R.id.switchWebNotifyEnable);
- if (senderModel != null) {
- editTextWebNotifyName.setText(senderModel.getName());
- switchWebNotifyEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final EditText editTextWebNotifyWebServer = view1.findViewById(R.id.editTextWebNotifyWebServer);
- final EditText editTextWebNotifyWebParams = view1.findViewById(R.id.editTextWebNotifyWebParams);
- final ClearEditText editTextWebNotifySecret = view1.findViewById(R.id.editTextWebNotifySecret);
- final RadioGroup radioGroupWebNotifyMethod = view1.findViewById(R.id.radioGroupWebNotifyMethod);
-
- Map headerItemMap = new HashMap<>(2);
- final LinearLayout linearLayoutWebNotifyHeaders = view1.findViewById(R.id.linearLayoutWebNotifyHeaders);
- final ImageView imageViewWebNotifyAddHeader = view1.findViewById(R.id.imageViewWebNotifyAddHeader);
-
- if (webNotifySettingVo != null) {
- editTextWebNotifyWebServer.setText(webNotifySettingVo.getWebServer());
- editTextWebNotifyWebParams.setText(webNotifySettingVo.getWebParams());
- editTextWebNotifySecret.setText(webNotifySettingVo.getSecret());
- radioGroupWebNotifyMethod.check(webNotifySettingVo.getWebNotifyMethodCheckId());
- //set header
- Map headers = webNotifySettingVo.getHeaders();
- if (headers != null) {
- for (Map.Entry header : headers.entrySet()) {
- addHeaderItemLinearLayout(headerItemMap, linearLayoutWebNotifyHeaders, header.getKey(), header.getValue());
- }
- }
- }
-
- //add header
- imageViewWebNotifyAddHeader.setOnClickListener(view -> addHeaderItemLinearLayout(headerItemMap, linearLayoutWebNotifyHeaders, null, null));
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setwebnotifytitle)
- .setIcon(R.mipmap.webhook)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextWebNotifyName.getText().toString().trim();
- int senderStatus = switchWebNotifyEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String webServer = editTextWebNotifyWebServer.getText().toString().trim();
- String secret = editTextWebNotifySecret.getText().trim();
- String method = radioGroupWebNotifyMethod.getCheckedRadioButtonId() == R.id.radioWebNotifyMethodGet ? "GET" : "POST";
- String webParams = editTextWebNotifyWebParams.getText().toString().trim();
- Map headers = getHeadersFromHeaderItemMap(headerItemMap);
-
- if (!CommonUtils.checkUrl(webServer, false)) {
- ToastUtils.delayedShow(R.string.invalid_webserver, 3000);
- return;
- }
-
- WebNotifySettingVo webNotifySettingVoNew = new WebNotifySettingVo(webServer, secret, method, webParams, headers);
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_WEB_NOTIFY);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(webNotifySettingVoNew));
- SenderUtil.addSender(newSenderModel);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_WEB_NOTIFY);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(webNotifySettingVoNew));
- SenderUtil.updateSender(senderModel);
- }
- initSenders();
- adapter.update(senderModels);
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String webServer = editTextWebNotifyWebServer.getText().toString().trim();
- String secret = editTextWebNotifySecret.getText().trim();
- String method = radioGroupWebNotifyMethod.getCheckedRadioButtonId() == R.id.radioWebNotifyMethodGet ? "GET" : "POST";
- String webParams = editTextWebNotifyWebParams.getText().toString().trim();
- Map headers = getHeadersFromHeaderItemMap(headerItemMap);
-
- if (!CommonUtils.checkUrl(webServer, false)) {
- ToastUtils.delayedShow(R.string.invalid_webserver, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderWebNotifyMsg.sendMsg(0, handler, null, webServer, webParams, secret, method, headers, smsVo, "", "");
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //企业微信群机器人
- @SuppressLint("SimpleDateFormat")
- private void setQYWXGroupRobot(final SenderModel senderModel, final boolean isClone) {
- QYWXGroupRobotSettingVo qywxGroupRobotSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- qywxGroupRobotSettingVo = JSON.parseObject(jsonSettingStr, QYWXGroupRobotSettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_qywxgrouprobot, null);
-
- final EditText editTextQYWXGroupRobotName = view1.findViewById(R.id.editTextQYWXGroupRobotName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchQYWXGroupRobotEnable = view1.findViewById(R.id.switchQYWXGroupRobotEnable);
- if (senderModel != null) {
- editTextQYWXGroupRobotName.setText(senderModel.getName());
- switchQYWXGroupRobotEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextQYWXGroupRobotWebHook = view1.findViewById(R.id.editTextQYWXGroupRobotWebHook);
- if (qywxGroupRobotSettingVo != null) {
- editTextQYWXGroupRobotWebHook.setText(qywxGroupRobotSettingVo.getWebHook());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setqywxgrouprobottitle)
- .setIcon(R.mipmap.qywx)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextQYWXGroupRobotName.getText().toString().trim();
- int senderStatus = switchQYWXGroupRobotEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String webHook = editTextQYWXGroupRobotWebHook.getText().trim();
- if (!CommonUtils.checkUrl(webHook, false)) {
- ToastUtils.delayedShow(R.string.invalid_webhook, 3000);
- return;
- }
-
- QYWXGroupRobotSettingVo qywxGroupRobotSettingVoNew = new QYWXGroupRobotSettingVo(webHook);
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_QYWX_GROUP_ROBOT);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(qywxGroupRobotSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_QYWX_GROUP_ROBOT);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(qywxGroupRobotSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String webHook = editTextQYWXGroupRobotWebHook.getText().trim();
- if (!CommonUtils.checkUrl(webHook, false)) {
- ToastUtils.delayedShow(R.string.invalid_webhook, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderQyWxGroupRobotMsg.sendMsg(0, handler, null, webHook, smsVo.getMobile(), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //企业微信应用
- @SuppressLint({"SimpleDateFormat", "SetTextI18n"})
- private void setQYWXApp(final SenderModel senderModel, final boolean isClone) {
- QYWXAppSettingVo QYWXAppSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- QYWXAppSettingVo = JSON.parseObject(jsonSettingStr, QYWXAppSettingVo.class);
- }
- }
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_qywxapp, null);
-
- final EditText editTextQYWXAppName = view1.findViewById(R.id.editTextQYWXAppName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchQYWXAppEnable = view1.findViewById(R.id.switchQYWXAppEnable);
- if (senderModel != null) {
- editTextQYWXAppName.setText(senderModel.getName());
- switchQYWXAppEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final EditText editTextQYWXAppCorpID = view1.findViewById(R.id.editTextQYWXAppCorpID);
- final EditText editTextQYWXAppAgentID = view1.findViewById(R.id.editTextQYWXAppAgentID);
- final ClearEditText editTextQYWXAppSecret = view1.findViewById(R.id.editTextQYWXAppSecret);
- final LinearLayout linearLayoutQYWXAppToUser = view1.findViewById(R.id.linearLayoutQYWXAppToUser);
- final EditText editTextQYWXAppToUser = view1.findViewById(R.id.editTextQYWXAppToUser);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchQYWXAppAtAll = view1.findViewById(R.id.switchQYWXAppAtAll);
- if (QYWXAppSettingVo != null) {
- editTextQYWXAppCorpID.setText(QYWXAppSettingVo.getCorpID());
- editTextQYWXAppAgentID.setText(QYWXAppSettingVo.getAgentID());
- editTextQYWXAppSecret.setText(QYWXAppSettingVo.getSecret());
- editTextQYWXAppToUser.setText(QYWXAppSettingVo.getToUser());
- switchQYWXAppAtAll.setChecked(QYWXAppSettingVo.getAtAll());
- linearLayoutQYWXAppToUser.setVisibility(QYWXAppSettingVo.getAtAll() ? View.GONE : View.VISIBLE);
- }
- switchQYWXAppAtAll.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (isChecked) {
- linearLayoutQYWXAppToUser.setVisibility(View.GONE);
- editTextQYWXAppToUser.setText("@all");
- } else {
- linearLayoutQYWXAppToUser.setVisibility(View.VISIBLE);
- editTextQYWXAppToUser.setText("");
- }
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- });
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setqywxapptitle)
- .setIcon(R.mipmap.qywxapp)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextQYWXAppName.getText().toString().trim();
- int senderStatus = switchQYWXAppEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String toUser = editTextQYWXAppToUser.getText().toString().trim();
- if (toUser.isEmpty()) {
- ToastUtils.delayedShow(R.string.invalid_at_mobiles, 3000);
- editTextQYWXAppToUser.setFocusable(true);
- editTextQYWXAppToUser.requestFocus();
- return;
- }
-
- QYWXAppSettingVo QYWXAppSettingVoNew = new QYWXAppSettingVo(
- editTextQYWXAppCorpID.getText().toString().trim(),
- editTextQYWXAppAgentID.getText().toString().trim(),
- editTextQYWXAppSecret.getText().trim(),
- editTextQYWXAppToUser.getText().toString().trim(),
- switchQYWXAppAtAll.isChecked());
- if (!QYWXAppSettingVoNew.checkParms()) {
- ToastUtils.delayedShow(R.string.invalid_webcom_app_parm, 3000);
- return;
- }
-
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_QYWX_APP);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(QYWXAppSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_QYWX_APP);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(QYWXAppSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- QYWXAppSettingVo QYWXAppSettingVoNew = new QYWXAppSettingVo(
- editTextQYWXAppCorpID.getText().toString().trim(),
- editTextQYWXAppAgentID.getText().toString().trim(),
- editTextQYWXAppSecret.getText().trim(),
- editTextQYWXAppToUser.getText().toString().trim(),
- switchQYWXAppAtAll.isChecked());
- if (!QYWXAppSettingVoNew.checkParms()) {
- ToastUtils.delayedShow(R.string.invalid_webcom_app_parm, 3000);
- return;
- }
- if (QYWXAppSettingVoNew.getToUser().isEmpty()) {
- ToastUtils.delayedShow(R.string.invalid_at_mobiles, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderQyWxAppMsg.sendMsg(0, handler, null, senderModel, QYWXAppSettingVoNew, smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //Server酱·Turbo版
- private void setServerChan(final SenderModel senderModel, final boolean isClone) {
- ServerChanSettingVo serverchanSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- serverchanSettingVo = JSON.parseObject(jsonSettingStr, ServerChanSettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_serverchan, null);
-
- final EditText editTextServerChanName = view1.findViewById(R.id.editTextServerChanName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchServerChanEnable = view1.findViewById(R.id.switchServerChanEnable);
- if (senderModel != null) {
- editTextServerChanName.setText(senderModel.getName());
- switchServerChanEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextServerChanSendKey = view1.findViewById(R.id.editTextServerChanSendKey);
- if (serverchanSettingVo != null)
- editTextServerChanSendKey.setText(serverchanSettingVo.getSendKey());
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setserverchantitle)
- .setIcon(R.mipmap.serverchan)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextServerChanName.getText().toString().trim();
- int senderStatus = switchServerChanEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String serverChanServer = editTextServerChanSendKey.getText().trim();
- if (TextUtils.isEmpty(serverChanServer)) {
- ToastUtils.delayedShow(R.string.invalid_sendkey, 3000);
- return;
- }
- ServerChanSettingVo serverChanSettingVoNew = new ServerChanSettingVo(serverChanServer);
-
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_SERVER_CHAN);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(serverChanSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_SERVER_CHAN);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(serverChanSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String serverChanServer = editTextServerChanSendKey.getText().trim();
- if (TextUtils.isEmpty(serverChanServer)) {
- ToastUtils.delayedShow(R.string.invalid_sendkey, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderServerChanMsg.sendMsg(0, handler, null, serverChanServer, smsVo.getMobile(), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //Telegram机器人
- private void setTelegram(final SenderModel senderModel, final boolean isClone) {
- TelegramSettingVo telegramSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- telegramSettingVo = JSON.parseObject(jsonSettingStr, TelegramSettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_telegram, null);
-
- final EditText editTextTelegramName = view1.findViewById(R.id.editTextTelegramName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchTelegramEnable = view1.findViewById(R.id.switchTelegramEnable);
- if (senderModel != null) {
- editTextTelegramName.setText(senderModel.getName());
- switchTelegramEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextTelegramApiToken = view1.findViewById(R.id.editTextTelegramApiToken);
- final EditText editTextTelegramChatId = view1.findViewById(R.id.editTextTelegramChatId);
- final RadioGroup radioGroupTelegramMethod = view1.findViewById(R.id.radioGroupTelegramMethod);
-
- final RadioGroup radioGroupProxyType = view1.findViewById(R.id.radioGroupProxyType);
- final EditText editTextProxyHost = view1.findViewById(R.id.editTextProxyHost);
- final EditText editTextProxyPort = view1.findViewById(R.id.editTextProxyPort);
-
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchProxyAuthenticator = view1.findViewById(R.id.switchProxyAuthenticator);
- final EditText editTextProxyUsername = view1.findViewById(R.id.editTextProxyUsername);
- final ClearEditText editTextProxyPassword = view1.findViewById(R.id.editTextProxyPassword);
-
- final LinearLayout layoutProxyHost = view1.findViewById(R.id.layoutProxyHost);
- final LinearLayout layoutProxyPort = view1.findViewById(R.id.layoutProxyPort);
- final LinearLayout layoutProxyAuthenticator = view1.findViewById(R.id.layoutProxyAuthenticator);
-
- switchProxyAuthenticator.setOnCheckedChangeListener((buttonView, isChecked) -> {
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- layoutProxyAuthenticator.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- });
-
- radioGroupProxyType.setOnCheckedChangeListener((group, checkedId) -> {
- if (group != null && checkedId > 0) {
- if (checkedId == R.id.btnProxyNone) {
- layoutProxyHost.setVisibility(View.GONE);
- layoutProxyPort.setVisibility(View.GONE);
- layoutProxyAuthenticator.setVisibility(View.GONE);
- } else {
- layoutProxyHost.setVisibility(View.VISIBLE);
- layoutProxyPort.setVisibility(View.VISIBLE);
- layoutProxyAuthenticator.setVisibility(switchProxyAuthenticator.isChecked() ? View.VISIBLE : View.GONE);
- }
- group.check(checkedId);
- }
- });
-
- if (telegramSettingVo != null) {
- editTextTelegramApiToken.setText(telegramSettingVo.getApiToken());
- editTextTelegramChatId.setText(telegramSettingVo.getChatId());
- radioGroupTelegramMethod.check(telegramSettingVo.getMethodCheckId());
-
- radioGroupProxyType.check(telegramSettingVo.getProxyTypeCheckId());
- layoutProxyAuthenticator.setVisibility(telegramSettingVo.getProxyAuthenticator() ? View.VISIBLE : View.GONE);
-
- switchProxyAuthenticator.setChecked(telegramSettingVo.getProxyAuthenticator());
- if (Proxy.Type.DIRECT == telegramSettingVo.getProxyType()) {
- layoutProxyHost.setVisibility(View.GONE);
- layoutProxyPort.setVisibility(View.GONE);
- } else {
- layoutProxyHost.setVisibility(View.VISIBLE);
- layoutProxyPort.setVisibility(View.VISIBLE);
- }
- editTextProxyHost.setText(telegramSettingVo.getProxyHost());
- editTextProxyPort.setText(telegramSettingVo.getProxyPort());
-
- editTextProxyUsername.setText(telegramSettingVo.getProxyUsername());
- editTextProxyPassword.setText(telegramSettingVo.getProxyPassword());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.settelegramtitle)
- .setIcon(R.mipmap.telegram)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextTelegramName.getText().toString().trim();
- int senderStatus = switchTelegramEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String apiToken = editTextTelegramApiToken.getText().trim();
- String chatId = editTextTelegramChatId.getText().toString().trim();
- if (apiToken.isEmpty() || chatId.isEmpty()) {
- ToastUtils.delayedShow(R.string.invalid_apiToken_or_chatId, 3000);
- return;
- }
-
- int proxyTypeId = radioGroupProxyType.getCheckedRadioButtonId();
- String proxyHost = editTextProxyHost.getText().toString().trim();
- String proxyPort = editTextProxyPort.getText().toString().trim();
- if (proxyTypeId != R.id.btnProxyNone && (TextUtils.isEmpty(proxyHost) || TextUtils.isEmpty(proxyPort))) {
- ToastUtils.delayedShow(R.string.invalid_host_or_port, 3000);
- return;
- }
-
- boolean proxyAuthenticator = switchProxyAuthenticator.isChecked();
- String proxyUsername = editTextProxyUsername.getText().toString().trim();
- String proxyPassword = editTextProxyPassword.getText().trim();
- if (proxyAuthenticator && TextUtils.isEmpty(proxyUsername) && TextUtils.isEmpty(proxyPassword)) {
- ToastUtils.delayedShow(R.string.invalid_username_or_password, 3000);
- return;
- }
-
- String method = radioGroupTelegramMethod.getCheckedRadioButtonId() == R.id.radioTelegramMethodGet ? "GET" : "POST";
- TelegramSettingVo telegramSettingVoNew = new TelegramSettingVo(apiToken, chatId, proxyTypeId, proxyHost, proxyPort, proxyAuthenticator, proxyUsername, proxyPassword, method);
-
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_TELEGRAM);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(telegramSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_TELEGRAM);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(telegramSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String apiToken = editTextTelegramApiToken.getText().trim();
- String chatId = editTextTelegramChatId.getText().toString().trim();
- if (apiToken.isEmpty() || chatId.isEmpty()) {
- ToastUtils.delayedShow(R.string.invalid_apiToken_or_chatId, 3000);
- return;
- }
-
- int proxyTypeId = radioGroupProxyType.getCheckedRadioButtonId();
- String proxyHost = editTextProxyHost.getText().toString().trim();
- String proxyPort = editTextProxyPort.getText().toString().trim();
- if (proxyTypeId != R.id.btnProxyNone && (TextUtils.isEmpty(proxyHost) || TextUtils.isEmpty(proxyPort))) {
- ToastUtils.delayedShow(R.string.invalid_host_or_port, 3000);
- return;
- }
-
- boolean proxyAuthenticator = switchProxyAuthenticator.isChecked();
- String proxyUsername = editTextProxyUsername.getText().toString().trim();
- String proxyPassword = editTextProxyPassword.getText().trim();
- if (proxyAuthenticator && TextUtils.isEmpty(proxyUsername) && TextUtils.isEmpty(proxyPassword)) {
- ToastUtils.delayedShow(R.string.invalid_username_or_password, 3000);
- return;
- }
-
- String method = radioGroupTelegramMethod.getCheckedRadioButtonId() == R.id.radioTelegramMethodGet ? "GET" : "POST";
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- TelegramSettingVo telegramSettingVoNew = new TelegramSettingVo(apiToken, chatId, proxyTypeId, proxyHost, proxyPort, proxyAuthenticator, proxyUsername, proxyPassword, method);
- SenderTelegramMsg.sendMsg(0, handler, null, telegramSettingVoNew, smsVo.getMobile(), smsVo.getSmsVoForSend(), telegramSettingVoNew.getMethod());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //短信
- private void setSms(final SenderModel senderModel, final boolean isClone) {
- if (!isClone) {
- XXPermissions.with(this)
- // 接收短信
- .permission(Permission.RECEIVE_SMS)
- // 发送短信
- .permission(Permission.SEND_SMS)
- // 读取短信
- .permission(Permission.READ_SMS)
- .request(new OnPermissionCallback() {
-
- @Override
- public void onGranted(List permissions, boolean all) {
- if (!all) {
- ToastUtils.show(R.string.toast_granted_part);
- }
- }
-
- @Override
- public void onDenied(List permissions, boolean never) {
- if (never) {
- ToastUtils.show(R.string.toast_denied_never);
- // 如果是被永久拒绝就跳转到应用权限系统设置页面
- XXPermissions.startPermissionActivity(SenderActivity.this, permissions);
- } else {
- ToastUtils.show(R.string.toast_denied);
- }
- }
- });
- }
-
- SmsSettingVo smsSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- Log.d(TAG, "jsonSettingStr = " + jsonSettingStr);
- if (jsonSettingStr != null) {
- smsSettingVo = JSON.parseObject(jsonSettingStr, SmsSettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_sms, null);
-
- final EditText editTextSmsName = view1.findViewById(R.id.editTextSmsName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchSmsEnable = view1.findViewById(R.id.switchSmsEnable);
- if (senderModel != null) {
- editTextSmsName.setText(senderModel.getName());
- switchSmsEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final RadioGroup radioGroupSmsSimSlot = view1.findViewById(R.id.radioGroupSmsSimSlot);
- final EditText editTextSmsMobiles = view1.findViewById(R.id.editTextSmsMobiles);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchSmsOnlyNoNetwork = view1.findViewById(R.id.switchSmsOnlyNoNetwork);
- if (smsSettingVo != null) {
- radioGroupSmsSimSlot.check(smsSettingVo.getSmsSimSlotCheckId());
- editTextSmsMobiles.setText(smsSettingVo.getMobiles());
- switchSmsOnlyNoNetwork.setChecked(smsSettingVo.getOnlyNoNetwork());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setsmstitle)
- .setIcon(R.mipmap.sms)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextSmsName.getText().toString().trim();
- int senderStatus = switchSmsEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- Boolean onlyNoNetwork = switchSmsOnlyNoNetwork.isChecked();
- String mobiles = editTextSmsMobiles.getText().toString().trim();
- if (TextUtils.isEmpty(mobiles)) {
- ToastUtils.delayedShow(R.string.invalid_phone_num, 3000);
- return;
- }
-
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_SMS);
- newSenderModel.setStatus(senderStatus);
- SmsSettingVo smsSettingVoNew = new SmsSettingVo(
- newSenderModel.getSmsSimSlotId(radioGroupSmsSimSlot.getCheckedRadioButtonId()),
- mobiles,
- onlyNoNetwork
- );
- newSenderModel.setJsonSetting(JSON.toJSONString(smsSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_SMS);
- senderModel.setStatus(senderStatus);
- SmsSettingVo smsSettingVoNew = new SmsSettingVo(
- senderModel.getSmsSimSlotId(radioGroupSmsSimSlot.getCheckedRadioButtonId()),
- mobiles,
- onlyNoNetwork
- );
- senderModel.setJsonSetting(JSON.toJSONString(smsSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- int simSlot = R.id.btnSmsSimSlot2 == radioGroupSmsSimSlot.getCheckedRadioButtonId() ? 1 : 0;
- Boolean onlyNoNetwork = switchSmsOnlyNoNetwork.isChecked();
- String mobiles = editTextSmsMobiles.getText().toString().trim();
- if (TextUtils.isEmpty(mobiles)) {
- ToastUtils.delayedShow(R.string.invalid_phone_num, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderSmsMsg.sendMsg(0, handler, simSlot, mobiles, onlyNoNetwork, smsVo.getMobile(), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
- }
-
- //飞书机器人
- @SuppressLint("SimpleDateFormat")
- private void setFeiShu(final SenderModel senderModel, final boolean isClone) {
- FeiShuSettingVo feiShuSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- feiShuSettingVo = JSON.parseObject(jsonSettingStr, FeiShuSettingVo.class);
- }
- }
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_feishu, null);
-
- final EditText editTextFeishuName = view1.findViewById(R.id.editTextFeishuName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchFeishuEnable = view1.findViewById(R.id.switchFeishuEnable);
- if (senderModel != null) {
- editTextFeishuName.setText(senderModel.getName());
- switchFeishuEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextFeishuWebhook = view1.findViewById(R.id.editTextFeishuWebhook);
- final ClearEditText editTextFeishuSecret = view1.findViewById(R.id.editTextFeishuSecret);
- final RadioGroup radioGroupFeishuMsgType = view1.findViewById(R.id.radioGroupFeishuMsgType);
- final EditText editTextFeishuTitle = view1.findViewById(R.id.editTextFeishuTitle);
- final LinearLayout layoutTitleTemplate = view1.findViewById(R.id.layoutTitleTemplate);
-
- if (feiShuSettingVo != null) {
- editTextFeishuWebhook.setText(feiShuSettingVo.getWebhook());
- editTextFeishuSecret.setText(feiShuSettingVo.getSecret());
- radioGroupFeishuMsgType.check(feiShuSettingVo.getMsgTypeCheckId());
- editTextFeishuTitle.setText(feiShuSettingVo.getTitleTemplate());
- if ("text".equals(feiShuSettingVo.getMsgType())) {
- layoutTitleTemplate.setVisibility(View.GONE);
- } else {
- layoutTitleTemplate.setVisibility(View.VISIBLE);
- }
- }
-
- radioGroupFeishuMsgType.setOnCheckedChangeListener((group, checkedId) -> {
- if (group != null && checkedId > 0) {
- layoutTitleTemplate.setVisibility(checkedId == R.id.radioFeishuMsgTypeText ? View.GONE : View.VISIBLE);
- group.check(checkedId);
- }
- });
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setfeishutitle)
- .setIcon(R.mipmap.feishu)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextFeishuName.getText().toString().trim();
- int senderStatus = switchFeishuEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String webHook = editTextFeishuWebhook.getText().trim();
- String secret = editTextFeishuSecret.getText().trim();
- String msgType = radioGroupFeishuMsgType.getCheckedRadioButtonId() == R.id.radioFeishuMsgTypeText ? "text" : "interactive";
- String titleTemplate = editTextFeishuTitle.getText().toString().trim();
- if (!CommonUtils.checkUrl(webHook, false)) {
- ToastUtils.delayedShow(R.string.invalid_webhook, 3000);
- return;
- }
-
- if (TextUtils.isEmpty(titleTemplate)) titleTemplate = "【{{设备名称}}】来自{{来源号码}}的通知";
-
- FeiShuSettingVo feiShuSettingVoNew = new FeiShuSettingVo(webHook, secret, msgType, titleTemplate);
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_FEISHU);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(feiShuSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_FEISHU);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(feiShuSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String webHook = editTextFeishuWebhook.getText().trim();
- String secret = editTextFeishuSecret.getText().trim();
- String msgType = radioGroupFeishuMsgType.getCheckedRadioButtonId() == R.id.radioFeishuMsgTypeText ? "text" : "interactive";
- String titleTemplate = editTextFeishuTitle.getText().toString().trim();
- if (!CommonUtils.checkUrl(webHook, false)) {
- ToastUtils.delayedShow(R.string.invalid_webhook, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderFeishuMsg.sendMsg(0, handler, null, webHook, secret, msgType, smsVo.getMobile(), new Date(), smsVo.getTitleForSend(titleTemplate), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
-
- Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
- buttonInsertSender.setOnClickListener(view -> {
- editTextFeishuTitle.setFocusable(true);
- editTextFeishuTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextFeishuTitle, getString(R.string.tag_from));
- });
-
- Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
- buttonInsertExtra.setOnClickListener(view -> {
- editTextFeishuTitle.setFocusable(true);
- editTextFeishuTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextFeishuTitle, getString(R.string.tag_card_slot));
- });
-
- Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
- buttonInsertTime.setOnClickListener(view -> {
- editTextFeishuTitle.setFocusable(true);
- editTextFeishuTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextFeishuTitle, getString(R.string.tag_receive_time));
- });
-
- Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
- buttonInsertDeviceName.setOnClickListener(view -> {
- editTextFeishuTitle.setFocusable(true);
- editTextFeishuTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextFeishuTitle, getString(R.string.tag_device_name));
- });
- }
-
- //推送加
- @SuppressLint("SimpleDateFormat")
- private void setPushPlus(final SenderModel senderModel, final boolean isClone) {
- PushPlusSettingVo pushPlusSettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- pushPlusSettingVo = JSON.parseObject(jsonSettingStr, PushPlusSettingVo.class);
- }
- }
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_pushplus, null);
-
- final EditText editTextPushPlusName = view1.findViewById(R.id.editTextPushPlusName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchPushPlusEnable = view1.findViewById(R.id.switchPushPlusEnable);
- if (senderModel != null) {
- editTextPushPlusName.setText(senderModel.getName());
- switchPushPlusEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextPushPlusToken = view1.findViewById(R.id.editTextPushPlusToken);
- final EditText editTextPushPlusTopic = view1.findViewById(R.id.editTextPushPlusTopic);
- final EditText editTextPushPlusTemplate = view1.findViewById(R.id.editTextPushPlusTemplate);
- final EditText editTextPushPlusChannel = view1.findViewById(R.id.editTextPushPlusChannel);
- final EditText editTextPushPlusWebhook = view1.findViewById(R.id.editTextPushPlusWebhook);
- final EditText editTextPushPlusCallbackUrl = view1.findViewById(R.id.editTextPushPlusCallbackUrl);
- final EditText editTextPushPlusValidTime = view1.findViewById(R.id.editTextPushPlusValidTime);
- final EditText editTextPushPlusTitle = view1.findViewById(R.id.editTextPushPlusTitle);
-
- if (pushPlusSettingVo != null) {
- editTextPushPlusToken.setText(pushPlusSettingVo.getToken());
- editTextPushPlusTopic.setText(pushPlusSettingVo.getTopic());
- editTextPushPlusTemplate.setText(pushPlusSettingVo.getTemplate());
- editTextPushPlusChannel.setText(pushPlusSettingVo.getChannel());
- editTextPushPlusWebhook.setText(pushPlusSettingVo.getWebhook());
- editTextPushPlusCallbackUrl.setText(pushPlusSettingVo.getCallbackUrl());
- editTextPushPlusValidTime.setText(pushPlusSettingVo.getValidTime());
- editTextPushPlusTitle.setText(pushPlusSettingVo.getTitleTemplate());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setpushplustitle)
- .setIcon(R.mipmap.pushplus)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextPushPlusName.getText().toString().trim();
- int senderStatus = switchPushPlusEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- PushPlusSettingVo pushPlusSettingVoNew = new PushPlusSettingVo(
- editTextPushPlusToken.getText().trim(),
- editTextPushPlusTopic.getText().toString().trim(),
- editTextPushPlusTemplate.getText().toString().trim(),
- editTextPushPlusChannel.getText().toString().trim(),
- editTextPushPlusWebhook.getText().toString().trim(),
- editTextPushPlusCallbackUrl.getText().toString().trim(),
- editTextPushPlusValidTime.getText().toString().trim(),
- editTextPushPlusTitle.getText().toString().trim()
- );
- if (TextUtils.isEmpty(pushPlusSettingVoNew.getToken())) {
- ToastUtils.delayedShow(R.string.invalid_token, 3000);
- return;
- }
-
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_PUSHPLUS);
- newSenderModel.setStatus(senderStatus);
-
- newSenderModel.setJsonSetting(JSON.toJSONString(pushPlusSettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_PUSHPLUS);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(pushPlusSettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
-
- String title = editTextPushPlusTitle.getText().toString().trim();
- if (title.isEmpty()) title = "SmsForwarder Title";
-
- PushPlusSettingVo pushPlusSettingVoNew = new PushPlusSettingVo(
- editTextPushPlusToken.getText().trim(),
- editTextPushPlusTopic.getText().toString().trim(),
- editTextPushPlusTemplate.getText().toString().trim(),
- editTextPushPlusChannel.getText().toString().trim(),
- editTextPushPlusWebhook.getText().toString().trim(),
- editTextPushPlusCallbackUrl.getText().toString().trim(),
- editTextPushPlusValidTime.getText().toString().trim(),
- title
- );
-
- if (TextUtils.isEmpty(pushPlusSettingVoNew.getToken())) {
- ToastUtils.delayedShow(R.string.invalid_token, 3000);
- return;
- }
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderPushPlusMsg.sendMsg(0, handler, null, pushPlusSettingVoNew, smsVo.getTitleForSend(title), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
- });
-
- Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
- buttonInsertSender.setOnClickListener(view -> {
- editTextPushPlusTitle.setFocusable(true);
- editTextPushPlusTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextPushPlusTitle, getString(R.string.tag_from));
- });
-
- Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
- buttonInsertExtra.setOnClickListener(view -> {
- editTextPushPlusTitle.setFocusable(true);
- editTextPushPlusTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextPushPlusTitle, getString(R.string.tag_card_slot));
- });
-
- Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
- buttonInsertTime.setOnClickListener(view -> {
- editTextPushPlusTitle.setFocusable(true);
- editTextPushPlusTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextPushPlusTitle, getString(R.string.tag_receive_time));
- });
-
- Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
- buttonInsertDeviceName.setOnClickListener(view -> {
- editTextPushPlusTitle.setFocusable(true);
- editTextPushPlusTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextPushPlusTitle, getString(R.string.tag_device_name));
- });
- }
-
- //Gotify
- @SuppressLint("SimpleDateFormat")
- private void setGotify(final SenderModel senderModel, final boolean isClone) {
- GotifySettingVo gotifySettingVo = null;
- //try phrase json setting
- if (senderModel != null) {
- String jsonSettingStr = senderModel.getJsonSetting();
- if (jsonSettingStr != null) {
- gotifySettingVo = JSON.parseObject(jsonSettingStr, GotifySettingVo.class);
- }
- }
-
- final AlertDialog.Builder alertDialog71 = new AlertDialog.Builder(SenderActivity.this);
- View view1 = View.inflate(SenderActivity.this, R.layout.alert_dialog_setview_gotify, null);
-
- final EditText editTextGotifyName = view1.findViewById(R.id.editTextGotifyName);
- @SuppressLint("UseSwitchCompatOrMaterialCode") final Switch switchGotifyEnable = view1.findViewById(R.id.switchGotifyEnable);
- if (senderModel != null) {
- editTextGotifyName.setText(senderModel.getName());
- switchGotifyEnable.setChecked(senderModel.getStatusChecked());
- }
-
- final ClearEditText editTextGotifyWebServer = view1.findViewById(R.id.editTextGotifyWebServer);
- final EditText editTextGotifyTitle = view1.findViewById(R.id.editTextGotifyTitle);
- final EditText editTextGotifyPriority = view1.findViewById(R.id.editTextGotifyPriority);
- if (gotifySettingVo != null) {
- editTextGotifyWebServer.setText(gotifySettingVo.getWebServer());
- editTextGotifyTitle.setText(gotifySettingVo.getTitle());
- editTextGotifyPriority.setText(gotifySettingVo.getPriority());
- }
-
- Button buttonOk = view1.findViewById(R.id.buttonOk);
- Button buttonDel = view1.findViewById(R.id.buttonDel);
- buttonDel.setText(senderModel != null ? R.string.del : R.string.cancel);
- Button buttonTest = view1.findViewById(R.id.buttonTest);
- alertDialog71
- .setTitle(R.string.setgotifytitle)
- .setIcon(R.mipmap.gotify)
- .setView(view1)
- .create();
- final AlertDialog show = alertDialog71.show();
-
- buttonOk.setOnClickListener(view -> {
- String senderName = editTextGotifyName.getText().toString().trim();
- int senderStatus = switchGotifyEnable.isChecked() ? STATUS_ON : STATUS_OFF;
- if (TextUtils.isEmpty(senderName)) {
- ToastUtils.delayedShow(R.string.invalid_name, 3000);
- return;
- }
-
- String webServer = editTextGotifyWebServer.getText().trim();
- if (!CommonUtils.checkUrl(webServer, false)) {
- ToastUtils.delayedShow(R.string.invalid_webserver, 3000);
- return;
- }
-
- String title = editTextGotifyTitle.getText().toString().trim();
- if (title.isEmpty()) title = "SmsForwarder Title";
-
- String priority = editTextGotifyPriority.getText().toString().trim();
-
- GotifySettingVo gotifySettingVoNew = new GotifySettingVo(webServer, title, priority);
-
- if (isClone || senderModel == null) {
- SenderModel newSenderModel = new SenderModel();
- newSenderModel.setName(senderName);
- newSenderModel.setType(TYPE_GOTIFY);
- newSenderModel.setStatus(senderStatus);
- newSenderModel.setJsonSetting(JSON.toJSONString(gotifySettingVoNew));
- SenderUtil.addSender(newSenderModel);
- initSenders();
- adapter.add(senderModels);
- } else {
- senderModel.setName(senderName);
- senderModel.setType(TYPE_GOTIFY);
- senderModel.setStatus(senderStatus);
- senderModel.setJsonSetting(JSON.toJSONString(gotifySettingVoNew));
- SenderUtil.updateSender(senderModel);
- initSenders();
- adapter.update(senderModels);
- }
- show.dismiss();
- });
-
- buttonDel.setOnClickListener(view -> {
- if (senderModel != null) {
- SenderUtil.delSender(senderModel.getId());
- initSenders();
- adapter.del(senderModels);
- }
- show.dismiss();
- });
-
- buttonTest.setOnClickListener(view -> {
- String webServer = editTextGotifyWebServer.getText().trim();
- if (!CommonUtils.checkUrl(webServer, false)) {
- ToastUtils.delayedShow(R.string.invalid_webserver, 3000);
- return;
- }
-
- String title = editTextGotifyTitle.getText().toString().trim();
- if (title.isEmpty()) title = "SmsForwarder Title";
-
- String priority = editTextGotifyPriority.getText().toString().trim();
-
- GotifySettingVo gotifySettingVoNew = new GotifySettingVo(webServer, title, priority);
-
- try {
- SmsVo smsVo = new SmsVo(getString(R.string.test_phone_num), getString(R.string.test_sender_sms), new Date(), getString(R.string.test_sim_info));
- SenderGotifyMsg.sendMsg(0, handler, null, gotifySettingVoNew, smsVo.getTitleForSend(title), smsVo.getSmsVoForSend());
- } catch (Exception e) {
- ToastUtils.delayedShow(getString(R.string.failed_to_fwd) + e.getMessage(), 3000);
- e.printStackTrace();
- }
-
- });
-
- Button buttonInsertSender = view1.findViewById(R.id.bt_insert_sender);
- buttonInsertSender.setOnClickListener(view -> {
- editTextGotifyTitle.setFocusable(true);
- editTextGotifyTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextGotifyTitle, getString(R.string.tag_from));
- });
-
- Button buttonInsertExtra = view1.findViewById(R.id.bt_insert_extra);
- buttonInsertExtra.setOnClickListener(view -> {
- editTextGotifyTitle.setFocusable(true);
- editTextGotifyTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextGotifyTitle, getString(R.string.tag_card_slot));
- });
-
- Button buttonInsertTime = view1.findViewById(R.id.bt_insert_time);
- buttonInsertTime.setOnClickListener(view -> {
- editTextGotifyTitle.setFocusable(true);
- editTextGotifyTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextGotifyTitle, getString(R.string.tag_receive_time));
- });
-
- Button buttonInsertDeviceName = view1.findViewById(R.id.bt_insert_device_name);
- buttonInsertDeviceName.setOnClickListener(view -> {
- editTextGotifyTitle.setFocusable(true);
- editTextGotifyTitle.requestFocus();
- CommonUtils.insertOrReplaceText2Cursor(editTextGotifyTitle, getString(R.string.tag_device_name));
- });
-
- }
-
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java b/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java
deleted file mode 100644
index b087931d..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/SettingActivity.java
+++ /dev/null
@@ -1,1041 +0,0 @@
-package com.idormy.sms.forwarder;
-
-import android.annotation.SuppressLint;
-import android.app.ActivityManager;
-import android.app.TimePickerDialog;
-import android.content.ComponentName;
-import android.content.Context;
-import android.content.Intent;
-import android.content.SharedPreferences;
-import android.content.pm.PackageManager;
-import android.database.sqlite.SQLiteDatabase;
-import android.net.Uri;
-import android.os.Build;
-import android.os.Bundle;
-import android.preference.PreferenceManager;
-import android.provider.Settings;
-import android.text.Editable;
-import android.text.TextWatcher;
-import android.util.Log;
-import android.view.View;
-import android.widget.CheckBox;
-import android.widget.EditText;
-import android.widget.LinearLayout;
-import android.widget.ScrollView;
-import android.widget.Switch;
-import android.widget.TextView;
-
-import androidx.annotation.RequiresApi;
-import androidx.appcompat.app.AlertDialog;
-
-import com.hjq.permissions.OnPermissionCallback;
-import com.hjq.permissions.Permission;
-import com.hjq.permissions.XXPermissions;
-import com.hjq.toast.ToastUtils;
-import com.idormy.sms.forwarder.receiver.RebootBroadcastReceiver;
-import com.idormy.sms.forwarder.sender.BatteryReportCronTask;
-import com.idormy.sms.forwarder.sender.HttpServer;
-import com.idormy.sms.forwarder.sender.SenderUtil;
-import com.idormy.sms.forwarder.service.MusicService;
-import com.idormy.sms.forwarder.utils.CommonUtils;
-import com.idormy.sms.forwarder.utils.DbHelper;
-import com.idormy.sms.forwarder.utils.Define;
-import com.idormy.sms.forwarder.utils.HttpUtils;
-import com.idormy.sms.forwarder.utils.KeepAliveUtils;
-import com.idormy.sms.forwarder.utils.LogUtils;
-import com.idormy.sms.forwarder.utils.OnePixelManager;
-import com.idormy.sms.forwarder.utils.RuleUtils;
-import com.idormy.sms.forwarder.utils.SettingUtils;
-import com.idormy.sms.forwarder.view.StepBar;
-
-import java.util.Arrays;
-import java.util.Calendar;
-import java.util.HashMap;
-import java.util.List;
-import java.util.Map;
-import java.util.Set;
-
-public class SettingActivity extends BaseActivity {
- private final String TAG = "SettingActivity";
- private Context context;
- private boolean isIgnoreBatteryOptimization;
-
- @Override
- public void onCreate(Bundle savedInstanceState) {
- Log.d(TAG, "onCreate");
- super.onCreate(savedInstanceState);
- context = SettingActivity.this;
- setContentView(R.layout.activity_setting);
-
- LogUtils.init(this);
- RuleUtils.init(this);
- SenderUtil.init(this);
- }
-
- @SuppressLint("NewApi")
- @Override
- protected void onStart() {
- super.onStart();
- Log.d(TAG, "onStart");
-
- //是否关闭页面提示
- ScrollView scrollView = findViewById(R.id.scrollView);
- CommonUtils.calcMarginBottom(this, null, null, scrollView);
-
- //转发短信广播
- switchEnableSms(findViewById(R.id.switch_enable_sms));
- //转发通话记录
- switchEnablePhone(findViewById(R.id.switch_enable_phone), findViewById(R.id.cbCallType1), findViewById(R.id.cbCallType2), findViewById(R.id.cbCallType3));
- //转发应用通知 & 自动关闭通知
- switchEnableAppNotify(findViewById(R.id.switch_enable_app_notify), findViewById(R.id.checkbox_cancel_app_notify), findViewById(R.id.checkbox_not_user_present));
-
- //HttpServer
- switchEnableHttpServer(findViewById(R.id.switch_enable_http_server));
-
- //监听电池状态变化
- switchBatteryReceiver(findViewById(R.id.switch_battery_receiver));
- //电量预警
- editBatteryLevelAlarm(findViewById(R.id.et_battery_level_alarm_min), findViewById(R.id.et_battery_level_alarm_max), findViewById(R.id.cb_battery_level_alarm_once));
- //定时推送电池状态
- switchBatteryCron(findViewById(R.id.switch_battery_cron));
- //设置推送电池状态时机
- editBatteryCronTiming(findViewById(R.id.et_battery_cron_start_time), findViewById(R.id.et_battery_cron_interval));
-
- //开机启动
- checkWithReboot(findViewById(R.id.switch_with_reboot), findViewById(R.id.tv_auto_startup));
- //电池优化设置
- batterySetting(findViewById(R.id.layout_battery_setting), findViewById(R.id.switch_battery_setting));
- //不在最近任务列表中显示
- switchExcludeFromRecents(findViewById(R.id.switch_exclude_from_recents));
- //后台播放无声音乐
- switchPlaySilenceMusic(findViewById(R.id.switch_play_silence_music));
- //1像素透明Activity保活
- switchOnePixelActivity(findViewById(R.id.switch_one_pixel_activity));
- //接口请求失败重试时间间隔
- editRetryDelayTime(findViewById(R.id.et_retry_times), findViewById(R.id.et_delay_time));
-
- //设备备注
- editAddExtraDeviceMark(findViewById(R.id.et_add_extra_device_mark));
- //SIM1备注
- editAddExtraSim1(findViewById(R.id.et_add_extra_sim1));
- //SIM2备注
- editAddExtraSim2(findViewById(R.id.et_add_extra_sim2));
- //启用自定义模版
- switchSmsTemplate(findViewById(R.id.switch_sms_template));
- //自定义模板
- editSmsTemplate(findViewById(R.id.text_sms_template));
-
- //帮助提示
- SwitchHelpTip(findViewById(R.id.switch_help_tip));
-
- //步骤完成状态校验
- StepBar stepBar = findViewById(R.id.stepBar);
- stepBar.setHighlight();
- }
-
- @Override
- protected void onPause() {
- overridePendingTransition(0, 0);
- super.onPause();
- }
-
- //设置转发短信
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- private void switchEnableSms(Switch switch_enable_sms) {
- switch_enable_sms.setChecked(SettingUtils.getSwitchEnableSms());
-
- switch_enable_sms.setOnCheckedChangeListener((buttonView, isChecked) -> {
- Log.d(TAG, "switchEnableSms:" + isChecked);
- if (isChecked) {
- //检查权限是否获取
- PackageManager pm = getPackageManager();
- CommonUtils.CheckPermission(pm, this);
- XXPermissions.with(this)
- // 接收短信
- .permission(Permission.RECEIVE_SMS)
- // 发送短信
- //.permission(Permission.SEND_SMS)
- // 读取短信
- .permission(Permission.READ_SMS)
- .request(new OnPermissionCallback() {
-
- @Override
- public void onGranted(List permissions, boolean all) {
- if (all) {
- ToastUtils.show(R.string.toast_granted_all);
- } else {
- ToastUtils.show(R.string.toast_granted_part);
- }
- SettingUtils.switchEnableSms(true);
- }
-
- @Override
- public void onDenied(List permissions, boolean never) {
- if (never) {
- ToastUtils.show(R.string.toast_denied_never);
- // 如果是被永久拒绝就跳转到应用权限系统设置页面
- XXPermissions.startPermissionActivity(SettingActivity.this, permissions);
- } else {
- ToastUtils.show(R.string.toast_denied);
- }
- SettingUtils.switchEnableSms(false);
- }
- });
- } else {
- SettingUtils.switchEnableSms(false);
- }
- });
- }
-
- //转发通话记录
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- private void switchEnablePhone(Switch switch_enable_phone, CheckBox check_box_call_type_1, CheckBox check_box_call_type_2, CheckBox check_box_call_type_3) {
- switch_enable_phone.setChecked(SettingUtils.getSwitchEnablePhone());
- check_box_call_type_1.setChecked(SettingUtils.getSwitchCallType1());
- check_box_call_type_2.setChecked(SettingUtils.getSwitchCallType2());
- check_box_call_type_3.setChecked(SettingUtils.getSwitchCallType3());
-
- switch_enable_phone.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (isChecked && !SettingUtils.getSwitchCallType1() && !SettingUtils.getSwitchCallType2() && !SettingUtils.getSwitchCallType3()) {
- ToastUtils.show(R.string.enable_phone_fw_tips);
- SettingUtils.switchEnablePhone(false);
- return;
- }
-
- Log.d(TAG, "switchEnablePhone:" + isChecked);
- if (isChecked) {
- //检查权限是否获取
- PackageManager pm = getPackageManager();
- CommonUtils.CheckPermission(pm, this);
- XXPermissions.with(this)
- // 读取电话状态
- .permission(Permission.READ_PHONE_STATE)
- // 读取手机号码
- .permission(Permission.READ_PHONE_NUMBERS)
- // 读取通话记录
- .permission(Permission.READ_CALL_LOG)
- // 读取联系人
- .permission(Permission.READ_CONTACTS)
- .request(new OnPermissionCallback() {
-
- @Override
- public void onGranted(List permissions, boolean all) {
- if (all) {
- ToastUtils.show(R.string.toast_granted_all);
- } else {
- ToastUtils.show(R.string.toast_granted_part);
- }
- SettingUtils.switchEnablePhone(true);
- }
-
- @Override
- public void onDenied(List permissions, boolean never) {
- if (never) {
- ToastUtils.show(R.string.toast_denied_never);
- // 如果是被永久拒绝就跳转到应用权限系统设置页面
- XXPermissions.startPermissionActivity(SettingActivity.this, permissions);
- } else {
- ToastUtils.show(R.string.toast_denied);
- }
- SettingUtils.switchEnablePhone(false);
- }
- });
- } else {
- SettingUtils.switchEnablePhone(false);
- }
- });
-
- check_box_call_type_1.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchCallType1(isChecked);
- if (!isChecked && !SettingUtils.getSwitchCallType1() && !SettingUtils.getSwitchCallType2() && !SettingUtils.getSwitchCallType3()) {
- ToastUtils.show(R.string.enable_phone_fw_tips);
- SettingUtils.switchEnablePhone(false);
- }
- });
-
- check_box_call_type_2.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchCallType2(isChecked);
- if (!isChecked && !SettingUtils.getSwitchCallType1() && !SettingUtils.getSwitchCallType2() && !SettingUtils.getSwitchCallType3()) {
- ToastUtils.show(R.string.enable_phone_fw_tips);
- SettingUtils.switchEnablePhone(false);
- }
- });
-
- check_box_call_type_3.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchCallType3(isChecked);
- if (!isChecked && !SettingUtils.getSwitchCallType1() && !SettingUtils.getSwitchCallType2() && !SettingUtils.getSwitchCallType3()) {
- ToastUtils.show(R.string.enable_phone_fw_tips);
- SettingUtils.switchEnablePhone(false);
- }
- });
- }
-
- //转发应用通知 & 自动关闭通知
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- private void switchEnableAppNotify(Switch switch_enable_app_notify, CheckBox checkbox_cancel_app_notify, CheckBox checkbox_not_user_present) {
- final LinearLayout layout_cancel_app_notify = findViewById(R.id.layout_cancel_app_notify);
- boolean isEnable = SettingUtils.getSwitchEnableAppNotify();
- switch_enable_app_notify.setChecked(isEnable);
- layout_cancel_app_notify.setVisibility(isEnable ? View.VISIBLE : View.GONE);
-
- switch_enable_app_notify.setOnCheckedChangeListener((buttonView, isChecked) -> {
- layout_cancel_app_notify.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- //TODO:校验使用APP通知转发必备的权限
- if (isChecked) {
- if (!CommonUtils.isNotificationListenerServiceEnabled(this)) {
- CommonUtils.openNotificationAccess(this);
- ToastUtils.delayedShow(R.string.tips_notification_listener, 3000);
- return;
- } else {
- ToastUtils.delayedShow(R.string.notification_service_is_on, 3000);
- CommonUtils.toggleNotificationListenerService(this);
- }
- }
- SettingUtils.switchEnableAppNotify(isChecked);
- Log.d(TAG, "switchEnableAppNotify:" + isChecked);
- });
-
- checkbox_cancel_app_notify.setChecked(SettingUtils.getSwitchCancelAppNotify());
- checkbox_cancel_app_notify.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchCancelAppNotify(isChecked);
- Log.d(TAG, "switchCancelAppNotify:" + isChecked);
- });
-
- checkbox_not_user_present.setChecked(SettingUtils.getSwitchNotUserPresent());
- checkbox_not_user_present.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchNotUserPresent(isChecked);
- Log.d(TAG, "switchNotUserPresent:" + isChecked);
-
- //1像素透明Activity保活 or 仅锁屏状态转发APP通知
- OnePixelManager onePixelManager = new OnePixelManager();
- if (SettingUtils.getOnePixelActivity() || SettingUtils.getSwitchNotUserPresent()) {
- onePixelManager.registerOnePixelReceiver(this);//注册广播接收者
- } else {
- onePixelManager.unregisterOnePixelReceiver(this);
- }
- });
- }
-
- //请求通知使用权限
- public void requestNotificationPermission(View view) {
- if (!CommonUtils.isNotificationListenerServiceEnabled(this)) {
- CommonUtils.openNotificationAccess(this);
- } else {
- ToastUtils.show(R.string.notification_listener_service_enabled);
- CommonUtils.toggleNotificationListenerService(this);
- }
- }
-
- @Override
- protected void onActivityResult(int requestCode, int resultCode, Intent data) {
- super.onActivityResult(requestCode, resultCode, data);
- if (requestCode == CommonUtils.NOTIFICATION_REQUEST_CODE) {
- if (CommonUtils.isNotificationListenerServiceEnabled(this)) {
- ToastUtils.show(R.string.notification_listener_service_enabled);
- CommonUtils.toggleNotificationListenerService(this);
- SettingUtils.switchEnableAppNotify(true);
- } else {
- ToastUtils.show(R.string.notification_listener_service_disabled);
- SettingUtils.switchEnableAppNotify(false);
- }
-
- @SuppressLint("UseSwitchCompatOrMaterialCode") Switch switch_enable_app_notify = findViewById(R.id.switch_enable_app_notify);
- switch_enable_app_notify.setChecked(SettingUtils.getSwitchEnableAppNotify());
- }
- }
-
- //HttpServer
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- private void switchEnableHttpServer(Switch switch_enable_http_server) {
- switch_enable_http_server.setChecked(SettingUtils.getSwitchEnableHttpServer());
-
- switch_enable_http_server.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchEnableHttpServer(isChecked);
- Log.d(TAG, "switchEnableHttpServer:" + isChecked);
-
- HttpUtils.init(this);
- HttpServer.init(this);
- HttpServer.update();
- });
- }
-
- //监听电池状态变化
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- private void switchBatteryReceiver(Switch switch_battery_receiver) {
- switch_battery_receiver.setChecked(SettingUtils.getSwitchEnableBatteryReceiver());
-
- switch_battery_receiver.setOnCheckedChangeListener((buttonView, isChecked) -> {
- //TODO:校验使用来电转发必备的权限
- SettingUtils.switchEnableBatteryReceiver(isChecked);
- Log.d(TAG, "switchEnablePhone:" + isChecked);
- });
- }
-
- //设置低电量报警
- private void editBatteryLevelAlarm(final EditText et_battery_level_alarm_min, final EditText et_battery_level_alarm_max, CheckBox cb_battery_level_alarm_once) {
- et_battery_level_alarm_min.setText(String.valueOf(SettingUtils.getBatteryLevelAlarmMin()));
- et_battery_level_alarm_min.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String batteryLevel = et_battery_level_alarm_min.getText().toString().trim();
- if (!batteryLevel.isEmpty()) {
- SettingUtils.setBatteryLevelAlarmMin(Integer.parseInt(batteryLevel));
- } else {
- SettingUtils.setBatteryLevelAlarmMin(0);
- }
- }
- });
-
- et_battery_level_alarm_max.setText(String.valueOf(SettingUtils.getBatteryLevelAlarmMax()));
- et_battery_level_alarm_max.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String batteryLevel = et_battery_level_alarm_max.getText().toString().trim();
- if (!batteryLevel.isEmpty()) {
- SettingUtils.setBatteryLevelAlarmMax(Integer.parseInt(batteryLevel));
- } else {
- SettingUtils.setBatteryLevelAlarmMax(0);
- }
- }
- });
-
- cb_battery_level_alarm_once.setChecked(SettingUtils.getBatteryLevelAlarmOnce());
- cb_battery_level_alarm_once.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchBatteryLevelAlarmOnce(isChecked);
- if (isChecked && 0 == SettingUtils.getBatteryLevelAlarmMin() && 0 == SettingUtils.getBatteryLevelAlarmMax()) {
- ToastUtils.show(R.string.tips_battery_level_alarm_once);
- SettingUtils.switchEnablePhone(false);
- }
- });
- }
-
- //定时推送电池状态
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- private void switchBatteryCron(Switch switch_battery_cron) {
- boolean isOn = SettingUtils.getSwitchEnableBatteryCron();
- switch_battery_cron.setChecked(isOn);
-
- final LinearLayout layout_battery_cron = findViewById(R.id.layout_battery_cron);
- layout_battery_cron.setVisibility(isOn ? View.VISIBLE : View.GONE);
-
- switch_battery_cron.setOnCheckedChangeListener((buttonView, isChecked) -> {
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- layout_battery_cron.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- SettingUtils.switchEnableBatteryCron(isChecked);
- BatteryReportCronTask.getSingleton().updateTimer();
- });
- }
-
- //设置推送电池状态时机
- private void editBatteryCronTiming(final EditText et_battery_cron_start_time, final EditText et_battery_cron_interval) {
- et_battery_cron_start_time.setText(SettingUtils.getBatteryCronStartTime());
-
- Calendar calendar = Calendar.getInstance();
- et_battery_cron_start_time.setOnClickListener(view -> {
- TimePickerDialog dialog = new TimePickerDialog(SettingActivity.this, (timePicker, hourOfDay, minute) -> {
- StringBuilder sb = new StringBuilder();
- if (hourOfDay < 10) {
- sb.append("0");
- }
- sb.append(hourOfDay);
- sb.append(":");
- if (minute < 10) {
- sb.append("0");
- }
- sb.append(minute);
- String startTime = sb.toString();
- et_battery_cron_start_time.setText(startTime);
- SettingUtils.setBatteryCronStartTime(startTime);
- BatteryReportCronTask.getSingleton().updateTimer();
- }, calendar.get(Calendar.HOUR_OF_DAY) + 1, 0, true);
- dialog.show();
- });
-
- et_battery_cron_interval.setText(String.valueOf(SettingUtils.getBatteryCronInterval()));
- et_battery_cron_interval.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String interval = et_battery_cron_interval.getText().toString().trim();
- if (!interval.isEmpty() && Integer.parseInt(interval) > 0) {
- SettingUtils.setBatteryCronInterval(Integer.parseInt(interval));
- BatteryReportCronTask.getSingleton().updateTimer();
- } else {
- SettingUtils.setBatteryCronInterval(60);
- }
- }
- });
- }
-
- //开机启动
- private void checkWithReboot(@SuppressLint("UseSwitchCompatOrMaterialCode") Switch withrebootSwitch, TextView tvAutoStartup) {
- tvAutoStartup.setText(getAutoStartTips());
-
- //获取组件
- final ComponentName cm = new ComponentName(this.getPackageName(), RebootBroadcastReceiver.class.getName());
-
- final PackageManager pm = getPackageManager();
- int state = pm.getComponentEnabledSetting(cm);
- withrebootSwitch.setChecked(state != PackageManager.COMPONENT_ENABLED_STATE_DISABLED
- && state != PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER);
- withrebootSwitch.setOnCheckedChangeListener((buttonView, isChecked) -> {
- int newState = isChecked ? PackageManager.COMPONENT_ENABLED_STATE_ENABLED
- : PackageManager.COMPONENT_ENABLED_STATE_DISABLED;
- pm.setComponentEnabledSetting(cm, newState, PackageManager.DONT_KILL_APP);
- Log.d(TAG, "onCheckedChanged:" + isChecked);
-
- if (isChecked) startToAutoStartSetting(this);
- });
- }
-
- //Intent跳转到[自启动]页面全网最全适配机型解决方案
- private static final HashMap> hashMap = new HashMap<>() {
- {
- put("Xiaomi", Arrays.asList(
- "com.miui.securitycenter/com.miui.permcenter.autostart.AutoStartManagementActivity",//MIUI10_9.8.1(9.0)
- "com.miui.securitycenter"
- ));
-
- put("samsung", Arrays.asList(
- "com.samsung.android.sm_cn/com.samsung.android.sm.ui.ram.AutoRunActivity",
- "com.samsung.android.sm_cn/com.samsung.android.sm.ui.appmanagement.AppManagementActivity",
- "com.samsung.android.sm_cn/com.samsung.android.sm.ui.cstyleboard.SmartManagerDashBoardActivity",
- "com.samsung.android.sm_cn/.ui.ram.RamActivity",
- "com.samsung.android.sm_cn/.app.dashboard.SmartManagerDashBoardActivity",
-
- "com.samsung.android.sm/com.samsung.android.sm.ui.ram.AutoRunActivity",
- "com.samsung.android.sm/com.samsung.android.sm.ui.appmanagement.AppManagementActivity",
- "com.samsung.android.sm/com.samsung.android.sm.ui.cstyleboard.SmartManagerDashBoardActivity",
- "com.samsung.android.sm/.ui.ram.RamActivity",
- "com.samsung.android.sm/.app.dashboard.SmartManagerDashBoardActivity",
-
- "com.samsung.android.lool/com.samsung.android.sm.ui.battery.BatteryActivity",
- "com.samsung.android.sm_cn",
- "com.samsung.android.sm"
- ));
-
- put("HUAWEI", Arrays.asList(
- "com.huawei.systemmanager/.startupmgr.ui.StartupNormalAppListActivity",//EMUI9.1.0(方舟,9.0)
- "com.huawei.systemmanager/.appcontrol.activity.StartupAppControlActivity",
- "com.huawei.systemmanager/.optimize.process.ProtectActivity",
- "com.huawei.systemmanager/.optimize.bootstart.BootStartActivity",
- "com.huawei.systemmanager"//最后一行可以写包名, 这样如果签名的类路径在某些新版本的ROM中没找到 就直接跳转到对应的安全中心/手机管家 首页.
- ));
-
- put("vivo", Arrays.asList(
- "com.iqoo.secure/.ui.phoneoptimize.BgStartUpManager",
- "com.iqoo.secure/.safeguard.PurviewTabActivity",
- "com.vivo.permissionmanager/.activity.BgStartUpManagerActivity",
- //"com.iqoo.secure/.ui.phoneoptimize.AddWhiteListActivity", //这是白名单, 不是自启动
- "com.iqoo.secure",
- "com.vivo.permissionmanager"
- ));
-
- put("Meizu", Arrays.asList(
- "com.meizu.safe/.permission.SmartBGActivity",//Flyme7.3.0(7.1.2)
- "com.meizu.safe/.permission.PermissionMainActivity",//网上的
- "com.meizu.safe"
- ));
-
- put("OPPO", Arrays.asList(
- "com.coloros.safecenter/.startupapp.StartupAppListActivity",
- "com.coloros.safecenter/.permission.startup.StartupAppListActivity",
- "com.oppo.safe/.permission.startup.StartupAppListActivity",
- "com.coloros.oppoguardelf/com.coloros.powermanager.fuelgaue.PowerUsageModelActivity",
- "com.coloros.safecenter/com.coloros.privacypermissionsentry.PermissionTopActivity",
- "com.coloros.safecenter",
- "com.oppo.safe",
- "com.coloros.oppoguardelf"
- ));
-
- put("oneplus", Arrays.asList(
- "com.oneplus.security/.chainlaunch.view.ChainLaunchAppListActivity",
- "com.oneplus.security"
- ));
-
- put("letv", Arrays.asList(
- "com.letv.android.letvsafe/.AutobootManageActivity",
- "com.letv.android.letvsafe/.BackgroundAppManageActivity",//应用保护
- "com.letv.android.letvsafe"
- ));
-
- put("zte", Arrays.asList(
- "com.zte.heartyservice/.autorun.AppAutoRunManager",
- "com.zte.heartyservice"
- ));
-
- //金立
- put("F", Arrays.asList(
- "com.gionee.softmanager/.MainActivity",
- "com.gionee.softmanager"
- ));
-
- //以下为未确定(厂商名也不确定)
- put("smartisanos", Arrays.asList(
- "com.smartisanos.security/.invokeHistory.InvokeHistoryActivity",
- "com.smartisanos.security"
- ));
-
- //360
- put("360", Arrays.asList(
- "com.yulong.android.coolsafe/.ui.activity.autorun.AutoRunListActivity",
- "com.yulong.android.coolsafe"
- ));
-
- //360
- put("ulong", Arrays.asList(
- "com.yulong.android.coolsafe/.ui.activity.autorun.AutoRunListActivity",
- "com.yulong.android.coolsafe"
- ));
-
- //酷派
- put("coolpad"/*厂商名称不确定是否正确*/, Arrays.asList(
- "com.yulong.android.security/com.yulong.android.seccenter.tabbarmain",
- "com.yulong.android.security"
- ));
-
- //联想
- put("lenovo"/*厂商名称不确定是否正确*/, Arrays.asList(
- "com.lenovo.security/.purebackground.PureBackgroundActivity",
- "com.lenovo.security"
- ));
-
- put("htc"/*厂商名称不确定是否正确*/, Arrays.asList(
- "com.htc.pitroad/.landingpage.activity.LandingPageActivity",
- "com.htc.pitroad"
- ));
-
- //华硕
- put("asus"/*厂商名称不确定是否正确*/, Arrays.asList(
- "com.asus.mobilemanager/.MainActivity",
- "com.asus.mobilemanager"
- ));
-
- }
- };
-
- //跳转自启动页面
- public static void startToAutoStartSetting(Context context) {
- Log.e("Util", "******************The current phone model is:" + Build.MANUFACTURER);
-
- Set>> entries = hashMap.entrySet();
- boolean has = false;
- for (Map.Entry> entry : entries) {
- String manufacturer = entry.getKey();
- List actCompatList = entry.getValue();
- if (Build.MANUFACTURER.equalsIgnoreCase(manufacturer)) {
- for (String act : actCompatList) {
- try {
- Intent intent;
- if (act.contains("/")) {
- intent = new Intent();
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- ComponentName componentName = ComponentName.unflattenFromString(act);
- intent.setComponent(componentName);
- } else {
- //找不到? 网上的做法都是跳转到设置... 这基本上是没意义的 基本上自启动这个功能是第三方厂商自己写的安全管家类app
- //所以我是直接跳转到对应的安全管家/安全中心
- intent = context.getPackageManager().getLaunchIntentForPackage(act);
- }
- context.startActivity(intent);
- has = true;
- break;
- } catch (Exception e) {
- e.printStackTrace();
- }
- }
- }
- }
- if (!has) {
- ToastUtils.show(R.string.tips_compatible_solution);
- try {
- Intent intent = new Intent();
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- intent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS");
- intent.setData(Uri.fromParts("package", context.getPackageName(), null));
- context.startActivity(intent);
- } catch (Exception e) {
- e.printStackTrace();
- Intent intent = new Intent(Settings.ACTION_SETTINGS);
- intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
- context.startActivity(intent);
- }
- }
- }
-
- //电池优化设置
- @RequiresApi(api = Build.VERSION_CODES.M)
- @SuppressLint("UseSwitchCompatOrMaterialCode")
- public void batterySetting(LinearLayout layout_battery_setting, Switch switch_battery_setting) {
- //安卓6.0以下没有忽略电池优化
- if (android.os.Build.VERSION.SDK_INT < android.os.Build.VERSION_CODES.M) {
- layout_battery_setting.setVisibility(View.GONE);
- return;
- }
-
- isIgnoreBatteryOptimization = KeepAliveUtils.isIgnoreBatteryOptimization(this);
- switch_battery_setting.setChecked(isIgnoreBatteryOptimization);
-
- switch_battery_setting.setOnCheckedChangeListener((buttonView, isChecked) -> {
- if (isChecked && !isIgnoreBatteryOptimization) {
- KeepAliveUtils.ignoreBatteryOptimization(this);
- } else if (isChecked) {
- ToastUtils.show(R.string.isIgnored);
- switch_battery_setting.setChecked(isIgnoreBatteryOptimization);
- } else {
- ToastUtils.show(R.string.isIgnored2);
- switch_battery_setting.setChecked(isIgnoreBatteryOptimization);
- }
- });
- }
-
- //不在最近任务列表中显示
- @SuppressLint("ObsoleteSdkInt,UseSwitchCompatOrMaterialCode")
- private void switchExcludeFromRecents(Switch switch_exclude_from_recents) {
- switch_exclude_from_recents.setChecked(SettingUtils.getExcludeFromRecents());
-
- switch_exclude_from_recents.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchExcludeFromRecents(isChecked);
- if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
- ActivityManager am = (ActivityManager) this.getSystemService(Context.ACTIVITY_SERVICE);
- if (am != null) {
- List appTasks = am.getAppTasks();
- if (appTasks != null && !appTasks.isEmpty()) {
- appTasks.get(0).setExcludeFromRecents(isChecked);
- }
- }
- }
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- });
- }
-
- //后台播放无声音乐
- @SuppressLint("ObsoleteSdkInt,UseSwitchCompatOrMaterialCode")
- private void switchPlaySilenceMusic(Switch switch_play_silence_music) {
- switch_play_silence_music.setChecked(SettingUtils.getPlaySilenceMusic());
-
- switch_play_silence_music.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchPlaySilenceMusic(isChecked);
-
- if (isChecked) {
- startService(new Intent(context, MusicService.class));
- } else {
- stopService(new Intent(context, MusicService.class));
- }
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- });
- }
-
- //1像素透明Activity保活
- @SuppressLint("ObsoleteSdkInt,UseSwitchCompatOrMaterialCode")
- private void switchOnePixelActivity(Switch switch_one_pixel_activity) {
- switch_one_pixel_activity.setChecked(SettingUtils.getOnePixelActivity());
-
- switch_one_pixel_activity.setOnCheckedChangeListener((buttonView, isChecked) -> {
- SettingUtils.switchOnePixelActivity(isChecked);
- Log.d(TAG, "onCheckedChanged:" + isChecked);
-
- //1像素透明Activity保活 or 仅锁屏状态转发APP通知
- OnePixelManager onePixelManager = new OnePixelManager();
- if (SettingUtils.getOnePixelActivity() || SettingUtils.getSwitchNotUserPresent()) {
- onePixelManager.registerOnePixelReceiver(this);//注册广播接收者
- } else {
- onePixelManager.unregisterOnePixelReceiver(this);
- }
- });
- }
-
- //接口请求失败重试时间间隔
- private void editRetryDelayTime(final EditText et_retry_times, final EditText et_delay_time) {
- et_retry_times.setText(String.valueOf(SettingUtils.getRetryTimes()));
- et_retry_times.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String retryTimes = et_retry_times.getText().toString().trim();
- if (!retryTimes.isEmpty()) {
- SettingUtils.setRetryTimes(Integer.parseInt(retryTimes));
- } else {
- SettingUtils.setRetryTimes(0);
- }
- }
- });
-
- et_delay_time.setText(String.valueOf(SettingUtils.getDelayTime()));
- et_delay_time.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- String delayTime = et_delay_time.getText().toString().trim();
- if (!delayTime.isEmpty()) {
- SettingUtils.setDelayTime(Integer.parseInt(delayTime));
- } else {
- SettingUtils.setDelayTime(1);
- }
- }
- });
- }
-
- //设置设备名称
- private void editAddExtraDeviceMark(final EditText et_add_extra_device_mark) {
- et_add_extra_device_mark.setText(SettingUtils.getAddExtraDeviceMark());
-
- et_add_extra_device_mark.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- SettingUtils.setAddExtraDeviceMark(et_add_extra_device_mark.getText().toString().trim());
- }
- });
- }
-
- //设置SIM1备注
- private void editAddExtraSim1(final EditText et_add_extra_sim1) {
- et_add_extra_sim1.setText(SettingUtils.getAddExtraSim1());
-
- et_add_extra_sim1.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- SettingUtils.setAddExtraSim1(et_add_extra_sim1.getText().toString().trim());
- }
- });
- }
-
- //设置SIM2备注
- private void editAddExtraSim2(final EditText et_add_extra_sim2) {
- et_add_extra_sim2.setText(SettingUtils.getAddExtraSim2());
-
- et_add_extra_sim2.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- SettingUtils.setAddExtraSim2(et_add_extra_sim2.getText().toString().trim());
- }
- });
- }
-
- //设置转发时启用自定义模版
- @SuppressLint({"UseSwitchCompatOrMaterialCode", "SetTextI18n"})
- private void switchSmsTemplate(Switch switch_sms_template) {
- boolean isOn = SettingUtils.getSwitchSmsTemplate();
- switch_sms_template.setChecked(isOn);
-
- final LinearLayout layout_sms_template = findViewById(R.id.layout_sms_template);
- layout_sms_template.setVisibility(isOn ? View.VISIBLE : View.GONE);
- final EditText textSmsTemplate = findViewById(R.id.text_sms_template);
-
- switch_sms_template.setOnCheckedChangeListener((buttonView, isChecked) -> {
- Log.d(TAG, "onCheckedChanged:" + isChecked);
- layout_sms_template.setVisibility(isChecked ? View.VISIBLE : View.GONE);
- SettingUtils.switchSmsTemplate(isChecked);
- if (!isChecked) {
- textSmsTemplate.setText(getString(R.string.tag_from) + "\n" +
- getString(R.string.tag_sms) + "\n" +
- getString(R.string.tag_card_slot) + "\n" +
- getString(R.string.tag_receive_time) + "\n" +
- getString(R.string.tag_device_name));
- }
- });
- }
-
- //设置转发信息模版
- private void editSmsTemplate(final EditText textSmsTemplate) {
- textSmsTemplate.setText(SettingUtils.getSmsTemplate());
-
- textSmsTemplate.addTextChangedListener(new TextWatcher() {
- @Override
- public void beforeTextChanged(CharSequence s, int start, int count, int after) {
-
- }
-
- @Override
- public void onTextChanged(CharSequence s, int start, int before, int count) {
-
- }
-
- @Override
- public void afterTextChanged(Editable s) {
- SettingUtils.setSmsTemplate(textSmsTemplate.getText().toString().trim());
- }
- });
- }
-
- //插入标签
- @SuppressLint("NonConstantResourceId")
- public void toInsertLabel(View v) {
- EditText textSmsTemplate = findViewById(R.id.text_sms_template);
- textSmsTemplate.setFocusable(true);
- textSmsTemplate.requestFocus();
- switch (v.getId()) {
- case R.id.bt_insert_sender:
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_from));
- return;
- case R.id.bt_insert_content:
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_sms));
- return;
- case R.id.bt_insert_extra:
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_card_slot));
- return;
- case R.id.bt_insert_time:
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_receive_time));
- return;
- case R.id.bt_insert_device_name:
- CommonUtils.insertOrReplaceText2Cursor(textSmsTemplate, getString(R.string.tag_device_name));
- return;
- default:
- }
- }
-
- //页面帮助提示
- private void SwitchHelpTip(@SuppressLint("UseSwitchCompatOrMaterialCode") Switch switchHelpTip) {
- switchHelpTip.setChecked(MyApplication.showHelpTip);
-
- switchHelpTip.setOnCheckedChangeListener((buttonView, isChecked) -> {
- MyApplication.showHelpTip = isChecked;
- SharedPreferences sp = context.getSharedPreferences(Define.SP_CONFIG, Context.MODE_PRIVATE);
- sp.edit().putBoolean(Define.SP_CONFIG_SWITCH_HELP_TIP, isChecked).apply();
- Log.d(TAG, "onCheckedChanged:" + isChecked);
-
- StepBar stepBar = findViewById(R.id.stepBar);
- stepBar.setHighlight();
- CommonUtils.calcMarginBottom(this, null, null, findViewById(R.id.scrollView));
- });
- }
-
- //恢复初始化配置
- public void initSetting(View view) {
-
- AlertDialog.Builder builder = new AlertDialog.Builder(SettingActivity.this);
- builder.setTitle(R.string.init_setting);
- builder.setMessage(R.string.init_setting_tips);
-
- //添加AlertDialog.Builder对象的setPositiveButton()方法
- builder.setPositiveButton(R.string.confirm, (dialog, which) -> {
- //初始化配置
- SharedPreferences preferences = PreferenceManager.getDefaultSharedPreferences(this);
- SharedPreferences.Editor editor = preferences.edit();
- editor.clear();
- editor.apply();
-
- //初始化数据库
- DbHelper dbHelper = new DbHelper(this);
- SQLiteDatabase db = dbHelper.getReadableDatabase();
- dbHelper.delCreateTable(db);
- dbHelper.onCreate(db);
-
- Intent intent = new Intent(this, MainActivity.class);
- startActivity(intent);
- });
-
- //添加AlertDialog.Builder对象的setNegativeButton()方法
- builder.setNegativeButton(R.string.cancel, (dialog, which) -> {
-
- });
-
- builder.create().show();
- }
-
- /**
- * 获取当前手机品牌
- *
- * @return 手机品牌
- */
- public static String getAutoStartTips() {
- String brand = Build.BRAND.toLowerCase();
- String tips;
-
- switch (brand) {
- case "huawei":
- tips = "华为手机:应用启动管理 -> 关闭应用开关 -> 打开允许自启动";
- break;
- case "honor":
- tips = "荣耀手机:应用启动管理 -> 关闭应用开关 -> 打开允许自启动";
- break;
- case "xiaomi":
- tips = "小米手机:授权管理 -> 自启动管理 -> 允许应用自启动";
- break;
- case "oppo":
- tips = "OPPO手机:权限隐私 -> 自启动管理 -> 允许应用自启动";
- break;
- case "vivo":
- tips = "vivo手机:权限管理 -> 自启动 -> 允许应用自启动";
- break;
- case "meizu":
- tips = "魅族手机:权限管理 -> 后台管理 -> 点击应用 -> 允许后台运行";
- break;
- case "samsung":
- tips = "三星手机:自动运行应用程序 -> 打开应用开关 -> 电池管理 -> 未监视的应用程序 -> 添加应用";
- break;
- case "letv":
- tips = "乐视手机:自启动管理 -> 允许应用自启动";
- break;
- case "smartisan":
- tips = "锤子手机:权限管理 -> 自启动权限管理 -> 点击应用 -> 允许被系统启动";
- break;
- default:
- tips = "未知手机品牌:需要自主查看设置操作";
- break;
- }
-
- return tips;
- }
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/activity/LoginActivity.kt b/app/src/main/java/com/idormy/sms/forwarder/activity/LoginActivity.kt
new file mode 100644
index 00000000..153744a4
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/activity/LoginActivity.kt
@@ -0,0 +1,28 @@
+package com.idormy.sms.forwarder.activity
+
+import android.os.Bundle
+import android.view.KeyEvent
+import androidx.viewbinding.ViewBinding
+import com.idormy.sms.forwarder.core.BaseActivity
+import com.idormy.sms.forwarder.fragment.LoginFragment
+import com.xuexiang.xui.utils.KeyboardUtils
+import com.xuexiang.xui.utils.StatusBarUtils
+import com.xuexiang.xutil.display.Colors
+
+class LoginActivity : BaseActivity() {
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ openPage(LoginFragment::class.java, intent.extras)
+ }
+
+ override val isSupportSlideBack: Boolean
+ get() = false
+
+ override fun initStatusBarStyle() {
+ StatusBarUtils.initStatusBarStyle(this, false, Colors.WHITE)
+ }
+
+ override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
+ return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt b/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt
new file mode 100644
index 00000000..9446787a
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/activity/MainActivity.kt
@@ -0,0 +1,402 @@
+package com.idormy.sms.forwarder.activity
+
+import android.annotation.SuppressLint
+import android.app.ActivityManager
+import android.content.Context
+import android.content.Intent
+import android.os.Build
+import android.os.Bundle
+import android.util.Log
+import android.view.LayoutInflater
+import android.view.MenuItem
+import android.view.View
+import android.widget.TextView
+import androidx.appcompat.app.ActionBarDrawerToggle
+import androidx.appcompat.widget.Toolbar
+import androidx.recyclerview.widget.RecyclerView
+import androidx.viewpager.widget.ViewPager
+import com.google.android.material.bottomnavigation.BottomNavigationView
+import com.google.android.material.bottomsheet.BottomSheetDialog
+import com.gyf.cactus.ext.cactusUpdateNotification
+import com.idormy.sms.forwarder.App
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.adapter.WidgetItemAdapter
+import com.idormy.sms.forwarder.core.BaseActivity
+import com.idormy.sms.forwarder.core.webview.AgentWebActivity
+import com.idormy.sms.forwarder.database.AppDatabase
+import com.idormy.sms.forwarder.databinding.ActivityMainBinding
+import com.idormy.sms.forwarder.fragment.*
+import com.idormy.sms.forwarder.utils.*
+import com.idormy.sms.forwarder.widget.GuideTipsDialog.Companion.showTips
+import com.idormy.sms.forwarder.widget.GuideTipsDialog.Companion.showTipsForce
+import com.jeremyliao.liveeventbus.LiveEventBus
+import com.xuexiang.xaop.annotation.SingleClick
+import com.xuexiang.xpage.base.XPageFragment
+import com.xuexiang.xpage.core.PageOption
+import com.xuexiang.xpage.model.PageInfo
+import com.xuexiang.xui.adapter.FragmentAdapter
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
+import com.xuexiang.xui.utils.DensityUtils
+import com.xuexiang.xui.utils.ResUtils
+import com.xuexiang.xui.utils.WidgetUtils
+import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
+import com.xuexiang.xui.widget.dialog.materialdialog.GravityEnum
+import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
+import com.xuexiang.xupdate.XUpdate
+import com.xuexiang.xupdate.service.OnFileDownloadListener
+import com.xuexiang.xutil.common.CollectionUtils
+import com.xuexiang.xutil.file.FileUtils
+import frpclib.Frpclib
+import io.reactivex.CompletableObserver
+import io.reactivex.android.schedulers.AndroidSchedulers
+import io.reactivex.disposables.Disposable
+import io.reactivex.schedulers.Schedulers
+import java.io.File
+import kotlin.math.roundToInt
+
+
+@Suppress("DEPRECATION", "PrivatePropertyName")
+class MainActivity : BaseActivity(),
+ View.OnClickListener,
+ BottomNavigationView.OnNavigationItemSelectedListener,
+ Toolbar.OnMenuItemClickListener,
+ RecyclerViewHolder.OnItemClickListener {
+
+ private val TAG: String = MainActivity::class.java.simpleName
+ private lateinit var mTitles: Array
+ private var logsType: String = "sms"
+ private var ruleType: String = "sms"
+
+ override fun viewBindingInflate(inflater: LayoutInflater?): ActivityMainBinding {
+ return ActivityMainBinding.inflate(inflater!!)
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ initViews()
+ initData()
+ initListeners()
+
+ //不在最近任务列表中显示
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SettingUtils.enableExcludeFromRecents) {
+ val am = App.context.getSystemService(Context.ACTIVITY_SERVICE) as ActivityManager
+ am.let {
+ val tasks = it.appTasks
+ if (!tasks.isNullOrEmpty()) {
+ tasks[0].setExcludeFromRecents(true)
+ }
+ }
+ }
+ }
+
+ override val isSupportSlideBack: Boolean
+ get() = false
+
+ private fun initViews() {
+ WidgetUtils.clearActivityBackground(this)
+ mTitles = ResUtils.getStringArray(R.array.home_titles)
+ binding!!.includeMain.toolbar.title = mTitles[0]
+ binding!!.includeMain.toolbar.inflateMenu(R.menu.menu_logs)
+ binding!!.includeMain.toolbar.setOnMenuItemClickListener(this)
+
+ //主页内容填充
+ val fragments = arrayOf(
+ LogsFragment(),
+ RulesFragment(),
+ SendersFragment(),
+ SettingsFragment()
+ )
+ val adapter = FragmentAdapter(supportFragmentManager, fragments)
+ binding!!.includeMain.viewPager.offscreenPageLimit = mTitles.size - 1
+ binding!!.includeMain.viewPager.adapter = adapter
+
+ if (!SettingUtils.enableHelpTip) {
+ val headerView = binding!!.navView.getHeaderView(0)
+ val tvSlogan = headerView.findViewById(R.id.tv_slogan)
+ tvSlogan.visibility = View.GONE
+ }
+ }
+
+ private fun initData() {
+ showTips(this)
+ //XUpdateInit.checkUpdate(this, true)
+ }
+
+ fun initListeners() {
+ val toggle = ActionBarDrawerToggle(
+ this,
+ binding!!.drawerLayout,
+ binding!!.includeMain.toolbar,
+ R.string.navigation_drawer_open,
+ R.string.navigation_drawer_close
+ )
+ binding!!.drawerLayout.addDrawerListener(toggle)
+ toggle.syncState()
+
+ //侧边栏点击事件
+ binding!!.navView.setNavigationItemSelectedListener { menuItem: MenuItem ->
+ if (menuItem.isCheckable) {
+ binding!!.drawerLayout.closeDrawers()
+ return@setNavigationItemSelectedListener handleNavigationItemSelected(menuItem)
+ } else {
+ when (menuItem.itemId) {
+ R.id.nav_server -> openNewPage(ServerFragment::class.java)
+ R.id.nav_client -> openNewPage(ClientFragment::class.java)
+ R.id.nav_frpc -> {
+ if (FileUtils.isFileExists(filesDir.absolutePath + "/libs/libgojni.so")) {
+ if (FRPC_LIB_VERSION == Frpclib.getVersion()) {
+ openNewPage(FrpcFragment::class.java)
+ } else {
+ XToastUtils.error(getString(R.string.frpclib_version_mismatch))
+ downloadFrpcLib()
+ }
+ } else {
+ downloadFrpcLib()
+ }
+ }
+ R.id.nav_app_list -> openNewPage(AppListFragment::class.java)
+ R.id.nav_logcat -> openNewPage(LogcatFragment::class.java)
+ R.id.nav_help -> AgentWebActivity.goWeb(this, getString(R.string.url_help))
+ R.id.nav_about -> openNewPage(AboutFragment::class.java)
+ else -> XToastUtils.toast("点击了:" + menuItem.title)
+ }
+ }
+ true
+ }
+
+ //主页事件监听
+ binding!!.includeMain.viewPager.addOnPageChangeListener(object :
+ ViewPager.OnPageChangeListener {
+ override fun onPageScrolled(
+ position: Int,
+ positionOffset: Float,
+ positionOffsetPixels: Int,
+ ) {
+ }
+
+ override fun onPageSelected(position: Int) {
+ val item = binding!!.includeMain.bottomNavigation.menu.getItem(position)
+ binding!!.includeMain.toolbar.title = item.title
+ binding!!.includeMain.toolbar.menu.clear()
+ when {
+ item.title.equals(getString(R.string.menu_rules)) -> binding!!.includeMain.toolbar.inflateMenu(R.menu.menu_rules)
+ item.title.equals(getString(R.string.menu_senders)) -> binding!!.includeMain.toolbar.inflateMenu(R.menu.menu_senders)
+ item.title.equals(getString(R.string.menu_settings)) -> binding!!.includeMain.toolbar.inflateMenu(R.menu.menu_settings)
+ else -> binding!!.includeMain.toolbar.inflateMenu(R.menu.menu_logs)
+ }
+ item.isChecked = true
+ updateSideNavStatus(item)
+ }
+
+ override fun onPageScrollStateChanged(state: Int) {}
+ })
+ binding!!.includeMain.bottomNavigation.setOnNavigationItemSelectedListener(this)
+
+ //tabBar分类切换
+ LiveEventBus.get(EVENT_UPDATE_LOGS_TYPE, String::class.java).observe(this) { type: String ->
+ logsType = type
+ }
+ LiveEventBus.get(EVENT_UPDATE_RULE_TYPE, String::class.java).observe(this) { type: String ->
+ ruleType = type
+ }
+
+ //更新通知栏文案
+ LiveEventBus.get(EVENT_UPDATE_NOTIFY, String::class.java).observe(this) { notify: String ->
+ cactusUpdateNotification {
+ setContent(notify)
+ }
+ }
+ }
+
+ /**
+ * 处理侧边栏点击事件
+ *
+ * @param menuItem
+ * @return
+ */
+ private fun handleNavigationItemSelected(menuItem: MenuItem): Boolean {
+ val index = CollectionUtils.arrayIndexOf(mTitles, menuItem.title)
+ if (index != -1) {
+ binding!!.includeMain.toolbar.title = menuItem.title
+ binding!!.includeMain.viewPager.setCurrentItem(index, false)
+ return true
+ }
+ return false
+ }
+
+ @SuppressLint("InflateParams")
+ override fun onMenuItemClick(item: MenuItem): Boolean {
+ when (item.itemId) {
+ R.id.action_notifications -> {
+ showTipsForce(this)
+ }
+ R.id.action_clear_logs -> {
+ MaterialDialog.Builder(this)
+ .content(R.string.delete_type_log_tips)
+ .positiveText(R.string.lab_yes)
+ .negativeText(R.string.lab_no)
+ .onPositive { _: MaterialDialog?, _: DialogAction? ->
+ AppDatabase.getInstance(this)
+ .logsDao()
+ .deleteAll(logsType)
+ .subscribeOn(Schedulers.io())
+ .observeOn(AndroidSchedulers.mainThread())
+ .subscribe(object : CompletableObserver {
+ override fun onSubscribe(d: Disposable) {}
+ override fun onComplete() {
+ XToastUtils.success(R.string.delete_type_log_toast)
+ }
+
+ override fun onError(e: Throwable) {
+ e.message?.let { XToastUtils.error(it) }
+ }
+ })
+ }
+ .show()
+ }
+ R.id.action_add_sender -> {
+ val dialog = BottomSheetDialog(this)
+ val view: View = LayoutInflater.from(this).inflate(R.layout.dialog_sender_bottom_sheet, null)
+ val recyclerView: RecyclerView = view.findViewById(R.id.recyclerView)
+
+ WidgetUtils.initGridRecyclerView(recyclerView, 4, DensityUtils.dp2px(1f))
+ val widgetItemAdapter = WidgetItemAdapter(SENDER_FRAGMENT_LIST)
+ widgetItemAdapter.setOnItemClickListener(this)
+ recyclerView.adapter = widgetItemAdapter
+
+ dialog.setContentView(view)
+ dialog.setCancelable(true)
+ dialog.setCanceledOnTouchOutside(true)
+ dialog.show()
+ WidgetUtils.transparentBottomSheetDialogBackground(dialog)
+ }
+ R.id.action_add_rule -> {
+ PageOption.to(RulesEditFragment::class.java)
+ .putString(KEY_RULE_TYPE, ruleType)
+ .setNewActivity(true)
+ .open(this)
+ }
+ /*R.id.action_restore_settings -> {
+ XToastUtils.success(logsType)
+ }*/
+ }
+ return false
+ }
+
+ @SingleClick
+ override fun onClick(v: View) {
+ }
+
+ //================Navigation================//
+ /**
+ * 底部导航栏点击事件
+ *
+ * @param menuItem
+ * @return
+ */
+ override fun onNavigationItemSelected(menuItem: MenuItem): Boolean {
+ val index = CollectionUtils.arrayIndexOf(mTitles, menuItem.title)
+ if (index != -1) {
+ binding!!.includeMain.toolbar.title = menuItem.title
+ binding!!.includeMain.viewPager.setCurrentItem(index, false)
+ updateSideNavStatus(menuItem)
+ return true
+ }
+ return false
+ }
+
+ /**
+ * 更新侧边栏菜单选中状态
+ *
+ * @param menuItem
+ */
+ private fun updateSideNavStatus(menuItem: MenuItem) {
+ val side = binding!!.navView.menu.findItem(menuItem.itemId)
+ if (side != null) {
+ side.isChecked = true
+ }
+ }
+
+ //按返回键不退出回到桌面
+ override fun onBackPressed() {
+ val intent = Intent(Intent.ACTION_MAIN)
+ intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
+ intent.addCategory(Intent.CATEGORY_HOME)
+ startActivity(intent)
+ }
+
+ @SingleClick
+ override fun onItemClick(itemView: View, widgetInfo: PageInfo, pos: Int) {
+ try {
+ @Suppress("UNCHECKED_CAST")
+ PageOption.to(Class.forName(widgetInfo.classPath) as Class) //跳转的fragment
+ .setNewActivity(true)
+ .putInt(KEY_SENDER_TYPE, pos) //TODO:需要注意这里,目前刚好是这个顺序而已
+ .open(this)
+ } catch (e: Exception) {
+ e.printStackTrace()
+ XToastUtils.error(e.message.toString())
+ }
+ }
+
+ //动态加载FrpcLib
+ private fun downloadFrpcLib() {
+ val cpuAbi = when (Build.CPU_ABI) {
+ "x86" -> "x86"
+ "x86_64" -> "x86_64"
+ "arm64-v8a" -> "arm64-v8a"
+ else -> "armeabi-v7a"
+ }
+
+ val libPath = filesDir.absolutePath + "/libs"
+ val soFile = File(libPath)
+ if (!soFile.exists()) soFile.mkdirs()
+ val downloadUrl = "https://xupdate.bms.ink/uploads/$FRPC_LIB_VERSION/$cpuAbi/libgojni.so"
+ val mContext = this
+ val dialog: MaterialDialog = MaterialDialog.Builder(mContext)
+ .title(getString(R.string.frpclib_download_title))
+ .content(getString(R.string.frpclib_download_content))
+ .contentGravity(GravityEnum.CENTER)
+ .progress(false, 0, true)
+ .progressNumberFormat("%2dMB/%1dMB")
+ .build()
+ XUpdate.newBuild(mContext)
+ .apkCacheDir(cacheDir.absolutePath) //设置下载缓存的根目录
+ .build()
+ .download(downloadUrl, object : OnFileDownloadListener {
+
+ override fun onStart() {
+ dialog.show()
+ }
+
+ override fun onProgress(progress: Float, total: Long) {
+ Log.d(TAG, "onProgress: progress=$progress, total=$total")
+
+ val max = (total / 1024F / 1024F).roundToInt()
+ dialog.maxProgress = max
+ dialog.setProgress((progress * max).roundToInt())
+ }
+
+ override fun onCompleted(srcFile: File): Boolean {
+ dialog.dismiss()
+ Log.d(TAG, srcFile.path)
+
+ val destFile = File("$libPath/libgojni.so")
+ FileUtils.moveFile(srcFile, destFile, null)
+
+ val intent: Intent? = packageManager.getLaunchIntentForPackage(packageName)
+ intent?.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
+ startActivity(intent)
+ android.os.Process.killProcess(android.os.Process.myPid()) //杀掉以前进程
+
+ return false
+ }
+
+ override fun onError(throwable: Throwable) {
+ dialog.dismiss()
+ XToastUtils.error(throwable.message!!)
+ }
+ })
+ }
+
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/activity/SplashActivity.kt b/app/src/main/java/com/idormy/sms/forwarder/activity/SplashActivity.kt
new file mode 100644
index 00000000..4c1cac6b
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/activity/SplashActivity.kt
@@ -0,0 +1,79 @@
+package com.idormy.sms.forwarder.activity
+
+import android.annotation.SuppressLint
+import android.util.Log
+import android.view.KeyEvent
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.utils.CommonUtils.Companion.showPrivacyDialog
+import com.idormy.sms.forwarder.utils.MMKVUtils
+import com.idormy.sms.forwarder.utils.SettingUtils.Companion.isAgreePrivacy
+import com.idormy.sms.forwarder.utils.SettingUtils.Companion.isFirstOpen
+import com.xuexiang.xui.utils.KeyboardUtils
+import com.xuexiang.xui.widget.activity.BaseSplashActivity
+import com.xuexiang.xui.widget.dialog.materialdialog.DialogAction
+import com.xuexiang.xui.widget.dialog.materialdialog.MaterialDialog
+import com.xuexiang.xutil.app.ActivityUtils
+import me.jessyan.autosize.internal.CancelAdapt
+
+@Suppress("PropertyName")
+@SuppressLint("CustomSplashScreen")
+class SplashActivity : BaseSplashActivity(), CancelAdapt {
+
+ val TAG: String = SplashActivity::class.java.simpleName
+
+ override fun getSplashDurationMillis(): Long {
+ return 500
+ }
+
+ /**
+ * activity启动后的初始化
+ */
+ override fun onCreateActivity() {
+ initSplashView(R.drawable.xui_config_bg_splash)
+ startSplash(false)
+ }
+
+ /**
+ * 启动页结束后的动作
+ */
+ override fun onSplashFinished() {
+ if (isFirstOpen) {
+ isFirstOpen = false
+ Log.d(TAG, "从SP迁移数据")
+ MMKVUtils.importSharedPreferences(this)
+ }
+
+ if (isAgreePrivacy) {
+ loginOrGoMainPage()
+ } else {
+ showPrivacyDialog(this) { dialog: MaterialDialog, _: DialogAction? ->
+ dialog.dismiss()
+ isAgreePrivacy = true
+ loginOrGoMainPage()
+ }
+ }
+ }
+
+ private fun loginOrGoMainPage() {
+ /*if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP && SettingUtils.enableExcludeFromRecents) {
+ val intent = Intent(App.context, if (hasToken()) MainActivity::class.java else LoginActivity::class.java)
+ intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK or Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
+ App.context.startActivity(intent)
+ } else {
+ if (hasToken()) {
+ ActivityUtils.startActivity(MainActivity::class.java)
+ } else {
+ ActivityUtils.startActivity(LoginActivity::class.java)
+ }
+ }*/
+ ActivityUtils.startActivity(MainActivity::class.java)
+ finish()
+ }
+
+ /**
+ * 菜单、返回键响应
+ */
+ override fun onKeyDown(keyCode: Int, event: KeyEvent): Boolean {
+ return KeyboardUtils.onDisableBackKeyDown(keyCode) && super.onKeyDown(keyCode, event)
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/AppAdapter.java b/app/src/main/java/com/idormy/sms/forwarder/adapter/AppAdapter.java
deleted file mode 100644
index 5bc17325..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/adapter/AppAdapter.java
+++ /dev/null
@@ -1,113 +0,0 @@
-package com.idormy.sms.forwarder.adapter;
-
-import android.annotation.SuppressLint;
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.idormy.sms.forwarder.R;
-import com.idormy.sms.forwarder.model.AppInfo;
-
-import java.util.List;
-
-public class AppAdapter extends ArrayAdapter {
- private final int resourceId;
- private List list;
-
- // 适配器的构造函数,把要适配的数据传入这里
- public AppAdapter(Context context, int textViewResourceId, List objects) {
- super(context, textViewResourceId, objects);
- resourceId = textViewResourceId;
- list = objects;
- }
-
- @Override
- public int getCount() {
- return list.size();
- }
-
- @Override
- public AppInfo getItem(int position) {
- return list.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- AppInfo item = list.get(position);
- return 0;
- }
-
- @SuppressLint("SetTextI18n")
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- AppInfo appInfo = getItem(position); //获取当前项的TLog实例
-
- // 加个判断,以免ListView每次滚动时都要重新加载布局,以提高运行效率
- View view;
- AppAdapter.ViewHolder viewHolder;
- if (convertView == null) {
-
- // 避免ListView每次滚动时都要重新加载布局,以提高运行效率
- view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
-
- // 避免每次调用getView()时都要重新获取控件实例
- viewHolder = new AppAdapter.ViewHolder();
- viewHolder.appName = view.findViewById(R.id.appName);
- viewHolder.pkgName = view.findViewById(R.id.pkgName);
- viewHolder.appIcon = view.findViewById(R.id.appIcon);
- viewHolder.verName = view.findViewById(R.id.verName);
- viewHolder.verCode = view.findViewById(R.id.verCode);
-
- // 将ViewHolder存储在View中(即将控件的实例存储在其中)
- view.setTag(viewHolder);
- } else {
- view = convertView;
- viewHolder = (AppAdapter.ViewHolder) view.getTag();
- }
-
- // 获取控件实例,并调用set...方法使其显示出来
- if (appInfo != null) {
- viewHolder.appName.setText(appInfo.getAppName());
- viewHolder.pkgName.setText(appInfo.getPkgName());
- viewHolder.appIcon.setBackground(appInfo.getAppIcon());
- viewHolder.verName.setText(appInfo.getVerName());
- viewHolder.verCode.setText(appInfo.getVerCode() + "");
- }
-
- return view;
- }
-
- public void add(List appModels) {
- if (list != null) {
- list = appModels;
- notifyDataSetChanged();
- }
- }
-
- public void del(List appModels) {
- if (list != null) {
- list = appModels;
- notifyDataSetChanged();
- }
- }
-
- public void update(List appModels) {
- if (list != null) {
- list = appModels;
- notifyDataSetChanged();
- }
- }
-
- // 定义一个内部类,用于对控件的实例进行缓存
- static class ViewHolder {
- TextView appName;
- TextView pkgName;
- ImageView appIcon;
- TextView verName;
- TextView verCode;
- }
-}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/AppListAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/AppListAdapter.kt
new file mode 100644
index 00000000..8436bdfd
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/AppListAdapter.kt
@@ -0,0 +1,65 @@
+package com.idormy.sms.forwarder.adapter
+
+import android.widget.ImageView
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.adapter.base.broccoli.BroccoliRecyclerAdapter
+import com.idormy.sms.forwarder.utils.PlaceholderHelper
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
+import com.xuexiang.xui.widget.imageview.ImageLoader
+import com.xuexiang.xutil.app.AppUtils
+import com.xuexiang.xutil.app.AppUtils.AppInfo
+import me.samlss.broccoli.Broccoli
+
+class AppListAdapter(
+ /**
+ * 是否是加载占位
+ */
+ private val mIsAnim: Boolean,
+) : BroccoliRecyclerAdapter(AppUtils.getAppsInfo()) {
+
+ override fun getItemLayoutId(viewType: Int): Int {
+ return R.layout.adapter_app_list_item
+ }
+
+ /**
+ * 绑定控件
+ *
+ * @param holder
+ * @param model
+ * @param position
+ */
+ override fun onBindData(holder: RecyclerViewHolder?, model: AppInfo?, position: Int) {
+ if (holder == null || model == null) return
+ val ivAppIcon = holder.findViewById(R.id.iv_app_icon)
+ ImageLoader.get().loadImage(ivAppIcon, model.icon)
+ holder.text(R.id.tv_app_name, model.name)
+ holder.text(R.id.tv_pkg_name, model.packageName)
+ holder.text(R.id.tv_ver_name, model.versionName)
+ //holder.text(R.id.tv_ver_code, model.versionCode)
+ }
+
+ /**
+ * 绑定占位控件
+ *
+ * @param holder
+ * @param broccoli
+ */
+ override fun onBindBroccoli(holder: RecyclerViewHolder?, broccoli: Broccoli?) {
+ if (holder == null || broccoli == null) return
+ if (mIsAnim) {
+ broccoli.addPlaceholder(PlaceholderHelper.getParameter(holder.findView(R.id.iv_app_icon)))
+ .addPlaceholder(PlaceholderHelper.getParameter(holder.findView(R.id.tv_app_name)))
+ .addPlaceholder(PlaceholderHelper.getParameter(holder.findView(R.id.tv_pkg_name)))
+ .addPlaceholder(PlaceholderHelper.getParameter(holder.findView(R.id.tv_ver_name)))
+ //.addPlaceholder(PlaceholderHelper.getParameter(holder.findView(R.id.tv_ver_code)))
+ } else {
+ broccoli.addPlaceholders(
+ holder.findView(R.id.iv_app_icon),
+ holder.findView(R.id.tv_app_name),
+ holder.findView(R.id.tv_pkg_name),
+ holder.findView(R.id.tv_ver_name),
+ //holder.findView(R.id.tv_ver_code)
+ )
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/FrpcPagingAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/FrpcPagingAdapter.kt
new file mode 100644
index 00000000..499c6af4
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/FrpcPagingAdapter.kt
@@ -0,0 +1,77 @@
+package com.idormy.sms.forwarder.adapter
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.paging.PagingDataAdapter
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.adapter.FrpcPagingAdapter.MyViewHolder
+import com.idormy.sms.forwarder.database.entity.Frpc
+import com.idormy.sms.forwarder.databinding.AdapterFrpcsCardViewListItemBinding
+import com.xuexiang.xutil.resource.ResUtils.getColors
+import frpclib.Frpclib
+
+class FrpcPagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter(diffCallback) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
+ val binding = AdapterFrpcsCardViewListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return MyViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
+ val item = getItem(position)
+ if (item != null) {
+ holder.binding.ivImage.setImageResource(R.drawable.ic_menu_frpc)
+ holder.binding.ivAutorun.setImageResource(item.autorunImageId)
+ holder.binding.tvName.text = item.name
+
+ if (item.connecting || Frpclib.isRunning(item.uid)) {
+ holder.binding.ivPlay.setImageResource(R.drawable.ic_stop)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ holder.binding.ivPlay.imageTintList = getColors(R.color.colorStop)
+ }
+ } else {
+ holder.binding.ivPlay.setImageResource(R.drawable.ic_start)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
+ holder.binding.ivPlay.imageTintList = getColors(R.color.colorStart)
+ }
+ }
+
+ holder.binding.ivEdit.setImageResource(R.drawable.ic_edit)
+ holder.binding.ivDelete.setImageResource(R.drawable.ic_delete)
+
+ holder.binding.ivPlay.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ holder.binding.ivEdit.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ holder.binding.ivDelete.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ }
+ }
+
+ class MyViewHolder(val binding: AdapterFrpcsCardViewListItemBinding) : RecyclerView.ViewHolder(binding.root)
+ interface OnItemClickListener {
+ fun onItemClicked(view: View?, item: Frpc)
+ fun onItemRemove(view: View?, id: Int)
+ }
+
+ companion object {
+ var diffCallback: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: Frpc, newItem: Frpc): Boolean {
+ return oldItem.uid == newItem.uid
+ }
+
+ @SuppressLint("DiffUtilEquals")
+ override fun areContentsTheSame(oldItem: Frpc, newItem: Frpc): Boolean {
+ return oldItem === newItem
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/LogAdapter.java b/app/src/main/java/com/idormy/sms/forwarder/adapter/LogAdapter.java
deleted file mode 100644
index 8661f4c9..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/adapter/LogAdapter.java
+++ /dev/null
@@ -1,124 +0,0 @@
-package com.idormy.sms.forwarder.adapter;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.idormy.sms.forwarder.R;
-import com.idormy.sms.forwarder.model.vo.LogVo;
-import com.idormy.sms.forwarder.utils.TimeUtils;
-
-import java.util.List;
-
-@SuppressWarnings("unused")
-public class LogAdapter extends ArrayAdapter {
- private final int resourceId;
- private List list;
-
- // 适配器的构造函数,把要适配的数据传入这里
- public LogAdapter(Context context, int textViewResourceId, List objects) {
- super(context, textViewResourceId, objects);
- resourceId = textViewResourceId;
- list = objects;
- }
-
- @Override
- public int getCount() {
- return list.size();
- }
-
- @Override
- public LogVo getItem(int position) {
- return list.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- return 0;
- }
-
- // convertView 参数用于将之前加载好的布局进行缓存
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- LogVo logVo = getItem(position); //获取当前项的TLog实例
-
- // 加个判断,以免ListView每次滚动时都要重新加载布局,以提高运行效率
- View view;
- ViewHolder viewHolder;
- if (convertView == null) {
-
- // 避免ListView每次滚动时都要重新加载布局,以提高运行效率
- view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
-
- // 避免每次调用getView()时都要重新获取控件实例
- viewHolder = new ViewHolder();
- viewHolder.tLogFrom = view.findViewById(R.id.tlog_from);
- viewHolder.tLogContent = view.findViewById(R.id.tlog_content);
- viewHolder.tLogRule = view.findViewById(R.id.tlog_rule);
- viewHolder.tLogTime = view.findViewById(R.id.tlog_time);
- viewHolder.senderImage = view.findViewById(R.id.tlog_sender_image);
- viewHolder.statusImage = view.findViewById(R.id.tlog_status_image);
- viewHolder.simImage = view.findViewById(R.id.tlog_sim_image);
-
- // 将ViewHolder存储在View中(即将控件的实例存储在其中)
- view.setTag(viewHolder);
- } else {
- view = convertView;
- viewHolder = (ViewHolder) view.getTag();
- }
-
- // 获取控件实例,并调用set...方法使其显示出来
- if (logVo != null) {
- viewHolder.tLogFrom.setText(logVo.getFrom());
- viewHolder.tLogContent.setText(logVo.getContent());
- viewHolder.tLogRule.setText(logVo.getRule());
- viewHolder.tLogTime.setText(TimeUtils.friendlyTime(logVo.getTime()));
- viewHolder.senderImage.setImageResource(logVo.getSenderImageId());
- viewHolder.simImage.setImageResource(logVo.getSimImageId());
- viewHolder.statusImage.setImageResource(logVo.getStatusImageId());
- }
-
- return view;
- }
-
- public void add(List logVos) {
- if (list != null) {
- list = logVos;
- notifyDataSetChanged();
- }
- }
-
- public void del(List logVos) {
- if (list != null) {
- list = logVos;
- notifyDataSetChanged();
- }
- }
-
- public void update(List logVos) {
- if (list != null) {
- list = logVos;
- notifyDataSetChanged();
- }
- }
-
- public void onDateChange(List logVos) {
- list = logVos;
- notifyDataSetChanged();
- }
-
- // 定义一个内部类,用于对控件的实例进行缓存
- static class ViewHolder {
- TextView tLogFrom;
- TextView tLogContent;
- TextView tLogRule;
- TextView tLogTime;
- ImageView senderImage;
- ImageView simImage;
- ImageView statusImage;
- }
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt
new file mode 100644
index 00000000..1eadb6ac
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/LogsPagingAdapter.kt
@@ -0,0 +1,57 @@
+package com.idormy.sms.forwarder.adapter
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.paging.PagingDataAdapter
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.idormy.sms.forwarder.adapter.LogsPagingAdapter.MyViewHolder
+import com.idormy.sms.forwarder.database.entity.LogsAndRuleAndSender
+import com.idormy.sms.forwarder.database.entity.Sender
+import com.idormy.sms.forwarder.databinding.AdapterLogsCardViewListItemBinding
+import com.xuexiang.xutil.data.DateUtils
+
+class LogsPagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter(diffCallback) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
+ val binding = AdapterLogsCardViewListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return MyViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
+ val item = getItem(position)
+ if (item != null) {
+ holder.binding.tvFrom.text = item.logs.from
+ holder.binding.tvTime.text = DateUtils.getFriendlyTimeSpanByNow(item.logs.time)
+ holder.binding.tvContent.text = item.logs.content
+ holder.binding.ivSenderImage.setImageResource(Sender.getImageId(item.relation.sender.type))
+ holder.binding.ivStatusImage.setImageResource(item.logs.statusImageId)
+ holder.binding.ivSimImage.setImageResource(item.logs.simImageId)
+
+ holder.binding.cardView.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ }
+ }
+
+ class MyViewHolder(val binding: AdapterLogsCardViewListItemBinding) : RecyclerView.ViewHolder(binding.root)
+ interface OnItemClickListener {
+ fun onItemClicked(view: View?, item: LogsAndRuleAndSender)
+ fun onItemRemove(view: View?, id: Int)
+ }
+
+ companion object {
+ var diffCallback: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: LogsAndRuleAndSender, newItem: LogsAndRuleAndSender): Boolean {
+ return oldItem.logs.id == newItem.logs.id
+ }
+
+ @SuppressLint("DiffUtilEquals")
+ override fun areContentsTheSame(oldItem: LogsAndRuleAndSender, newItem: LogsAndRuleAndSender): Boolean {
+ return oldItem.logs === newItem.logs
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/RuleAdapter.java b/app/src/main/java/com/idormy/sms/forwarder/adapter/RuleAdapter.java
deleted file mode 100644
index 7db40969..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/adapter/RuleAdapter.java
+++ /dev/null
@@ -1,127 +0,0 @@
-package com.idormy.sms.forwarder.adapter;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.idormy.sms.forwarder.R;
-import com.idormy.sms.forwarder.model.RuleModel;
-import com.idormy.sms.forwarder.model.SenderModel;
-import com.idormy.sms.forwarder.sender.SenderUtil;
-
-import java.util.List;
-
-public class RuleAdapter extends ArrayAdapter {
- private final int resourceId;
- private List list;
-
- // 适配器的构造函数,把要适配的数据传入这里
- public RuleAdapter(Context context, int textViewResourceId, List objects) {
- super(context, textViewResourceId, objects);
- resourceId = textViewResourceId;
- list = objects;
- }
-
- @Override
- public int getCount() {
- return list.size();
- }
-
- @Override
- public RuleModel getItem(int position) {
- return list.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- RuleModel item = list.get(position);
- if (item == null) {
- return 0;
- }
- return item.getId();
- }
-
- // convertView 参数用于将之前加载好的布局进行缓存
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- RuleModel ruleModel = getItem(position); //获取当前项的TLog实例
-
- // 加个判断,以免ListView每次滚动时都要重新加载布局,以提高运行效率
- View view;
- ViewHolder viewHolder;
- if (convertView == null) {
-
- // 避免ListView每次滚动时都要重新加载布局,以提高运行效率
- view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
-
- // 避免每次调用getView()时都要重新获取控件实例
- viewHolder = new ViewHolder();
- viewHolder.ruleMatch = view.findViewById(R.id.rule_match);
- viewHolder.ruleSender = view.findViewById(R.id.rule_sender);
- viewHolder.ruleImage = view.findViewById(R.id.rule_image);
- viewHolder.ruleStatus = view.findViewById(R.id.rule_status);
- viewHolder.ruleSenderImage = view.findViewById(R.id.rule_sender_image);
- viewHolder.ruleSenderStatus = view.findViewById(R.id.rule_sender_status);
-
- // 将ViewHolder存储在View中(即将控件的实例存储在其中)
- view.setTag(viewHolder);
- } else {
- view = convertView;
- viewHolder = (ViewHolder) view.getTag();
- }
-
- // 获取控件实例,并调用set...方法使其显示出来
- if (ruleModel != null) {
- viewHolder.ruleImage.setImageResource(ruleModel.getImageId());
- viewHolder.ruleStatus.setImageResource(ruleModel.getStatusImageId());
-
- List senderModel = SenderUtil.getSender(ruleModel.getSenderId(), null);
- viewHolder.ruleMatch.setText(ruleModel.getRuleMatch());
- if (!senderModel.isEmpty()) {
- viewHolder.ruleSender.setText(senderModel.get(0).getName());
- viewHolder.ruleSenderImage.setImageResource(senderModel.get(0).getImageId());
- viewHolder.ruleSenderStatus.setImageResource(senderModel.get(0).getStatusImageId());
- } else {
- viewHolder.ruleSender.setText("");
- }
- }
-
- return view;
- }
-
- public void add(List ruleModels) {
- if (list != null) {
- list = ruleModels;
- notifyDataSetChanged();
- }
- }
-
- public void del(List ruleModels) {
- if (list != null) {
- list = ruleModels;
- notifyDataSetChanged();
- }
- }
-
- public void update(List ruleModels) {
- if (list != null) {
- list = ruleModels;
- notifyDataSetChanged();
- }
- }
-
- // 定义一个内部类,用于对控件的实例进行缓存
- static class ViewHolder {
- TextView ruleMatch;
- TextView ruleSender;
- ImageView ruleImage;
- ImageView ruleStatus;
- ImageView ruleSenderImage;
- ImageView ruleSenderStatus;
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/RulePagingAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/RulePagingAdapter.kt
new file mode 100644
index 00000000..f4ae8c74
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/RulePagingAdapter.kt
@@ -0,0 +1,68 @@
+package com.idormy.sms.forwarder.adapter
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.paging.PagingDataAdapter
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.adapter.RulePagingAdapter.MyViewHolder
+import com.idormy.sms.forwarder.database.entity.RuleAndSender
+import com.idormy.sms.forwarder.databinding.AdapterRulesCardViewListItemBinding
+
+class RulePagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter(diffCallback) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
+ val binding = AdapterRulesCardViewListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return MyViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
+ val item = getItem(position)
+ if (item != null) {
+ holder.binding.ivRuleImage.setImageResource(item.rule.imageId)
+ holder.binding.ivRuleStatus.setImageResource(item.rule.statusImageId)
+ holder.binding.tvRuleMatch.text = item.rule.ruleMatch
+ holder.binding.ivSenderImage.setImageResource(item.sender.imageId)
+ holder.binding.ivSenderStatus.setImageResource(item.sender.statusImageId)
+ holder.binding.tvSenderName.text = item.sender.name
+
+ /*holder.binding.cardView.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }*/
+ holder.binding.ivCopy.setImageResource(R.drawable.ic_copy)
+ holder.binding.ivEdit.setImageResource(R.drawable.ic_edit)
+ holder.binding.ivDelete.setImageResource(R.drawable.ic_delete)
+ holder.binding.ivCopy.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ holder.binding.ivEdit.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ holder.binding.ivDelete.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ }
+ }
+
+ class MyViewHolder(val binding: AdapterRulesCardViewListItemBinding) : RecyclerView.ViewHolder(binding.root)
+ interface OnItemClickListener {
+ fun onItemClicked(view: View?, item: RuleAndSender)
+ fun onItemRemove(view: View?, id: Int)
+ }
+
+ companion object {
+ var diffCallback: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: RuleAndSender, newItem: RuleAndSender): Boolean {
+ return oldItem.rule.id == newItem.rule.id
+ }
+
+ @SuppressLint("DiffUtilEquals")
+ override fun areContentsTheSame(oldItem: RuleAndSender, newItem: RuleAndSender): Boolean {
+ return oldItem.rule === newItem.rule
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/SenderAdapter.java b/app/src/main/java/com/idormy/sms/forwarder/adapter/SenderAdapter.java
deleted file mode 100644
index cee01407..00000000
--- a/app/src/main/java/com/idormy/sms/forwarder/adapter/SenderAdapter.java
+++ /dev/null
@@ -1,132 +0,0 @@
-package com.idormy.sms.forwarder.adapter;
-
-import android.content.Context;
-import android.view.LayoutInflater;
-import android.view.View;
-import android.view.ViewGroup;
-import android.widget.ArrayAdapter;
-import android.widget.ImageView;
-import android.widget.TextView;
-
-import com.idormy.sms.forwarder.R;
-import com.idormy.sms.forwarder.model.SenderModel;
-
-import java.util.List;
-
-@SuppressWarnings("unused")
-public class SenderAdapter extends ArrayAdapter {
- private final int resourceId;
- private List list;
-
- // 适配器的构造函数,把要适配的数据传入这里
- public SenderAdapter(Context context, int textViewResourceId, List objects) {
- super(context, textViewResourceId, objects);
- resourceId = textViewResourceId;
- list = objects;
- }
-
- @Override
- public int getCount() {
- return list.size();
- }
-
- @Override
- public SenderModel getItem(int position) {
- return list.get(position);
- }
-
- @Override
- public long getItemId(int position) {
- SenderModel item = list.get(position);
- if (item == null) {
- return 0;
- }
- return item.getId();
- }
-
- // convertView 参数用于将之前加载好的布局进行缓存
- @Override
- public View getView(int position, View convertView, ViewGroup parent) {
- SenderModel senderModel = getItem(position); //获取当前项的TLog实例
-
- // 加个判断,以免ListView每次滚动时都要重新加载布局,以提高运行效率
- View view;
- ViewHolder viewHolder;
- if (convertView == null) {
-
- // 避免ListView每次滚动时都要重新加载布局,以提高运行效率
- view = LayoutInflater.from(getContext()).inflate(resourceId, parent, false);
-
- // 避免每次调用getView()时都要重新获取控件实例
- viewHolder = new ViewHolder();
- viewHolder.senderImage = view.findViewById(R.id.sender_image);
- viewHolder.senderStatus = view.findViewById(R.id.sender_status);
- viewHolder.senderName = view.findViewById(R.id.sender_name);
-
- // 将ViewHolder存储在View中(即将控件的实例存储在其中)
- view.setTag(viewHolder);
- } else {
- view = convertView;
- viewHolder = (ViewHolder) view.getTag();
- }
-
- // 获取控件实例,并调用set...方法使其显示出来
- if (senderModel != null) {
- viewHolder.senderImage.setImageResource(senderModel.getImageId());
- viewHolder.senderStatus.setImageResource(senderModel.getStatusImageId());
- viewHolder.senderName.setText(senderModel.getName());
- }
-
- return view;
- }
-
- public void add(SenderModel senderModel) {
- if (list != null) {
- list.add(senderModel);
- notifyDataSetChanged();
- }
- }
-
- public void del(int position) {
- if (list != null) {
- list.remove(position);
- notifyDataSetChanged();
- }
- }
-
- public void update(SenderModel senderModel, int position) {
- if (list != null) {
- list.set(position, senderModel);
- notifyDataSetChanged();
- }
- }
-
- public void add(List senderModels) {
- if (list != null) {
- list = senderModels;
- notifyDataSetChanged();
- }
- }
-
- public void del(List senderModels) {
- if (list != null) {
- list = senderModels;
- notifyDataSetChanged();
- }
- }
-
- public void update(List senderModels) {
- if (list != null) {
- list = senderModels;
- notifyDataSetChanged();
- }
- }
-
- // 定义一个内部类,用于对控件的实例进行缓存
- static class ViewHolder {
- ImageView senderImage;
- ImageView senderStatus;
- TextView senderName;
- }
-
-}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/SenderPagingAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/SenderPagingAdapter.kt
new file mode 100644
index 00000000..1f0757b3
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/SenderPagingAdapter.kt
@@ -0,0 +1,65 @@
+package com.idormy.sms.forwarder.adapter
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.paging.PagingDataAdapter
+import androidx.recyclerview.widget.DiffUtil
+import androidx.recyclerview.widget.RecyclerView
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.adapter.SenderPagingAdapter.MyViewHolder
+import com.idormy.sms.forwarder.database.entity.Sender
+import com.idormy.sms.forwarder.databinding.AdapterSendersCardViewListItemBinding
+
+class SenderPagingAdapter(private val itemClickListener: OnItemClickListener) : PagingDataAdapter(diffCallback) {
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): MyViewHolder {
+ val binding = AdapterSendersCardViewListItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
+ return MyViewHolder(binding)
+ }
+
+ override fun onBindViewHolder(holder: MyViewHolder, position: Int) {
+ val item = getItem(position)
+ if (item != null) {
+ holder.binding.ivImage.setImageResource(item.imageId)
+ holder.binding.ivStatus.setImageResource(item.statusImageId)
+ holder.binding.tvName.text = item.name
+
+ /*holder.binding.cardView.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }*/
+ holder.binding.ivCopy.setImageResource(R.drawable.ic_copy)
+ holder.binding.ivEdit.setImageResource(R.drawable.ic_edit)
+ holder.binding.ivDelete.setImageResource(R.drawable.ic_delete)
+ holder.binding.ivCopy.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ holder.binding.ivEdit.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ holder.binding.ivDelete.setOnClickListener { view: View? ->
+ itemClickListener.onItemClicked(view, item)
+ }
+ }
+ }
+
+ class MyViewHolder(val binding: AdapterSendersCardViewListItemBinding) : RecyclerView.ViewHolder(binding.root)
+ interface OnItemClickListener {
+ fun onItemClicked(view: View?, item: Sender)
+ fun onItemRemove(view: View?, id: Int)
+ }
+
+ companion object {
+ var diffCallback: DiffUtil.ItemCallback = object : DiffUtil.ItemCallback() {
+ override fun areItemsTheSame(oldItem: Sender, newItem: Sender): Boolean {
+ return oldItem.id == newItem.id
+ }
+
+ @SuppressLint("DiffUtilEquals")
+ override fun areContentsTheSame(oldItem: Sender, newItem: Sender): Boolean {
+ return oldItem === newItem
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/WidgetItemAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/WidgetItemAdapter.kt
new file mode 100644
index 00000000..39364d7c
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/WidgetItemAdapter.kt
@@ -0,0 +1,20 @@
+package com.idormy.sms.forwarder.adapter
+
+import com.idormy.sms.forwarder.R
+import com.xuexiang.xpage.model.PageInfo
+import com.xuexiang.xui.adapter.recyclerview.BaseRecyclerAdapter
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
+
+class WidgetItemAdapter(list: List) : BaseRecyclerAdapter(list) {
+
+ public override fun getItemLayoutId(viewType: Int): Int {
+ return R.layout.layout_widget_item
+ }
+
+ override fun bindData(holder: RecyclerViewHolder, position: Int, item: PageInfo) {
+ holder.text(R.id.item_name, item.name)
+ if (item.extra != 0) {
+ holder.image(R.id.item_icon, item.extra)
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/broccoli/BroccoliRecyclerAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/broccoli/BroccoliRecyclerAdapter.kt
new file mode 100644
index 00000000..bd943c0b
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/broccoli/BroccoliRecyclerAdapter.kt
@@ -0,0 +1,67 @@
+package com.idormy.sms.forwarder.adapter.base.broccoli
+
+import android.view.View
+import com.xuexiang.xui.adapter.recyclerview.BaseRecyclerAdapter
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
+import com.xuexiang.xui.adapter.recyclerview.XRecyclerAdapter
+import me.samlss.broccoli.Broccoli
+
+/**
+ * 使用Broccoli占位的基础适配器
+ *
+ * @author XUE
+ * @since 2019/4/8 16:33
+ */
+abstract class BroccoliRecyclerAdapter(collection: Collection?) :
+ BaseRecyclerAdapter(collection) {
+ /**
+ * 是否已经加载成功
+ */
+ private var mHasLoad = false
+ private val mBroccoliMap: MutableMap = HashMap()
+ override fun bindData(holder: RecyclerViewHolder, position: Int, item: T) {
+ var broccoli = mBroccoliMap[holder.itemView]
+ if (broccoli == null) {
+ broccoli = Broccoli()
+ mBroccoliMap[holder.itemView] = broccoli
+ }
+ if (mHasLoad) {
+ broccoli.removeAllPlaceholders()
+ onBindData(holder, item, position)
+ } else {
+ onBindBroccoli(holder, broccoli)
+ broccoli.show()
+ }
+ }
+
+ /**
+ * 绑定控件
+ *
+ * @param holder
+ * @param model
+ * @param position
+ */
+ protected abstract fun onBindData(holder: RecyclerViewHolder?, model: T, position: Int)
+
+ /**
+ * 绑定占位控件
+ *
+ * @param broccoli
+ */
+ protected abstract fun onBindBroccoli(holder: RecyclerViewHolder?, broccoli: Broccoli?)
+ override fun refresh(collection: Collection): XRecyclerAdapter<*, *> {
+ mHasLoad = true
+ return super.refresh(collection)
+ }
+
+ /**
+ * 资源释放,防止内存泄漏
+ */
+ fun recycle() {
+ for (broccoli in mBroccoliMap.values) {
+ broccoli.removeAllPlaceholders()
+ }
+ mBroccoliMap.clear()
+ clear()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.kt
new file mode 100644
index 00000000..94a6d4c5
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/broccoli/BroccoliSimpleDelegateAdapter.kt
@@ -0,0 +1,85 @@
+@file:Suppress("unused")
+
+package com.idormy.sms.forwarder.adapter.base.broccoli
+
+import android.view.View
+import com.alibaba.android.vlayout.LayoutHelper
+import com.idormy.sms.forwarder.adapter.base.delegate.SimpleDelegateAdapter
+import com.idormy.sms.forwarder.adapter.base.delegate.XDelegateAdapter
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
+import me.samlss.broccoli.Broccoli
+
+/**
+ * 使用Broccoli占位的基础适配器
+ *
+ * @author xuexiang
+ * @since 2021/1/9 4:52 PM
+ */
+abstract class BroccoliSimpleDelegateAdapter : SimpleDelegateAdapter {
+ /**
+ * 是否已经加载成功
+ */
+ private var mHasLoad = false
+ private val mBroccoliMap: MutableMap = HashMap()
+
+ constructor(layoutId: Int, layoutHelper: LayoutHelper) : super(layoutId, layoutHelper)
+ constructor(layoutId: Int, layoutHelper: LayoutHelper, list: Collection?) : super(
+ layoutId,
+ layoutHelper,
+ list
+ )
+
+ constructor(layoutId: Int, layoutHelper: LayoutHelper?, data: Array?) : super(
+ layoutId,
+ layoutHelper!!,
+ data
+ )
+
+ override fun bindData(holder: RecyclerViewHolder, position: Int, item: T) {
+ var broccoli = mBroccoliMap[holder.itemView]
+ if (broccoli == null) {
+ broccoli = Broccoli()
+ mBroccoliMap[holder.itemView] = broccoli
+ }
+ if (mHasLoad) {
+ broccoli.removeAllPlaceholders()
+ onBindData(holder, item, position)
+ } else {
+ onBindBroccoli(holder, broccoli)
+ broccoli.show()
+ }
+ }
+
+ /**
+ * 绑定控件
+ *
+ * @param holder
+ * @param model
+ * @param position
+ */
+ protected abstract fun onBindData(holder: RecyclerViewHolder, model: T, position: Int)
+
+ /**
+ * 绑定占位控件
+ *
+ * @param holder
+ * @param broccoli
+ */
+ protected abstract fun onBindBroccoli(holder: RecyclerViewHolder, broccoli: Broccoli)
+
+ override fun refresh(collection: Collection?): XDelegateAdapter<*, *> {
+ mHasLoad = true
+ return super.refresh(collection)
+ }
+
+ /**
+ * 资源释放,防止内存泄漏
+ */
+ fun recycle() {
+ for (broccoli in mBroccoliMap.values) {
+ broccoli.removeAllPlaceholders()
+ }
+ mBroccoliMap.clear()
+ clear()
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/BaseDelegateAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/BaseDelegateAdapter.kt
new file mode 100644
index 00000000..27561ea1
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/BaseDelegateAdapter.kt
@@ -0,0 +1,27 @@
+package com.idormy.sms.forwarder.adapter.base.delegate
+
+import android.view.ViewGroup
+import com.xuexiang.xui.adapter.recyclerview.RecyclerViewHolder
+
+/**
+ * 通用的DelegateAdapter适配器
+ *
+ * @author xuexiang
+ * @since 2020/3/20 12:44 AM
+ */
+abstract class BaseDelegateAdapter : XDelegateAdapter {
+ constructor() : super()
+ constructor(list: Collection?) : super(list)
+ constructor(data: Array?) : super(data)
+
+ /**
+ * 适配的布局
+ *
+ * @param viewType
+ * @return
+ */
+ protected abstract fun getItemLayoutId(viewType: Int): Int
+ override fun getViewHolder(parent: ViewGroup, viewType: Int): RecyclerViewHolder {
+ return RecyclerViewHolder(inflateView(parent, getItemLayoutId(viewType)))
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/SimpleDelegateAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/SimpleDelegateAdapter.kt
new file mode 100644
index 00000000..ef03b98b
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/SimpleDelegateAdapter.kt
@@ -0,0 +1,37 @@
+package com.idormy.sms.forwarder.adapter.base.delegate
+
+import com.alibaba.android.vlayout.LayoutHelper
+
+/**
+ * 简易DelegateAdapter适配器
+ *
+ * @author xuexiang
+ * @since 2020/3/20 12:55 AM
+ */
+abstract class SimpleDelegateAdapter : BaseDelegateAdapter {
+ private var mLayoutId: Int
+ private var mLayoutHelper: LayoutHelper
+
+ constructor(layoutId: Int, layoutHelper: LayoutHelper) : super() {
+ mLayoutId = layoutId
+ mLayoutHelper = layoutHelper
+ }
+
+ constructor(layoutId: Int, layoutHelper: LayoutHelper, list: Collection?) : super(list) {
+ mLayoutId = layoutId
+ mLayoutHelper = layoutHelper
+ }
+
+ constructor(layoutId: Int, layoutHelper: LayoutHelper, data: Array?) : super(data) {
+ mLayoutId = layoutId
+ mLayoutHelper = layoutHelper
+ }
+
+ override fun getItemLayoutId(viewType: Int): Int {
+ return mLayoutId
+ }
+
+ override fun onCreateLayoutHelper(): LayoutHelper {
+ return mLayoutHelper
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt
new file mode 100644
index 00000000..89e13353
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/base/delegate/XDelegateAdapter.kt
@@ -0,0 +1,269 @@
+package com.idormy.sms.forwarder.adapter.base.delegate
+
+import android.annotation.SuppressLint
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import androidx.annotation.LayoutRes
+import androidx.recyclerview.widget.RecyclerView
+import com.alibaba.android.vlayout.DelegateAdapter
+
+/**
+ * 基础DelegateAdapter
+ *
+ * @author xuexiang
+ * @since 2020/3/20 12:17 AM
+ */
+@Suppress("unused")
+abstract class XDelegateAdapter : DelegateAdapter.Adapter {
+ /**
+ * 数据源
+ */
+ private val mData: MutableList = ArrayList()
+ /**
+ * @return 当前列表的选中项
+ */
+ /**
+ * 当前点击的条目
+ */
+ private var selectPosition = -1
+
+ constructor()
+ constructor(list: Collection?) {
+ if (list != null) {
+ mData.addAll(list)
+ }
+ }
+
+ constructor(data: Array?) {
+ if (data != null && data.isNotEmpty()) {
+ mData.addAll(listOf(*data))
+ }
+ }
+
+ /**
+ * 构建自定义的ViewHolder
+ *
+ * @param parent
+ * @param viewType
+ * @return
+ */
+ protected abstract fun getViewHolder(parent: ViewGroup, viewType: Int): V
+
+ /**
+ * 绑定数据
+ *
+ * @param holder
+ * @param position 索引
+ * @param item 列表项
+ */
+ protected abstract fun bindData(holder: V, position: Int, item: T)
+
+ /**
+ * 加载布局获取控件
+ *
+ * @param parent 父布局
+ * @param layoutId 布局ID
+ * @return
+ */
+ protected fun inflateView(parent: ViewGroup, @LayoutRes layoutId: Int): View {
+ return LayoutInflater.from(parent.context).inflate(layoutId, parent, false)
+ }
+
+ override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): V {
+ return getViewHolder(parent, viewType)
+ }
+
+ override fun onBindViewHolder(holder: V, position: Int) {
+ bindData(holder, position, mData[position])
+ }
+
+ /**
+ * 获取列表项
+ *
+ * @param position
+ * @return
+ */
+ private fun getItem(position: Int): T? {
+ return if (checkPosition(position)) mData[position] else null
+ }
+
+ private fun checkPosition(position: Int): Boolean {
+ return position >= 0 && position <= mData.size - 1
+ }
+
+ val isEmpty: Boolean
+ get() = itemCount == 0
+
+ override fun getItemCount(): Int {
+ return mData.size
+ }
+
+ /**
+ * @return 数据源
+ */
+ val data: List
+ get() = mData
+
+ /**
+ * 给指定位置添加一项
+ *
+ * @param pos
+ * @param item
+ * @return
+ */
+ fun add(pos: Int, item: T): XDelegateAdapter<*, *> {
+ mData.add(pos, item)
+ notifyItemInserted(pos)
+ return this
+ }
+
+ /**
+ * 在列表末端增加一项
+ *
+ * @param item
+ * @return
+ */
+ fun add(item: T): XDelegateAdapter<*, *> {
+ mData.add(item)
+ notifyItemInserted(mData.size - 1)
+ return this
+ }
+
+ /**
+ * 删除列表中指定索引的数据
+ *
+ * @param pos
+ * @return
+ */
+ fun delete(pos: Int): XDelegateAdapter<*, *> {
+ mData.removeAt(pos)
+ notifyItemRemoved(pos)
+ return this
+ }
+
+ /**
+ * 刷新列表中指定位置的数据
+ *
+ * @param pos
+ * @param item
+ * @return
+ */
+ fun refresh(pos: Int, item: T): XDelegateAdapter<*, *> {
+ mData[pos] = item
+ notifyItemChanged(pos)
+ return this
+ }
+
+ /**
+ * 刷新列表数据
+ *
+ * @param collection
+ * @return
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ open fun refresh(collection: Collection?): XDelegateAdapter<*, *> {
+ if (collection != null) {
+ mData.clear()
+ mData.addAll(collection)
+ selectPosition = -1
+ notifyDataSetChanged()
+ }
+ return this
+ }
+
+ /**
+ * 刷新列表数据
+ *
+ * @param array
+ * @return
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ fun refresh(array: Array?): XDelegateAdapter<*, *> {
+ if (array != null && array.isNotEmpty()) {
+ mData.clear()
+ mData.addAll(listOf(*array))
+ selectPosition = -1
+ notifyDataSetChanged()
+ }
+ return this
+ }
+
+ /**
+ * 加载更多
+ *
+ * @param collection
+ * @return
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ fun loadMore(collection: Collection?): XDelegateAdapter<*, *> {
+ if (collection != null) {
+ mData.addAll(collection)
+ notifyDataSetChanged()
+ }
+ return this
+ }
+
+ /**
+ * 加载更多
+ *
+ * @param array
+ * @return
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ fun loadMore(array: Array?): XDelegateAdapter<*, *> {
+ if (array != null && array.isNotEmpty()) {
+ mData.addAll(listOf(*array))
+ notifyDataSetChanged()
+ }
+ return this
+ }
+
+ /**
+ * 添加一个
+ *
+ * @param item
+ * @return
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ fun load(item: T?): XDelegateAdapter<*, *> {
+ if (item != null) {
+ mData.add(item)
+ notifyDataSetChanged()
+ }
+ return this
+ }
+
+ /**
+ * 设置当前列表的选中项
+ *
+ * @param selectPosition
+ * @return
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ fun setSelectPosition(selectPosition: Int): XDelegateAdapter<*, *> {
+ this.selectPosition = selectPosition
+ notifyDataSetChanged()
+ return this
+ }
+
+ /**
+ * 获取当前列表选中项
+ *
+ * @return 当前列表选中项
+ */
+ val selectItem: T?
+ get() = getItem(selectPosition)
+
+ /**
+ * 清除数据
+ */
+ @SuppressLint("NotifyDataSetChanged")
+ fun clear() {
+ if (!isEmpty) {
+ mData.clear()
+ selectPosition = -1
+ notifyDataSetChanged()
+ }
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt
new file mode 100644
index 00000000..aeee8a37
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListAdapterItem.kt
@@ -0,0 +1,45 @@
+package com.idormy.sms.forwarder.adapter.spinner
+
+import android.graphics.drawable.Drawable
+import com.xuexiang.xui.utils.ResUtils
+
+@Suppress("unused")
+class AppListAdapterItem {
+
+ var name: String = ""
+ var icon: Drawable? = null
+ var packageName: String? = null
+ //var packagePath: String? = null
+ //var versionName: String? = null
+ //var versionCode: Int = 0
+ //var isSystem: Boolean = false
+
+
+ constructor(name: String, icon: Drawable?, packageName: String?) {
+ this.name = name
+ this.icon = icon
+ this.packageName = packageName
+ }
+
+ constructor(name: String) : this(name, null, null)
+ constructor(name: String, drawableId: Int, packageName: String) : this(name, ResUtils.getDrawable(drawableId), packageName)
+
+ //TODO:注意自定义实体,需要重写对象的toString方法
+ override fun toString(): String {
+ return name
+ }
+
+ companion object {
+ fun of(name: String): AppListAdapterItem {
+ return AppListAdapterItem(name)
+ }
+
+ fun arrayof(title: Array): Array {
+ val array = arrayOfNulls(title.size)
+ for (i in array.indices) {
+ array[i] = AppListAdapterItem(title[i])
+ }
+ return array
+ }
+ }
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt
new file mode 100644
index 00000000..90028aa2
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/AppListSpinnerAdapter.kt
@@ -0,0 +1,153 @@
+package com.idormy.sms.forwarder.adapter.spinner
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.text.Html
+import android.text.TextUtils
+import android.util.Log
+import android.util.TypedValue
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import com.idormy.sms.forwarder.R
+import com.xuexiang.xui.utils.CollectionUtils
+import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter
+import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter
+
+@Suppress("unused", "NAME_SHADOWING", "SENSELESS_COMPARISON", "DEPRECATION")
+class AppListSpinnerAdapter : BaseEditSpinnerAdapter, EditSpinnerFilter {
+ /**
+ * 选项的文字颜色
+ */
+ private var mTextColor = 0
+
+ /**
+ * 选项的文字大小
+ */
+ private var mTextSize = 0f
+
+ /**
+ * 背景颜色
+ */
+ private var mBackgroundSelector = 0
+
+ /**
+ * 过滤关键词的选中颜色
+ */
+ private var mFilterColor = "#F15C58"
+ private var mIsFilterKey = false
+
+ /**
+ * 构造方法
+ *
+ * @param data 选项数据
+ */
+ constructor(data: List?) : super(data)
+
+ /**
+ * 构造方法
+ *
+ * @param data 选项数据
+ */
+ constructor(data: Array?) : super(data)
+
+ override fun getEditSpinnerFilter(): EditSpinnerFilter {
+ return this
+ }
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
+ var convertView = convertView
+ val holder: ViewHolder
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false)
+ holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector)
+ convertView.tag = holder
+ } else {
+ holder = convertView.tag as ViewHolder
+ }
+ val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as AppListAdapterItem
+ holder.iconView.setImageDrawable(item.icon)
+ //holder.titleView.text = Html.fromHtml(item.toString())
+ holder.titleView.text = Html.fromHtml(getItem(position))
+ return convertView
+ }
+
+ override fun onFilter(keyword: String): Boolean {
+ mDisplayData.clear()
+ Log.d("AppListSpinnerAdapter", "keyword = $keyword")
+ Log.d("AppListSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}")
+ if (TextUtils.isEmpty(keyword)) {
+ initDisplayData(mDataSource)
+ for (i in mIndexs.indices) {
+ mIndexs[i] = i
+ }
+ } else {
+ try {
+ for (i in mDataSource.indices) {
+ if (getDataSourceString(i).contains(keyword, ignoreCase = true)) {
+ mIndexs[mDisplayData.size] = i
+ if (mIsFilterKey) {
+ mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "$keyword"))
+ } else {
+ mDisplayData.add(getDataSourceString(i))
+ }
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ Log.d("AppListSpinnerAdapter", "mDisplayData = $mDisplayData")
+ notifyDataSetChanged()
+ return mDisplayData.size > 0
+ }
+
+ fun setTextColor(@ColorInt textColor: Int): AppListSpinnerAdapter<*> {
+ mTextColor = textColor
+ return this
+ }
+
+ fun setTextSize(textSize: Float): AppListSpinnerAdapter<*> {
+ mTextSize = textSize
+ return this
+ }
+
+ fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): AppListSpinnerAdapter<*> {
+ mBackgroundSelector = backgroundSelector
+ return this
+ }
+
+ fun setFilterColor(filterColor: String): AppListSpinnerAdapter<*> {
+ mFilterColor = filterColor
+ return this
+ }
+
+ fun setIsFilterKey(isFilterKey: Boolean): AppListSpinnerAdapter<*> {
+ mIsFilterKey = isFilterKey
+ return this
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("ObsoleteSdkInt")
+ private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) {
+ val iconView: ImageView = convertView.findViewById(R.id.iv_icon)
+ val statusView: ImageView = convertView.findViewById(R.id.iv_status)
+ val titleView: TextView = convertView.findViewById(R.id.tv_title)
+
+ init {
+ if (textColor > 0) titleView.setTextColor(textColor)
+ if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
+ if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ val config = convertView.resources.configuration
+ if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ titleView.textDirection = View.TEXT_DIRECTION_RTL
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderAdapterItem.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderAdapterItem.kt
new file mode 100644
index 00000000..d9561af9
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderAdapterItem.kt
@@ -0,0 +1,92 @@
+package com.idormy.sms.forwarder.adapter.spinner
+
+import android.content.Context
+import android.graphics.drawable.Drawable
+import com.xuexiang.xui.utils.ResUtils
+
+@Suppress("unused")
+class SenderAdapterItem {
+
+ //标题内容
+ var title: CharSequence
+
+ //图标
+ var icon: Drawable? = null
+
+ //ID
+ var id: Long? = 0L
+
+ //状态
+ var status: Int? = 1
+
+ constructor(title: CharSequence) {
+ this.title = title
+ }
+
+ constructor(title: CharSequence, icon: Drawable?) {
+ this.title = title
+ this.icon = icon
+ }
+
+ constructor(title: CharSequence, icon: Drawable?, id: Long?) {
+ this.title = title
+ this.icon = icon
+ this.id = id
+ }
+
+ constructor(title: CharSequence, icon: Drawable?, id: Long?, status: Int?) {
+ this.title = title
+ this.icon = icon
+ this.id = id
+ this.status = status
+ }
+
+ constructor(title: CharSequence, drawableId: Int) : this(title, ResUtils.getDrawable(drawableId))
+ constructor(title: CharSequence, drawableId: Int, id: Long) : this(title, ResUtils.getDrawable(drawableId), id)
+ constructor(title: CharSequence, drawableId: Int, id: Long, status: Int) : this(title, ResUtils.getDrawable(drawableId), id, status)
+ constructor(context: Context?, titleId: Int, drawableId: Int) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId))
+ constructor(context: Context?, titleId: Int, drawableId: Int, id: Long) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId), id)
+ constructor(context: Context?, titleId: Int, drawableId: Int, id: Long, status: Int) : this(ResUtils.getString(titleId), ResUtils.getDrawable(context, drawableId), id, status)
+ constructor(context: Context?, title: CharSequence, drawableId: Int) : this(title, ResUtils.getDrawable(context, drawableId))
+ constructor(context: Context?, title: CharSequence, drawableId: Int, id: Long) : this(title, ResUtils.getDrawable(context, drawableId), id)
+ constructor(context: Context?, title: CharSequence, drawableId: Int, id: Long, status: Int) : this(title, ResUtils.getDrawable(context, drawableId), id, status)
+
+ fun setStatus(status: Int): SenderAdapterItem {
+ this.status = status
+ return this
+ }
+
+ fun setId(id: Long): SenderAdapterItem {
+ this.id = id
+ return this
+ }
+
+ fun setTitle(title: CharSequence): SenderAdapterItem {
+ this.title = title
+ return this
+ }
+
+ fun setIcon(icon: Drawable?): SenderAdapterItem {
+ this.icon = icon
+ return this
+ }
+
+ //TODO:注意自定义实体,需要重写对象的toString方法
+ override fun toString(): String {
+ return title.toString()
+ }
+
+ companion object {
+ fun of(title: CharSequence): SenderAdapterItem {
+ return SenderAdapterItem(title)
+ }
+
+ fun arrayof(title: Array): Array {
+ val array = arrayOfNulls(title.size)
+ for (i in array.indices) {
+ array[i] = SenderAdapterItem(title[i])
+ }
+ return array
+ }
+ }
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt
new file mode 100644
index 00000000..a0ff255d
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/adapter/spinner/SenderSpinnerAdapter.kt
@@ -0,0 +1,163 @@
+package com.idormy.sms.forwarder.adapter.spinner
+
+import android.annotation.SuppressLint
+import android.os.Build
+import android.text.Html
+import android.text.TextUtils
+import android.util.Log
+import android.util.TypedValue
+import android.view.LayoutInflater
+import android.view.View
+import android.view.ViewGroup
+import android.widget.ImageView
+import android.widget.TextView
+import androidx.annotation.ColorInt
+import androidx.annotation.DrawableRes
+import com.idormy.sms.forwarder.R
+import com.idormy.sms.forwarder.utils.STATUS_OFF
+import com.xuexiang.xui.utils.CollectionUtils
+import com.xuexiang.xui.utils.ResUtils
+import com.xuexiang.xui.widget.spinner.editspinner.BaseEditSpinnerAdapter
+import com.xuexiang.xui.widget.spinner.editspinner.EditSpinnerFilter
+
+@Suppress("unused", "NAME_SHADOWING", "SENSELESS_COMPARISON", "DEPRECATION")
+class SenderSpinnerAdapter : BaseEditSpinnerAdapter, EditSpinnerFilter {
+ /**
+ * 选项的文字颜色
+ */
+ private var mTextColor = 0
+
+ /**
+ * 选项的文字大小
+ */
+ private var mTextSize = 0f
+
+ /**
+ * 背景颜色
+ */
+ private var mBackgroundSelector = 0
+
+ /**
+ * 过滤关键词的选中颜色
+ */
+ private var mFilterColor = "#F15C58"
+ private var mIsFilterKey = false
+
+ /**
+ * 构造方法
+ *
+ * @param data 选项数据
+ */
+ constructor(data: List?) : super(data)
+
+ /**
+ * 构造方法
+ *
+ * @param data 选项数据
+ */
+ constructor(data: Array?) : super(data)
+
+ override fun getEditSpinnerFilter(): EditSpinnerFilter {
+ return this
+ }
+
+ override fun getView(position: Int, convertView: View?, parent: ViewGroup): View? {
+ var convertView = convertView
+ val holder: ViewHolder
+ if (convertView == null) {
+ convertView = LayoutInflater.from(parent.context).inflate(R.layout.item_spinner_with_icon, parent, false)
+ holder = ViewHolder(convertView, mTextColor, mTextSize, mBackgroundSelector)
+ convertView.tag = holder
+ } else {
+ holder = convertView.tag as ViewHolder
+ }
+ val item = CollectionUtils.getListItem(mDataSource, mIndexs[position]) as SenderAdapterItem
+ holder.iconView.setImageDrawable(item.icon)
+ holder.statusView.setImageDrawable(
+ ResUtils.getDrawable(
+ when (item.status) {
+ STATUS_OFF -> R.drawable.icon_off
+ else -> R.drawable.icon_on
+ }
+ )
+ )
+ //holder.titleView.text = Html.fromHtml(item.toString())
+ holder.titleView.text = Html.fromHtml(getItem(position))
+ return convertView
+ }
+
+ override fun onFilter(keyword: String): Boolean {
+ mDisplayData.clear()
+ Log.d("SenderSpinnerAdapter", "keyword = $keyword")
+ Log.d("SenderSpinnerAdapter", "mIndexs.indices = ${mIndexs.indices}")
+ if (TextUtils.isEmpty(keyword)) {
+ initDisplayData(mDataSource)
+ for (i in mIndexs.indices) {
+ mIndexs[i] = i
+ }
+ } else {
+ try {
+ for (i in mDataSource.indices) {
+ if (getDataSourceString(i).contains(keyword, ignoreCase = true)) {
+ mIndexs[mDisplayData.size] = i
+ if (mIsFilterKey) {
+ mDisplayData.add(getDataSourceString(i).replaceFirst(keyword.toRegex(), "$keyword"))
+ } else {
+ mDisplayData.add(getDataSourceString(i))
+ }
+ }
+ }
+ } catch (e: Exception) {
+ e.printStackTrace()
+ }
+ }
+ Log.d("SenderSpinnerAdapter", "mDisplayData = $mDisplayData")
+ notifyDataSetChanged()
+ return mDisplayData.size > 0
+ }
+
+ fun setTextColor(@ColorInt textColor: Int): SenderSpinnerAdapter<*> {
+ mTextColor = textColor
+ return this
+ }
+
+ fun setTextSize(textSize: Float): SenderSpinnerAdapter<*> {
+ mTextSize = textSize
+ return this
+ }
+
+ fun setBackgroundSelector(@DrawableRes backgroundSelector: Int): SenderSpinnerAdapter<*> {
+ mBackgroundSelector = backgroundSelector
+ return this
+ }
+
+ fun setFilterColor(filterColor: String): SenderSpinnerAdapter<*> {
+ mFilterColor = filterColor
+ return this
+ }
+
+ fun setIsFilterKey(isFilterKey: Boolean): SenderSpinnerAdapter<*> {
+ mIsFilterKey = isFilterKey
+ return this
+ }
+
+ @Suppress("DEPRECATION")
+ @SuppressLint("ObsoleteSdkInt")
+ private class ViewHolder(convertView: View, @ColorInt textColor: Int, textSize: Float, @DrawableRes backgroundSelector: Int) {
+ val iconView: ImageView = convertView.findViewById(R.id.iv_icon)
+ val statusView: ImageView = convertView.findViewById(R.id.iv_status)
+ val titleView: TextView = convertView.findViewById(R.id.tv_title)
+
+ init {
+ if (textColor > 0) titleView.setTextColor(textColor)
+ if (textSize > 0F) titleView.setTextSize(TypedValue.COMPLEX_UNIT_PX, textSize)
+ if (backgroundSelector != 0) titleView.setBackgroundResource(backgroundSelector)
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
+ val config = convertView.resources.configuration
+ if (config.layoutDirection == View.LAYOUT_DIRECTION_RTL) {
+ titleView.textDirection = View.TEXT_DIRECTION_RTL
+ }
+ }
+ }
+ }
+}
diff --git a/app/src/main/java/com/idormy/sms/forwarder/core/BaseActivity.kt b/app/src/main/java/com/idormy/sms/forwarder/core/BaseActivity.kt
new file mode 100644
index 00000000..a36e7205
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/core/BaseActivity.kt
@@ -0,0 +1,157 @@
+package com.idormy.sms.forwarder.core
+
+import android.content.Context
+import android.os.Bundle
+import android.view.LayoutInflater
+import android.view.View
+import androidx.viewbinding.ViewBinding
+import com.xuexiang.xpage.base.XPageActivity
+import com.xuexiang.xpage.base.XPageFragment
+import com.xuexiang.xpage.core.CoreSwitchBean
+import com.xuexiang.xrouter.facade.service.SerializationService
+import com.xuexiang.xrouter.launcher.XRouter
+import com.xuexiang.xui.utils.ResUtils
+import com.xuexiang.xui.widget.slideback.SlideBack
+import io.github.inflationx.viewpump.ViewPumpContextWrapper
+
+/**
+ * 基础容器Activity
+ *
+ * @author XUE
+ * @since 2019/3/22 11:21
+ */
+@Suppress("MemberVisibilityCanBePrivate", "UNCHECKED_CAST")
+open class BaseActivity : XPageActivity() {
+ /**
+ * 获取Binding
+ *
+ * @return Binding
+ */
+ /**
+ * ViewBinding
+ */
+ var binding: Binding? = null
+ protected set
+
+ override fun attachBaseContext(newBase: Context) {
+ //注入字体
+ super.attachBaseContext(ViewPumpContextWrapper.wrap(newBase))
+ }
+
+ override fun getCustomRootView(): View? {
+ binding = viewBindingInflate(layoutInflater)
+ return if (binding != null) binding!!.root else null
+ }
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ initStatusBarStyle()
+ super.onCreate(savedInstanceState)
+ registerSlideBack()
+ }
+
+ /**
+ * 构建ViewBinding
+ *
+ * @param inflater inflater
+ * @return ViewBinding
+ */
+ protected open fun viewBindingInflate(inflater: LayoutInflater?): Binding? {
+ return null
+ }
+
+ /**
+ * 初始化状态栏的样式
+ */
+ protected open fun initStatusBarStyle() {}
+
+ /**
+ * 打开fragment
+ *
+ * @param clazz 页面类
+ * @param addToBackStack 是否添加到栈中
+ * @return 打开的fragment对象
+ */
+ fun openPage(clazz: Class?, addToBackStack: Boolean): T {
+ val page = CoreSwitchBean(clazz)
+ .setAddToBackStack(addToBackStack)
+ return openPage(page) as T
+ }
+
+ /**
+ * 打开fragment
+ *
+ * @return 打开的fragment对象
+ */
+ fun openNewPage(clazz: Class?): T {
+ val page = CoreSwitchBean(clazz)
+ .setNewActivity(true)
+ return openPage(page) as T
+ }
+
+ /**
+ * 切换fragment
+ *
+ * @param clazz 页面类
+ * @return 打开的fragment对象
+ */
+ fun switchPage(clazz: Class?): T {
+ return openPage(clazz, false)
+ }
+
+ /**
+ * 序列化对象
+ *
+ * @param object
+ * @return
+ */
+ fun serializeObject(`object`: Any?): String {
+ return XRouter.getInstance().navigation(SerializationService::class.java)
+ .object2Json(`object`)
+ }
+
+ override fun onRelease() {
+ unregisterSlideBack()
+ super.onRelease()
+ }
+
+ /**
+ * 注册侧滑回调
+ */
+ protected fun registerSlideBack() {
+ if (isSupportSlideBack) {
+ SlideBack.with(this)
+ .haveScroll(true)
+ .edgeMode(if (ResUtils.isRtl()) SlideBack.EDGE_RIGHT else SlideBack.EDGE_LEFT)
+ .callBack { popPage() }
+ .register()
+ }
+ }
+
+ /**
+ * 注销侧滑回调
+ */
+ protected fun unregisterSlideBack() {
+ if (isSupportSlideBack) {
+ SlideBack.unregister(this)
+ }
+ }
+
+ /**
+ * @return 是否支持侧滑返回
+ */
+ protected open val isSupportSlideBack: Boolean
+ get() {
+ val page: CoreSwitchBean? = intent.getParcelableExtra(CoreSwitchBean.KEY_SWITCH_BEAN)
+ return page == null || page.bundle == null || page.bundle.getBoolean(
+ KEY_SUPPORT_SLIDE_BACK,
+ true
+ )
+ }
+
+ companion object {
+ /**
+ * 是否支持侧滑返回
+ */
+ const val KEY_SUPPORT_SLIDE_BACK = "key_support_slide_back"
+ }
+}
\ No newline at end of file
diff --git a/app/src/main/java/com/idormy/sms/forwarder/core/BaseContainerFragment.kt b/app/src/main/java/com/idormy/sms/forwarder/core/BaseContainerFragment.kt
new file mode 100644
index 00000000..053eae9d
--- /dev/null
+++ b/app/src/main/java/com/idormy/sms/forwarder/core/BaseContainerFragment.kt
@@ -0,0 +1,87 @@
+package com.idormy.sms.forwarder.core
+
+import android.content.res.Configuration
+import android.view.View
+import android.view.ViewGroup
+import android.widget.AdapterView
+import com.umeng.analytics.MobclickAgent
+import com.xuexiang.xaop.annotation.SingleClick
+import com.xuexiang.xpage.base.XPageContainerListFragment
+import com.xuexiang.xui.widget.actionbar.TitleBar
+import com.xuexiang.xui.widget.actionbar.TitleUtils
+
+/**
+ * 修改列表样式为主副标题显示
+ *
+ * @author xuexiang
+ * @since 2018/11/22 上午11:26
+ */
+@Suppress("unused")
+abstract class BaseContainerFragment : XPageContainerListFragment() {
+ override fun initPage() {
+ initTitle()
+ initViews()
+ initListeners()
+ }
+
+ protected fun initTitle(): TitleBar {
+ return TitleUtils.addTitleBarDynamic(
+ rootView as ViewGroup,
+ pageTitle
+ ) { popToBack() }
+ }
+
+ override fun initData() {
+ mSimpleData = initSimpleData(mSimpleData)
+ val data: MutableList