添加MyMessageManager项目
This commit is contained in:
		
							
								
								
									
										1
									
								
								mymessagemanager/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mymessagemanager/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| /build | ||||
							
								
								
									
										45
									
								
								mymessagemanager/README.md
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								mymessagemanager/README.md
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| # MyMessageManager | ||||
|  | ||||
| #### 介绍 | ||||
| 用正则表达式方法自定义短信过滤和语音播报的短信应用。 | ||||
|  | ||||
| #### 软件架构 | ||||
| 软件架构说明 | ||||
|  | ||||
|  | ||||
| #### 安装教程 | ||||
|  | ||||
| 1.  xxxx | ||||
| 2.  xxxx | ||||
| 3.  xxxx | ||||
|  | ||||
| #### 使用说明 | ||||
|  | ||||
| 1.  xxxx | ||||
| 2.  xxxx | ||||
| 3.  xxxx | ||||
|  | ||||
| #### 参与贡献 | ||||
|  | ||||
| 1.  Fork 本仓库 | ||||
| 2.  新建 Feat_xxx 分支 | ||||
| 3.  提交代码:ZhanGSKen(ZhanGSKen@QQ.COM) | ||||
| 4.  新建 Pull Request | ||||
|  | ||||
|  | ||||
| #### 特技 | ||||
|  | ||||
| 1.  使用 Readme\_XXX.md 来支持不同的语言,例如 Readme\_en.md, Readme\_zh.md | ||||
| 2.  Gitee 官方博客 [blog.gitee.com](https://blog.gitee.com) | ||||
| 3.  你可以 [https://gitee.com/explore](https://gitee.com/explore) 这个地址来了解 Gitee 上的优秀开源项目 | ||||
| 4.  [GVP](https://gitee.com/gvp) 全称是 Gitee 最有价值开源项目,是综合评定出的优秀开源项目 | ||||
| 5.  Gitee 官方提供的使用手册 [https://gitee.com/help](https://gitee.com/help) | ||||
| 6.  Gitee 封面人物是一档用来展示 Gitee 会员风采的栏目 [https://gitee.com/gitee-stars/](https://gitee.com/gitee-stars/) | ||||
|  | ||||
| #### 参考文档 | ||||
|  | ||||
| 使用GitHub Actions实现Android自动打包apk | ||||
| https://blog.csdn.net/ZZL23333/article/details/115798615?app_version=6.0.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22115798615%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app | ||||
|  | ||||
| Android中assets的使用(用于读取内容) | ||||
| https://blog.csdn.net/qq_27664947/article/details/103924058?app_version=6.0.0&code=app_1562916241&csdn_share_tail=%7B%22type%22%3A%22blog%22%2C%22rType%22%3A%22article%22%2C%22rId%22%3A%22103924058%22%2C%22source%22%3A%22weixin_38986226%22%7D&uLinkId=usr1mkqgl919blen&utm_source=app | ||||
							
								
								
									
										1
									
								
								mymessagemanager/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								mymessagemanager/app_update_description.txt
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
|  | ||||
							
								
								
									
										69
									
								
								mymessagemanager/build.gradle
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								mymessagemanager/build.gradle
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| apply plugin: 'com.android.application' | ||||
| apply from: '../.winboll/winboll_app_build.gradle' | ||||
| apply from: '../.winboll/winboll_lint_build.gradle' | ||||
|  | ||||
| def genVersionName(def versionName){ | ||||
|     // 检查编译标志位配置 | ||||
|     assert (winbollBuildProps['stageCount'] != null) | ||||
|     assert (winbollBuildProps['baseVersion'] != null) | ||||
|     // 保存基础版本号 | ||||
|     winbollBuildProps.setProperty("baseVersion", "${versionName}"); | ||||
|     //保存编译标志配置 | ||||
|     FileOutputStream fos = new FileOutputStream(winbollBuildPropsFile) | ||||
|     winbollBuildProps.store(fos, "${winbollBuildPropsDesc}"); | ||||
|     fos.close(); | ||||
|      | ||||
|     // 返回编译版本号 | ||||
|     return "${versionName}." + winbollBuildProps['stageCount'] | ||||
| } | ||||
|  | ||||
| android { | ||||
|     compileSdkVersion 30 | ||||
|     buildToolsVersion "30.0.3" | ||||
|  | ||||
|     defaultConfig { | ||||
|         applicationId "cc.winboll.studio.mymessagemanager" | ||||
|         minSdkVersion 26 | ||||
|         targetSdkVersion 29 | ||||
|         versionCode 8 | ||||
|         // versionName 更新后需要手动设置  | ||||
|         // .winboll/winbollBuildProps.properties 文件的 stageCount=0 | ||||
|         // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" | ||||
|         versionName "4.1"  | ||||
|         if(true) { | ||||
|             versionName = genVersionName("${versionName}") | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     buildTypes { | ||||
|         release { | ||||
|             minifyEnabled false | ||||
|             proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| dependencies { | ||||
| 	api 'cc.winboll.studio:winboll-shared:1.6.4' | ||||
|     api 'io.github.medyo:android-about-page:2.0.0' | ||||
|     api 'com.github.getActivity:ToastUtils:10.5' | ||||
|     api 'com.jcraft:jsch:0.1.55' | ||||
|     api 'org.jsoup:jsoup:1.13.1' | ||||
|     api 'com.squareup.okhttp3:okhttp:4.4.1' | ||||
|      | ||||
|     api 'androidx.appcompat:appcompat:1.0.0' | ||||
|     api 'androidx.fragment:fragment:1.0.0' | ||||
|     api 'com.google.android.material:material:1.0.0' | ||||
|      | ||||
|     // 权限请求框架:https://github.com/getActivity/XXPermissions | ||||
|     api 'com.github.getActivity:XXPermissions:18.63' | ||||
|     api 'com.baoyz.pullrefreshlayout:library:1.2.0' | ||||
|      | ||||
|     api 'androidx.appcompat:appcompat:1.0.0' | ||||
|     api 'androidx.fragment:fragment:1.0.0' | ||||
|     api 'com.google.android.material:material:1.0.0' | ||||
|      | ||||
|     api 'cc.winboll.studio:libaes:7.6.0' | ||||
|      | ||||
|     api fileTree(dir: 'libs', include: ['*.jar']) | ||||
| } | ||||
							
								
								
									
										8
									
								
								mymessagemanager/build.properties
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										8
									
								
								mymessagemanager/build.properties
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,8 @@ | ||||
| #Created by .winboll/winboll_app_build.gradle | ||||
| #Tue Feb 25 10:52:41 GMT 2025 | ||||
| stageCount=14 | ||||
| libraryProject= | ||||
| baseVersion=4.1 | ||||
| publishVersion=4.1.13 | ||||
| buildCount=5 | ||||
| baseBetaVersion=4.1.14 | ||||
							
								
								
									
										17
									
								
								mymessagemanager/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								mymessagemanager/proguard-rules.pro
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| @@ -0,0 +1,17 @@ | ||||
| # Add project specific ProGuard rules here. | ||||
| # By default, the flags in this file are appended to flags specified | ||||
| # in C:\tools\adt-bundle-windows-x86_64-20131030\sdk/tools/proguard/proguard-android.txt | ||||
| # You can edit the include path and order by changing the proguardFiles | ||||
| # directive in build.gradle. | ||||
| # | ||||
| # For more details, see | ||||
| #   http://developer.android.com/guide/developing/tools/proguard.html | ||||
|  | ||||
| # Add any project specific keep options here: | ||||
|  | ||||
| # 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 *; | ||||
| #} | ||||
							
								
								
									
										23
									
								
								mymessagemanager/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								mymessagemanager/src/beta/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,23 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <manifest xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     xmlns:tools="http://schemas.android.com/tools" > | ||||
|  | ||||
|     <application> | ||||
|  | ||||
|         <!-- Put flavor specific code here --> | ||||
|         <provider | ||||
|             android:name="androidx.core.content.FileProvider" | ||||
|             android:authorities="cc.winboll.studio.mymessagemanager.beta.fileprovider" | ||||
|             android:exported="false" | ||||
|             android:grantUriPermissions="true"> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.support.FILE_PROVIDER_PATHS" | ||||
|                 android:resource="@xml/file_provider"/> | ||||
|  | ||||
|         </provider> | ||||
|          | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
|  | ||||
							
								
								
									
										6
									
								
								mymessagemanager/src/beta/res/values-zh/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								mymessagemanager/src/beta/res/values-zh/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">我的短信管家 ☆</string> | ||||
|      | ||||
| </resources> | ||||
							
								
								
									
										6
									
								
								mymessagemanager/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								mymessagemanager/src/beta/res/values/strings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources> | ||||
|  | ||||
|     <string name="app_name">My Message Manager +</string> | ||||
|  | ||||
| </resources> | ||||
							
								
								
									
										231
									
								
								mymessagemanager/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										231
									
								
								mymessagemanager/src/main/AndroidManifest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,231 @@ | ||||
| <?xml version='1.0' encoding='utf-8'?> | ||||
| <manifest | ||||
|     xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     package="cc.winboll.studio.mymessagemanager"> | ||||
|  | ||||
|     <!-- 发送短信 --> | ||||
|     <uses-permission android:name="android.permission.SEND_SMS"/> | ||||
|  | ||||
|     <!-- 接收讯息(短信) --> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_SMS"/> | ||||
|  | ||||
|     <!-- 读取短信 --> | ||||
|     <uses-permission android:name="android.permission.READ_SMS"/> | ||||
|  | ||||
|     <!-- WRITE_SMS --> | ||||
|     <uses-permission android:name="android.permission.WRITE_SMS"/> | ||||
|  | ||||
|     <!-- 接收讯息(彩信) --> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_MMS"/> | ||||
|  | ||||
|     <!-- 开机启动 --> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/> | ||||
|  | ||||
|     <!-- 运行前台服务 --> | ||||
|     <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> | ||||
|  | ||||
|     <!-- 读取联系人 --> | ||||
|     <uses-permission android:name="android.permission.READ_CONTACTS"/> | ||||
|  | ||||
|     <!-- 读取您共享存储空间中的内容 --> | ||||
|     <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/> | ||||
|  | ||||
|     <!-- 修改或删除您共享存储空间中的内容 --> | ||||
|     <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/> | ||||
|  | ||||
|     <!-- 接收讯息 (WAP) --> | ||||
|     <uses-permission android:name="android.permission.RECEIVE_WAP_PUSH"/> | ||||
|  | ||||
|     <!-- MANAGE_EXTERNAL_STORAGE --> | ||||
|     <uses-permission android:name="android.permission.MANAGE_EXTERNAL_STORAGE"/> | ||||
|  | ||||
|     <!-- 此应用可显示在其他应用上方 --> | ||||
|     <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/> | ||||
|  | ||||
|     <queries> | ||||
|  | ||||
|         <intent> | ||||
|  | ||||
|             <action android:name="android.intent.action.TTS_SERVICE"/> | ||||
|  | ||||
|         </intent> | ||||
|  | ||||
|     </queries> | ||||
|  | ||||
|     <application | ||||
|         android:name=".GlobalApplication" | ||||
|         android:allowBackup="true" | ||||
|         android:icon="@drawable/ic_launcher" | ||||
|         android:roundIcon="@drawable/ic_launcher" | ||||
|         android:label="@string/app_name" | ||||
|         android:theme="@style/WinBoll.SupportThemeNoActionBar" | ||||
|         android:persistent="true" | ||||
|         android:resizeableActivity="true" | ||||
|         android:supportsRtl="true" | ||||
|         android:requestLegacyExternalStorage="true"> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.SMSActivity" | ||||
|             android:process=":sms"/> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.SMSReceiveRuleActivity" | ||||
|             android:process=":smsars"> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.SharedJSONReceiveActivity" | ||||
|             android:process=":smssjr" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|  | ||||
|                 <action android:name="android.intent.action.SEND"/> | ||||
|  | ||||
|                 <action android:name="android.intent.action.VIEW"/> | ||||
|  | ||||
|                 <action android:name="android.intent.action.EDIT"/> | ||||
|  | ||||
|                 <data android:mimeType="application/json"/> | ||||
|  | ||||
|                 <data android:mimeType="text/x-json"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.TTSPlayRuleActivity" | ||||
|             android:process=":ttsrule"/> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.AboutActivity" | ||||
|             android:process=":about"/> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.MainActivity" | ||||
|             android:exported="true" | ||||
|             android:process=":main"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.MAIN"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.LAUNCHER"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity | ||||
|             android:name=".activitys.ComposeSMSActivity" | ||||
|             android:exported="true" | ||||
|             android:process=":csms"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.SEND"/> | ||||
|  | ||||
|                 <action android:name="android.intent.action.SENDTO"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.BROWSABLE"/> | ||||
|  | ||||
|                 <data android:scheme="sms"/> | ||||
|  | ||||
|                 <data android:scheme="smsto"/> | ||||
|  | ||||
|                 <data android:scheme="mms"/> | ||||
|  | ||||
|                 <data android:scheme="mmsto"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </activity> | ||||
|  | ||||
|         <activity android:name=".activitys.AppSettingsActivity"/> | ||||
|  | ||||
|         <service android:name=".services.TTSPlayService"/> | ||||
|  | ||||
|         <service android:name=".services.MainService"/> | ||||
|  | ||||
|         <service android:name=".services.AssistantService"/> | ||||
|  | ||||
|         <service | ||||
|             android:name=".services.DefaultSMSManagerService" | ||||
|             android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.RESPOND_VIA_MESSAGE"/> | ||||
|  | ||||
|                 <category android:name="android.intent.category.DEFAULT"/> | ||||
|  | ||||
|                 <data android:scheme="sms"/> | ||||
|  | ||||
|                 <data android:scheme="smsto"/> | ||||
|  | ||||
|                 <data android:scheme="mms"/> | ||||
|  | ||||
|                 <data android:scheme="mmsto"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </service> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receivers.MainReceiver" | ||||
|             android:enabled="true" | ||||
|             android:exported="false" | ||||
|             android:directBootAware="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.intent.action.BOOT_COMPLETED"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receivers.SMSRecevier" | ||||
|             android:exported="true" | ||||
|             android:permission="android.permission.BROADCAST_SMS"> | ||||
|  | ||||
|             <intent-filter android:priority="1"> | ||||
|  | ||||
|                 <action android:name="android.provider.Telephony.SMS_DELIVER"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <receiver | ||||
|             android:name=".receivers.MmsReceiver" | ||||
|             android:exported="true" | ||||
|             android:permission="android.permission.BROADCAST_WAP_PUSH"> | ||||
|  | ||||
|             <intent-filter> | ||||
|  | ||||
|                 <action android:name="android.provider.Telephony.WAP_PUSH_DELIVER"/> | ||||
|  | ||||
|                 <data android:mimeType="application/vnd.wap.mms-message"/> | ||||
|  | ||||
|             </intent-filter> | ||||
|  | ||||
|         </receiver> | ||||
|  | ||||
|         <meta-data | ||||
|             android:name="android.max_aspect" | ||||
|             android:value="4.0"/> | ||||
|  | ||||
|         <activity android:name="cc.winboll.studio.mymessagemanager.activitys.SMSRecycleActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| @@ -0,0 +1,7 @@ | ||||
| [ | ||||
|   { | ||||
|     "userId": -1, | ||||
|     "ruleData": ".*", | ||||
|     "isEnable": true | ||||
|   } | ||||
| ] | ||||
| @@ -0,0 +1,38 @@ | ||||
| [ | ||||
|   { | ||||
|     "userId": 1, | ||||
|     "ruleName": "规则1", | ||||
|     "demoSMSText": "【短信应用A】验证码123456", | ||||
|     "patternText": "^(【.*】)验证码(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)$", | ||||
|     "ttdRuleText": "$1验证码是($2)($3)($4)($5)($6)($7)。", | ||||
|     "isSimpleView": false, | ||||
|     "isEnable": true | ||||
|   }, | ||||
|   { | ||||
|     "userId": 1, | ||||
|     "ruleName": "规则2", | ||||
|     "demoSMSText": "[短信应用A]验证码123456", | ||||
|     "patternText": "^(\\[.*\\])验证码(\\d)(\\d)(\\d)(\\d)(\\d)(\\d)$", | ||||
|     "ttdRuleText": "$1验证码是($2)($3)($4)($5)($6)($7)。", | ||||
|     "isSimpleView": false, | ||||
|     "isEnable": true | ||||
|   }, | ||||
|   { | ||||
|     "userId": 1, | ||||
|     "ruleName": "规则3", | ||||
|     "demoSMSText": "【短信应用A】验证码123456", | ||||
|     "patternText": ".*(【.+】).*", | ||||
|     "ttdRuleText": "短信来自$1。", | ||||
|     "isSimpleView": false, | ||||
|     "isEnable": true | ||||
|   }, | ||||
|   { | ||||
|     "userId": 1, | ||||
|     "ruleName": "规则4", | ||||
|     "demoSMSText": "[短信应用A]验证码123456", | ||||
|     "patternText": ".*(\\[.*\\]).*", | ||||
|     "ttdRuleText": "短信来自$1。", | ||||
|     "isSimpleView": false, | ||||
|     "isEnable": true | ||||
|   } | ||||
| ] | ||||
| @@ -0,0 +1,52 @@ | ||||
| package cc.winboll.studio.mymessagemanager; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2023/07/24 01:46:59 | ||||
|  * @Describe 全局应用类 | ||||
|  */ | ||||
| import android.view.Gravity; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.shared.app.WinBollApplication; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.io.File; | ||||
|  | ||||
| public class GlobalApplication extends WinBollApplication { | ||||
|  | ||||
|     public static final String TAG = "GlobalApplication"; | ||||
|  | ||||
|     static String _mszAppExternalFilesDir; | ||||
|     static String _mszConfigUtilFileName = "ConfigUtil.json"; | ||||
|     static String _mszConfigUtilPath; | ||||
|     static String _mszSMSReceiveRuleUtilFileName = "SMSReceiveRuleUtil.json"; | ||||
|     static String _mszSMSReceiveRuleUtilPath; | ||||
|  | ||||
|     public static final int USER_ID = -1; | ||||
|     Long mszVersionName = 1L; | ||||
|     Long mszDataVersionName = 1L; | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         //setIsDebug(cc.winboll.studio.mymessagemanager.BuildConfig.DEBUG); | ||||
|  | ||||
|         // 初始化 Toast 框架 | ||||
|         ToastUtils.init(this); | ||||
|         // 设置 Toast 布局样式 | ||||
|         ToastUtils.setView(R.layout.toast_custom_view); | ||||
|         //ToastUtils.setStyle(new WhiteToastStyle()); | ||||
|         ToastUtils.setGravity(Gravity.BOTTOM, 0, 200); | ||||
|  | ||||
|         //LogUtils.d(TAG, "BuildConfig.DEBUG " + Boolean.toString(BuildConfig.DEBUG)); | ||||
|  | ||||
|         _mszAppExternalFilesDir = getExternalFilesDir(TAG).toString(); | ||||
|         _mszConfigUtilPath = _mszAppExternalFilesDir + File.separator + _mszConfigUtilFileName; | ||||
|         _mszSMSReceiveRuleUtilPath = _mszAppExternalFilesDir + File.separator + _mszSMSReceiveRuleUtilFileName; | ||||
|     } | ||||
|  | ||||
|     public static void showApplicationMessage(String szMessage) { | ||||
|         LogUtils.i(TAG, szMessage); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,74 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/14 13:20:33 | ||||
|  * @Describe 应用关于对话窗口 | ||||
|  */ | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.shared.app.WinBollActivity; | ||||
| import cc.winboll.studio.shared.app.WinBollActivityManager; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import cc.winboll.studio.libaes.utils.AESThemeUtil; | ||||
| import android.content.Context; | ||||
|  | ||||
| final public class AboutActivity extends WinBollActivity { | ||||
|  | ||||
|     public static final String TAG = "AboutActivity"; | ||||
|  | ||||
|     Context mContext; | ||||
|      | ||||
|     @Override | ||||
|     public String getTag() { | ||||
|         return TAG; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected boolean isEnableDisplayHomeAsUp() { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         setTheme(AESThemeUtil.getThemeTypeID(getApplicationContext())); | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_about); | ||||
|         mContext = getApplicationContext(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onPostCreate(Bundle savedInstanceState) { | ||||
|         super.onPostCreate(savedInstanceState); | ||||
|         setTitle(mContext.getString(R.string.text_about) + mContext.getString(R.string.app_name)); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected boolean isAddWinBollToolBar() { | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected Toolbar initToolBar() { | ||||
|         return findViewById(R.id.activityaboutASupportToolbar1); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         getMenuInflater().inflate(R.menu.toolbar_about, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         /*if (item.getItemId() == R.id.item_help) { | ||||
|             ToastUtils.show("R.id.item_help"); | ||||
|         } else */if (item.getItemId() == android.R.id.home) { | ||||
|             WinBollActivityManager.getInstance(getApplicationContext()).finish(this); | ||||
|         } | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,99 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/12 20:03:42 | ||||
|  * @Describe 应用设置窗口 | ||||
|  */ | ||||
| import android.content.Intent; | ||||
| import android.os.Bundle; | ||||
| import android.provider.Settings; | ||||
| import android.view.View; | ||||
| import android.widget.EditText; | ||||
| import android.widget.Switch; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; | ||||
| import cc.winboll.studio.libaes.views.AToolbar; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.PermissionUtil; | ||||
|  | ||||
| public class AppSettingsActivity extends BaseActivity { | ||||
|  | ||||
|     public static final String TAG = "AppSettingsActivity"; | ||||
|  | ||||
|     AppConfigUtil mAppConfigUtil; | ||||
|     AToolbar mAToolbar; | ||||
|     AOHPCTCSeekBar mAOHPCTCSeekBar; | ||||
|     EditText metTTSPlayDelayTimes; | ||||
|     EditText metPhoneMergePrefix; | ||||
|     Switch mswMergePrefixPhone; | ||||
|     Switch mswSMSRecycleProtectMode; | ||||
|     EditText metProtectModerRefuseChars; | ||||
|     EditText metProtectModerReplaceChars; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_appsettings); | ||||
|  | ||||
|         // 初始化属性 | ||||
|         mAppConfigUtil = AppConfigUtil.getInstance(this); | ||||
|         int nTtsPlayDelayTimes = mAppConfigUtil.mAppConfigBean.getTtsPlayDelayTimes(); | ||||
|         metTTSPlayDelayTimes = findViewById(R.id.activityappsettingsEditText1); | ||||
|         metTTSPlayDelayTimes.setText(Integer.toString(nTtsPlayDelayTimes / 1000)); | ||||
|  | ||||
|         // 初始化标题栏 | ||||
|         mAToolbar = findViewById(R.id.activityappsettingsAToolbar1); | ||||
|         mAToolbar.setSubtitle(getString(R.string.activity_name_appsettings)); | ||||
|         setActionBar(mAToolbar); | ||||
|  | ||||
|         metPhoneMergePrefix = findViewById(R.id.activityappsettingsEditText2); | ||||
|         metPhoneMergePrefix.setText(mAppConfigUtil.mAppConfigBean.getCountryCode()); | ||||
|  | ||||
|         mswMergePrefixPhone = findViewById(R.id.activityappsettingsSwitch1); | ||||
|         mswMergePrefixPhone.setChecked(mAppConfigUtil.mAppConfigBean.isMergeCountryCodePrefix()); | ||||
|  | ||||
|         mswSMSRecycleProtectMode = findViewById(R.id.activityappsettingsSwitch3); | ||||
|         mswSMSRecycleProtectMode.setChecked(mAppConfigUtil.mAppConfigBean.isSMSRecycleProtectMode()); | ||||
|          | ||||
|         metProtectModerRefuseChars = findViewById(R.id.activityappsettingsEditText3); | ||||
|         metProtectModerRefuseChars.setText(mAppConfigUtil.mAppConfigBean.getProtectModerRefuseChars()); | ||||
|          | ||||
|         metProtectModerReplaceChars = findViewById(R.id.activityappsettingsEditText4); | ||||
|         metProtectModerReplaceChars.setText(mAppConfigUtil.mAppConfigBean.getProtectModerReplaceChars()); | ||||
|          | ||||
|         mAOHPCTCSeekBar = findViewById(R.id.activityappsettingsAOHPCTCSeekBar1); | ||||
|         mAOHPCTCSeekBar.setThumb(getDrawable(R.drawable.cursor_pointer)); | ||||
|         mAOHPCTCSeekBar.setThumbOffset(0); | ||||
|         mAOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener(){ | ||||
|  | ||||
|                 @Override | ||||
|                 public void onOHPCommit() { | ||||
|                     mAppConfigUtil.reLoadConfig(); | ||||
|                     mAppConfigUtil.mAppConfigBean.setIsSMSRecycleProtectMode(mswSMSRecycleProtectMode.isChecked()); | ||||
|                     mAppConfigUtil.mAppConfigBean.setProtectModerRefuseChars(metProtectModerRefuseChars.getText().toString()); | ||||
|                     mAppConfigUtil.mAppConfigBean.setProtectModerReplaceChars(metProtectModerReplaceChars.getText().toString()); | ||||
|                     mAppConfigUtil.mAppConfigBean.setCountryCode(metPhoneMergePrefix.getText().toString()); | ||||
|                     mAppConfigUtil.mAppConfigBean.setIsMergeCountryCodePrefix(mswMergePrefixPhone.isChecked()); | ||||
|                     int nTtsPlayDelayTimes = 1000 * Integer.parseInt(metTTSPlayDelayTimes.getText().toString()); | ||||
|                     mAppConfigUtil.mAppConfigBean.setTtsPlayDelayTimes(nTtsPlayDelayTimes); | ||||
|                     mAppConfigUtil.saveConfig(); | ||||
|                     Toast.makeText(getApplication(), "App config data is saved.", Toast.LENGTH_SHORT).show(); | ||||
|                     //LogUtils.d(TAG, "TTS Play Delay Times is setting to : " + Integer.toString(mAppConfigData.getTtsPlayDelayTimes()));Toast.makeText(getApplication(), "onOHPCommit", Toast.LENGTH_SHORT).show(); | ||||
|                 } | ||||
|             }); | ||||
|     }; | ||||
|  | ||||
|     public void onOpenSystemDefaultAppSettings(View view) { | ||||
|         Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS); | ||||
|         startActivity(intent); | ||||
|     } | ||||
|  | ||||
|     public void onCheckAndGetAppPermission(View view) { | ||||
|         //LogUtils.d(TAG, "onCheckAndGetAppPermission"); | ||||
|         if (PermissionUtil.checkAndGetAppPermission(this)) { | ||||
|             Toast.makeText(getApplication(), "应用已获得所需权限。", Toast.LENGTH_SHORT).show(); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,113 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import androidx.appcompat.app.AppCompatActivity; | ||||
| import cc.winboll.studio.libaes.utils.AESThemeUtil; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import cc.winboll.studio.libaes.beans.AESThemeBean; | ||||
|  | ||||
| abstract public class BaseActivity extends AppCompatActivity { | ||||
|  | ||||
|     public static final String TAG = "BaseActivity"; | ||||
|  | ||||
|     IOnActivityMessageReceived mIOnActivityMessageReceived; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         //AppConfigUtil configUtil = AppConfigUtil.getInstance(this); | ||||
|         //setTheme(configUtil.mAppConfigBean.getAppThemeID()); | ||||
|         LogUtils.d(TAG, "AESThemeUtil.getThemeTypeID(this) is : " + Integer.toString(AESThemeUtil.getThemeTypeID(this))); | ||||
|         setTheme(AESThemeUtil.getThemeTypeID(this)); | ||||
|         super.onCreate(savedInstanceState); | ||||
|     } | ||||
|  | ||||
|     public void sendActivityMessage(Message msg) { | ||||
|         mHandler.sendMessage(msg); | ||||
|     } | ||||
|  | ||||
|     protected void setOnActivityMessageReceived(IOnActivityMessageReceived iOnActivityMessageReceived) { | ||||
|         mIOnActivityMessageReceived = iOnActivityMessageReceived; | ||||
|     } | ||||
|  | ||||
|     Handler mHandler = new Handler(){ | ||||
|  | ||||
|         @Override | ||||
|         public void handleMessage(Message msg) { | ||||
|             super.handleMessage(msg); | ||||
|             if (mIOnActivityMessageReceived != null) { | ||||
|                 mIOnActivityMessageReceived.onActivityMessageReceived(msg); | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     protected interface IOnActivityMessageReceived { | ||||
|         void onActivityMessageReceived(Message msg); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         AESThemeUtil.inflateMenu(this, menu); | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         /*if (AESThemeUtil.onAppCompatThemeItemSelected(this, item)) { | ||||
|          ToastUtils.show("onAppCompatThemeItemSelected"); | ||||
|          recreate(); | ||||
|          }*/ | ||||
|  | ||||
|         /*int nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEFAULT); | ||||
|         if (R.id.item_depththeme == item.getItemId()) { | ||||
|             nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEPTH); | ||||
|             AESThemeUtil.saveThemeStyleID(this, nThemeStyleID); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_skytheme == item.getItemId()) { | ||||
|             nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.SKY); | ||||
|             AESThemeUtil.saveThemeStyleID(this, nThemeStyleID); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_goldentheme == item.getItemId()) { | ||||
|             nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.GOLDEN); | ||||
|             AESThemeUtil.saveThemeStyleID(this, nThemeStyleID); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_taotheme == item.getItemId()) { | ||||
|             nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.TAO); | ||||
|             AESThemeUtil.saveThemeStyleID(this, nThemeStyleID); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_defaulttheme == item.getItemId()) { | ||||
|             nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEFAULT); | ||||
|             AESThemeUtil.saveThemeStyleID(this, nThemeStyleID); | ||||
|             recreate(); | ||||
|         }*/ | ||||
|          | ||||
|         //int nThemeStyleID = AESThemeBean.getThemeStyleID(AESThemeBean.ThemeType.DEFAULT); | ||||
|         if (R.id.item_depththeme == item.getItemId()) { | ||||
|             AESThemeUtil.saveThemeStyleID(this, R.style.MyDepthAESTheme); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_skytheme == item.getItemId()) { | ||||
|             AESThemeUtil.saveThemeStyleID(this, R.style.MySkyAESTheme); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_goldentheme == item.getItemId()) { | ||||
|             AESThemeUtil.saveThemeStyleID(this, R.style.MyGoldenAESTheme); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_memortheme == item.getItemId()) { | ||||
|             AESThemeUtil.saveThemeStyleID(this, R.style.MyMemorAESTheme); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_taotheme == item.getItemId()) { | ||||
|             AESThemeUtil.saveThemeStyleID(this, R.style.MyTaoAESTheme); | ||||
|             recreate(); | ||||
|         } else if (R.id.item_defaulttheme == item.getItemId()) { | ||||
|             AESThemeUtil.saveThemeStyleID(this, R.style.MyDefaultAESTheme); | ||||
|             recreate(); | ||||
|         } | ||||
|         //ToastUtils.show("nThemeStyleID " + Integer.toString(nThemeStyleID)); | ||||
|  | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,192 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| import android.os.Bundle; | ||||
| import android.text.Editable; | ||||
| import android.text.TextWatcher; | ||||
| import android.view.View; | ||||
| import android.widget.AdapterView; | ||||
| import android.widget.EditText; | ||||
| import android.widget.ListView; | ||||
| import android.widget.RelativeLayout; | ||||
| import android.widget.SimpleAdapter; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.ComposeSMSActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.PhoneBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.PhoneUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
| import java.util.HashMap; | ||||
| import java.util.List; | ||||
| import java.util.Map; | ||||
|  | ||||
| public class ComposeSMSActivity extends BaseActivity { | ||||
|  | ||||
|     public static String TAG = "ComposeSMSActivity"; | ||||
|  | ||||
|     public static String EXTRA_SMSBODY = "sms_body"; | ||||
|  | ||||
|     static String MAP_NAME = "NAME"; | ||||
|     static String MAP_PHONE = "PHONE"; | ||||
|  | ||||
|     String mszSMSBody; | ||||
|     String mszScheme; | ||||
|     String mszPhoneTo; | ||||
|     EditText metTO; | ||||
|     EditText metSMSBody; | ||||
|     SimpleAdapter mSimpleAdapter; | ||||
|     List<Map<String,Object>> mAdapterData = new ArrayList<>(); | ||||
|     ListView mlvContracts; | ||||
|     List<PhoneBean> mListPhoneBeanContracts; | ||||
|     Toolbar mToolbar; | ||||
|     AOHPCTCSeekBar mAOHPCTCSeekBar; | ||||
|     RelativeLayout mrlContracts; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_composesms); | ||||
|         mszSMSBody = getIntent().getStringExtra(EXTRA_SMSBODY); | ||||
|         mszScheme = getIntent().getData().getScheme(); | ||||
|         mszPhoneTo = getIntent().getData().getSchemeSpecificPart(); | ||||
|         if (!mszScheme.equals("smsto")) { | ||||
|             // 其他方式未支持就退出 | ||||
|             finish(); | ||||
|         } | ||||
|         // 初始化视图 | ||||
|         initView(); | ||||
|         // 设置适配器 | ||||
|         initAdapter(); | ||||
|         // 设置搜索到的匹配位置 | ||||
|         setListViewPrePosition(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 初始化视图 | ||||
|     // | ||||
|     void initView() { | ||||
|         //Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame); | ||||
|  | ||||
|         // 初始化标题栏 | ||||
|         mToolbar = findViewById(R.id.activitycomposesmsASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.activity_name_composesms)); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         // 初始化联系人栏目框 | ||||
|         mrlContracts = findViewById(R.id.activitycomposesmsRelativeLayout1); | ||||
|         //mrlContracts.setBackground(drawableFrame); | ||||
|  | ||||
|         // 初始化联系人列表 | ||||
|         mlvContracts = findViewById(R.id.activitycomposesmsListView1); | ||||
|  | ||||
|         // 初始化联系人输入框 | ||||
|         metTO = findViewById(R.id.activitycomposesmsEditText1); | ||||
|         metTO.setText(mszPhoneTo); | ||||
|         metTO.addTextChangedListener(new TextWatcher() {            | ||||
|                 @Override   | ||||
|                 public void onTextChanged(CharSequence s, int start, int before, int count) { | ||||
|                     setListViewPrePosition(); | ||||
|                 } | ||||
|                 @Override   | ||||
|                 public void beforeTextChanged(CharSequence s, int start, int count, int after) { | ||||
|                 } | ||||
|  | ||||
|                 @Override   | ||||
|                 public void afterTextChanged(Editable s) { | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         // 初始化发送拉动控件 | ||||
|         mAOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1); | ||||
|         mAOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message)); | ||||
|         mAOHPCTCSeekBar.setThumbOffset(20); | ||||
|         mAOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() { | ||||
|                 @Override | ||||
|                 public void onOHPCommit() { | ||||
|                     // 空号码不发送 | ||||
|                     mszPhoneTo = metTO.getText().toString(); | ||||
|                     if (mszPhoneTo.trim().equals("")) { | ||||
|                         ToastUtils.show("没有设置接收号码。"); | ||||
|                         return; | ||||
|                     } | ||||
|                     // 空消息不发送 | ||||
|                     mszSMSBody = metSMSBody.getText().toString(); | ||||
|                     if (mszSMSBody.equals("")) { | ||||
|                         ToastUtils.show("没有消息内容可发送。"); | ||||
|                         return; | ||||
|                     } | ||||
|                     // 发送消息 | ||||
|                     if (SMSUtil.sendMessageByInterface2(ComposeSMSActivity.this, mszPhoneTo, mszSMSBody)) { | ||||
|                         ComposeSMSActivity.this.finish(); | ||||
|                     } | ||||
|                 } | ||||
| 			}); | ||||
|  | ||||
|         // 初始化提示框 | ||||
|         TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1); | ||||
|         tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg); | ||||
|  | ||||
|         // 初始化发送消息框 | ||||
|         metSMSBody = findViewById(R.id.viewsmssendpart1EditText1); | ||||
|         //metSMSBody.setBackground(drawableFrame); | ||||
|         metSMSBody.setText(mszSMSBody); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 设置搜索到的匹配位置 | ||||
|     // | ||||
|     void setListViewPrePosition() { | ||||
|         int nPrePosition = getContractsDataPrePosition(metTO.getText().toString()); | ||||
|         mlvContracts.setSelected(false); | ||||
|         mlvContracts.setSelection(nPrePosition); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 返回搜索到的匹配位置 | ||||
|     // | ||||
|     int getContractsDataPrePosition(String szPhone) { | ||||
|         for (int i = 0; i < mListPhoneBeanContracts.size(); i++) { | ||||
|             if (mListPhoneBeanContracts.get(i).getTelPhone().compareTo(szPhone) > -1) { | ||||
|                 return i; | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 初始化适配器 | ||||
|     // | ||||
|     void initAdapter() { | ||||
|         // 初始化联系人数据适配器 | ||||
|         mAdapterData = new ArrayList<>(); | ||||
|         // 读取联系人数据 | ||||
|         PhoneUtil phoneUtils = new PhoneUtil(this); | ||||
|         mListPhoneBeanContracts = phoneUtils.getPhoneList(); | ||||
|         // 映射联系人数据给适配器数据对象 | ||||
|         for (int i = 0;i < mListPhoneBeanContracts.size();i++) { | ||||
|             Map<String,Object> map =new HashMap<>(); | ||||
|             map.put(MAP_NAME, mListPhoneBeanContracts.get(i).getName()); | ||||
|             map.put(MAP_PHONE, mListPhoneBeanContracts.get(i).getTelPhone()); | ||||
|             mAdapterData.add(map); | ||||
|         } | ||||
|         // 绑定适配器与数据 | ||||
|         mSimpleAdapter = new SimpleAdapter(ComposeSMSActivity.this, mAdapterData, R.layout.listview_contracts | ||||
|                                            , new String[]{MAP_NAME, MAP_PHONE} | ||||
|                                            , new int[]{R.id.listviewcontractsTextView1, R.id.listviewcontractsTextView2}); | ||||
|         mSimpleAdapter.setDropDownViewResource(R.layout.listview_contracts); | ||||
|         mlvContracts.setAdapter(mSimpleAdapter); | ||||
|         mlvContracts.setOnItemClickListener(new ListView.OnItemClickListener() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onItemClick(AdapterView<?> parent, View view, int position, long id) { | ||||
|                     metTO.setText(mAdapterData.get(position).get(MAP_PHONE).toString()); | ||||
|  | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,333 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| import android.Manifest; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.os.Message; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.ScrollView; | ||||
| import cc.winboll.studio.libaes.views.AToolbar; | ||||
| import cc.winboll.studio.mymessagemanager.BuildConfig; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.MainActivity; | ||||
| import cc.winboll.studio.mymessagemanager.adapters.PhoneArrayAdapter; | ||||
| import cc.winboll.studio.mymessagemanager.services.MainService; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppGoToSettingsUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.NotificationUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.PermissionUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ThemeUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ViewUtil; | ||||
| import cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView; | ||||
| import cc.winboll.studio.mymessagemanager.views.PhoneListViewForScrollView; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import cc.winboll.studio.shared.log.LogView; | ||||
| import com.baoyz.widget.PullRefreshLayout; | ||||
| import java.util.ArrayList; | ||||
| import cc.winboll.studio.libaes.utils.AESThemeUtil; | ||||
| import cc.winboll.studio.libaes.views.ASupportToolbar; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
|  | ||||
| public class MainActivity extends BaseActivity { | ||||
|  | ||||
|     public final static String TAG = "MainActivity"; | ||||
|  | ||||
|     public static final int ACTIVITY_RESULT_APP_SETTINGS = -1; | ||||
|  | ||||
|     public final static int MSG_RELOADSMS = 0; | ||||
|  | ||||
|     public static final int PERMISSION_SETTING_FOR_RESULT = 0; | ||||
|     public static final int MY_PERMISSIONS_REQUEST = 0; | ||||
|  | ||||
|     static MainActivity _mMainActivity; | ||||
|     LogView mLogView; | ||||
|     AppConfigUtil mAppConfigUtil; | ||||
|     ConfirmSwitchView msvEnableService; | ||||
|     ConfirmSwitchView msvOnlyReceiveContacts; | ||||
|     ConfirmSwitchView msvEnableTTS; | ||||
|     ConfirmSwitchView msvEnableTTSRuleMode; | ||||
|     PhoneListViewForScrollView mListViewPhone; | ||||
|     Toolbar mToolbar; | ||||
|     PhoneArrayAdapter mPhoneArrayAdapter; | ||||
| 	AppGoToSettingsUtil mAppGoToSettingsUtil; | ||||
|     String[] mPermissionList = {Manifest.permission.READ_CONTACTS, | ||||
|         Manifest.permission.WRITE_EXTERNAL_STORAGE, | ||||
|         Manifest.permission.READ_EXTERNAL_STORAGE,  | ||||
|         Manifest.permission.READ_SMS}; | ||||
|     ArrayList<String> listPerms; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_main); | ||||
|         _mMainActivity = MainActivity.this; | ||||
|  | ||||
|         mAppConfigUtil = AppConfigUtil.getInstance(this); | ||||
| 		initView(); | ||||
|  | ||||
|         // 调用调试检查函数 | ||||
|         onOnceAndroidStory(null); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 这是一个测试函数, | ||||
|     // 用于调试读取 string.xml string-array使用。 | ||||
|     // | ||||
|     public void onOnceAndroidStory(View view) { | ||||
|         if (BuildConfig.DEBUG) { | ||||
|             // 获取strings.xml文件中的tab_names数组 | ||||
|             String[] tab_names = getResources().getStringArray(R.array.strings_OnceAndroidStory); | ||||
|             // 这里R.array.tab_names是你在XML文件中定义的数组资源ID | ||||
|             // 例如,在strings.xml中可能这样定义: | ||||
|             /*/            <!-- strings.xml --> | ||||
|              <resources> | ||||
|              <string-array name="tab_names"> | ||||
|              <item>Tab 1</item> | ||||
|              <item>Tab 2</item> | ||||
|              <item>Tab 3</item> | ||||
|              </string-array> | ||||
|              </resources> | ||||
|              */ | ||||
|             // 现在你可以遍历这个数组来访问每个元素 | ||||
|             for (int i = 0; i < tab_names.length; i++) { | ||||
|                 // 创建Random实例并传入任意非负种子(这里是1) | ||||
|                 java.util.Random r = new java.util.Random(1); | ||||
|                 // 调用nextInt(6),范围是0到5(包括0和5),加1后得到1到5 | ||||
|                 int randomNum = r.nextInt(6) + 1; | ||||
|                 System.out.println("Random number between 1 and 5: " + randomNum); | ||||
|                 LogUtils.d("OnceAndroidStory", tab_names[i]); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void scrollScrollView() { | ||||
|         ScrollView sv = findViewById(R.id.activitymainScrollView1); | ||||
|         ViewUtil.scrollScrollView(sv); | ||||
|     } | ||||
|  | ||||
|     void genTestData() { | ||||
|         for (int i = 0; i < 2; i++) { | ||||
|             SMSUtil.saveReceiveSms(this, "13172887736", "调试阶段生成的短信" + Integer.toString(i), "0", -1, "inbox"); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 初始化视图控件 | ||||
|     // | ||||
|     void initView() { | ||||
|         // 设置调试日志 | ||||
|         mLogView = findViewById(R.id.logview); | ||||
|         mLogView.start(); | ||||
|  | ||||
|         // 设置消息处理函数 | ||||
|         setOnActivityMessageReceived(mIOnActivityMessageReceived); | ||||
|  | ||||
|         // 设置标题栏 | ||||
|         mToolbar = findViewById(R.id.activitymainASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.activity_name_main)); | ||||
|         setSupportActionBar(mToolbar); | ||||
|  | ||||
|         // 创建通知频道 | ||||
|         NotificationUtil nu = new NotificationUtil(); | ||||
|         nu.createServiceNotificationChannel(MainActivity.this); | ||||
|         nu.createSMSNotificationChannel(MainActivity.this); | ||||
|  | ||||
|         boolean isEnableService = mAppConfigUtil.mAppConfigBean.isEnableService(); | ||||
|         msvEnableService = findViewById(R.id.activitymainSwitchView1); | ||||
|         msvEnableService.setChecked(isEnableService); | ||||
|         msvEnableService.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					boolean isEnable = ((ConfirmSwitchView)v).isChecked(); | ||||
|                     mAppConfigUtil.reLoadConfig(); | ||||
| 					mAppConfigUtil.mAppConfigBean.setIsEnableService(isEnable); | ||||
|                     mAppConfigUtil.saveConfig(); | ||||
| 					initService(isEnable); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         boolean isOnlyReceiveContacts = mAppConfigUtil.mAppConfigBean.isEnableOnlyReceiveContacts(); | ||||
|         msvOnlyReceiveContacts = findViewById(R.id.activitymainSwitchView2); | ||||
|         msvOnlyReceiveContacts.setChecked(isOnlyReceiveContacts); | ||||
| 		msvOnlyReceiveContacts.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					boolean isEnable = ((ConfirmSwitchView)v).isChecked(); | ||||
|                     mAppConfigUtil.reLoadConfig(); | ||||
| 					mAppConfigUtil.mAppConfigBean.setIsEnableOnlyReceiveContacts(isEnable); | ||||
|                     mAppConfigUtil.saveConfig(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         boolean isEnableTTS = mAppConfigUtil.mAppConfigBean.isEnableTTS(); | ||||
|         msvEnableTTS = findViewById(R.id.activitymainSwitchView3); | ||||
|         msvEnableTTS.setChecked(isEnableTTS); | ||||
| 		msvEnableTTS.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					boolean isEnable = ((ConfirmSwitchView)v).isChecked(); | ||||
|                     mAppConfigUtil.reLoadConfig(); | ||||
| 					mAppConfigUtil.mAppConfigBean.setIsEnableTTS(isEnable); | ||||
|                     mAppConfigUtil.saveConfig(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         boolean isEnableTTSRuleMode = mAppConfigUtil.mAppConfigBean.isEnableTTSRuleMode(); | ||||
|         msvEnableTTSRuleMode = findViewById(R.id.activitymainSwitchView4); | ||||
|         msvEnableTTSRuleMode.setChecked(isEnableTTSRuleMode); | ||||
| 		msvEnableTTSRuleMode.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					boolean isEnable = ((ConfirmSwitchView)v).isChecked(); | ||||
|                     mAppConfigUtil.reLoadConfig(); | ||||
| 					mAppConfigUtil.mAppConfigBean.setIsEnableTTSRuleMode(isEnable); | ||||
|                     mAppConfigUtil.saveConfig(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
|         initService(isEnableService); | ||||
|  | ||||
| 		// 短信发送窗口按钮 | ||||
| 		Button btnSendSMS = findViewById(R.id.activitymainButton1); | ||||
| 		btnSendSMS.setOnClickListener(new View.OnClickListener() { | ||||
|  | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					Uri uri = Uri.parse("smsto:"); | ||||
| 					Intent it = new Intent(Intent.ACTION_SENDTO, uri); | ||||
| 					it.putExtra("sms_body", ""); | ||||
| 					startActivity(it); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 		mListViewPhone = (PhoneListViewForScrollView) findViewById(R.id.activitymainListView1); | ||||
|         //准备数据 | ||||
|         mPhoneArrayAdapter = new PhoneArrayAdapter(MainActivity.this); | ||||
|  | ||||
|         final PullRefreshLayout layout = (PullRefreshLayout) findViewById(R.id.activitymainPullRefreshLayout1); | ||||
| 		//将适配器加载到控件中 | ||||
|         mListViewPhone.setAdapter(mPhoneArrayAdapter); | ||||
|  | ||||
|         // listen refresh event | ||||
|         layout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { | ||||
|                 @Override | ||||
|                 public void onRefresh() { | ||||
|                     // start refresh | ||||
|                     reloadSMS(); | ||||
|                     layout.setRefreshing(false); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     void initService(boolean isEnableService) { | ||||
|         if (isEnableService) { | ||||
|             Intent service = new Intent(this, MainService.class); | ||||
|             startService(service); | ||||
|         } else { | ||||
|             Intent service = new Intent(this, MainService.class); | ||||
|             stopService(service); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 定义应用内消息处理函数 | ||||
|     // | ||||
|     IOnActivityMessageReceived mIOnActivityMessageReceived = new IOnActivityMessageReceived(){ | ||||
|  | ||||
|         @Override | ||||
|         public void onActivityMessageReceived(Message msg) { | ||||
|             switch (msg.arg1) { | ||||
|                 case MSG_RELOADSMS : { | ||||
|                         LogUtils.d(TAG, "MSG_RELOADSMS"); | ||||
|                         if (PermissionUtil.checkAppPermission(MainActivity.this)) { | ||||
|                             mPhoneArrayAdapter.loadData(); | ||||
|                             mPhoneArrayAdapter.notifyDataSetChanged(); | ||||
|                         } else { | ||||
|                             LogUtils.i(TAG, "遇到应用权限问题,请打开应用设置检查一下应用权限。"); | ||||
|                         } | ||||
|                         break; | ||||
|                     } | ||||
|             } | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreatePanelMenu(int featureId, Menu menu) { | ||||
|         return super.onCreatePanelMenu(featureId, menu); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         reloadSMS(); | ||||
|         mLogView.start(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         //return super.onCreateOptionsMenu(menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_main, menu); | ||||
|  | ||||
|         /*ThemeUtil.BaseTheme baseTheme = ThemeUtil.getTheme(mAppConfigUtil.mAppConfigBean.getAppThemeID()); | ||||
|         if (baseTheme == ThemeUtil.BaseTheme.DEFAULT) { | ||||
|             menu.findItem(R.id.app_defaulttheme).setChecked(true); | ||||
|         } else if (baseTheme == ThemeUtil.BaseTheme.SKY) { | ||||
|             menu.findItem(R.id.app_skytheme).setChecked(true); | ||||
|         } else if (baseTheme == ThemeUtil.BaseTheme.GOLDEN) { | ||||
|             menu.findItem(R.id.app_goldentheme).setChecked(true); | ||||
|         }*/ | ||||
|  | ||||
|         return super.onCreateOptionsMenu(menu); | ||||
|     } | ||||
|  | ||||
|     public static void reloadSMS() { | ||||
|         if (_mMainActivity != null) { | ||||
|             Message msg = new Message(); | ||||
|             msg.arg1 = MSG_RELOADSMS; | ||||
|             _mMainActivity.sendActivityMessage(msg); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
| 		int nItemId = item.getItemId(); | ||||
|         if (nItemId == R.id.app_ttsrule) { | ||||
| 			Intent i = new Intent(MainActivity.this, TTSPlayRuleActivity.class); | ||||
| 			i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
| 			startActivity(i); | ||||
| 		} else if (nItemId == R.id.app_smsrule) { | ||||
| 			Intent i = new Intent(MainActivity.this, SMSReceiveRuleActivity.class); | ||||
| 			i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
| 			startActivity(i); | ||||
| 		} else if (nItemId == R.id.app_appsettings) { | ||||
|             Intent i = new Intent(MainActivity.this, AppSettingsActivity.class); | ||||
|             i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             startActivity(i); | ||||
| 		} else if (nItemId ==  R.id.app_crashtest) { | ||||
|             for (int i = Integer.MIN_VALUE; i < Integer.MAX_VALUE; i++) { | ||||
|                 getString(i); | ||||
|             } | ||||
|         } else if (nItemId ==  R.id.app_about) { | ||||
|             Intent i = new Intent(MainActivity.this, AboutActivity.class); | ||||
|             i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             startActivity(i); | ||||
|         } else if (nItemId ==  R.id.app_smsrecycle) { | ||||
|             Intent i = new Intent(MainActivity.this, SMSRecycleActivity.class); | ||||
|             i.setFlags(Intent.FLAG_ACTIVITY_LAUNCH_ADJACENT | Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             startActivity(i); | ||||
|         } | ||||
|          | ||||
|         return super.onOptionsItemSelected(item); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,228 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import android.os.Bundle; | ||||
| import android.os.Handler; | ||||
| import android.os.Message; | ||||
| import android.widget.AbsListView; | ||||
| import android.widget.EditText; | ||||
| import android.widget.ScrollView; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import android.widget.Toolbar; | ||||
| import androidx.localbroadcastmanager.content.LocalBroadcastManager; | ||||
| import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.SMSActivity; | ||||
| import cc.winboll.studio.mymessagemanager.adapters.SMSArrayAdapter; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ViewUtil; | ||||
| import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView; | ||||
| import cc.winboll.studio.mymessagemanager.views.SMSView; | ||||
| import java.lang.ref.WeakReference; | ||||
|  | ||||
| public class SMSActivity extends BaseActivity { | ||||
|     public static String TAG = "SMSActivity"; | ||||
|  | ||||
|     public static final String ACTION_NOTIFY_SMS_CHANGED = "cc.winboll.studio.mymessagemanager.activitys.SMSActivity.ACTION_NOTIFY_SMS_CHANGED"; | ||||
|  | ||||
|     public static final String EXTRA_PHONE = "Phone"; | ||||
|     final static int MSG_SET_FOCUS = 0; | ||||
|  | ||||
|     SMSListViewForScrollView mlvSMS; | ||||
|     Toolbar mToolbar; | ||||
|     String mszPhoneTo; | ||||
|     SMSArrayAdapter mSMSArrayAdapter; | ||||
|     ScrollView mScrollView; | ||||
|     EditText metSMSBody; | ||||
|     SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver; | ||||
|     Handler mSetFocusHandler; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_sms); | ||||
|  | ||||
|         initView(); | ||||
| 		mSetFocusHandler = new MyHandler(SMSActivity.this); | ||||
|         scrollScrollView(); | ||||
|  | ||||
|         // 每隔一定时间设置输入框获得焦点 | ||||
|         // | ||||
|         new Thread() { | ||||
|             @Override | ||||
|             public void run() { | ||||
|                 while (true) { | ||||
|                     try { | ||||
|                         Thread.sleep(1500); | ||||
|                     } catch (InterruptedException e) {} | ||||
|                     Message message = mSetFocusHandler.obtainMessage(MSG_SET_FOCUS); | ||||
|                     mSetFocusHandler.sendMessage(message); | ||||
|                 } | ||||
|             }}.start(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 设置输入框获得焦点的类 | ||||
| 	// | ||||
| 	static class MyHandler extends Handler { | ||||
| 		WeakReference<SMSActivity> mActivity;   | ||||
| 		MyHandler(SMSActivity activity) {   | ||||
| 			mActivity = new WeakReference<SMSActivity>(activity);   | ||||
| 		} | ||||
|         public void handleMessage(Message msg) { | ||||
| 			SMSActivity theActivity = mActivity.get(); | ||||
|             switch (msg.what) { | ||||
|                 case MSG_SET_FOCUS: | ||||
|                     theActivity.metSMSBody.setFocusable(true); | ||||
|                     theActivity.metSMSBody.requestFocus(); | ||||
|                     break; | ||||
|                 default: | ||||
|                     break; | ||||
|             } | ||||
|             super.handleMessage(msg); | ||||
|         } | ||||
| 	} | ||||
|  | ||||
|     @Override | ||||
|     protected void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         LocalBroadcastManager.getInstance(this).unregisterReceiver(mSMSActivityBroadcastReceiver); | ||||
|     } | ||||
|  | ||||
|     void initView() { | ||||
|         // 发送端空号码退出 | ||||
|         mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE); | ||||
|         if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) { | ||||
|             finish(); | ||||
|         } | ||||
|  | ||||
|         // 初始化标题栏 | ||||
|         mToolbar = findViewById(R.id.activitysmsASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + mszPhoneTo + " >"); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         // 初始化滚动窗口 | ||||
|         mScrollView = findViewById(R.id.activitysmsinphoneScrollView1); | ||||
|  | ||||
|         // 初始化发送消息框 | ||||
|         //Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame); | ||||
|         metSMSBody = findViewById(R.id.viewsmssendpart1EditText1); | ||||
|         //metSMSBody.setBackground(drawableFrame); | ||||
|  | ||||
|         // 初始化发送拉动控件 | ||||
|         final AOHPCTCSeekBar aOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1); | ||||
|         aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message)); | ||||
|         aOHPCTCSeekBar.setThumbOffset(20); | ||||
|         aOHPCTCSeekBar.setOnOHPCListener( | ||||
|             new AOHPCTCSeekBar.OnOHPCListener(){ | ||||
|                 @Override | ||||
|                 public void onOHPCommit() { | ||||
|                     //Toast.makeText(getApplication(), "Send", Toast.LENGTH_SHORT).show(); | ||||
|                     sendSMS(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         // 初始化提示框 | ||||
|         TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1); | ||||
|         tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg); | ||||
|  | ||||
|         mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsinphoneListView1); | ||||
|  | ||||
|         // 准备数据 | ||||
|         mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo); | ||||
|         mlvSMS.setAdapter(mSMSArrayAdapter); | ||||
|  | ||||
|         // 设置短信列表滚动到底部就取消已发送的通知消息 | ||||
|         // | ||||
|         mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() { | ||||
|                 @Override | ||||
|                 public void onScrollStateChanged(AbsListView view, int scrollState) { | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { | ||||
|                     if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { | ||||
|                         // 滑动到了底部 | ||||
|                         mSMSArrayAdapter.cancelMessageNotification(); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver(); | ||||
|         IntentFilter intentFilter = new IntentFilter(); | ||||
|         intentFilter.addAction(ACTION_NOTIFY_SMS_CHANGED); | ||||
|         LocalBroadcastManager.getInstance(this).registerReceiver(mSMSActivityBroadcastReceiver, intentFilter); | ||||
|  | ||||
|         /*SMSView mSMSView = findViewById(R.id.viewsmssendSMSView1); | ||||
|         mSMSView.setSMSType(SMSView.SMSType.SEND);*/ | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 更新信息列表 | ||||
|     // | ||||
|     public void updateSMSView() { | ||||
|         mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo); | ||||
|         mSMSArrayAdapter.notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 滚动消息文本框 | ||||
|     // | ||||
|     void scrollScrollView() { | ||||
|  | ||||
|         ViewUtil.scrollScrollView(mScrollView); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 发送短信 | ||||
|     // | ||||
|     void sendSMS() { | ||||
|         // 空消息不发送 | ||||
|         String szSMSBody = metSMSBody.getText().toString(); | ||||
|         if (szSMSBody.equals("")) { | ||||
|             Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show(); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         // 发送短信 | ||||
|         if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) { | ||||
|             metSMSBody.setText(""); | ||||
|             new Handler().postDelayed(new Runnable(){ | ||||
|                     @Override | ||||
|                     public void run() { | ||||
|                         updateSMSView(); | ||||
|                         ViewUtil.scrollScrollView(mScrollView); | ||||
|                     } | ||||
|                 }, 1000); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     class SMSActivityBroadcastReceiver extends BroadcastReceiver { | ||||
|  | ||||
|         public SMSActivityBroadcastReceiver() { | ||||
|             //LogUtils.d(TAG, "SMSActivityBroadcastReceiver()"); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onReceive(Context context, Intent intent) { | ||||
|             switch (intent.getAction()) { | ||||
|                 case ACTION_NOTIFY_SMS_CHANGED : | ||||
|                     //Toast.makeText(context, "ACTION_NOTIFY_SMS_CHANGED", Toast.LENGTH_SHORT).show(); | ||||
|                     updateSMSView(); | ||||
|                     ViewUtil.scrollScrollView(mScrollView); | ||||
|                     //LogUtils.d(TAG, "ACTION_NOTIFY_SMS_CHANGED"); | ||||
|                     break; | ||||
|                 default: | ||||
|                     throw new IllegalStateException("Unexpected value: " + intent.getAction()); | ||||
|             } | ||||
|  | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,232 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 12:50:52 | ||||
|  * @Describe 短信匹配过滤规则设置窗口 | ||||
|  */ | ||||
| import android.app.AlertDialog; | ||||
| import android.app.Dialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.EditText; | ||||
| import android.widget.RadioButton; | ||||
| import android.widget.Toast; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import cc.winboll.studio.mymessagemanager.GlobalApplication; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.SMSReceiveRuleActivity; | ||||
| import cc.winboll.studio.mymessagemanager.adapters.SMSAcceptRuleArrayAdapter; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.FileUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSReceiveRuleUtil; | ||||
| import com.baoyz.widget.PullRefreshLayout; | ||||
|  | ||||
| public class SMSReceiveRuleActivity extends BaseActivity { | ||||
|  | ||||
|     public static final String TAG = "SMSReceiveRuleActivity"; | ||||
|  | ||||
|     Context mContext; | ||||
|     RecyclerView mRecyclerView; | ||||
|     Toolbar mToolbar; | ||||
|     RadioButton mrbAccept; | ||||
|     RadioButton mrbRefuse; | ||||
|     CheckBox mcbEnable; | ||||
|     SMSAcceptRuleBean mSMSAcceptRuleBeanAdd; | ||||
|     SMSAcceptRuleArrayAdapter mSMSAcceptRuleArrayAdapter; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_smsacceptrulesetting); | ||||
|         mContext = SMSReceiveRuleActivity.this; | ||||
|         initSMSAcceptRuleBeanAdd(); | ||||
|         // 初始化视图 | ||||
|         initView(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 初始化视图 | ||||
|     // | ||||
|     public void initView() { | ||||
|         // 初始化标题栏 | ||||
|         mToolbar = findViewById(R.id.activitysmsacceptrulesettingASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.text_smsrule)); | ||||
|         setSupportActionBar(mToolbar); | ||||
|  | ||||
|         mrbAccept = findViewById(R.id.activitysmsacceptrulesettingRadioButton1); | ||||
|         mrbRefuse = findViewById(R.id.activitysmsacceptrulesettingRadioButton2); | ||||
|         mcbEnable = findViewById(R.id.activitysmsacceptrulesettingCheckBox1); | ||||
|         if (mSMSAcceptRuleBeanAdd.getRuleType() == SMSAcceptRuleBean.RuleType.ACCEPT) { | ||||
|             mrbAccept.setChecked(true); | ||||
|             mrbRefuse.setChecked(false); | ||||
|         } | ||||
|         if (mSMSAcceptRuleBeanAdd.getRuleType() == SMSAcceptRuleBean.RuleType.REFUSE) { | ||||
|             mrbAccept.setChecked(false); | ||||
|             mrbRefuse.setChecked(true); | ||||
|         } | ||||
|         mcbEnable.setChecked(mSMSAcceptRuleBeanAdd.isEnable()); | ||||
|  | ||||
| 		Button btnAddSMSAcceptRule = findViewById(R.id.activitysmsacceptrulesettingButton1); | ||||
| 		btnAddSMSAcceptRule.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					EditText et = findViewById(R.id.activitysmsacceptrulesettingEditText1); | ||||
| 					String szRule = et.getText().toString().trim(); | ||||
| 					if (szRule.equals("")) { | ||||
| 						Toast.makeText(getApplication(), "空字符串规则不能添加", Toast.LENGTH_SHORT).show(); | ||||
| 					} else { | ||||
|                         mSMSAcceptRuleBeanAdd.setRuleData(et.getText().toString()); | ||||
|                         mSMSAcceptRuleBeanAdd.setIsEnable(mcbEnable.isChecked()); | ||||
|                         mSMSAcceptRuleBeanAdd.setRuleType(mrbRefuse.isChecked() ?SMSAcceptRuleBean.RuleType.REFUSE: SMSAcceptRuleBean.RuleType.ACCEPT); | ||||
| 						mSMSAcceptRuleArrayAdapter.addSMSAcceptRule(mSMSAcceptRuleBeanAdd); | ||||
|                         initSMSAcceptRuleBeanAdd(); | ||||
| 						et.setText(""); | ||||
| 						Toast.makeText(getApplication(), "已添加规则 : " + szRule, Toast.LENGTH_SHORT).show(); | ||||
| 					} | ||||
| 				} | ||||
|             }); | ||||
|  | ||||
|         // 绑定控件 | ||||
|         mRecyclerView = findViewById(R.id.activitysmsacceptrulesettingRecyclerView1); | ||||
|         RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); | ||||
|         mRecyclerView.setLayoutManager(layoutManager); | ||||
|         mSMSAcceptRuleArrayAdapter = new SMSAcceptRuleArrayAdapter(this); | ||||
|         mRecyclerView.setAdapter(mSMSAcceptRuleArrayAdapter); | ||||
|  | ||||
|         final PullRefreshLayout pullRefreshLayout = findViewById(R.id.activitysmsacceptrulesettingPullRefreshLayout1); | ||||
|         pullRefreshLayout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener(){ | ||||
|                 @Override | ||||
|                 public void onRefresh() { | ||||
|                     pullRefreshLayout.setRefreshing(false); | ||||
|                     mSMSAcceptRuleArrayAdapter.loadConfigData(); | ||||
|                     mSMSAcceptRuleArrayAdapter.notifyDataSetChanged(); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     void initSMSAcceptRuleBeanAdd() { | ||||
|         mSMSAcceptRuleBeanAdd = new SMSAcceptRuleBean(GlobalApplication.USER_ID, "", true, SMSAcceptRuleBean.RuleType.REFUSE, true); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         //return super.onCreateOptionsMenu(menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_rule, menu); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int nItemId = item.getItemId(); | ||||
|         if (nItemId == R.id.item_rule_share) { | ||||
|             //SMSReceiveRuleUtil smsAcceptRuleConfig = SMSReceiveRuleUtil.getInstance(this, false); | ||||
|             SMSAcceptRuleBean beanTemp = new SMSAcceptRuleBean(); | ||||
|             String szConfigPath = beanTemp.getBeanListJsonFilePath(mContext); | ||||
|             FileUtil.shareJSONFile(SMSReceiveRuleActivity.this, szConfigPath); | ||||
|         } else if (nItemId == R.id.item_rule_reset) { | ||||
|             showResetConfigDialog(); | ||||
|         } else if (nItemId == R.id.item_rule_clean) { | ||||
|             showCleanConfigDialog(); | ||||
|         }  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 短信匹配过滤规则数据重置对话框 | ||||
|     // | ||||
|     void showResetConfigDialog() { | ||||
|         Dialog alertDialog = new AlertDialog.Builder(this). | ||||
|             setTitle("确定重置?"). | ||||
|             setMessage("您确定重置短信接收规则为默认设置吗?"). | ||||
|             setIcon(R.drawable.ic_launcher). | ||||
|             setPositiveButton("确定", new DialogInterface.OnClickListener() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onClick(DialogInterface dialog, int which) { | ||||
|                     // TODO Auto-generated method stub | ||||
|                     SMSReceiveRuleUtil smsAcceptRuleConfig = SMSReceiveRuleUtil.getInstance(getApplicationContext(), false); | ||||
|                     smsAcceptRuleConfig.resetConfig(); | ||||
|                     mSMSAcceptRuleArrayAdapter.notifyDataSetChanged(); | ||||
|                     Toast.makeText(getApplication(), "Rules Reset", Toast.LENGTH_SHORT).show(); | ||||
|                 } | ||||
|             }). | ||||
|             setNegativeButton("取消", new DialogInterface.OnClickListener() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onClick(DialogInterface dialog, int which) { | ||||
|                     // TODO Auto-generated method stub | ||||
|  | ||||
|                 } | ||||
|             }). | ||||
|             /*setNeutralButton("查看详情", new DialogInterface.OnClickListener() { | ||||
|  | ||||
|              @Override | ||||
|              public void onClick(DialogInterface dialog, int which) { | ||||
|              // TODO Auto-generated method stub | ||||
|              } | ||||
|              }).*/ | ||||
|             create(); | ||||
|         alertDialog.show(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 短信匹配过滤规则数据清空对话框 | ||||
|     // | ||||
|     void showCleanConfigDialog() { | ||||
|         Dialog alertDialog = new AlertDialog.Builder(this). | ||||
|             setTitle("确定清理"). | ||||
|             setMessage("您确定清理所有短信接收规则吗?"). | ||||
|             setIcon(R.drawable.ic_launcher). | ||||
|             setPositiveButton("确定", new DialogInterface.OnClickListener() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onClick(DialogInterface dialog, int which) { | ||||
|                     // TODO Auto-generated method stub | ||||
|                     SMSReceiveRuleUtil smsAcceptRuleConfig = SMSReceiveRuleUtil.getInstance(getApplicationContext(), false); | ||||
|                     smsAcceptRuleConfig.cleanConfig(); | ||||
|                     mSMSAcceptRuleArrayAdapter.notifyDataSetChanged(); | ||||
|                     Toast.makeText(getApplication(), "Rules Cleaned.", Toast.LENGTH_SHORT).show(); | ||||
|                 } | ||||
|             }). | ||||
|             setNegativeButton("取消", new DialogInterface.OnClickListener() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onClick(DialogInterface dialog, int which) { | ||||
|                     // TODO Auto-generated method stub | ||||
|  | ||||
|                 } | ||||
|             }). | ||||
|             /*setNeutralButton("查看详情", new DialogInterface.OnClickListener() { | ||||
|              @Override | ||||
|              public void onClick(DialogInterface dialog, int which) { | ||||
|              // TODO Auto-generated method stub | ||||
|              } | ||||
|              }).*/ | ||||
|             create(); | ||||
|         alertDialog.show(); | ||||
|     } | ||||
|  | ||||
|     public void onAcceptRuleType(View view) { | ||||
|         mrbRefuse.setChecked(false); | ||||
|     } | ||||
|  | ||||
|     public void onRefuseRuleType(View view) { | ||||
|         mrbAccept.setChecked(false); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|         mSMSAcceptRuleArrayAdapter.loadConfigData(); | ||||
|         mSMSAcceptRuleArrayAdapter.notifyDataSetChanged(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,92 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 16:56:18 | ||||
|  * @Describe 短信回收站 | ||||
|  */ | ||||
| import android.os.Bundle; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.SMSRecycleActivity; | ||||
| import cc.winboll.studio.mymessagemanager.adapters.SMSRecycleAdapter; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSRecycleUtil; | ||||
| import cc.winboll.studio.shared.view.YesNoAlertDialog; | ||||
| import com.baoyz.widget.PullRefreshLayout; | ||||
| import java.io.File; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
|  | ||||
| public class SMSRecycleActivity extends BaseActivity { | ||||
|  | ||||
|     public static final String TAG = "SMSRecycleActivity"; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|     RecyclerView mRecyclerView; | ||||
|     SMSRecycleAdapter mSMSRecycleAdapter; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_smsrecycle); | ||||
|         // 初始化标题栏 | ||||
|         mToolbar = findViewById(R.id.activitysmsrecycleASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.activity_name_about)); | ||||
|         setSupportActionBar(mToolbar); | ||||
|         initView(); | ||||
|     } | ||||
|  | ||||
|     void initView() { | ||||
|         // 绑定控件 | ||||
|         mRecyclerView = findViewById(R.id.activitysmsrecycleRecyclerView1); | ||||
|         RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); | ||||
|         mRecyclerView.setLayoutManager(layoutManager); | ||||
|  | ||||
|         mSMSRecycleAdapter = new SMSRecycleAdapter(this); | ||||
|         mRecyclerView.setAdapter(mSMSRecycleAdapter); | ||||
|  | ||||
|         final PullRefreshLayout pullRefreshLayout = findViewById(R.id.activitysmsrecyclePullRefreshLayout1); | ||||
|         pullRefreshLayout.setOnRefreshListener(new PullRefreshLayout.OnRefreshListener() { | ||||
|                 @Override | ||||
|                 public void onRefresh() { | ||||
|                     mSMSRecycleAdapter.loadSMSRecycleList(); | ||||
|                     mSMSRecycleAdapter.notifyDataSetChanged(); | ||||
|                     pullRefreshLayout.setRefreshing(false); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         //return super.onCreateOptionsMenu(menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_smsrecycle, menu); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int nItemId = item.getItemId(); | ||||
|         if (nItemId == R.id.item_cleansmsrecycle) { | ||||
|             YesNoAlertDialog.show(this, "回收站清空确认", "是否清空回收站", mDeleteListener); | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|      | ||||
|     YesNoAlertDialog.OnDialogResultListener mDeleteListener = new YesNoAlertDialog.OnDialogResultListener() { | ||||
|  | ||||
|         @Override | ||||
|         public void onNo() { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onYes() { | ||||
|             File file = new File(SMSRecycleUtil.getSMSRecycleListDataPath(SMSRecycleActivity.this)); | ||||
|             file.delete(); | ||||
|             mSMSRecycleAdapter.loadSMSRecycleList(); | ||||
|             mSMSRecycleAdapter.notifyDataSetChanged(); | ||||
|         } | ||||
|     }; | ||||
| } | ||||
| @@ -0,0 +1,139 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.text.TextUtils; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import android.widget.Toolbar; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSPlayRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.mymessagemanager.utils.UriUtil; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class SharedJSONReceiveActivity extends BaseActivity { | ||||
|  | ||||
|     public static final String TAG = "SharedJSONReceive"; | ||||
|  | ||||
|     Toolbar mToolbar; | ||||
|  | ||||
|     @Override | ||||
|     protected void onCreate(Bundle savedInstanceState) { | ||||
|         super.onCreate(savedInstanceState); | ||||
|         setContentView(R.layout.activity_sharedjsonreceive); | ||||
|  | ||||
|         StringBuilder sb = new StringBuilder(); | ||||
|         // 接收分享数据 | ||||
|         Intent intent = getIntent(); | ||||
|         String action = intent.getAction();//action | ||||
|         String type = intent.getType();//类型 | ||||
|         //LogUtils.d(TAG, "action is " + action); | ||||
|         //LogUtils.d(TAG, "type is " + type); | ||||
|         if ((Intent.ACTION_SEND.equals(action) || Intent.ACTION_VIEW.equals(action) || Intent.ACTION_EDIT.equals(action)) | ||||
|             && type != null && (("application/json".equals(type)) || ("text/x-json".equals(type)))) { | ||||
|  | ||||
|             //取出文件uri | ||||
|             Uri uri = intent.getData(); | ||||
|             if (uri == null) { | ||||
|                 uri = intent.getParcelableExtra(Intent.EXTRA_STREAM); | ||||
|             } | ||||
|             //获取文件真实地址 | ||||
|             String szSrcJSON = UriUtil.getFileFromUri(getApplication(), uri); | ||||
|             if (TextUtils.isEmpty(szSrcJSON)) { | ||||
|                 return; | ||||
|             } | ||||
|  | ||||
|             String szCheck = TTSPlayRuleBean.checkIsTheSameBeanListAndFile(szSrcJSON, TTSPlayRuleBean.class); | ||||
|             if (szCheck.equals("")) { | ||||
|                 importTTSPlayRuleBean(szSrcJSON); | ||||
|             } else { | ||||
|                 sb.append("\n语音规则数据检测结果\n"); | ||||
|                 sb.append(szCheck); | ||||
|             } | ||||
|             //LogUtils.d(TAG, "szCheck is " + szCheck); | ||||
|  | ||||
|             szCheck = SMSAcceptRuleBean.checkIsTheSameBeanListAndFile(szSrcJSON, SMSAcceptRuleBean.class); | ||||
|             if (szCheck.equals("")) { | ||||
|                 importSMSAcceptRuleBean(szSrcJSON); | ||||
|             } else { | ||||
|                 sb.append("\n短信接收规则数据检测结果\n"); | ||||
|                 sb.append(szCheck); | ||||
|             } | ||||
|             //LogUtils.d(TAG, "szCheck is " + szCheck); | ||||
|         } else { | ||||
|             sb.append("Not supported action."); | ||||
|         } | ||||
|  | ||||
|         mToolbar = findViewById(R.id.activitysharedjsonreceiveASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.activity_name_sharedjsonreceive)); | ||||
|         setActionBar(mToolbar); | ||||
|  | ||||
|         TextView tvMessage = findViewById(R.id.activitysharedjsonreceiveTextView1); | ||||
|         tvMessage.setText(sb.toString()); | ||||
|     } | ||||
|  | ||||
|     void importSMSAcceptRuleBean(final String szSrcJSON) { | ||||
|         ArrayList<SMSAcceptRuleBean> beanList = new ArrayList<SMSAcceptRuleBean>(); | ||||
|         boolean bCheck = SMSAcceptRuleBean.loadBeanListFromFile(szSrcJSON, beanList, SMSAcceptRuleBean.class); | ||||
|         if (bCheck && beanList.size() > 0) { | ||||
|             YesNoAlertDialog.show(SharedJSONReceiveActivity.this, | ||||
|                                   "短信接收规则共享提示", | ||||
|                                   "已收到短信接收规则" + Integer.toString(beanList.size()) + "个,\n是否导入应用?" | ||||
|                                   , (new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                                       @Override | ||||
|                                       public void onYes() { | ||||
|                                           ArrayList<SMSAcceptRuleBean> beanListShare = new ArrayList<SMSAcceptRuleBean>(); | ||||
|                                           SMSAcceptRuleBean.loadBeanListFromFile(szSrcJSON, beanListShare, SMSAcceptRuleBean.class); | ||||
|                                           ArrayList<SMSAcceptRuleBean> beanListApp = new ArrayList<SMSAcceptRuleBean>(); | ||||
|                                           SMSAcceptRuleBean.loadBeanList(SharedJSONReceiveActivity.this, beanListApp, SMSAcceptRuleBean.class); | ||||
|                                           beanListApp.addAll(0, beanListShare); | ||||
|                                           SMSAcceptRuleBean.saveBeanList(SharedJSONReceiveActivity.this, beanListApp, SMSAcceptRuleBean.class); | ||||
|                                           Toast.makeText(getApplication(), "已导入" + Integer.toString(beanListShare.size()) + "个数据。", Toast.LENGTH_SHORT).show(); | ||||
|                                           finish(); | ||||
|                                           Intent intent = new Intent(SharedJSONReceiveActivity.this, SMSReceiveRuleActivity.class); | ||||
|                                           startActivity(intent); | ||||
|                                       } | ||||
|  | ||||
|                                       @Override | ||||
|                                       public void onNo() { | ||||
|                                           finish(); | ||||
|                                       } | ||||
|                                   })); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void importTTSPlayRuleBean(final String szSrcJSON) { | ||||
|         ArrayList<TTSPlayRuleBean> beanList = new ArrayList<TTSPlayRuleBean>(); | ||||
|         boolean bCheck = TTSPlayRuleBean.loadBeanListFromFile(szSrcJSON, beanList, TTSPlayRuleBean.class); | ||||
|         if (bCheck && beanList.size() > 0) { | ||||
|             YesNoAlertDialog.show(SharedJSONReceiveActivity.this, | ||||
|                                   "语音规则共享提示", | ||||
|                                   "已收到语音规则" + Integer.toString(beanList.size()) + "个,\n是否导入应用?" | ||||
|                                   , (new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                                       @Override | ||||
|                                       public void onYes() { | ||||
|                                           ArrayList<TTSPlayRuleBean> beanListShare = new ArrayList<TTSPlayRuleBean>(); | ||||
|                                           TTSPlayRuleBean.loadBeanListFromFile(szSrcJSON, beanListShare, TTSPlayRuleBean.class); | ||||
|                                           ArrayList<TTSPlayRuleBean> beanListApp = new ArrayList<TTSPlayRuleBean>(); | ||||
|                                           TTSPlayRuleBean.loadBeanList(SharedJSONReceiveActivity.this, beanListApp, TTSPlayRuleBean.class); | ||||
|                                           beanListApp.addAll(0, beanListShare); | ||||
|                                           TTSPlayRuleBean.saveBeanList(SharedJSONReceiveActivity.this, beanListApp, TTSPlayRuleBean.class); | ||||
|                                           Toast.makeText(getApplication(), "已导入" + Integer.toString(beanListShare.size()) + "个数据。", Toast.LENGTH_SHORT).show(); | ||||
|                                           finish(); | ||||
|                                           Intent intent = new Intent(SharedJSONReceiveActivity.this, TTSPlayRuleActivity.class); | ||||
|                                           startActivity(intent); | ||||
|                                       } | ||||
|  | ||||
|                                       @Override | ||||
|                                       public void onNo() { | ||||
|                                           finish(); | ||||
|                                       } | ||||
|                                   })); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,188 @@ | ||||
| package cc.winboll.studio.mymessagemanager.activitys; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 12:50:52 | ||||
|  * @Describe TTS 语音播放规则规则设置窗口 | ||||
|  */ | ||||
| import android.os.Bundle; | ||||
| import android.os.Message; | ||||
| import android.view.Menu; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.widget.Button; | ||||
| import android.widget.EditText; | ||||
| import android.widget.Toast; | ||||
| import androidx.appcompat.widget.Toolbar; | ||||
| import androidx.recyclerview.widget.LinearLayoutManager; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.adapters.TTSRuleBeanRecyclerViewAdapter; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSPlayRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.FileUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.TTSPlayRuleUtil; | ||||
|  | ||||
| public class TTSPlayRuleActivity extends BaseActivity { | ||||
|  | ||||
|     public static final String TAG = "TTSPlayRuleActivity"; | ||||
|  | ||||
|     public static final int MSG_RELOAD = 0; | ||||
|  | ||||
| 	public static final String EXTRA_TTSDEMOTEXT = "EXTRA_TTSDEMOTEXT"; | ||||
|  | ||||
| 	Toolbar mToolbar; | ||||
|     TTSRuleBeanRecyclerViewAdapter mTTSRuleBeanRecyclerViewAdapter; | ||||
| 	TTSPlayRuleUtil mTTSPlayRuleUtil; | ||||
| 	TTSPlayRuleBean mTTSRuleBeanCurrent; | ||||
|     RecyclerView mRecyclerView; | ||||
|     EditText metCurrentDemoSMSText; | ||||
|     EditText metPatternText; | ||||
|     EditText metCurrentTTSRuleText; | ||||
|  | ||||
| 	@Override | ||||
| 	protected void onCreate(Bundle savedInstanceState) { | ||||
| 		super.onCreate(savedInstanceState); | ||||
| 		setContentView(R.layout.activity_ttsplayrule); | ||||
|  | ||||
| 		mTTSPlayRuleUtil = TTSPlayRuleUtil.getInstance(TTSPlayRuleActivity.this); | ||||
|  | ||||
|         initView(); | ||||
|  | ||||
|         // 设置窗口消息处理 | ||||
|         setOnActivityMessageReceived(new IOnActivityMessageReceived(){ | ||||
|                 @Override | ||||
|                 public void onActivityMessageReceived(Message msg) { | ||||
|                     switch (msg.what) { | ||||
|                         case MSG_RELOAD : { | ||||
|                                 //Toast.makeText(getApplication(), "MSG_RELOAD", Toast.LENGTH_SHORT).show(); | ||||
|                                 mTTSRuleBeanRecyclerViewAdapter.reloadConfigData(); | ||||
|                                 break; | ||||
|                             } | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
| 	} | ||||
|  | ||||
|     void initView() { | ||||
|         // 初始化标题栏 | ||||
|         mToolbar = findViewById(R.id.activityttsplayruleASupportToolbar1); | ||||
|         mToolbar.setSubtitle(getString(R.string.text_ttsrule)); | ||||
|         setSupportActionBar(mToolbar); | ||||
|  | ||||
|         metCurrentDemoSMSText = findViewById(R.id.activityttsplayruleEditText1); | ||||
|         metPatternText = findViewById(R.id.activityttsplayruleEditText2); | ||||
|         metCurrentTTSRuleText = findViewById(R.id.activityttsplayruleEditText3); | ||||
|  | ||||
| 		Button btnTestTTSRule = findViewById(R.id.activityttsplayruleButton1); | ||||
| 		btnTestTTSRule.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					TTSPlayRuleBean ttsRuleBean = new TTSPlayRuleBean(); | ||||
|                     ttsRuleBean.setDemoSMSText(metCurrentDemoSMSText.getText().toString()); | ||||
|                     ttsRuleBean.setPatternText(metPatternText.getText().toString()); | ||||
|                     ttsRuleBean.setTtsRuleText(metCurrentTTSRuleText.getText().toString()); | ||||
|  | ||||
|                     String sz = mTTSPlayRuleUtil.testTTSAnalyzeModeReply(ttsRuleBean); | ||||
|                     Toast.makeText(getApplication(), sz, Toast.LENGTH_SHORT).show(); | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 		Button btnAcceptTTSRule = findViewById(R.id.activityttsplayruleButton2); | ||||
| 		btnAcceptTTSRule.setOnClickListener(new View.OnClickListener() { | ||||
| 				@Override | ||||
| 				public void onClick(View v) { | ||||
| 					if (mTTSRuleBeanCurrent != null) { | ||||
| 						mTTSRuleBeanCurrent.setDemoSMSText(metCurrentDemoSMSText.getText().toString()); | ||||
|                         mTTSRuleBeanCurrent.setPatternText(metPatternText.getText().toString()); | ||||
|                         mTTSRuleBeanCurrent.setTtsRuleText(metCurrentTTSRuleText.getText().toString()); | ||||
|                         mTTSRuleBeanRecyclerViewAdapter.saveConfigData(); | ||||
| 					} else { | ||||
|                         if (!metCurrentDemoSMSText.getText().toString().equals("")) { | ||||
|                             mTTSRuleBeanCurrent = new TTSPlayRuleBean(); | ||||
|                             mTTSRuleBeanCurrent.setDemoSMSText(metCurrentDemoSMSText.getText().toString()); | ||||
|                             mTTSRuleBeanCurrent.setPatternText(metPatternText.getText().toString()); | ||||
|                             mTTSRuleBeanCurrent.setTtsRuleText(metCurrentTTSRuleText.getText().toString()); | ||||
|                             mTTSRuleBeanRecyclerViewAdapter.addNewTTSRuleBean(mTTSRuleBeanCurrent); | ||||
|                             LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); | ||||
|                             layoutManager.scrollToPositionWithOffset(0, 0); | ||||
|                         } | ||||
|                     } | ||||
| 				} | ||||
| 			}); | ||||
|  | ||||
| 		// 绑定控件 | ||||
|         mRecyclerView = findViewById(R.id.activityttsplayruleRecyclerView1); | ||||
|         RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this); | ||||
|         mRecyclerView.setLayoutManager(layoutManager); | ||||
|  | ||||
|         mTTSRuleBeanRecyclerViewAdapter = new TTSRuleBeanRecyclerViewAdapter(TTSPlayRuleActivity.this, mOnTTSRuleChangeListener); | ||||
|         mRecyclerView.setAdapter(mTTSRuleBeanRecyclerViewAdapter); | ||||
|  | ||||
| 		// 处理传入的窗口启动参数 | ||||
|         // | ||||
|         String szNewDemoText = getIntent().getStringExtra(EXTRA_TTSDEMOTEXT); | ||||
|         metCurrentDemoSMSText.setText(szNewDemoText); | ||||
| 	} | ||||
|  | ||||
|     @Override | ||||
|     public boolean onCreateOptionsMenu(Menu menu) { | ||||
|         //return super.onCreateOptionsMenu(menu); | ||||
|         getMenuInflater().inflate(R.menu.toolbar_rule, menu); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public void onScrollToDemoSMSTextMatchingRule(View view) { | ||||
|         int rowIndex = mTTSPlayRuleUtil.speakTTSAnalyzeModeText(metCurrentDemoSMSText.getText().toString()); | ||||
|  | ||||
|         LinearLayoutManager layoutManager = (LinearLayoutManager) mRecyclerView.getLayoutManager(); | ||||
|         layoutManager.scrollToPositionWithOffset(rowIndex, 0); | ||||
|         Toast.makeText(getApplication(), "当前文本匹配的规则序号为 " + Integer.toString(rowIndex + 1), Toast.LENGTH_SHORT).show(); | ||||
|     } | ||||
|      | ||||
|     @Override | ||||
|     public boolean onOptionsItemSelected(MenuItem item) { | ||||
|         int nItemId = item.getItemId(); | ||||
|         if (nItemId == R.id.item_rule_share) { | ||||
|             TTSPlayRuleBean bean = new TTSPlayRuleBean(); | ||||
|             FileUtil.shareJSONFile(this, bean.getBeanListJsonFilePath(TTSPlayRuleActivity.this)); | ||||
|         } else if (nItemId == R.id.item_rule_reset) { | ||||
|             showResetConfigDialog(); | ||||
|         } else if (nItemId == R.id.item_rule_clean) { | ||||
|             showCleanConfigDialog(); | ||||
|         }  | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 规则数据重置对话框 | ||||
|     // | ||||
|     void showResetConfigDialog() { | ||||
|         mTTSPlayRuleUtil.resetConfig(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 规则数据重置对话框 | ||||
|     // | ||||
|     void showCleanConfigDialog() { | ||||
|         mTTSPlayRuleUtil.cleanConfig(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onResume() { | ||||
|         super.onResume(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 规则项选择事件监听类 | ||||
|     // | ||||
| 	TTSRuleBeanRecyclerViewAdapter.OnTTSRuleChangeListener mOnTTSRuleChangeListener = new TTSRuleBeanRecyclerViewAdapter.OnTTSRuleChangeListener() { | ||||
| 		@Override | ||||
| 		public void onTTSRuleChange(TTSPlayRuleBean bean) { | ||||
| 			metCurrentDemoSMSText.setText(bean.getDemoSMSText()); | ||||
| 			metPatternText.setText(bean.getPatternText()); | ||||
| 			metCurrentTTSRuleText.setText(bean.getTtsRuleText()); | ||||
| 			mTTSRuleBeanCurrent = bean; | ||||
| 		} | ||||
| 	}; | ||||
| } | ||||
| @@ -0,0 +1,114 @@ | ||||
| package cc.winboll.studio.mymessagemanager.adapters; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.View.OnClickListener; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.BaseAdapter; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.TextView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.SMSActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.PhoneBean; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.PhoneUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import java.util.ArrayList; | ||||
| import java.util.List; | ||||
|  | ||||
| public class PhoneArrayAdapter extends BaseAdapter { | ||||
|  | ||||
|     public final static String TAG = "PhoneArrayAdapter"; | ||||
|  | ||||
|     Context mContext; | ||||
|     ArrayList<SMSBean> mData; | ||||
|     List<PhoneBean> mlistContacts; | ||||
|     PhoneUtil mPhoneUtil; | ||||
|  | ||||
|     public PhoneArrayAdapter(Context context) { | ||||
|         mContext = context; | ||||
| 		mData = new ArrayList<SMSBean>(); | ||||
|     } | ||||
|  | ||||
|     public void loadData() { | ||||
|         ArrayList<SMSBean> listTemp = SMSUtil.getAllSMSList(mContext); | ||||
|         mData.clear(); | ||||
|         mData.addAll(listTemp); | ||||
|         mPhoneUtil = new PhoneUtil(mContext); | ||||
|         mlistContacts = mPhoneUtil.getPhoneList(); | ||||
|         LogUtils.i(TAG, "SMS List Reload."); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getCount() { | ||||
|         return mData.size(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object getItem(int p1) { | ||||
|         return mData.get(p1); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long getItemId(int p1) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public View getView(int position, View convertView, ViewGroup parent) { | ||||
| 		final ViewHolder viewHolder; | ||||
|         if (convertView == null) { | ||||
|             viewHolder = new ViewHolder(); | ||||
|             convertView = LayoutInflater.from(mContext).inflate(R.layout.listview_phone, parent, false); | ||||
|  | ||||
|             //分别获取 image view 和 textview 的实例 | ||||
| 			viewHolder.tvAddress = convertView.findViewById(R.id.listviewphoneTextView1); | ||||
| 			viewHolder.tvName = convertView.findViewById(R.id.listviewphoneTextView2); | ||||
| 			viewHolder.ll = convertView.findViewById(R.id.listviewphoneLinearLayout1); | ||||
|  | ||||
|             convertView.setTag(viewHolder); | ||||
|         } else { | ||||
|             viewHolder = (ViewHolder) convertView.getTag(); | ||||
|         } | ||||
|  | ||||
| 		String szAddress = ((SMSBean)getItem(position)).getAddress(); | ||||
|  | ||||
| 		viewHolder.tvAddress.setText(szAddress); | ||||
| 		viewHolder.tvName.setText(getName(szAddress)); | ||||
|  | ||||
|         //Drawable drawableFrame = AppCompatResources.getDrawable(mContext, R.drawable.bg_frame); | ||||
|         //viewHolder.ll.setBackground(drawableFrame); | ||||
|         viewHolder.ll.setOnClickListener(new OnClickListener() { | ||||
|                 @Override | ||||
|                 public void onClick(View arg0) { | ||||
|  | ||||
|                     //Toast.makeText(mContext, tv.getText(), Toast.LENGTH_SHORT).show(); | ||||
|                     Intent intent = new Intent(mContext, SMSActivity.class); | ||||
|                     intent.putExtra(SMSActivity.EXTRA_PHONE, viewHolder.tvAddress.getText()); | ||||
|                     mContext.startActivity(intent); | ||||
|                 } | ||||
|  | ||||
|             }); | ||||
|         return convertView; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     String getName(String szAddress) { | ||||
|         for (int i = 0; i < mlistContacts.size(); i++) { | ||||
|             if (mlistContacts.get(i).getTelPhone().equals(szAddress)) { | ||||
|                 return mlistContacts.get(i).getName(); | ||||
|             } | ||||
|         } | ||||
|         return mContext.getString(R.string.text_notincontacts); | ||||
|     } | ||||
|  | ||||
| 	class ViewHolder { | ||||
|         TextView tvAddress; | ||||
| 		TextView tvName; | ||||
| 		LinearLayout ll; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,229 @@ | ||||
| package cc.winboll.studio.mymessagemanager.adapters; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/20 12:27:34 | ||||
|  * @Describe 短信过滤规则数据适配器 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.EditText; | ||||
| import android.widget.RadioButton; | ||||
| import android.widget.TextView; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSReceiveRuleUtil; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class SMSAcceptRuleArrayAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     public static final String TAG = "SMSAcceptRuleArrayAdapter"; | ||||
|  | ||||
|     Context mContext; | ||||
|     ArrayList<SMSAcceptRuleBean> mDataList; | ||||
|     SMSReceiveRuleUtil mSMSReceiveRuleUtil; | ||||
|  | ||||
|     public SMSAcceptRuleArrayAdapter(Context context) { | ||||
|         mContext = context; | ||||
|         mSMSReceiveRuleUtil = SMSReceiveRuleUtil.getInstance(mContext, true); | ||||
|         loadConfigData(); | ||||
|     } | ||||
|  | ||||
|     public void addSMSAcceptRule(SMSAcceptRuleBean bean) { | ||||
|         mSMSReceiveRuleUtil.addRule(bean); | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     public void loadConfigData() { | ||||
|         mDataList = mSMSReceiveRuleUtil.loadConfigData(); | ||||
|         for (int i = 0; i < mDataList.size(); i++) { | ||||
|             mDataList.get(i).setIsSimpleView(true); | ||||
|             //LogUtils.d(TAG, "loadConfigData isEnable : " + Boolean.toString(mDataList.get(i).isEnable())); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void deleteItem(int position) { | ||||
|         mDataList.remove(position); | ||||
|         mSMSReceiveRuleUtil.saveConfigData(); | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemViewType(int position) { | ||||
|         if (mDataList.get(position).isSimpleView()) { | ||||
|             return 0; | ||||
|         } else { | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         if (viewType == 0) { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_smsacceptrule_simple, parent, false); | ||||
|             return new SimpleViewHolder(view); | ||||
|         } else { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_smsacceptrule, parent, false); | ||||
|             return new ComplexViewHolder(view); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { | ||||
|         final SMSAcceptRuleBean item = mDataList.get(position); | ||||
|         if (holder.getItemViewType() == 0) { | ||||
|             final SimpleViewHolder viewHolder = (SimpleViewHolder) holder; | ||||
|             viewHolder.mtvContent.setText(item.getRuleData()); | ||||
|             viewHolder.mcbEnable.setChecked(item.isEnable()); | ||||
|             viewHolder.mcbEnable.setOnClickListener(new View.OnClickListener() { | ||||
|                     @Override | ||||
|                     public void onClick(View p1) { | ||||
|                         item.setIsEnable(viewHolder.mcbEnable.isChecked()); | ||||
|                         item.setIsSimpleView(true); | ||||
|                         mSMSReceiveRuleUtil.saveConfigData(); | ||||
|                         notifyDataSetChanged(); | ||||
|                     } | ||||
|                 }); | ||||
|             viewHolder.mtvRuleType.setText(item.getRuleType().toString()); | ||||
|             viewHolder.mbtnEdit.setOnClickListener(new View.OnClickListener(){ | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         for (int i = 0; i < mDataList.size(); i++) { | ||||
|                             mDataList.get(i).setIsSimpleView(true); | ||||
|                         } | ||||
|                         item.setIsSimpleView(false); | ||||
|                         notifyDataSetChanged(); | ||||
|                         //ToastUtils.show("setIsSimpleView"); | ||||
|                     } | ||||
|                 }); | ||||
|         } else { | ||||
|             final ComplexViewHolder viewHolder = (ComplexViewHolder) holder; | ||||
|             if (item != null) { | ||||
|                 //Drawable drawableFrame = AppCompatResources.getDrawable(mContext, R.drawable.bg_frame); | ||||
|                 viewHolder.metContent.setText(item.getRuleData()); | ||||
|                 if (item.getRuleType() == SMSAcceptRuleBean.RuleType.ACCEPT) { | ||||
|                     viewHolder.mrbAccept.setChecked(true); | ||||
|                     viewHolder.mrbRefuse.setChecked(false); | ||||
|                 } | ||||
|                 if (item.getRuleType() == SMSAcceptRuleBean.RuleType.REFUSE) { | ||||
|                     viewHolder.mrbAccept.setChecked(false); | ||||
|                     viewHolder.mrbRefuse.setChecked(true); | ||||
|                 } | ||||
|                 viewHolder.mrbAccept.setOnClickListener(new View.OnClickListener(){ | ||||
|                         @Override | ||||
|                         public void onClick(View view) { | ||||
|                             viewHolder.mrbRefuse.setChecked(false); | ||||
|                             item.setRuleType(SMSAcceptRuleBean.RuleType.ACCEPT); | ||||
|                             mSMSReceiveRuleUtil.saveConfigData(); | ||||
|                             notifyDataSetChanged(); | ||||
|                         } | ||||
|                     }); | ||||
|                 viewHolder.mrbRefuse.setOnClickListener(new View.OnClickListener(){ | ||||
|                         @Override | ||||
|                         public void onClick(View view) { | ||||
|                             viewHolder.mrbAccept.setChecked(false); | ||||
|                             item.setRuleType(SMSAcceptRuleBean.RuleType.REFUSE); | ||||
|                             mSMSReceiveRuleUtil.saveConfigData(); | ||||
|                             notifyDataSetChanged(); | ||||
|                         } | ||||
|                     }); | ||||
|                 viewHolder.mbtnUp.setOnClickListener(new View.OnClickListener() { | ||||
|                         @Override | ||||
|                         public void onClick(View p1) { | ||||
|                             if (position > 0) { | ||||
|                                 mDataList.add(position-1, mDataList.get(position)); | ||||
|                                 mDataList.remove(position+1); | ||||
|                                 mSMSReceiveRuleUtil.saveConfigData(); | ||||
|                                 notifyDataSetChanged(); | ||||
|                             } | ||||
|                         } | ||||
|                     }); | ||||
|                 viewHolder.mbtnDown.setOnClickListener(new View.OnClickListener() { | ||||
|                         @Override | ||||
|                         public void onClick(View p1) { | ||||
|                             if (position < mDataList.size() - 1) { | ||||
|                                 //ToastUtils.show("mbtnDown"); | ||||
|                                 ToastUtils.show("position " + Integer.toString(position)); | ||||
|                                 mDataList.add(position+2, mDataList.get(position)); | ||||
|                                 mDataList.remove(position); | ||||
|                                 mSMSReceiveRuleUtil.saveConfigData(); | ||||
|                                 notifyDataSetChanged(); | ||||
|                             } | ||||
|                         } | ||||
|                     }); | ||||
|                 viewHolder.mbtnOK.setOnClickListener(new View.OnClickListener() { | ||||
|                         @Override | ||||
|                         public void onClick(View p1) { | ||||
|                             item.setRuleData(viewHolder.metContent.getText().toString()); | ||||
|                             item.setRuleType(viewHolder.mrbAccept.isChecked() ?SMSAcceptRuleBean.RuleType.ACCEPT: SMSAcceptRuleBean.RuleType.REFUSE); | ||||
|                             item.setIsEnable(viewHolder.mcbEnable.isChecked()); | ||||
|                             item.setIsSimpleView(true); | ||||
|                             mSMSReceiveRuleUtil.saveConfigData(); | ||||
|                             notifyDataSetChanged(); | ||||
|                         } | ||||
|                     }); | ||||
|                 viewHolder.mbtnDelete.setOnClickListener(new View.OnClickListener() { | ||||
|                         @Override | ||||
|                         public void onClick(View p1) { | ||||
|                             deleteItem(position); | ||||
|                         } | ||||
|                     }); | ||||
|                 viewHolder.mcbEnable.setChecked(item.isEnable()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return mDataList.size(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long getItemId(int posttion) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     private static class SimpleViewHolder extends RecyclerView.ViewHolder { | ||||
|         TextView mtvContent; | ||||
|         CheckBox mcbEnable; | ||||
|         TextView mtvRuleType; | ||||
|         Button mbtnEdit; | ||||
|  | ||||
|         SimpleViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             mtvContent = itemView.findViewById(R.id.listviewsmsacceptrulesimpleTextView1); | ||||
|             mcbEnable = itemView.findViewById(R.id.listviewsmsacceptrulesimpleCheckBox1); | ||||
|             mtvRuleType = itemView.findViewById(R.id.listviewsmsacceptrulesimpleTextView2); | ||||
|             mbtnEdit = itemView.findViewById(R.id.listviewsmsacceptrulesimpleButton1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class ComplexViewHolder extends RecyclerView.ViewHolder { | ||||
|         EditText metContent; | ||||
|         RadioButton mrbAccept; | ||||
|         RadioButton mrbRefuse; | ||||
|         CheckBox mcbEnable; | ||||
|         Button mbtnUp; | ||||
|         Button mbtnDown; | ||||
|         Button mbtnOK; | ||||
|         Button mbtnDelete; | ||||
|  | ||||
|         ComplexViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             metContent = itemView.findViewById(R.id.listviewsmsacceptruleEditText1); | ||||
|             mrbAccept = itemView.findViewById(R.id.listviewsmsacceptruleRadioButton1); | ||||
|             mrbRefuse = itemView.findViewById(R.id.listviewsmsacceptruleRadioButton2); | ||||
|             mcbEnable = itemView.findViewById(R.id.listviewsmsacceptruleCheckBox1); | ||||
|             mbtnUp = itemView.findViewById(R.id.listviewsmsacceptruleButton3); | ||||
|             mbtnDown = itemView.findViewById(R.id.listviewsmsacceptruleButton4); | ||||
|             mbtnOK = itemView.findViewById(R.id.listviewsmsacceptruleButton1); | ||||
|             mbtnDelete = itemView.findViewById(R.id.listviewsmsacceptruleButton2); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,213 @@ | ||||
| package cc.winboll.studio.mymessagemanager.adapters; | ||||
|  | ||||
| import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.view.Gravity; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.BaseAdapter; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.PopupMenu; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.TTSPlayRuleActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSBean; | ||||
| import cc.winboll.studio.mymessagemanager.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.mymessagemanager.utils.NotificationUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSReceiveRuleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSRecycleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.TTSPlayRuleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.views.DateAgoTextView; | ||||
| import cc.winboll.studio.mymessagemanager.views.SMSView; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean; | ||||
|  | ||||
| public class SMSArrayAdapter extends BaseAdapter { | ||||
|  | ||||
|     public static String TAG = "SMSArrayAdapter"; | ||||
|  | ||||
|     Context mContext; | ||||
|     String mszPhone; | ||||
|     ArrayList<SMSBean> mData; | ||||
|  | ||||
|     public SMSArrayAdapter(Context context, String szPhone) { | ||||
|         mContext = context; | ||||
|         mszPhone = szPhone; | ||||
|         mData = new ArrayList<SMSBean>(); | ||||
|         mData = loadSMSList(context, szPhone); | ||||
|     } | ||||
|  | ||||
|     ArrayList<SMSBean> loadSMSList(Context context, String szPhone) { | ||||
|         ArrayList<SMSBean> data = SMSUtil.getSMSListByPhone(context, szPhone); | ||||
|         SMSBean.sortSMSByDateDesc(data, false); | ||||
|         mData.clear(); | ||||
|         mData.addAll(data); | ||||
|         return mData; | ||||
|     } | ||||
|  | ||||
|     public void cancelMessageNotification() { | ||||
|         for (SMSBean bean : mData) { | ||||
|             NotificationUtil.cancelNotification(mContext, bean.getId()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     void deleteSMSById(final int position) { | ||||
|         YesNoAlertDialog.show(mContext, | ||||
|                               "短信删除提示", | ||||
|                               "请确认删除动作!" | ||||
|                               , (new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                                   @Override | ||||
|                                   public void onYes() { | ||||
|                                       SMSRecycleUtil.addSMSRecycleItem(mContext, (SMSBean)getItem(position)); | ||||
|                                       SMSUtil.deleteSMSById(mContext, ((SMSBean)getItem(position)).getId()); | ||||
|                                       mData.remove(position); | ||||
|                                       notifyDataSetChanged(); | ||||
|                                       Toast.makeText(mContext, "SMS delete.", Toast.LENGTH_SHORT).show(); | ||||
|                                   } | ||||
|  | ||||
|                                   @Override | ||||
|                                   public void onNo() { | ||||
|  | ||||
|                                   } | ||||
|                               })); | ||||
|     } | ||||
|  | ||||
|     public void reLoadSMSList(Context context, String szPhone) { | ||||
|         mData = loadSMSList(context, szPhone); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getCount() { | ||||
|         return mData.size(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public Object getItem(int p1) { | ||||
|         return mData.get(p1); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public long getItemId(int p1) { | ||||
|         return 0; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public View getView(final int position, View convertView, ViewGroup parent) { | ||||
|         final ViewHolder viewHolder; | ||||
|         if (convertView == null) { | ||||
|             viewHolder = new ViewHolder(); | ||||
|             convertView = LayoutInflater.from(mContext).inflate(R.layout.listview_sms, parent, false); | ||||
|             viewHolder.mSMSView = convertView.findViewById(R.id.listviewsmsSMSView1); | ||||
|  | ||||
|             viewHolder.mllMain = convertView.findViewById(R.id.listviewsmspart1LinearLayout1); | ||||
|             viewHolder.mllContent = convertView.findViewById(R.id.listviewsmspart1LinearLayout2); | ||||
|             viewHolder.mvMenu = convertView.findViewById(R.id.listviewsmspart1View1); | ||||
|             viewHolder.mtvBody = (TextView) convertView | ||||
|                 .findViewById(R.id.listviewsmspart1TextView1); | ||||
|             viewHolder.mdatvDate = convertView.findViewById(R.id.listviewsmspart1DateAgoTextView1); | ||||
|  | ||||
|             viewHolder.mvLeft = convertView.findViewById(R.id.listviewsmsView1); | ||||
| 			viewHolder.mvRight = convertView.findViewById(R.id.listviewsmsView2); | ||||
|  | ||||
|             convertView.setTag(viewHolder); | ||||
|         } else { | ||||
|             viewHolder = (ViewHolder) convertView.getTag(); | ||||
|         } | ||||
|  | ||||
|         final SMSBean item = (SMSBean) getItem(position); | ||||
|         if (item != null) { | ||||
|             if (item.getType() == SMSBean.Type.INBOX) { | ||||
| 				viewHolder.mvLeft.setVisibility(View.GONE); | ||||
| 				viewHolder.mvRight.setVisibility(View.VISIBLE); | ||||
|  | ||||
| 				viewHolder.mSMSView.setSMSType(SMSView.SMSType.INBOX); | ||||
| 				viewHolder.mllMain.setGravity(Gravity.LEFT); | ||||
| 			} else { | ||||
| 				viewHolder.mvLeft.setVisibility(View.VISIBLE); | ||||
| 				viewHolder.mvRight.setVisibility(View.GONE); | ||||
| 				viewHolder.mSMSView.setSMSType(SMSView.SMSType.SEND); | ||||
|             } | ||||
|  | ||||
|             //Drawable drawableFrame = AppCompatResources.getDrawable(mContext, R.drawable.bg_frame); | ||||
|             //viewHolder.mllContent.setBackground(drawableFrame); | ||||
|  | ||||
|             viewHolder.mtvBody.setText(item.getBody()); | ||||
|             viewHolder.mdatvDate.setDate(item.getDate()); | ||||
|             //viewHolder.mtvType.setText(" [" + item.getType().name() + "] "); | ||||
|  | ||||
|             viewHolder.mSMSView.setOnLongClickListener(new View.OnLongClickListener() { | ||||
|                     @Override | ||||
|                     public boolean onLongClick(View p1) { | ||||
|                         // 弹出复制菜单 | ||||
|                         PopupMenu menu = new PopupMenu(mContext, viewHolder.mvMenu); | ||||
|                         //加载菜单资源 | ||||
|                         menu.getMenuInflater().inflate(R.menu.toolbar_item_sms, menu.getMenu()); | ||||
|                         //设置点击事件的响应 | ||||
|                         menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { | ||||
|                                 @Override | ||||
|                                 public boolean onMenuItemClick(MenuItem menuItem) { | ||||
|                                     int nItemId = menuItem.getItemId(); | ||||
|                                     if (nItemId == R.id.copy) { | ||||
|                                         // Gets a handle to the clipboard service. | ||||
|                                         ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); | ||||
|                                         // Creates a new text clip to put on the clipboard | ||||
|                                         ClipData clip = ClipData.newPlainText("simple text", item.getBody()); | ||||
|                                         // Set the clipboard's primary clip. | ||||
|                                         clipboard.setPrimaryClip(clip); | ||||
|                                         Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show(); | ||||
|                                     } else if (nItemId == R.id.delete) { | ||||
|                                         deleteSMSById(position); | ||||
|                                     } else if (nItemId == R.id.addttsrule) { | ||||
|                                         Intent intent = new Intent(mContext, TTSPlayRuleActivity.class); | ||||
|                                         intent.putExtra(TTSPlayRuleActivity.EXTRA_TTSDEMOTEXT, viewHolder.mtvBody.getText().toString()); | ||||
|                                         mContext.startActivity(intent); | ||||
|                                     } else if (nItemId == R.id.testtts) { | ||||
|                                         //Toast.makeText(mContext, "Testing TTS.", Toast.LENGTH_SHORT).show(); | ||||
|                                         TTSPlayRuleUtil ttsPlayRuleUtil = TTSPlayRuleUtil.getInstance(mContext); | ||||
|                                         ttsPlayRuleUtil.speakTTSAnalyzeModeText(viewHolder.mtvBody.getText().toString()); | ||||
|                                     } else if (nItemId == R.id.testreceivetule) { | ||||
|                                         //Toast.makeText(mContext, "Testing Receive Rule.", Toast.LENGTH_SHORT).show(); | ||||
|                                         SMSReceiveRuleUtil smsReceiveRuleUtil = SMSReceiveRuleUtil.getInstance(mContext, true); | ||||
|                                         SMSReceiveRuleUtil.MatchResult matchResult = smsReceiveRuleUtil.getReceiveRuleMatchResult(mContext, viewHolder.mtvBody.getText().toString()); | ||||
|                                         if (matchResult.matchPositionInRules == SMSReceiveRuleUtil.VALID_MATCHRESULT_POSITION | ||||
|                                             || matchResult.matchRuleType == SMSAcceptRuleBean.RuleType.REGEXPPIUTILS_ISPPIOK_FALSE) { | ||||
|                                             //ToastUtils.show("Test"); | ||||
|                                             ToastUtils.show("Not Receive Rule is Matched.\nResult is : " + matchResult.matchRuleType); | ||||
|                                         } else { | ||||
|                                             ToastUtils.show("MatchResult : " + matchResult.matchRuleType + "\nReceiveRule Match Position : " + Integer.toString(matchResult.matchPositionInRules + 1)); | ||||
|                                         } | ||||
|                                     } | ||||
|  | ||||
|                                     return true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         //一定要调用show()来显示弹出式菜单 | ||||
|                         menu.show(); | ||||
|  | ||||
|                         return true; | ||||
|                     } | ||||
|                 }); | ||||
|         } | ||||
|  | ||||
|         return convertView; | ||||
|     } | ||||
|  | ||||
|     class ViewHolder { | ||||
|         SMSView mSMSView; | ||||
|         LinearLayout mllMain; | ||||
|         LinearLayout mllContent; | ||||
|         TextView mtvBody; | ||||
|         View mvMenu; | ||||
|         DateAgoTextView mdatvDate; | ||||
|         View mvLeft; | ||||
| 		View mvRight; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,289 @@ | ||||
| package cc.winboll.studio.mymessagemanager.adapters; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 17:07:34 | ||||
|  * @Describe 短信回收站短信数据适配器 | ||||
|  */ | ||||
| import android.content.ClipData; | ||||
| import android.content.ClipboardManager; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.view.Gravity; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.PopupMenu; | ||||
| import android.widget.TextView; | ||||
| import android.widget.Toast; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.TTSPlayRuleActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSBean; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSRecycleBean; | ||||
| import cc.winboll.studio.mymessagemanager.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSRecycleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.TTSPlayRuleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.UserVisionSystemProtectModeUtil; | ||||
| import cc.winboll.studio.mymessagemanager.views.DateAgoTextView; | ||||
| import cc.winboll.studio.mymessagemanager.views.SMSView; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class SMSRecycleAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     public static final String TAG = "SMSRecycleAdapter"; | ||||
|  | ||||
|     Context mContext; | ||||
|     ArrayList<SMSRecycleBean> mDataList; | ||||
|     String mszSMSRecycleListDataPath; | ||||
|     AppConfigUtil mAppConfigUtil; | ||||
|  | ||||
|     public SMSRecycleAdapter(Context context) { | ||||
|         mContext = context; | ||||
|         mAppConfigUtil = AppConfigUtil.getInstance(mContext); | ||||
|         mszSMSRecycleListDataPath = SMSRecycleUtil.getSMSRecycleListDataPath(mContext); | ||||
|         mDataList = new ArrayList<SMSRecycleBean>(); | ||||
|         mDataList = loadSMSRecycleList(); | ||||
|     } | ||||
|  | ||||
|     public ArrayList<SMSRecycleBean> loadSMSRecycleList() { | ||||
|         ArrayList<SMSRecycleBean> list = new ArrayList<SMSRecycleBean>(); | ||||
|         SMSRecycleBean.loadBeanListFromFile(mszSMSRecycleListDataPath, list, SMSRecycleBean.class); | ||||
|         SMSRecycleBean.sortSMSByDeleteDateDesc(list, true); | ||||
|         mDataList.clear(); | ||||
|         mDataList.addAll(list); | ||||
|         for (int i = 0; i < mDataList.size(); i++) { | ||||
|             mDataList.get(i).setIsSimpleView(true); | ||||
|         } | ||||
|         //ToastUtils.show("mDataList.size() : " + Integer.toString(mDataList.size())); | ||||
|         return mDataList; | ||||
|     } | ||||
|  | ||||
|     public void saveSMSRecycleList() { | ||||
|         SMSBean.saveBeanListToFile(mszSMSRecycleListDataPath, mDataList); | ||||
|     } | ||||
|  | ||||
|     void restoreSMSRecycleItem(final int position) { | ||||
|         YesNoAlertDialog.show(mContext, | ||||
|                               "短信恢复提示", | ||||
|                               "是否恢复该短信!" | ||||
|                               , (new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                                   @Override | ||||
|                                   public void onYes() { | ||||
|                                       SMSBean item = mDataList.get(position); | ||||
|                                       long nResultId = 0; | ||||
|                                       //LogUtils.d(TAG, "item.getType() : " + item.getType()); | ||||
|                                       if (item.getType() == SMSBean.Type.INBOX) { | ||||
|                                           nResultId = SMSUtil.saveReceiveSms(mContext, item.getAddress(), item.getBody(), | ||||
|                                                                              (item.getReadStatus() == SMSBean.ReadStatus.READ) ?"1": "0", | ||||
|                                                                              item.getDate(), "inbox"); | ||||
|                                       } else if (item.getType() == SMSBean.Type.SENT) { | ||||
|                                           nResultId = SMSUtil.saveOldSendedSMS(mContext, item); | ||||
|                                       } | ||||
|                                       if (nResultId == 0) { | ||||
|                                           ToastUtils.show("SMS Restored Failed!\nPlease confirm that the application has the SMS management authority."); | ||||
|                                       } else { | ||||
|                                           mDataList.remove(position); | ||||
|                                           SMSBean.saveBeanListToFile(mszSMSRecycleListDataPath, mDataList); | ||||
|                                           notifyDataSetChanged(); | ||||
|                                           ToastUtils.show("SMS Restored. ID : " + Long.toString(nResultId)); | ||||
|                                       } | ||||
|                                   } | ||||
|  | ||||
|                                   @Override | ||||
|                                   public void onNo() { | ||||
|  | ||||
|                                   } | ||||
|                               })); | ||||
|     } | ||||
|  | ||||
|     void deleteSMSRecycleItem(final int position) { | ||||
|         YesNoAlertDialog.show(mContext, | ||||
|                               "短信删除提示", | ||||
|                               "请确认删除动作!" | ||||
|                               , (new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|  | ||||
|                                   @Override | ||||
|                                   public void onYes() { | ||||
|                                       mDataList.remove(position); | ||||
|                                       SMSBean.saveBeanListToFile(mszSMSRecycleListDataPath, mDataList); | ||||
|                                       notifyDataSetChanged(); | ||||
|                                       Toast.makeText(mContext, "SMS delete.", Toast.LENGTH_SHORT).show(); | ||||
|                                   } | ||||
|  | ||||
|                                   @Override | ||||
|                                   public void onNo() { | ||||
|  | ||||
|                                   } | ||||
|                               })); | ||||
|     } | ||||
|  | ||||
|     public void reLoadSMSList(Context context, String szPhone) { | ||||
|         mDataList = loadSMSRecycleList(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemViewType(int position) { | ||||
|         if (mDataList.get(position).isSimpleView()) { | ||||
|             return 0; | ||||
|         } else { | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         if (viewType == 0) { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_smsrecycle_simple, parent, false); | ||||
|             return new SimpleViewHolder(view); | ||||
|         } else { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_smsrecycle, parent, false); | ||||
|             return new ComplexViewHolder(view); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { | ||||
|         final SMSRecycleBean item = mDataList.get(position); | ||||
|         if (holder.getItemViewType() == 0) { | ||||
|             SimpleViewHolder viewHolder = (SimpleViewHolder) holder; | ||||
|             viewHolder.mtvAddress.setText(item.getAddress()); | ||||
|             viewHolder.mbtnViewBody.setOnClickListener(new View.OnClickListener(){ | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         for (int i = 0; i < mDataList.size(); i++) { | ||||
|                             mDataList.get(i).setIsSimpleView(true); | ||||
|                         } | ||||
|                         item.setIsSimpleView(false); | ||||
|                         notifyDataSetChanged(); | ||||
|                         //ToastUtils.show("setIsSimpleView"); | ||||
|                     } | ||||
|                 }); | ||||
|         } else { | ||||
|             final ComplexViewHolder viewHolder = (ComplexViewHolder) holder; | ||||
|             if (item.getType() == SMSBean.Type.INBOX) { | ||||
|                 viewHolder.mvLeft.setVisibility(View.GONE); | ||||
|                 viewHolder.mvRight.setVisibility(View.VISIBLE); | ||||
|  | ||||
|                 viewHolder.mSMSView.setSMSType(SMSView.SMSType.INBOX); | ||||
|                 viewHolder.mllMain.setGravity(Gravity.LEFT); | ||||
|             } else { | ||||
|                 viewHolder.mvLeft.setVisibility(View.VISIBLE); | ||||
|                 viewHolder.mvRight.setVisibility(View.GONE); | ||||
|                 viewHolder.mSMSView.setSMSType(SMSView.SMSType.SEND); | ||||
|             } | ||||
|             viewHolder.mtvAddress.setText(item.getAddress()); | ||||
|             viewHolder.mdatvDeleteDate.setDate(item.getDeleteDate()); | ||||
|             viewHolder.mdatvDate.setDate(item.getDate()); | ||||
|             if(mAppConfigUtil.mAppConfigBean.isSMSRecycleProtectMode()) { | ||||
|                 viewHolder.mtvBody.setText("ProtectMode : " + UserVisionSystemProtectModeUtil.PreviewShuffleSMS(item.getBody(), mAppConfigUtil.mAppConfigBean.getProtectModerRefuseChars(), mAppConfigUtil.mAppConfigBean.getProtectModerReplaceChars())); | ||||
|             } else { | ||||
|                 viewHolder.mtvBody.setText(item.getBody()); | ||||
|             } | ||||
|             /*viewHolder.mTagsAdapter = new TagsAdapter(mContext, item); | ||||
|              RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(mContext); | ||||
|              viewHolder.mTagsRecyclerView.setLayoutManager(layoutManager); | ||||
|              viewHolder.mTagsRecyclerView.setAdapter(viewHolder.mTagsAdapter); | ||||
|              // 这个设置可以解决嵌套listvew的内部listview拉动问题。 | ||||
|              viewHolder.mTagsRecyclerView.setParentScrollView(viewHolder.mScrollView);*/ | ||||
|             viewHolder.mllMain.setOnLongClickListener(new View.OnLongClickListener() { | ||||
|                     @Override | ||||
|                     public boolean onLongClick(View p1) { | ||||
|                         // 弹出复制菜单 | ||||
|                         PopupMenu menu = new PopupMenu(mContext, viewHolder.mvMenu); | ||||
|                         //加载菜单资源 | ||||
|                         menu.getMenuInflater().inflate(R.menu.toolbar_item_smsrecycle, menu.getMenu()); | ||||
|                         menu.getMenuInflater().inflate(R.menu.toolbar_item_sms, menu.getMenu()); | ||||
|                         //设置点击事件的响应 | ||||
|                         menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { | ||||
|                                 @Override | ||||
|                                 public boolean onMenuItemClick(MenuItem menuItem) { | ||||
|                                     int nItemId = menuItem.getItemId(); | ||||
|                                     if (nItemId == R.id.item_restoresms) { | ||||
|                                         restoreSMSRecycleItem(position); | ||||
|                                     } else if (nItemId == R.id.copy) { | ||||
|                                         // Gets a handle to the clipboard service. | ||||
|                                         ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE); | ||||
|                                         // Creates a new text clip to put on the clipboard | ||||
|                                         ClipData clip = ClipData.newPlainText("simple text", item.getBody()); | ||||
|                                         // Set the clipboard's primary clip. | ||||
|                                         clipboard.setPrimaryClip(clip); | ||||
|                                         Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show(); | ||||
|                                     } else if (nItemId == R.id.delete) { | ||||
|                                         deleteSMSRecycleItem(position); | ||||
|                                         /*loadSMSRecycleList(); | ||||
|                                          mDataList.remove(item); | ||||
|                                          saveSMSRecycleList();*/ | ||||
|                                         notifyDataSetChanged(); | ||||
|                                     } else if (nItemId == R.id.addttsrule) { | ||||
|                                         Intent intent = new Intent(mContext, TTSPlayRuleActivity.class); | ||||
|                                         intent.putExtra(TTSPlayRuleActivity.EXTRA_TTSDEMOTEXT, viewHolder.mtvBody.getText().toString()); | ||||
|                                         mContext.startActivity(intent); | ||||
|                                     } else if (nItemId == R.id.testtts) { | ||||
|                                         //Toast.makeText(mContext, "Testing TTS.", Toast.LENGTH_SHORT).show(); | ||||
|                                         TTSPlayRuleUtil ttsPlayRuleUtil = TTSPlayRuleUtil.getInstance(mContext); | ||||
|                                         ttsPlayRuleUtil.speakTTSAnalyzeModeText(viewHolder.mtvBody.getText().toString()); | ||||
|                                     } | ||||
|  | ||||
|                                     return true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         //一定要调用show()来显示弹出式菜单 | ||||
|                         menu.show(); | ||||
|  | ||||
|                         return true; | ||||
|                     } | ||||
|                 }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return mDataList.size(); | ||||
|     } | ||||
|  | ||||
|     private static class SimpleViewHolder extends RecyclerView.ViewHolder { | ||||
|         TextView mtvAddress; | ||||
|         Button mbtnViewBody; | ||||
|  | ||||
|         SimpleViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             mtvAddress = itemView.findViewById(R.id.listviewsmsrecyclesimpleTextView1); | ||||
|             mbtnViewBody = itemView.findViewById(R.id.listviewsmsrecyclesimpleButton1); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class ComplexViewHolder extends RecyclerView.ViewHolder { | ||||
|         TextView mtvAddress; | ||||
|         DateAgoTextView mdatvDeleteDate; | ||||
|         SMSView mSMSView; | ||||
|         LinearLayout mllMain; | ||||
|         LinearLayout mllContent; | ||||
|         TextView mtvBody; | ||||
|         View mvMenu; | ||||
|         DateAgoTextView mdatvDate; | ||||
|         View mvLeft; | ||||
| 		View mvRight; | ||||
|  | ||||
|         ComplexViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             mtvAddress = itemView.findViewById(R.id.listviewsmsrecycleTextView1); | ||||
|             mdatvDeleteDate = itemView.findViewById(R.id.listviewsmsrecycleDateAgoTextView1); | ||||
|             mSMSView = itemView.findViewById(R.id.listviewsmsrecycleSMSView1); | ||||
|             mllMain = itemView.findViewById(R.id.listviewsmspart1LinearLayout1); | ||||
|             mllContent = itemView.findViewById(R.id.listviewsmspart1LinearLayout2); | ||||
|             mvMenu = itemView.findViewById(R.id.listviewsmsrecycleView1); | ||||
|             mtvBody = itemView.findViewById(R.id.listviewsmspart1TextView1); | ||||
|             mdatvDate = itemView.findViewById(R.id.listviewsmspart1DateAgoTextView1); | ||||
|             mvLeft = itemView.findViewById(R.id.listviewsmsrecycleView1); | ||||
|             mvRight = itemView.findViewById(R.id.listviewsmsrecycleView2); | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,193 @@ | ||||
| package cc.winboll.studio.mymessagemanager.adapters; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/18 16:08:20 | ||||
|  * @Describe TTSRuleBean RecyclerView Adapter | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.view.LayoutInflater; | ||||
| import android.view.MenuItem; | ||||
| import android.view.View; | ||||
| import android.view.ViewGroup; | ||||
| import android.widget.Button; | ||||
| import android.widget.CheckBox; | ||||
| import android.widget.LinearLayout; | ||||
| import android.widget.PopupMenu; | ||||
| import android.widget.TextView; | ||||
| import androidx.recyclerview.widget.RecyclerView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.TTSPlayRuleActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSPlayRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.TTSPlayRuleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.views.TTSRuleView; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class TTSRuleBeanRecyclerViewAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     public static final String TAG = "TTSRuleBeanRecyclerViewAdapter"; | ||||
|  | ||||
|     Context mContext; | ||||
|     ArrayList<TTSPlayRuleBean> mDataList; | ||||
|     OnTTSRuleChangeListener mOnTTSRuleChangeListener; | ||||
|     TTSPlayRuleUtil mTTSPlayRuleUtil; | ||||
|  | ||||
|     public TTSRuleBeanRecyclerViewAdapter(TTSPlayRuleActivity ttsPlayRuleActivity, OnTTSRuleChangeListener onTTSRuleChangeListener) { | ||||
|         mContext = ttsPlayRuleActivity; | ||||
|         mOnTTSRuleChangeListener = onTTSRuleChangeListener; | ||||
|  | ||||
|         mTTSPlayRuleUtil = TTSPlayRuleUtil.getInstance(ttsPlayRuleActivity); | ||||
|         mTTSPlayRuleUtil.initTTSPlayRuleActivity(ttsPlayRuleActivity); | ||||
| 		mDataList = mTTSPlayRuleUtil.loadConfigData(); | ||||
|     } | ||||
|  | ||||
|     public void addNewTTSRuleBean(TTSPlayRuleBean bean) { | ||||
|         mTTSPlayRuleUtil.addNewTTSRuleBean(bean); | ||||
|         //notifyDataSetChanged(); | ||||
| 	} | ||||
|  | ||||
|     public void saveConfigData() { | ||||
|         mTTSPlayRuleUtil.saveConfigData(); | ||||
|         //notifyDataSetChanged(); | ||||
| 	} | ||||
|  | ||||
|     public void reloadConfigData() { | ||||
|         mDataList = mTTSPlayRuleUtil.loadConfigData(); | ||||
|         notifyDataSetChanged(); | ||||
|     } | ||||
|  | ||||
|     public interface OnTTSRuleChangeListener { | ||||
|         abstract void onTTSRuleChange(TTSPlayRuleBean bean); | ||||
| 	} | ||||
|  | ||||
|     @Override | ||||
|     public int getItemViewType(int position) { | ||||
|         if (mDataList.get(position).isSimpleView()) { | ||||
|             return 0; | ||||
|         } else { | ||||
|             return 1; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { | ||||
|         if (viewType == 0) { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_ttsplayrule_simple, parent, false); | ||||
|             return new SimpleViewHolder(view); | ||||
|         } else { | ||||
|             View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listview_ttsplayrule, parent, false); | ||||
|             return new ComplexViewHolder(view); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onBindViewHolder(RecyclerView.ViewHolder holder, final int position) { | ||||
|         final TTSPlayRuleBean item = mDataList.get(position); | ||||
|         if (holder.getItemViewType() == 0) { | ||||
|             SimpleViewHolder viewHolder = (SimpleViewHolder) holder; | ||||
|             viewHolder.mSortNumber.setText(Integer.toString(position + 1)); | ||||
|             viewHolder.mtvDemoSMSText.setText(item.getDemoSMSText()); | ||||
|         } else { | ||||
|             final ComplexViewHolder viewHolder = (ComplexViewHolder) holder; | ||||
|             viewHolder.mSortNumber.setText(Integer.toString(position + 1)); | ||||
|             viewHolder.mtvDemoSMSText.setText(item.getDemoSMSText()); | ||||
|             viewHolder.mTTSRuleView.setOnClickListener(new View.OnClickListener(){ | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         mOnTTSRuleChangeListener.onTTSRuleChange(item); | ||||
|                     } | ||||
|                 }); | ||||
|             viewHolder.mbtnUp.setOnClickListener(new View.OnClickListener(){ | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         //Toast.makeText(mContext, Integer.toString(position), Toast.LENGTH_SHORT).show(); | ||||
|                         mTTSPlayRuleUtil.changeBeanPosition(position, true); | ||||
|                         //notifyDataSetChanged(); | ||||
|                     } | ||||
|                 }); | ||||
|             viewHolder.mbtnDown.setOnClickListener(new View.OnClickListener(){ | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         //Toast.makeText(mContext, Integer.toString(position), Toast.LENGTH_SHORT).show(); | ||||
|                         mTTSPlayRuleUtil.changeBeanPosition(position, false); | ||||
|                         //notifyDataSetChanged(); | ||||
|                     } | ||||
|                 }); | ||||
|             viewHolder.mchbEnable.setChecked(item.isEnable()); | ||||
|             viewHolder.mchbEnable.setOnClickListener(new View.OnClickListener(){ | ||||
|                     @Override | ||||
|                     public void onClick(View v) { | ||||
|                         mTTSPlayRuleUtil.setBeanEnable(position, ((CheckBox)v).isChecked()); | ||||
|                         //notifyDataSetChanged(); | ||||
|                     } | ||||
|                 }); | ||||
|             viewHolder.mTTSRuleView.setOnLongClickListener(new View.OnLongClickListener() { | ||||
|  | ||||
|                     @Override | ||||
|                     public boolean onLongClick(View p1) { | ||||
|                         // 弹出复制菜单 | ||||
|                         PopupMenu menu = new PopupMenu(mContext, viewHolder.mSortNumber); | ||||
|                         //加载菜单资源 | ||||
|                         menu.getMenuInflater().inflate(R.menu.toolbar_ttsrule, menu.getMenu()); | ||||
|                         //设置点击事件的响应 | ||||
|                         menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() { | ||||
|                                 @Override | ||||
|                                 public boolean onMenuItemClick(MenuItem menuItem) { | ||||
|                                     int nItemId = menuItem.getItemId(); | ||||
|                                     if (nItemId == R.id.deletettsrule) { | ||||
|                                         mTTSPlayRuleUtil.deleteTTSRuleBean(position); | ||||
|                                         //notifyDataSetChanged(); | ||||
|                                     } | ||||
|  | ||||
|                                     return true; | ||||
|                                 } | ||||
|                             }); | ||||
|                         //一定要调用show()来显示弹出式菜单 | ||||
|                         menu.show(); | ||||
|  | ||||
|                         return true; | ||||
|                     } | ||||
|                 }); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int getItemCount() { | ||||
|         return mDataList.size(); | ||||
|     } | ||||
|  | ||||
|     private static class SimpleViewHolder extends RecyclerView.ViewHolder { | ||||
|         TextView mSortNumber; | ||||
|         TextView mtvDemoSMSText; | ||||
|  | ||||
|  | ||||
|         SimpleViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             mSortNumber = itemView.findViewById(R.id.itemttsplayrulesimpleTextView2); | ||||
|             mtvDemoSMSText = itemView.findViewById(R.id.itemttsplayrulesimpleTextView1); | ||||
|  | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     private static class ComplexViewHolder extends RecyclerView.ViewHolder { | ||||
|         TextView mSortNumber; | ||||
|         TTSRuleView mTTSRuleView; | ||||
|         LinearLayout mllMain; | ||||
|         TextView mtvDemoSMSText; | ||||
|         Button mbtnUp; | ||||
|         Button mbtnDown; | ||||
|         CheckBox mchbEnable; | ||||
|  | ||||
|         ComplexViewHolder(View itemView) { | ||||
|             super(itemView); | ||||
|             mSortNumber = itemView.findViewById(R.id.itemttsplayruleTextView2); | ||||
|             mTTSRuleView = itemView.findViewById(R.id.listviewttsplayruleTTSRuleView1); | ||||
|             mllMain = itemView.findViewById(R.id.itemttsplayruleLinearLayout1); | ||||
|             mtvDemoSMSText = itemView.findViewById(R.id.itemttsplayruleTextView1); | ||||
|             mbtnUp = itemView.findViewById(R.id.itemttsplayruleButton1); | ||||
|             mbtnDown = itemView.findViewById(R.id.itemttsplayruleButton2); | ||||
|             mchbEnable = itemView.findViewById(R.id.itemttsplayruleCheckBox1); | ||||
|  | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,185 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/06/02 20:07:44 | ||||
|  * @Describe 应用配置数据类 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ThemeUtil; | ||||
| import cc.winboll.studio.shared.app.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class AppConfigBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "AppConfigBean"; | ||||
|  | ||||
|     // 当前国家代码(如+8612345678901代码就是86.) | ||||
|     String countryCode = "86"; | ||||
|     // 是否合并的手机号码前缀 | ||||
|     boolean isMergeCountryCodePrefix = true; | ||||
|     // TT语音延时播放毫秒数 | ||||
|     int ttsPlayDelayTimes = 3000; | ||||
|     boolean isEnableService = false; | ||||
|     boolean isEnableOnlyReceiveContacts = false; | ||||
|     boolean isEnableTTS = false; | ||||
|     boolean isEnableTTSRuleMode = false; | ||||
|     boolean isSMSRecycleProtectMode = false; | ||||
|     // 保护式预览拒绝显示的字符集 | ||||
|     String protectModerRefuseChars = "设定被和谐的字符"; | ||||
|     // 保护式预览拒绝显示的字符集的替代字符 | ||||
|     String protectModerReplaceChars = "当前替代显示字符"; | ||||
|     //int appThemeID = ThemeUtil.getThemeID(ThemeUtil.BaseTheme.DEFAULT); | ||||
|  | ||||
|     public void setProtectModerRefuseChars(String protectModerRefuseChars) { | ||||
|         this.protectModerRefuseChars = protectModerRefuseChars; | ||||
|     } | ||||
|  | ||||
|     public String getProtectModerRefuseChars() { | ||||
|         return protectModerRefuseChars; | ||||
|     } | ||||
|  | ||||
|     public void setProtectModerReplaceChars(String protectModerReplaceChars) { | ||||
|         this.protectModerReplaceChars = protectModerReplaceChars; | ||||
|     } | ||||
|  | ||||
|     public String getProtectModerReplaceChars() { | ||||
|         return protectModerReplaceChars; | ||||
|     } | ||||
|  | ||||
|     public void setIsSMSRecycleProtectMode(boolean isSMSRecycleProtectMode) { | ||||
|         this.isSMSRecycleProtectMode = isSMSRecycleProtectMode; | ||||
|     } | ||||
|  | ||||
|     public boolean isSMSRecycleProtectMode() { | ||||
|         return isSMSRecycleProtectMode; | ||||
|     } | ||||
|  | ||||
|     public void setCountryCode(String countryCode) { | ||||
|         this.countryCode = countryCode; | ||||
|     } | ||||
|  | ||||
|     public String getCountryCode() { | ||||
|         return countryCode; | ||||
|     } | ||||
|  | ||||
|     public void setIsMergeCountryCodePrefix(boolean isMergeCountryCodePrefix) { | ||||
|         this.isMergeCountryCodePrefix = isMergeCountryCodePrefix; | ||||
|     } | ||||
|  | ||||
|     public boolean isMergeCountryCodePrefix() { | ||||
|         return isMergeCountryCodePrefix; | ||||
|     } | ||||
|  | ||||
|     public void setTtsPlayDelayTimes(int ttsPlayDelayTimes) { | ||||
|         this.ttsPlayDelayTimes = ttsPlayDelayTimes; | ||||
|     } | ||||
|  | ||||
|     public int getTtsPlayDelayTimes() { | ||||
|         return ttsPlayDelayTimes; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnableService(boolean isEnableService) { | ||||
|         this.isEnableService = isEnableService; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableService() { | ||||
|         return isEnableService; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnableOnlyReceiveContacts(boolean isEnableOnlyReceiveContacts) { | ||||
|         this.isEnableOnlyReceiveContacts = isEnableOnlyReceiveContacts; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableOnlyReceiveContacts() { | ||||
|         return isEnableOnlyReceiveContacts; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnableTTS(boolean isEnableTTS) { | ||||
|         this.isEnableTTS = isEnableTTS; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableTTS() { | ||||
|         return isEnableTTS; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnableTTSRuleMode(boolean isEnableTTSRuleMode) { | ||||
|         this.isEnableTTSRuleMode = isEnableTTSRuleMode; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableTTSRuleMode() { | ||||
|         return isEnableTTSRuleMode; | ||||
|     } | ||||
|  | ||||
|     /*public void setAppThemeID(int appThemeID) { | ||||
|         this.appThemeID = appThemeID; | ||||
|     } | ||||
|  | ||||
|     public int getAppThemeID() { | ||||
|         return appThemeID; | ||||
|     } | ||||
|  | ||||
|     public void setAppTheme(ThemeUtil.BaseTheme baseTheme) { | ||||
|         setAppThemeID(ThemeUtil.getThemeID(baseTheme)); | ||||
|     }*/ | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return AppConfigBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         AppConfigBean bean = this; | ||||
|         jsonWriter.name("countryCode").value(bean.getCountryCode()); | ||||
|         jsonWriter.name("isMergeCountryCodePrefix").value(bean.isMergeCountryCodePrefix()); | ||||
|         jsonWriter.name("ttsPlayDelayTimes").value(bean.getTtsPlayDelayTimes()); | ||||
|         jsonWriter.name("isEnableService").value(bean.isEnableService()); | ||||
|         jsonWriter.name("isEnableOnlyReceiveContacts").value(bean.isEnableOnlyReceiveContacts()); | ||||
|         jsonWriter.name("isEnableTTS").value(bean.isEnableTTS()); | ||||
|         jsonWriter.name("isEnableTTSRuleMode").value(bean.isEnableTTSRuleMode()); | ||||
|         jsonWriter.name("isSMSRecycleProtectMode").value(bean.isSMSRecycleProtectMode()); | ||||
|         jsonWriter.name("protectModerRefuseChars").value(bean.getProtectModerRefuseChars()); | ||||
|         jsonWriter.name("protectModerReplaceChars").value(bean.getProtectModerReplaceChars()); | ||||
|         //jsonWriter.name("appThemeID").value(bean.getAppThemeID()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         AppConfigBean bean = new AppConfigBean(); | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (name.equals("countryCode")) { | ||||
|                 bean.setCountryCode(jsonReader.nextString()); | ||||
|             } else if (name.equals("isMergeCountryCodePrefix")) { | ||||
|                 bean.setIsMergeCountryCodePrefix(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("ttsPlayDelayTimes")) { | ||||
|                 bean.setTtsPlayDelayTimes(jsonReader.nextInt()); | ||||
|             } else if (name.equals("isEnableService")) { | ||||
|                 bean.setIsEnableService(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("isEnableOnlyReceiveContacts")) { | ||||
|                 bean.setIsEnableOnlyReceiveContacts(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("isEnableTTS")) { | ||||
|                 bean.setIsEnableTTS(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("isEnableTTSRuleMode")) { | ||||
|                 bean.setIsEnableTTSRuleMode(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("isSMSRecycleProtectMode")) { | ||||
|                 bean.setIsSMSRecycleProtectMode(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("protectModerRefuseChars")) { | ||||
|                 bean.setProtectModerRefuseChars(jsonReader.nextString()); | ||||
|             } else if (name.equals("protectModerReplaceChars")) { | ||||
|                 bean.setProtectModerReplaceChars(jsonReader.nextString()); | ||||
|             } /*else if (name.equals("appThemeID")) { | ||||
|                 bean.setAppThemeID(jsonReader.nextInt()); | ||||
|             }*/ else { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return bean; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,88 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2023/06/30 23:21:27 | ||||
|  * @Describe 应用配置数据类,V1 旧版。 | ||||
|  */ | ||||
| import cc.winboll.studio.mymessagemanager.utils.ThemeUtil; | ||||
|  | ||||
| public class AppConfigBean_V1 { | ||||
|  | ||||
|     // 当前国家代码(如+8612345678901代码就是86.) | ||||
|     String countryCode = "86"; | ||||
|     // 是否合并的手机号码前缀 | ||||
|     boolean isMergeCountryCodePrefix = true; | ||||
|     // TT语音延时播放毫秒数 | ||||
|     int ttsPlayDelayTimes = 3000; | ||||
|     boolean enableService = false; | ||||
|     boolean enableOnlyReceiveContacts = false; | ||||
|     boolean enableTTS = false; | ||||
|     boolean enableTTSRuleMode = false; | ||||
|     //int appThemeID = ThemeUtil.getThemeID(ThemeUtil.BaseTheme.DEFAULT); | ||||
|  | ||||
|     public void setCountryCode(String countryCode) { | ||||
|         this.countryCode = countryCode; | ||||
|     } | ||||
|  | ||||
|     public String getCountryCode() { | ||||
|         return countryCode; | ||||
|     } | ||||
|  | ||||
|     public void setIsMergeCountryCodePrefix(boolean isMergeCountryCodePrefix) { | ||||
|         this.isMergeCountryCodePrefix = isMergeCountryCodePrefix; | ||||
|     } | ||||
|  | ||||
|     public boolean isMergeCountryCodePrefix() { | ||||
|         return isMergeCountryCodePrefix; | ||||
|     } | ||||
|  | ||||
|     public void setTtsPlayDelayTimes(int ttsPlayDelayTimes) { | ||||
|         this.ttsPlayDelayTimes = ttsPlayDelayTimes; | ||||
|     } | ||||
|  | ||||
|     public int getTtsPlayDelayTimes() { | ||||
|         return ttsPlayDelayTimes; | ||||
|     } | ||||
|  | ||||
|     public void setEnableService(boolean enableService) { | ||||
|         this.enableService = enableService; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableService() { | ||||
|         return enableService; | ||||
|     } | ||||
|  | ||||
|     public void setEnableOnlyReceiveContacts(boolean enableOnlyReceiveContacts) { | ||||
|         this.enableOnlyReceiveContacts = enableOnlyReceiveContacts; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableOnlyReceiveContacts() { | ||||
|         return enableOnlyReceiveContacts; | ||||
|     } | ||||
|  | ||||
|     public void setEnableTTS(boolean enableTTS) { | ||||
|         this.enableTTS = enableTTS; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableTTS() { | ||||
|         return enableTTS; | ||||
|     } | ||||
|  | ||||
|     public void setEnableTTSRuleMode(boolean enableTTSRuleMode) { | ||||
|         this.enableTTSRuleMode = enableTTSRuleMode; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnableTTSRuleMode() { | ||||
|         return enableTTSRuleMode; | ||||
|     } | ||||
|  | ||||
|     /*public void setAppThemeID(int appThemeID) { | ||||
|         this.appThemeID = appThemeID; | ||||
|     } | ||||
|  | ||||
|     public int getAppThemeID() { | ||||
|         return appThemeID; | ||||
|     }*/ | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,29 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| public class ContractsBean { | ||||
|  | ||||
|     private String mszName; | ||||
|     private String mszTelPhone; | ||||
|  | ||||
|     public ContractsBean(String szName, String szTelPhone) { | ||||
|         this.mszName = szName; | ||||
|         this.mszTelPhone = szTelPhone; | ||||
|     } | ||||
|  | ||||
|     public void setName(String szName) { | ||||
|         this.mszName = szName; | ||||
|     } | ||||
|  | ||||
|     public String getName() { | ||||
|         return mszName; | ||||
|     } | ||||
|  | ||||
|     public void setTelPhone(String szTelPhone) { | ||||
|         this.mszTelPhone = szTelPhone; | ||||
|     } | ||||
|  | ||||
|     public String getTelPhone() { | ||||
|         return mszTelPhone; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,53 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 13:10:44 | ||||
|  * @Describe 短信通知栏消息结构 | ||||
|  */ | ||||
| public class MessageNotificationBean { | ||||
|  | ||||
|     private int messageId; | ||||
|     private String mszPhone; | ||||
|     private String mszTitle; | ||||
|     private String mszContent; | ||||
|  | ||||
|     public MessageNotificationBean(int messageId, String mszPhone, String mszTitle, String mszContent) { | ||||
|         this.messageId = messageId; | ||||
|         this.mszPhone = mszPhone; | ||||
|         this.mszTitle = mszTitle; | ||||
|         this.mszContent = mszContent; | ||||
|     } | ||||
|  | ||||
|     public void setMessageId(int messageId) { | ||||
|         this.messageId = messageId; | ||||
|     } | ||||
|  | ||||
|     public int getMessageId() { | ||||
|         return messageId; | ||||
|     } | ||||
|  | ||||
|     public void setPhone(String szPhone) { | ||||
|         this.mszPhone = szPhone; | ||||
|     } | ||||
|  | ||||
|     public String getPhone() { | ||||
|         return mszPhone; | ||||
|     } | ||||
|  | ||||
|     public void setTitle(String szTitle) { | ||||
|         this.mszTitle = szTitle; | ||||
|     } | ||||
|  | ||||
|     public String getTitle() { | ||||
|         return mszTitle; | ||||
|     } | ||||
|  | ||||
|     public void setContent(String szContent) { | ||||
|         this.mszContent = szContent; | ||||
|     } | ||||
|  | ||||
|     public String getContent() { | ||||
|         return mszContent; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,39 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 13:10:44 | ||||
|  * @Describe 联系人信息类 | ||||
|  */ | ||||
| public class PhoneBean { | ||||
|  | ||||
|     //联系人姓名 | ||||
|     private String mszName; | ||||
|     //电话号码 | ||||
|     private String mszTelPhone; | ||||
|  | ||||
|     public String getName() { | ||||
|         return mszName; | ||||
|     } | ||||
|  | ||||
|     public void setName(String szName) { | ||||
|         this.mszName = szName; | ||||
|     } | ||||
|  | ||||
|     public String getTelPhone() { | ||||
|         return mszTelPhone; | ||||
|     } | ||||
|  | ||||
|     public void setTelPhone(String szTelPhone) { | ||||
|         this.mszTelPhone = szTelPhone; | ||||
|     } | ||||
|  | ||||
|     public PhoneBean() { | ||||
|     } | ||||
|  | ||||
|     public PhoneBean(String szName, String szTelPhone) { | ||||
|         this.mszName = szName; | ||||
|         this.mszTelPhone = szTelPhone; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,121 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/30 10:57:14 | ||||
|  * @Describe 短信接收规则类 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.shared.app.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class SMSAcceptRuleBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "SMSAcceptRuleBean"; | ||||
|  | ||||
|     // 规则类型枚举 | ||||
|     public enum RuleType { ACCEPT, REFUSE, REGEXPPIUTILS_ISPPIOK_FALSE } | ||||
|      | ||||
|     // 用户ID | ||||
|     int userId = -1; | ||||
|     // 规则数据 | ||||
|     String ruleData = ""; | ||||
|     // 是否启用 | ||||
|     boolean isEnable = false; | ||||
|     // 规则类型 | ||||
|     RuleType ruleType = RuleType.REFUSE; | ||||
|     // 是否简单视图 | ||||
|     boolean isSimpleView = false; | ||||
|  | ||||
|     public SMSAcceptRuleBean() {} | ||||
|  | ||||
|     public SMSAcceptRuleBean(int userId, String ruleData, boolean isEnable, RuleType ruleType, boolean isSimpleView) { | ||||
|         this.userId = userId; | ||||
|         this.ruleData = ruleData; | ||||
|         this.isEnable = isEnable; | ||||
|         this.ruleType = ruleType; | ||||
|         this.isSimpleView = isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public void setRuleType(RuleType ruleType) { | ||||
|         this.ruleType = ruleType; | ||||
|     } | ||||
|  | ||||
|     public RuleType getRuleType() { | ||||
|         return ruleType; | ||||
|     } | ||||
|      | ||||
|     public void setIsSimpleView(boolean isSimpleView) { | ||||
|         this.isSimpleView = isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public boolean isSimpleView() { | ||||
|         return isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public void setUserId(int userID) { | ||||
|         this.userId = userID; | ||||
|     } | ||||
|  | ||||
|     public int getUserId() { | ||||
|         return userId; | ||||
|     } | ||||
|  | ||||
|     public void setRuleData(String ruleData) { | ||||
|         this.ruleData = ruleData; | ||||
|     } | ||||
|  | ||||
|     public String getRuleData() { | ||||
|         return ruleData; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SMSAcceptRuleBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         SMSAcceptRuleBean bean = this; | ||||
|         jsonWriter.name("userId").value(bean.getUserId()); | ||||
|         jsonWriter.name("ruleData").value(bean.getRuleData()); | ||||
|         jsonWriter.name("isEnable").value(bean.isEnable()); | ||||
|         jsonWriter.name("ruleType").value(bean.getRuleType().ordinal()); | ||||
|         jsonWriter.name("isSimpleView").value(bean.isSimpleView()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         SMSAcceptRuleBean bean = new SMSAcceptRuleBean(); | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (name.equals("userId")) { | ||||
|                 bean.setUserId(jsonReader.nextInt()); | ||||
|             } else if (name.equals("ruleData")) { | ||||
|                 bean.setRuleData(jsonReader.nextString()); | ||||
|             } else if (name.equals("isEnable")) { | ||||
|                 bean.setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("ruleType")) { | ||||
|                 bean.setRuleType(RuleType.values()[jsonReader.nextInt()]); | ||||
|             } else if (name.equals("isSimpleView")) { | ||||
|                 bean.setIsSimpleView(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return bean; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,50 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/30 10:57:14 | ||||
|  * @Describe 短信接收规则类,V1 旧版。 | ||||
|  */ | ||||
| public class SMSAcceptRuleBean_V1 { | ||||
|  | ||||
|     public static final String TAG = "SMSAcceptRuleBean_V1"; | ||||
|  | ||||
|     // 用户ID | ||||
|     String userID = ""; | ||||
|     // 规则数据 | ||||
|     String ruleData = ""; | ||||
|     // 是否启用 | ||||
|     boolean enable = false; | ||||
|  | ||||
|     public SMSAcceptRuleBean_V1() {} | ||||
|  | ||||
|     public SMSAcceptRuleBean_V1(String userID, String ruleData, boolean enable) { | ||||
|         this.userID = userID; | ||||
|         this.ruleData = ruleData; | ||||
|         this.enable = enable; | ||||
|     } | ||||
|  | ||||
|     public void setUserID(String userID) { | ||||
|         this.userID = userID; | ||||
|     } | ||||
|  | ||||
|     public String getUserID() { | ||||
|         return userID; | ||||
|     } | ||||
|  | ||||
|     public void setRuleData(String ruleData) { | ||||
|         this.ruleData = ruleData; | ||||
|     } | ||||
|  | ||||
|     public String getRuleData() { | ||||
|         return ruleData; | ||||
|     } | ||||
|  | ||||
|     public void setEnable(boolean enable) { | ||||
|         this.enable = enable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return enable; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,272 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/30 10:57:14 | ||||
|  * @Describe 短信信息类 | ||||
|  参考资料: | ||||
|  https://blog.csdn.net/freeking101/article/details/121575985 | ||||
|  | ||||
|  获取短信只需要得到 ContentResolver 就行了,它的 URI 主要有: | ||||
|  content://sms/          所有短信 | ||||
|  content://sms/inbox     收件箱 | ||||
|  content://sms/sent      已发送 | ||||
|  content://sms/draft     草稿 | ||||
|  content://sms/outbox    发件箱 | ||||
|  content://sms/failed    发送失败 | ||||
|  content://sms/queued    待发送列表 | ||||
|  SMS 数据库中的字段如下: | ||||
|  _id        一个自增字段,从1开始 | ||||
|  thread_id  序号,同一发信人的id相同 | ||||
|  address    发件人手机号码 | ||||
|  person     联系人列表里的序号,陌生人为null | ||||
|  date       发件日期 | ||||
|  protocol   协议,分为: 0 SMS_RPOTO, 1 MMS_PROTO | ||||
|  read       是否阅读 0未读, 1已读 | ||||
|  status     状态 -1接收,0 complete, 64 pending, 128 failed | ||||
|  type       ALL = 0;INBOX = 1;SENT = 2;DRAFT = 3;OUTBOX = 4;FAILED = 5; QUEUED = 6; | ||||
|  body       短信内容 | ||||
|  service_center 短信服务中心号码编号。如+8613800755500 | ||||
|  subject        短信的主题 | ||||
|  reply_path_present TP-Reply-Path | ||||
|  locked | ||||
|  */ | ||||
| import android.content.ContentValues; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.shared.app.BaseBean; | ||||
| import java.io.IOException; | ||||
| import java.text.Collator; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.Comparator; | ||||
|  | ||||
| public class SMSBean extends BaseBean { | ||||
|  | ||||
|     //public enum Type { ALL(8), INBOX(0), SENT, DRAFT, OUTBOX, FAILED, QUEUED, TRASH } | ||||
|     public enum Type { ALL(0), INBOX(1), SENT(2), DRAFT(3), OUTBOX(4), FAILED(5), QUEUED(6), TRASH(7); | ||||
|         static String[] _mlistName = { "所有短信", "接收", "发送", "草稿", "发件箱", "发送失败", "待发送列表", "回收站" }; | ||||
|         private int value = 0; | ||||
|         private Type(int value) {    //必须是private的,否则编译错误 | ||||
|             this.value = value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public enum ReadStatus { UNREAD, READ } | ||||
|  | ||||
|     transient private static String _ContentValuesName_address = "address"; | ||||
|     transient private static String _ContentValuesName_body = "body"; | ||||
|     transient private static String _ContentValuesName_read = "read"; | ||||
|     transient private static String _ContentValuesName_date = "date"; | ||||
|  | ||||
|     // 短信标识 | ||||
|     protected int id; | ||||
|     // 发件人手机号码 | ||||
|     protected String mszAddress; | ||||
|     // 短信内容 | ||||
|     protected String mszBody; | ||||
|     // 发件日期 | ||||
|     protected long mnDate; | ||||
|     // 短息归类 | ||||
|     protected Type mType; | ||||
|     // 是否阅读 | ||||
|     protected ReadStatus mReadStatus; | ||||
|     // 联系人列表里的序号,陌生人为null | ||||
|     protected int mnPerson; | ||||
|      | ||||
|     public SMSBean() { | ||||
|         this.id = -1; | ||||
|         this.mszAddress = ""; | ||||
|         this.mszBody = ""; | ||||
|         this.mnDate = 0; | ||||
|         this.mType = Type.INBOX; | ||||
|         this.mReadStatus = ReadStatus.UNREAD; | ||||
|         this.mnPerson = 0; | ||||
|     } | ||||
|      | ||||
|     public SMSBean(int id, String mszAddress, String mszBody, long mnDate, Type mType, ReadStatus mReadStatus, int mnPerson) { | ||||
|         this.id = id; | ||||
|         this.mszAddress = mszAddress; | ||||
|         this.mszBody = mszBody; | ||||
|         this.mnDate = mnDate; | ||||
|         this.mType = mType; | ||||
|         this.mReadStatus = mReadStatus; | ||||
|         this.mnPerson = mnPerson; | ||||
|     } | ||||
|  | ||||
|     public void setId(int id) { | ||||
|         this.id = id; | ||||
|     } | ||||
|  | ||||
|     public int getId() { | ||||
|         return id; | ||||
|     } | ||||
|  | ||||
|     public void setAddress(String szAddress) { | ||||
|         this.mszAddress = szAddress; | ||||
|     } | ||||
|  | ||||
|     public String getAddress() { | ||||
|         return mszAddress; | ||||
|     } | ||||
|  | ||||
|     public void setBody(String szBody) { | ||||
|         this.mszBody = szBody; | ||||
|     } | ||||
|  | ||||
|     public String getBody() { | ||||
|         return mszBody; | ||||
|     } | ||||
|  | ||||
|     public void setDate(long date) { | ||||
|         this.mnDate = date; | ||||
|     } | ||||
|  | ||||
|     public long getDate() { | ||||
|         return mnDate; | ||||
|     } | ||||
|  | ||||
|     public void setType(Type type) { | ||||
|         this.mType = type; | ||||
|     } | ||||
|  | ||||
|     public Type getType() { | ||||
|         return mType; | ||||
|     } | ||||
|  | ||||
|     public void setReadStatus(ReadStatus readStatus) { | ||||
|         this.mReadStatus = readStatus; | ||||
|     } | ||||
|  | ||||
|     public ReadStatus getReadStatus() { | ||||
|         return mReadStatus; | ||||
|     } | ||||
|  | ||||
|     public void setPerson(int person) { | ||||
|         this.mnPerson = person; | ||||
|     } | ||||
|  | ||||
|     public int getPerson() { | ||||
|         return mnPerson; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SMSBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         SMSBean bean = this; | ||||
|         jsonWriter.name("id").value(bean.getId()); | ||||
|         jsonWriter.name("mszAddress").value(bean.getAddress()); | ||||
|         jsonWriter.name("mszBody").value(bean.getBody()); | ||||
|         jsonWriter.name("mnDate").value(bean.getDate()); | ||||
|         jsonWriter.name("mType").value(bean.getType().ordinal()); | ||||
|         jsonWriter.name("mReadStatus").value(bean.getReadStatus().ordinal()); | ||||
|         jsonWriter.name("mnPerson").value(bean.getPerson()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if(super.initObjectsFromJsonReader(jsonReader, name)) { return true; } | ||||
|         else{ | ||||
|             if (name.equals("id")) { | ||||
|                 setId(jsonReader.nextInt()); | ||||
|             } else if (name.equals("mszAddress")) { | ||||
|                 setAddress(jsonReader.nextString()); | ||||
|             } else if (name.equals("mszBody")) { | ||||
|                 setBody(jsonReader.nextString()); | ||||
|             } else if (name.equals("mnDate")) { | ||||
|                 setDate(jsonReader.nextLong()); | ||||
|             } else if (name.equals("mType")) { | ||||
|                 setType(Type.values()[jsonReader.nextInt()]); | ||||
|             } else if (name.equals("mReadStatus")) { | ||||
|                 setReadStatus(ReadStatus.values()[jsonReader.nextInt()]); | ||||
|             } else if (name.equals("mnPerson")) { | ||||
|                 setPerson(jsonReader.nextInt()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if(!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
|      | ||||
|     public static ContentValues createOldSendedSMSContentValues(SMSBean smsBean) { | ||||
|         ContentValues result = new ContentValues(); | ||||
|         result.put(_ContentValuesName_address, smsBean.mszAddress); | ||||
|         result.put(_ContentValuesName_body, smsBean.mszBody); | ||||
|         result.put(_ContentValuesName_read, smsBean.mReadStatus.toString()); //"0" for have not read sms and "1" for have read sms | ||||
|         result.put(_ContentValuesName_date, Long.toString(smsBean.getDate())); | ||||
|  | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     public static ContentValues createSendedSMSContentValues(SMSBean smsBean) { | ||||
|         ContentValues result = new ContentValues(); | ||||
|         result.put(_ContentValuesName_address, smsBean.mszAddress); | ||||
|         result.put(_ContentValuesName_body, smsBean.mszBody); | ||||
|         result.put(_ContentValuesName_read, smsBean.mReadStatus.toString()); //"0" for have not read sms and "1" for have read sms | ||||
|         result.put(_ContentValuesName_date, Long.toString(System.currentTimeMillis())); | ||||
|  | ||||
|         return result; | ||||
|     } | ||||
|  | ||||
|     public static String getTypeName(Type type) { | ||||
|         return Type._mlistName[type.ordinal()]; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         String szResult = "\n"; | ||||
|         szResult += "mszAddress is (" + mszAddress + ")\n"; | ||||
|         szResult += "mszBody is (" + mszBody + ")\n"; | ||||
|         szResult += "mnDate is (" + Long.toString(mnDate) + ")\n"; | ||||
|         szResult += "mType is (" + mType.name() + ")\n"; | ||||
|         if (mReadStatus != null) { | ||||
|             szResult += "mReadStatus is (" + mReadStatus.name() + ")\n"; | ||||
|         } | ||||
|         szResult += "mnPerson is (" + Integer.toString(mnPerson) + ")\n"; | ||||
|  | ||||
|  | ||||
|         return szResult; | ||||
|     } | ||||
|  | ||||
|     public static void sortSMSByDateDesc(ArrayList<SMSBean> list, boolean isDesc) { | ||||
|         Collections.sort(list, new SortSMSByDateDesc(isDesc)); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private static class SortSMSByDateDesc implements Comparator<SMSBean> { | ||||
|         private boolean mIsDesc = true; | ||||
|         // isDesc 是否降序排列 | ||||
|         public SortSMSByDateDesc(boolean isDesc) { | ||||
|             mIsDesc = isDesc; | ||||
|         } | ||||
|         Collator cmp = Collator.getInstance(java.util.Locale.CHINA); | ||||
|         @Override | ||||
|         public int compare(SMSBean o1, SMSBean o2) { | ||||
|             boolean b0_1 = (o1.getDate() < o2.getDate()); | ||||
|             if (mIsDesc) { | ||||
|                 return b0_1 ?1: -1; | ||||
|             } else { | ||||
|                 return b0_1 ?-1: 1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,127 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/20 01:51:44 | ||||
|  * @Describe 回收站短信存储类 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.shared.app.BaseBean; | ||||
| import java.io.IOException; | ||||
| import java.text.Collator; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.Comparator; | ||||
|  | ||||
| public class SMSRecycleBean extends SMSBean { | ||||
|  | ||||
|     public static final String TAG = "SMSRecycleBean"; | ||||
|  | ||||
|     // 短信删除日期 | ||||
|     long deleteDate; | ||||
|     // 当前是否是简单视图 | ||||
|     boolean isSimpleView; | ||||
|  | ||||
|     public void setDeleteDate(long deleteDate) { | ||||
|         this.deleteDate = deleteDate; | ||||
|     } | ||||
|  | ||||
|     public long getDeleteDate() { | ||||
|         return deleteDate; | ||||
|     } | ||||
|  | ||||
|     public void setIsSimpleView(boolean isSimpleView) { | ||||
|         this.isSimpleView = isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public boolean isSimpleView() { | ||||
|         return isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public SMSRecycleBean() { | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public SMSRecycleBean(SMSBean smsBean, long deleteDate) { | ||||
|         super.id = smsBean.getId(); | ||||
|         super.mszAddress = smsBean.getAddress(); | ||||
|         super.mszBody = smsBean.getBody(); | ||||
|         super.mnDate = smsBean.getDate(); | ||||
|         super.mType = smsBean.getType(); | ||||
|         super.mReadStatus = smsBean.getReadStatus(); | ||||
|         super.mnPerson = smsBean.getPerson(); | ||||
|         this.deleteDate = deleteDate; | ||||
|         this.isSimpleView = true; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return SMSRecycleBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         SMSRecycleBean bean = this; | ||||
|         jsonWriter.name("deleteDate").value(bean.getDeleteDate()); | ||||
|         jsonWriter.name("isSimpleView").value(bean.isSimpleView()); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         /*SMSRecycleBean bean = new SMSRecycleBean((SMSBean)super.readBeanFromJsonReader(jsonReader), 0); | ||||
|          // 只有在读取完成后,才能获取整个JSON字符串 | ||||
|          String completeJson = jsonReader.toString(); | ||||
|          JsonReader newJsonReader = new JsonReader(new StringReader(completeJson)); | ||||
|          newJsonReader.setLenient(true); | ||||
|          LogUtils.d(TAG, completeJson);*/ | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (!initObjectsFromJsonReader(jsonReader, name)) { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return this; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { | ||||
|         if(super.initObjectsFromJsonReader(jsonReader, name)) { return true; } | ||||
|         else{ | ||||
|             if (name.equals("deleteDate")) { | ||||
|                 setDeleteDate(jsonReader.nextLong()); | ||||
|             } else if (name.equals("isSimpleView")) { | ||||
|                 setIsSimpleView(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 return false; | ||||
|             } | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public static void sortSMSByDeleteDateDesc(ArrayList<SMSRecycleBean> list, boolean isDesc) { | ||||
|         Collections.sort(list, new SortSMSByDeleteDateDesc(isDesc)); | ||||
|     } | ||||
|  | ||||
|     private static class SortSMSByDeleteDateDesc implements Comparator<SMSRecycleBean> { | ||||
|         private boolean mIsDesc = true; | ||||
|         // isDesc 是否降序排列 | ||||
|         public SortSMSByDeleteDateDesc(boolean isDesc) { | ||||
|             mIsDesc = isDesc; | ||||
|         } | ||||
|         Collator cmp = Collator.getInstance(java.util.Locale.CHINA); | ||||
|         @Override | ||||
|         public int compare(SMSRecycleBean o1, SMSRecycleBean o2) { | ||||
|             boolean b0_1 = (o1.getDeleteDate() < o2.getDeleteDate()); | ||||
|             if (mIsDesc) { | ||||
|                 return b0_1 ?1: -1; | ||||
|             } else { | ||||
|                 return b0_1 ?-1: 1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,147 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/28 20:22:12 | ||||
|  * @Describe TTS 语音播放规则类 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.shared.app.BaseBean; | ||||
| import java.io.IOException; | ||||
|  | ||||
| public class TTSPlayRuleBean extends BaseBean { | ||||
|  | ||||
|     public static final String TAG = "TTSPlayRuleBean"; | ||||
|  | ||||
|     // 用户ID | ||||
|     int userId = -1; | ||||
|     // TTS语音规则名称 | ||||
|     String ruleName = ""; | ||||
|     // 短信测试文本 | ||||
|     String demoSMSText = ""; | ||||
|     // 短信内容查询正则文本 | ||||
|     String patternText = ""; | ||||
|     // TTS语音播报正则文本 | ||||
|     String ttsRuleText = ""; | ||||
|     // 是否启用简单视图 | ||||
|     boolean isSimpleView = false; | ||||
|     // 是否启用规则 | ||||
|     boolean isEnable = false; | ||||
|  | ||||
|     public TTSPlayRuleBean() {} | ||||
|  | ||||
|     public TTSPlayRuleBean(int userId, String ruleName, String demoSMSText, String patternText, String ttsRuleText, boolean isSimpleView, boolean isEnable) { | ||||
|         this.userId = userId; | ||||
|         this.ruleName = ruleName; | ||||
|         this.demoSMSText = demoSMSText; | ||||
|         this.patternText = patternText; | ||||
|         this.ttsRuleText = ttsRuleText; | ||||
|         this.isSimpleView = isSimpleView; | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public void setUserId(int userId) { | ||||
|         this.userId = userId; | ||||
|     } | ||||
|  | ||||
|     public int getUserId() { | ||||
|         return userId; | ||||
|     } | ||||
|  | ||||
|     public void setRuleName(String ruleName) { | ||||
|         this.ruleName = ruleName; | ||||
|     } | ||||
|  | ||||
|     public String getRuleName() { | ||||
|         return ruleName; | ||||
|     } | ||||
|  | ||||
|     public void setDemoSMSText(String demoSMSText) { | ||||
|         this.demoSMSText = demoSMSText; | ||||
|     } | ||||
|  | ||||
|     public String getDemoSMSText() { | ||||
|         return demoSMSText; | ||||
|     } | ||||
|  | ||||
|     public void setPatternText(String patternText) { | ||||
|         this.patternText = patternText; | ||||
|     } | ||||
|  | ||||
|     public String getPatternText() { | ||||
|         return patternText; | ||||
|     } | ||||
|  | ||||
|     public void setTtsRuleText(String ttsRuleText) { | ||||
|         this.ttsRuleText = ttsRuleText; | ||||
|     } | ||||
|  | ||||
|     public String getTtsRuleText() { | ||||
|         return ttsRuleText; | ||||
|     } | ||||
|  | ||||
|     public void setIsSimpleView(boolean isSimpleView) { | ||||
|         this.isSimpleView = isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public boolean isSimpleView() { | ||||
|         return isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|      | ||||
|  | ||||
|     @Override | ||||
|     public String getName() { | ||||
|         return TTSPlayRuleBean.class.getName(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { | ||||
|         super.writeThisToJsonWriter(jsonWriter); | ||||
|         TTSPlayRuleBean bean = this; | ||||
|         jsonWriter.name("userId").value(bean.userId); | ||||
|         jsonWriter.name("ruleName").value(bean.ruleName); | ||||
|         jsonWriter.name("demoSMSText").value(bean.demoSMSText); | ||||
|         jsonWriter.name("patternText").value(bean.patternText); | ||||
|         jsonWriter.name("ttdRuleText").value(bean.ttsRuleText); | ||||
|         jsonWriter.name("isSimpleView").value(bean.isSimpleView); | ||||
|         jsonWriter.name("isEnable").value(bean.isEnable); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { | ||||
|         TTSPlayRuleBean bean = new TTSPlayRuleBean(); | ||||
|         jsonReader.beginObject(); | ||||
|         while (jsonReader.hasNext()) { | ||||
|             String name = jsonReader.nextName(); | ||||
|             if (name.equals("userId")) { | ||||
|                 bean.setUserId(jsonReader.nextInt()); | ||||
|             } else if (name.equals("ruleName")) { | ||||
|                 bean.setRuleName(jsonReader.nextString()); | ||||
|             } else if (name.equals("demoSMSText")) { | ||||
|                 bean.setDemoSMSText(jsonReader.nextString()); | ||||
|             } else if (name.equals("patternText")) { | ||||
|                 bean.setPatternText(jsonReader.nextString()); | ||||
|             } else if (name.equals("ttdRuleText")) { | ||||
|                 bean.setTtsRuleText(jsonReader.nextString()); | ||||
|             } else if (name.equals("isSimpleView")) { | ||||
|                 bean.setIsSimpleView(jsonReader.nextBoolean()); | ||||
|             } else if (name.equals("isEnable")) { | ||||
|                 bean.setIsEnable(jsonReader.nextBoolean()); | ||||
|             } else { | ||||
|                 jsonReader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         // 结束 JSON 对象 | ||||
|         jsonReader.endObject(); | ||||
|         return bean; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,281 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/28 20:22:12 | ||||
|  * @Describe TTS 语音播放规则类,V1 旧版。 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.JsonReader; | ||||
| import android.util.JsonWriter; | ||||
| import cc.winboll.studio.mymessagemanager.utils.FileUtil; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import java.io.IOException; | ||||
| import java.io.StringReader; | ||||
| import java.io.StringWriter; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class TTSPlayRuleBean_V1 { | ||||
|  | ||||
|     public static final String TAG = "TTSPlayRuleBean2"; | ||||
|  | ||||
|     // 用户ID | ||||
|     int userId = -1; | ||||
|     // TTS语音规则名称 | ||||
| 	String ruleName = ""; | ||||
|     // 短信测试文本 | ||||
| 	String demoSMSText = ""; | ||||
|     // 短信内容查询正则文本 | ||||
| 	String patternText = ""; | ||||
|     // TTS语音播报正则文本 | ||||
| 	String ttsRuleText = ""; | ||||
|     // 是否启用简单视图 | ||||
|     boolean isSimpleView = false; | ||||
|     // 是否启用规则 | ||||
|     boolean isEnable = false; | ||||
|  | ||||
|     public TTSPlayRuleBean_V1(int userId, String ruleName, String demoSMSText, String patternText, String ttsRuleText, boolean isSimpleView, boolean isEnable) { | ||||
|         this.userId = userId; | ||||
|         this.ruleName = ruleName; | ||||
|         this.demoSMSText = demoSMSText; | ||||
|         this.patternText = patternText; | ||||
|         this.ttsRuleText = ttsRuleText; | ||||
|         this.isSimpleView = isSimpleView; | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public TTSPlayRuleBean_V1() {} | ||||
|  | ||||
|     public void setRuleName(String ruleName) { | ||||
|         this.ruleName = ruleName; | ||||
|     } | ||||
|  | ||||
|     public String getRuleName() { | ||||
|         return ruleName; | ||||
|     } | ||||
|  | ||||
|     public void setUserId(int userId) { | ||||
|         this.userId = userId; | ||||
|     } | ||||
|  | ||||
|     public int getUserId() { | ||||
|         return userId; | ||||
|     } | ||||
|  | ||||
|     public void setDemoSMSText(String demoSMSText) { | ||||
|         this.demoSMSText = demoSMSText; | ||||
|     } | ||||
|  | ||||
|     public String getDemoSMSText() { | ||||
|         return demoSMSText; | ||||
|     } | ||||
|  | ||||
|     public void setPatternText(String patternText) { | ||||
|         this.patternText = patternText; | ||||
|     } | ||||
|  | ||||
|     public String getPatternText() { | ||||
|         return patternText; | ||||
|     } | ||||
|  | ||||
|     public void setTtsRuleText(String ttsRuleText) { | ||||
|         this.ttsRuleText = ttsRuleText; | ||||
|     } | ||||
|  | ||||
|     public String getTtsRuleText() { | ||||
|         return ttsRuleText; | ||||
|     } | ||||
|  | ||||
|     public void setIsSimpleView(boolean isSimpleView) { | ||||
|         this.isSimpleView = isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public boolean isSimpleView() { | ||||
|         return isSimpleView; | ||||
|     } | ||||
|  | ||||
|     public void setIsEnable(boolean isEnable) { | ||||
|         this.isEnable = isEnable; | ||||
|     } | ||||
|  | ||||
|     public boolean isEnable() { | ||||
|         return isEnable; | ||||
|     } | ||||
|  | ||||
|     static String getBeanJsonFilePath(Context context) { | ||||
|         return context.getExternalFilesDir(TAG) + "/" + TAG + ".json"; | ||||
|     } | ||||
|  | ||||
|     static String getBeanListJsonFilePath(Context context) { | ||||
|         return context.getExternalFilesDir(TAG) + "/" + TAG + "_List.json"; | ||||
|     } | ||||
|  | ||||
|     static void writeBean(JsonWriter writer, TTSPlayRuleBean_V1 bean) throws IOException { | ||||
|         // 开始 JSON 对象 | ||||
|         writer.beginObject(); | ||||
|         // 写入键值对 | ||||
|         writer.name("userId").value(bean.userId); | ||||
|         writer.name("ruleName").value(bean.ruleName); | ||||
|         writer.name("demoSMSText").value(bean.demoSMSText); | ||||
|         writer.name("patternText").value(bean.patternText); | ||||
|         writer.name("ttdRuleText").value(bean.ttsRuleText); | ||||
|         writer.name("isSimpleView").value(bean.isSimpleView); | ||||
|         writer.name("isEnable").value(bean.isEnable); | ||||
|         // 结束 JSON 对象 | ||||
|         writer.endObject(); | ||||
|     } | ||||
|  | ||||
|     static TTSPlayRuleBean_V1 parseBean(JsonReader jsonReader) { | ||||
|         try { | ||||
|             TTSPlayRuleBean_V1 bean = new TTSPlayRuleBean_V1(); | ||||
|             // 开始 JSON 对象 | ||||
|             jsonReader.beginObject(); | ||||
|             // 写入键值对 | ||||
|             while (jsonReader.hasNext()) { | ||||
|                 String name = jsonReader.nextName(); | ||||
|                 if (name.equals("ruleName")) { | ||||
|                     bean.setRuleName(jsonReader.nextString()); | ||||
|                 } else if (name.equals("userId")) { | ||||
|                     bean.setUserId(jsonReader.nextInt()); | ||||
|                 } else if (name.equals("demoSMSText")) { | ||||
|                     bean.setDemoSMSText(jsonReader.nextString()); | ||||
|                 } else if (name.equals("patternText")) { | ||||
|                     bean.setPatternText(jsonReader.nextString()); | ||||
|                 } else if (name.equals("ttdRuleText")) { | ||||
|                     bean.setTtsRuleText(jsonReader.nextString()); | ||||
|                 } else if (name.equals("isSimpleView")) { | ||||
|                     bean.setIsSimpleView(jsonReader.nextBoolean()); | ||||
|                 } else if (name.equals("isEnable")) { | ||||
|                     bean.setIsEnable(jsonReader.nextBoolean()); | ||||
|                 } else { | ||||
|                     jsonReader.skipValue(); | ||||
|                 } | ||||
|             } | ||||
|             // 结束 JSON 对象 | ||||
|             jsonReader.endObject(); | ||||
|             return bean; | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     static ArrayList<TTSPlayRuleBean_V1> parseBeanList(String beanList) { | ||||
|         try { | ||||
|             StringReader stringReader = new StringReader(beanList); | ||||
|             JsonReader jsonReader = new JsonReader(stringReader); | ||||
|             ArrayList<TTSPlayRuleBean_V1> list = new ArrayList<TTSPlayRuleBean_V1>(); | ||||
|             jsonReader.beginArray(); | ||||
|             while (jsonReader.hasNext()) { | ||||
|                 TTSPlayRuleBean_V1 bean = parseBean(jsonReader); | ||||
|                 if (bean != null) { | ||||
|                     list.add(bean); | ||||
|                 } | ||||
|             } | ||||
|             jsonReader.endArray(); | ||||
|             return list; | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public String toString() { | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringWriter stringWriter = new StringWriter(); | ||||
|         JsonWriter jsonWriter = new JsonWriter(stringWriter); | ||||
|         jsonWriter.setIndent("  "); | ||||
|         try { | ||||
|             writeBean(jsonWriter, this); | ||||
|             return stringWriter.toString(); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         // 获取 JSON 字符串 | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static String toStringByBeanList(ArrayList<TTSPlayRuleBean_V1> beanList) { | ||||
|         try { | ||||
|             StringWriter stringWriter = new StringWriter(); | ||||
|             JsonWriter writer = new JsonWriter(stringWriter); | ||||
|             writer.setIndent("  "); | ||||
|             writer.beginArray(); | ||||
|             for (TTSPlayRuleBean_V1 bean : beanList) { | ||||
|                 writeBean(writer, bean); | ||||
|             } | ||||
|             writer.endArray(); | ||||
|             writer.close(); | ||||
|             return stringWriter.toString(); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return ""; | ||||
|     } | ||||
|  | ||||
|     public static TTSPlayRuleBean_V1 parseBean(String szBean) { | ||||
|         // 创建 JsonWriter 对象 | ||||
|         StringReader stringReader = new StringReader(szBean); | ||||
|         JsonReader jsonReader = new JsonReader(stringReader); | ||||
|         return parseBean(jsonReader); | ||||
|     } | ||||
|  | ||||
|     /*public static TTSPlayRuleBean_V1 loadBean(Context context) { | ||||
|         return loadBeanFromFile(getBeanJsonFilePath(context)); | ||||
|     } | ||||
|  | ||||
|     public static TTSPlayRuleBean_V1 loadBeanFromFile(String szFilePath) { | ||||
|         TTSPlayRuleBean_V1 bean = null; | ||||
|         try { | ||||
|             String szJson = FileUtil.readFile(szFilePath); | ||||
|             bean = TTSPlayRuleBean_V1.parseBean(szJson); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return bean; | ||||
|     } | ||||
|  | ||||
|     public static void saveBean(Context context, TTSPlayRuleBean_V1 bean) { | ||||
|         saveBeanToFile(getBeanJsonFilePath(context), bean); | ||||
|     } | ||||
|  | ||||
|     public static void saveBeanToFile(String szFilePath, TTSPlayRuleBean_V1 bean) { | ||||
|         try { | ||||
|             String szJson = bean.toString(); | ||||
|             FileUtil.writeFile(szFilePath, szJson); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static ArrayList<TTSPlayRuleBean_V1> loadBeanList(Context context) { | ||||
|         return loadBeanListFromFile(getBeanListJsonFilePath(context)); | ||||
|     }*/ | ||||
|  | ||||
|     public static ArrayList<TTSPlayRuleBean_V1> loadBeanListFromFile(String szFilePath) { | ||||
|         ArrayList<TTSPlayRuleBean_V1> beanList = null; | ||||
|         try { | ||||
|             String szListJson = FileUtil.readFile(szFilePath); | ||||
|             beanList = TTSPlayRuleBean_V1.parseBeanList(szListJson); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return beanList; | ||||
|     } | ||||
|  | ||||
|     /*public static boolean saveBeanList(Context context, ArrayList<TTSPlayRuleBean_V1> beanList) { | ||||
|         return saveBeanListToFile(getBeanListJsonFilePath(context), beanList); | ||||
|     } | ||||
|  | ||||
|     public static boolean saveBeanListToFile(String szFilePath, ArrayList<TTSPlayRuleBean_V1> beanList) { | ||||
|         try { | ||||
|             String szJson = TTSPlayRuleBean_V1.toStringByBeanList(beanList); | ||||
|             FileUtil.writeFile(szFilePath, szJson); | ||||
|             return true; | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return false; | ||||
|     }*/ | ||||
| } | ||||
| @@ -0,0 +1,24 @@ | ||||
| package cc.winboll.studio.mymessagemanager.beans; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/28 20:22:12 | ||||
|  * @Describe TTS 语音播放文本内容类 | ||||
|  */ | ||||
| import java.io.Serializable; | ||||
|  | ||||
| public class TTSSpeakTextBean implements Serializable { | ||||
|  | ||||
|     transient public static final String TAG = "TTSSpeakTextBean"; | ||||
|  | ||||
|     // 延迟播放 | ||||
|     public int mnDelay = 0; | ||||
|     // 语音播放内容 | ||||
|     public String mszSpeakContent = ""; | ||||
|  | ||||
|     public TTSSpeakTextBean(int nDelay, String szSpeakContent) { | ||||
|         this.mnDelay = nDelay; | ||||
|         this.mszSpeakContent = szSpeakContent; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,59 @@ | ||||
| package cc.winboll.studio.mymessagemanager.dialogs; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/30 09:53:26 | ||||
|  * @Describe 用户确定与否选择框 | ||||
|  */ | ||||
| import android.app.AlertDialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
|  | ||||
| public class YesNoAlertDialog { | ||||
|  | ||||
|     public static final String TAG = "YesNoAlertDialog"; | ||||
|  | ||||
|     public static void show(Context context, String szTitle, String szMessage, final OnDialogResultListener listener) { | ||||
|         AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder( | ||||
|             context); | ||||
|  | ||||
|         // set title | ||||
|         alertDialogBuilder.setTitle(szTitle); | ||||
|  | ||||
|         // set dialog message | ||||
|         alertDialogBuilder | ||||
|             .setMessage(szMessage) | ||||
|             .setCancelable(true) | ||||
|             .setOnCancelListener(new DialogInterface.OnCancelListener(){ | ||||
|                 @Override | ||||
|                 public void onCancel(DialogInterface dialog) { | ||||
|                     listener.onNo(); | ||||
|                 } | ||||
|             }) | ||||
|             .setPositiveButton("YES", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     // if this button is clicked, close | ||||
|                     // current activity | ||||
|                     listener.onYes(); | ||||
|                 } | ||||
|             }) | ||||
|             .setNegativeButton("NO", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     // if this button is clicked, just close | ||||
|                     // the dialog box and do nothing | ||||
|                     dialog.cancel(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         // create alert dialog | ||||
|         AlertDialog alertDialog = alertDialogBuilder.create(); | ||||
|  | ||||
|         // show it | ||||
|         alertDialog.show(); | ||||
|     } | ||||
|  | ||||
|     public interface OnDialogResultListener { | ||||
|         abstract void onYes(); | ||||
|         abstract void onNo(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,43 @@ | ||||
| package cc.winboll.studio.mymessagemanager.receivers; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/28 20:22:12 | ||||
|  * @Describe 在文件 AndroidManifest.xml 注册监听的广播接收类, | ||||
|  *           用于接收系统启动完毕的广播消息。 | ||||
|  */ | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Build; | ||||
| import cc.winboll.studio.mymessagemanager.services.MainService; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| public class MainReceiver extends BroadcastReceiver { | ||||
|  | ||||
|     public static String TAG = "ManagerReceiver"; | ||||
|  | ||||
|     static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; | ||||
|  | ||||
|     AppConfigUtil mConfigUtil; | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|         String szAction = intent.getAction(); | ||||
|         if (szAction.equals(ACTION_BOOT_COMPLETED)) { | ||||
|             mConfigUtil = AppConfigUtil.getInstance(context); | ||||
|             if (mConfigUtil.mAppConfigBean.isEnableService()) { | ||||
|                 Intent intentService = new Intent(context, MainService.class); | ||||
|                 if (Build.VERSION.SDK_INT >= 26) { | ||||
|                     context.startForegroundService(intentService); | ||||
|                 } else { | ||||
|                     context.startService(intentService); | ||||
|                 } | ||||
|                 LogUtils.i(TAG, "System Boot And Start ManagerService Completed!"); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,94 @@ | ||||
| package cc.winboll.studio.mymessagemanager.receivers; | ||||
|  | ||||
| import android.content.BroadcastReceiver; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import androidx.localbroadcastmanager.content.LocalBroadcastManager; | ||||
| import cc.winboll.studio.mymessagemanager.GlobalApplication; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.SMSActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.NotificationUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.PhoneUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSReceiveRuleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSRecycleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.SMSUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.TTSPlayRuleUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.RegexPPiUtils; | ||||
|  | ||||
| public class SMSRecevier extends BroadcastReceiver { | ||||
|  | ||||
|     public static String TAG = "SMSRecevier"; | ||||
|  | ||||
|     public static String ACTION_SMS_RECEIVED = "android.provider.Telephony.SMS_RECEIVED"; | ||||
|  | ||||
|     public SMSRecevier() { | ||||
|         super(); | ||||
|         //LogUtils.d(TAG, "SMSRecevier()"); | ||||
|     } | ||||
|  | ||||
|     /*public void init(ManagerService.SMSListener smsListener) { | ||||
|      mSMSListener = smsListener; | ||||
|      }*/ | ||||
|  | ||||
|     @Override | ||||
|     public void onReceive(Context context, Intent intent) { | ||||
|  | ||||
|         String szAction = intent.getAction(); | ||||
|         if (szAction.equals(ACTION_SMS_RECEIVED)) { | ||||
|             //LogUtils.d(TAG, "ACTION_SMS_RECEIVED"); | ||||
|             String szSmsBody = SMSUtil.getSmsBody(intent); | ||||
|             String szSmsAddress = SMSUtil.getSmsAddress(intent); | ||||
|             PhoneUtil phoneUtil = new PhoneUtil(context); | ||||
|             boolean isPhoneInContacts = phoneUtil.isPhoneInContacts(szSmsAddress); | ||||
|             AppConfigUtil configUtil = AppConfigUtil.getInstance(context); | ||||
|             boolean isOnlyReceiveContacts = configUtil.mAppConfigBean.isEnableOnlyReceiveContacts(); | ||||
|             boolean isEnableTTS = configUtil.mAppConfigBean.isEnableTTS(); | ||||
|             boolean isEnableTTSAnalyzeMode = configUtil.mAppConfigBean.isEnableTTSRuleMode(); | ||||
|             boolean isInSMSAcceptRule = SMSReceiveRuleUtil.getInstance(context, false).checkIsSMSAcceptInRule(context, szSmsBody); | ||||
|             //LogUtils.d(TAG, "isInSMSAcceptRule is : " + Boolean.toString(isInSMSAcceptRule)); | ||||
|  | ||||
|             if (!isPhoneInContacts) { | ||||
|                 GlobalApplication.showApplicationMessage(" The phone number " + szSmsAddress + " is not in contacts."); | ||||
|                 if (isOnlyReceiveContacts) { | ||||
|                     GlobalApplication.showApplicationMessage("Close the \"Only Receive Contacts\" switch will be receive The " + szSmsAddress + "'s message in future."); | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|             if ((!isOnlyReceiveContacts) | ||||
|                 || isPhoneInContacts | ||||
|                 || isInSMSAcceptRule) { | ||||
|                 int nResultId = SMSUtil.saveReceiveSms(context, szSmsAddress, szSmsBody, "0", System.currentTimeMillis(), "inbox"); | ||||
|                 if (nResultId >= 0) { | ||||
|                     NotificationUtil nu = new NotificationUtil(); | ||||
|                     nu.sendSMSReceivedMessage(context, nResultId, szSmsAddress, szSmsBody); | ||||
|                     LocalBroadcastManager.getInstance(context).sendBroadcast(new Intent(SMSActivity.ACTION_NOTIFY_SMS_CHANGED)); | ||||
|                     GlobalApplication.showApplicationMessage("<" + szSmsAddress + "> : ( " + szSmsBody + " ) [SAVED]"); | ||||
|                     if (isEnableTTS) { | ||||
|                         if (isEnableTTSAnalyzeMode) { | ||||
|                             TTSPlayRuleUtil ttsPlayRuleUtil = TTSPlayRuleUtil.getInstance(context); | ||||
|                             ttsPlayRuleUtil.speakTTSAnalyzeModeText(szSmsBody, configUtil.mAppConfigBean.getTtsPlayDelayTimes()); | ||||
|                         } else { | ||||
|                             TTSPlayRuleUtil.speakText(context, szSmsBody, configUtil.mAppConfigBean.getTtsPlayDelayTimes(), 0); | ||||
|                         } | ||||
|  | ||||
|                     } | ||||
|                 } | ||||
|  | ||||
|                 abortBroadcast(); | ||||
|             } else { | ||||
|                 SMSBean bean = new SMSBean(-1, szSmsAddress, szSmsBody, System.currentTimeMillis(), SMSBean.Type.INBOX, SMSBean.ReadStatus.UNREAD, 0); | ||||
|                 SMSRecycleUtil.addSMSRecycleItem(context, bean); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|  | ||||
|  | ||||
|     } | ||||
|  | ||||
|  | ||||
| } | ||||
|      | ||||
|      | ||||
|      | ||||
|  | ||||
| @@ -0,0 +1,96 @@ | ||||
| package cc.winboll.studio.mymessagemanager.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用主要服务组件类守护进程服务组件类 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ServiceUtil; | ||||
|  | ||||
| public class AssistantService extends Service { | ||||
|  | ||||
|     public final static String TAG = "AssistantService"; | ||||
|  | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     volatile boolean mIsServiceRunning; | ||||
|     AppConfigUtil mConfigUtil; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         super.onCreate(); | ||||
|         mConfigUtil = AppConfigUtil.getInstance(this); | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|         // 设置运行参数 | ||||
|         mIsServiceRunning = false; | ||||
|         run(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         run(); | ||||
|         return START_STICKY; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         mIsServiceRunning = false; | ||||
|         super.onDestroy(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 运行服务内容 | ||||
|     // | ||||
|     void run() { | ||||
|         mConfigUtil.reLoadConfig(); | ||||
|         if (mConfigUtil.mAppConfigBean.isEnableService()) { | ||||
|             if (mIsServiceRunning == false) { | ||||
|                 // 设置运行状态 | ||||
|                 mIsServiceRunning = true; | ||||
|                 // 唤醒和绑定主进程 | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 唤醒和绑定主进程 | ||||
|     // | ||||
|     void wakeupAndBindMain() { | ||||
|         if (ServiceUtil.isServiceAlive(getApplicationContext(), MainService.class.getName()) == false) { | ||||
|             startForegroundService(new Intent(AssistantService.this, MainService.class)); | ||||
|         } | ||||
|  | ||||
|         bindService(new Intent(AssistantService.this, MainService.class), mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             mConfigUtil.reLoadConfig(); | ||||
|             if (mConfigUtil.mAppConfigBean.isEnableService()) { | ||||
|                 wakeupAndBindMain(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,21 @@ | ||||
| package cc.winboll.studio.mymessagemanager.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:48:01 | ||||
|  * @Describe 默认短信应用服务组件类 | ||||
|  *           注册安卓系统默认短信应用使用。 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
|  | ||||
| public class DefaultSMSManagerService extends Service { | ||||
|  | ||||
|     public static final String TAG = "DefaultSMSManagerService"; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return null; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,157 @@ | ||||
| package cc.winboll.studio.mymessagemanager.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用主要服务组件类 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.IntentFilter; | ||||
| import android.content.ServiceConnection; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.beans.MessageNotificationBean; | ||||
| import cc.winboll.studio.mymessagemanager.receivers.SMSRecevier; | ||||
| import cc.winboll.studio.mymessagemanager.services.MainService; | ||||
| import cc.winboll.studio.mymessagemanager.utils.AppConfigUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.NotificationUtil; | ||||
| import cc.winboll.studio.mymessagemanager.utils.ServiceUtil; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import com.hjq.toast.ToastUtils; | ||||
|  | ||||
| public class MainService extends Service { | ||||
|  | ||||
|     public static String TAG = "ManagerService"; | ||||
|  | ||||
|     AppConfigUtil mConfigUtil; | ||||
|     //MyBinder mMyBinder; | ||||
|     MyServiceConnection mMyServiceConnection; | ||||
|     volatile static boolean _mIsServiceAlive; | ||||
|     SMSRecevier mSMSRecevier; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         //return mMyBinder; | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onCreate() { | ||||
|         LogUtils.d(TAG, "onCreate"); | ||||
|         super.onCreate(); | ||||
|         _mIsServiceAlive = false; | ||||
|         mConfigUtil = AppConfigUtil.getInstance(this); | ||||
|  | ||||
|         //mMyBinder = new MyBinder(); | ||||
|         if (mMyServiceConnection == null) { | ||||
|             mMyServiceConnection = new MyServiceConnection(); | ||||
|         } | ||||
|  | ||||
|         // 运行服务内容 | ||||
|         run(); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private void run() { | ||||
|         //LogUtils.d(TAG, "run"); | ||||
|         mConfigUtil.reLoadConfig(); | ||||
|         if (mConfigUtil.mAppConfigBean.isEnableService()) { | ||||
|             if (_mIsServiceAlive == false) { | ||||
|                 // 设置运行状态 | ||||
|                 _mIsServiceAlive = true; | ||||
|                 //LogUtils.d(TAG, "_mIsServiceAlive set to true."); | ||||
|  | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
|  | ||||
|                 // 运行其它服务内容 | ||||
|                 IntentFilter localIntentFilter = new IntentFilter(SMSRecevier.ACTION_SMS_RECEIVED); | ||||
|                 localIntentFilter.setPriority(1); | ||||
|                 mSMSRecevier = new SMSRecevier(); | ||||
|                 registerReceiver(mSMSRecevier, localIntentFilter); | ||||
|  | ||||
|  | ||||
|                 // 显示前台通知栏 | ||||
|                 MessageNotificationBean notificationMessage = createNotificationMessage(); | ||||
|                 NotificationUtil nu = new NotificationUtil(); | ||||
|                 nu.sendForegroundNotification(MainService.this, notificationMessage); | ||||
|  | ||||
|                 /*if (mConfigUtil.isEnableTTS()) { | ||||
|                  TTSPlayRuleUtil.speakText(ManagerService.this, getString(R.string.text_iamhere), 0); | ||||
|                  GlobalApplication.showApplicationMessage(getString(R.string.text_iamhere)); | ||||
|                  }*/ | ||||
|                   | ||||
|                 ToastUtils.show("Service is start."); | ||||
|                 LogUtils.i(TAG, "Service is start."); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public interface SMSListener { | ||||
|         void speakMessage(); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void onDestroy() { | ||||
|         super.onDestroy(); | ||||
|         unregisterReceiver(mSMSRecevier); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     private MessageNotificationBean createNotificationMessage() { | ||||
|         String szTitle = getApplicationContext().getString(R.string.app_name); | ||||
|         String szContent = getString(R.string.text_aboutservernotification); | ||||
|         return new MessageNotificationBean(NotificationUtil.ID_MSG_SERVICE, "", szTitle, szContent); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         //return super.onStartCommand(intent, flags, startId); | ||||
|         run(); | ||||
|         mConfigUtil.reLoadConfig(); | ||||
|         return mConfigUtil.mAppConfigBean.isEnableService() ? Service.START_STICKY: super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
|  | ||||
|    /*private class MyBinder extends IMyAidlInterface.Stub { | ||||
|         @Override | ||||
|         public String getServiceName() { | ||||
|             return MainService.class.getSimpleName(); | ||||
|         } | ||||
|     }*/ | ||||
|  | ||||
|     // 主进程与守护进程连接时需要用到此类 | ||||
|     // | ||||
|     private class MyServiceConnection implements ServiceConnection { | ||||
|         @Override | ||||
|         public void onServiceConnected(ComponentName name, IBinder service) { | ||||
|             //LogUtils.d(TAG, "call onServiceConnected(...)"); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onServiceDisconnected(ComponentName name) { | ||||
|             //LogUtils.d(TAG, "call onServiceConnected(...)"); | ||||
|             mConfigUtil.reLoadConfig(); | ||||
|             if (mConfigUtil.mAppConfigBean.isEnableService()) { | ||||
|                 // 唤醒守护进程 | ||||
|                 wakeupAndBindAssistant(); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // 唤醒和绑定守护进程 | ||||
|     // | ||||
|     void wakeupAndBindAssistant() { | ||||
|         if (ServiceUtil.isServiceAlive(getApplicationContext(), AssistantService.class.getName()) == false) { | ||||
|             startService(new Intent(MainService.this, AssistantService.class)); | ||||
|             //LogUtils.d(TAG, "call wakeupAndBindAssistant() : Binding... AssistantService"); | ||||
|             bindService(new Intent(MainService.this, AssistantService.class), mMyServiceConnection, Context.BIND_IMPORTANT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|  | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,42 @@ | ||||
| package cc.winboll.studio.mymessagemanager.services; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe TTS 语音播放服务组件类 | ||||
|  */ | ||||
| import android.app.Service; | ||||
| import android.content.Intent; | ||||
| import android.os.IBinder; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSSpeakTextBean; | ||||
| import cc.winboll.studio.mymessagemanager.utils.TextToSpeechUtil; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class TTSPlayService extends Service { | ||||
|  | ||||
|     public static final String TAG = "TTSService"; | ||||
|  | ||||
|     public static final String EXTRA_SPEAKDATA = "EXTRA_SPEAKDATA"; | ||||
|  | ||||
|     @Override | ||||
|     public IBinder onBind(Intent intent) { | ||||
|         return null; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public int onStartCommand(Intent intent, int flags, int startId) { | ||||
|         if (intent != null) { | ||||
|             ArrayList<TTSSpeakTextBean> listTTSSpeakTextBean = (ArrayList<TTSSpeakTextBean>)intent.getSerializableExtra(EXTRA_SPEAKDATA); | ||||
|             if (listTTSSpeakTextBean != null) { | ||||
|                  | ||||
|                 TextToSpeechUtil.getInstance(this).speekTTSList(listTTSSpeakTextBean); | ||||
|                  | ||||
|                 //Toast.makeText(getApplication(), "onStartCommand", Toast.LENGTH_SHORT).show(); | ||||
|                 //TTSThread ttsThread = new TTSThread(TTSService.this, listTTSSpeakTextBean); | ||||
|                 //ttsThread.start(); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return super.onStartCommand(intent, flags, startId); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,55 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/06/02 21:43:52 | ||||
|  * @Describe 应用配置工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import cc.winboll.studio.mymessagemanager.beans.AppConfigBean; | ||||
|  | ||||
| public class AppConfigUtil { | ||||
|      | ||||
|     public static final String TAG = "AppConfigUtil"; | ||||
|      | ||||
|     static AppConfigUtil _mConfigUtil; | ||||
|     Context mContext; | ||||
|     public AppConfigBean mAppConfigBean; | ||||
|  | ||||
|     AppConfigUtil(Context context) { | ||||
|         mContext = context; | ||||
|         mAppConfigBean = AppConfigBean.loadBean(context, AppConfigBean.class); | ||||
|         if(mAppConfigBean == null) { | ||||
|             mAppConfigBean = new AppConfigBean(); | ||||
|             AppConfigBean.saveBean(context, mAppConfigBean); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static AppConfigUtil getInstance(Context context) { | ||||
|         if (_mConfigUtil == null) { | ||||
|             _mConfigUtil = new AppConfigUtil(context); | ||||
|         } | ||||
|         return _mConfigUtil; | ||||
|     } | ||||
|      | ||||
|     public void reLoadConfig() { | ||||
|         mAppConfigBean = AppConfigBean.loadBean(mContext, AppConfigBean.class); | ||||
|     } | ||||
|      | ||||
|     public void saveConfig() { | ||||
|         AppConfigBean.saveBean(mContext, mAppConfigBean); | ||||
|     } | ||||
|      | ||||
|     public String getPhoneReplaceString() { | ||||
|         //String phoneNumber = "+86 123 4567 8901"; // 带有国家代码和空格的手机号码 | ||||
|         //String filteredNumber = phoneNumber.replaceAll("^\\+86|\\s", ""); // 过滤国家代码和空格 | ||||
|         //LogUtils.d(TAG, filteredNumber); | ||||
|  | ||||
|         String szReplace = "\\s"; | ||||
|         if (mAppConfigBean.isMergeCountryCodePrefix()) { | ||||
|             szReplace = "^\\+" + mAppConfigBean.getCountryCode() + "|\\s"; | ||||
|         } | ||||
|         //LogUtils.d(TAG, "szReplace is : " + szReplace); | ||||
|         return szReplace; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,170 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用配置工具类,V1 旧版。 | ||||
|  */ | ||||
| import android.util.JsonReader; | ||||
| import cc.winboll.studio.mymessagemanager.beans.AppConfigBean_V1; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class AppConfigUtil_V1 { | ||||
|  | ||||
|     public final static String TAG = "ConfigUtil"; | ||||
|  | ||||
|     static AppConfigUtil_V1 _mConfigUtil; | ||||
|     //AppConfigBean_V1 mAppConfigBean_V1; | ||||
|  | ||||
|     AppConfigUtil_V1() {} | ||||
|  | ||||
|     public static AppConfigUtil_V1 getInstance() { | ||||
|         if (_mConfigUtil == null) { | ||||
|             _mConfigUtil = new AppConfigUtil_V1(); | ||||
|         } | ||||
|         return _mConfigUtil; | ||||
|     } | ||||
|  | ||||
|     /*public void setAppTheme(ThemeUtil.BaseTheme baseTheme) { | ||||
|         loadConfigData(); | ||||
|         mAppConfigBean.setAppThemeID(ThemeUtil.getThemeID(baseTheme)); | ||||
|         saveConfigData(); | ||||
|     }*/ | ||||
|  | ||||
|     // | ||||
|     // 加载应用配置数据 | ||||
|     // | ||||
|     /*void loadConfigData() { | ||||
|         File fJson = new File(GlobalApplication._mszConfigUtilPath); | ||||
|         ArrayList<AppConfigBean> listTemp = null; | ||||
|         try { | ||||
|             if (fJson.exists()) { | ||||
|                 listTemp = readJsonStream(new FileInputStream(fJson)); | ||||
|                 if (listTemp != null) { | ||||
|                     mAppConfigBean = listTemp.get(0); | ||||
|                 } | ||||
|             } else { | ||||
|                 mAppConfigBean = new AppConfigBean(); | ||||
|                 saveConfigData(); | ||||
|             } | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|     }*/ | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件 | ||||
|     // | ||||
|     public ArrayList<AppConfigBean_V1> readJsonStream(InputStream in) throws IOException { | ||||
|         JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); | ||||
|         return readJsonArrayList(reader); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件的每一 Json 项 | ||||
|     // | ||||
|     public ArrayList<AppConfigBean_V1> readJsonArrayList(JsonReader reader) throws IOException { | ||||
|         ArrayList<AppConfigBean_V1> list = new ArrayList<AppConfigBean_V1>(); | ||||
|         reader.beginArray(); | ||||
|         while (reader.hasNext()) { | ||||
|             list.add(readBeanItem(reader)); | ||||
|         } | ||||
|         reader.endArray(); | ||||
|         return list; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     public AppConfigBean_V1 readBeanItem(JsonReader reader) throws IOException { | ||||
|         AppConfigBean_V1 bean = new AppConfigBean_V1(); | ||||
|         int nReaderCount = 0; | ||||
|         reader.beginObject(); | ||||
|         while (reader.hasNext()) { | ||||
|             String name = reader.nextName(); | ||||
|             if (name.equals("countryCode")) { | ||||
|                 bean.setCountryCode(reader.nextString()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("isMergeCountryCodePrefix")) { | ||||
|                 bean.setIsMergeCountryCodePrefix(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("ttsPlayDelayTimes")) { | ||||
|                 bean.setTtsPlayDelayTimes(reader.nextInt()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("enableService")) { | ||||
|                 bean.setEnableService(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("enableOnlyReceiveContacts")) { | ||||
|                 bean.setEnableOnlyReceiveContacts(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("enableTTS")) { | ||||
|                 bean.setEnableTTS(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("enableTTSRuleMode")) { | ||||
|                 bean.setEnableTTSRuleMode(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } /*else if (name.equals("appThemeID")) { | ||||
|                 bean.setAppThemeID(reader.nextInt()); | ||||
|                 nReaderCount++; | ||||
|             }*/ else { | ||||
|                 reader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         reader.endObject(); | ||||
|         return nReaderCount > 0 ? bean : null; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 写入 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     /*public void writeBeanItem(JsonWriter writer, AppConfigBean bean) throws IOException { | ||||
|         writer.beginObject(); | ||||
|         writer.name("countryCode").value(bean.getCountryCode()); | ||||
|         writer.name("isMergeCountryCodePrefix").value(bean.isMergeCountryCodePrefix()); | ||||
|         writer.name("ttsPlayDelayTimes").value(bean.getTtsPlayDelayTimes()); | ||||
|         writer.name("enableService").value(bean.isEnableService()); | ||||
|         writer.name("enableOnlyReceiveContacts").value(bean.isEnableOnlyReceiveContacts()); | ||||
|         writer.name("enableTTS").value(bean.isEnableTTS()); | ||||
|         writer.name("enableTTSRuleMode").value(bean.isEnableTTSRuleMode()); | ||||
|         writer.name("appThemeID").value(bean.getAppThemeID()); | ||||
|         writer.endObject(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 保存应用配置数据 | ||||
|     // | ||||
|     public void saveConfigData() { | ||||
|         try { | ||||
|             File fJson = new File(GlobalApplication._mszConfigUtilPath); | ||||
|             ArrayList<AppConfigBean> list = new ArrayList<AppConfigBean>(); | ||||
|             list.add(mAppConfigBean); | ||||
|             writeJsonStream(new FileOutputStream(fJson, false), list); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, "IOException : " + e.getMessage()); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 写入 Json 文件 | ||||
|     // | ||||
|     public void writeJsonStream(OutputStream out, ArrayList<AppConfigBean> beanList) throws IOException { | ||||
|         JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8")); | ||||
|         writer.setIndent("  "); | ||||
|         writeJsonArrayList(writer, beanList); | ||||
|         writer.close(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 记录 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     public void writeJsonArrayList(JsonWriter writer, ArrayList<AppConfigBean> beanList) throws IOException { | ||||
|         writer.beginArray(); | ||||
|         for (AppConfigBean bean : beanList) { | ||||
|             writeBeanItem(writer, bean); | ||||
|         } | ||||
|         writer.endArray(); | ||||
|     }*/ | ||||
| } | ||||
| @@ -0,0 +1,270 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/05/31 17:58:27 | ||||
|  * @Describe 调用应用属性设置页工具类 | ||||
|  *  来源:https://blog.csdn.net/zhuhai__yizhi/article/details/78737593 | ||||
|  *  Created by zyy on 2018/3/12. | ||||
|  *  直接跳转到权限后返回,可以监控权限授权情况,但是,跳转到应用详情页,无法监测权限情况 | ||||
|  *  是否要加以区分,若是应用详情页,则跳转回来后,onRestart检测所求权限,如果授权,则收回提示,如果没授权,则继续提示 | ||||
|  */ | ||||
| import android.app.Activity; | ||||
| import android.content.ComponentName; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import android.os.Build; | ||||
| import android.provider.Settings; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.MainActivity; | ||||
|  | ||||
| public class AppGoToSettingsUtil { | ||||
|  | ||||
|     public static final String TAG = "AppGoToSettingsUtil"; | ||||
|      | ||||
|     public static final int ACTIVITY_RESULT_APP_SETTINGS = MainActivity.ACTIVITY_RESULT_APP_SETTINGS; | ||||
|      | ||||
|     /** | ||||
|      * Build.MANUFACTURER判断各大手机厂商品牌 | ||||
|      */ | ||||
|     private static final String MANUFACTURER_HUAWEI = "Huawei";//华为 | ||||
|     private static final String MANUFACTURER_MEIZU = "Meizu";//魅族 | ||||
|     private static final String MANUFACTURER_XIAOMI = "Xiaomi";//小米 | ||||
|     private static final String MANUFACTURER_SONY = "Sony";//索尼 | ||||
|     private static final String MANUFACTURER_OPPO = "OPPO"; | ||||
|     private static final String MANUFACTURER_LG = "LG"; | ||||
|     private static final String MANUFACTURER_VIVO = "vivo"; | ||||
|     private static final String MANUFACTURER_SAMSUNG = "samsung";//三星 | ||||
|     private static final String MANUFACTURER_LETV = "Letv";//乐视 | ||||
|     private static final String MANUFACTURER_ZTE = "ZTE";//中兴 | ||||
|     private static final String MANUFACTURER_YULONG = "YuLong";//酷派 | ||||
|     private static final String MANUFACTURER_LENOVO = "LENOVO";//联想 | ||||
|  | ||||
|     public static boolean isAppSettingOpen=false; | ||||
|     /** | ||||
|      * 跳转到相应品牌手机系统权限设置页,如果跳转不成功,则跳转到应用详情页 | ||||
|      * 这里需要改造成返回true或者false,应用详情页:true,应用权限页:false | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void GoToSetting(Activity activity) { | ||||
|         switch (Build.MANUFACTURER) { | ||||
|             case MANUFACTURER_HUAWEI://华为 | ||||
|                 Huawei(activity); | ||||
|                 break; | ||||
|             case MANUFACTURER_MEIZU://魅族 | ||||
|                 Meizu(activity); | ||||
|                 break; | ||||
|             case MANUFACTURER_XIAOMI://小米 | ||||
|                 Xiaomi(activity); | ||||
|                 break; | ||||
|             case MANUFACTURER_SONY://索尼 | ||||
|                 Sony(activity); | ||||
|                 break; | ||||
|             case MANUFACTURER_OPPO://oppo | ||||
|                 OPPO(activity); | ||||
|                 break; | ||||
|             case MANUFACTURER_LG://lg | ||||
|                 LG(activity); | ||||
|                 break; | ||||
|             case MANUFACTURER_LETV://乐视 | ||||
|                 Letv(activity); | ||||
|                 break; | ||||
|             default://其他 | ||||
|                 try {//防止应用详情页也找不到,捕获异常后跳转到设置,这里跳转最好是两级,太多用户也会觉得麻烦,还不如不跳 | ||||
|                     openAppDetailSetting(activity); | ||||
|                     //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|                 } catch (Exception e) { | ||||
|                     SystemConfig(activity); | ||||
|                 } | ||||
|                 break; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 华为跳转权限设置页 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void Huawei(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent(); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             ComponentName comp = new ComponentName("com.huawei.systemmanager", "com.huawei.permissionmanager.ui.MainActivity"); | ||||
|             intent.setComponent(comp); | ||||
|             activity.startActivityForResult(intent, ACTIVITY_RESULT_APP_SETTINGS); | ||||
|             isAppSettingOpen = false; | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 魅族跳转权限设置页,测试时,点击无反应,具体原因不明 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void Meizu(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent("com.meizu.safe.security.SHOW_APPSEC"); | ||||
|             intent.addCategory(Intent.CATEGORY_DEFAULT); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             activity.startActivity(intent); | ||||
|             isAppSettingOpen = false; | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 小米,功能正常 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void Xiaomi(Activity activity) { | ||||
|         try { //MIUI 8 9 | ||||
|             Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR"); | ||||
|             localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.PermissionsEditorActivity"); | ||||
|             localIntent.putExtra("extra_pkgname", activity.getPackageName()); | ||||
|             activity.startActivityForResult(localIntent, ACTIVITY_RESULT_APP_SETTINGS); | ||||
|             isAppSettingOpen = false; | ||||
|             //activity.startActivity(localIntent); | ||||
|         } catch (Exception e) { | ||||
|             try { //MIUI 5/6/7 | ||||
|                 Intent localIntent = new Intent("miui.intent.action.APP_PERM_EDITOR"); | ||||
|                 localIntent.setClassName("com.miui.securitycenter", "com.miui.permcenter.permissions.AppPermissionsEditorActivity"); | ||||
|                 localIntent.putExtra("extra_pkgname", activity.getPackageName()); | ||||
|                 activity.startActivityForResult(localIntent, ACTIVITY_RESULT_APP_SETTINGS); | ||||
|                 isAppSettingOpen = false; | ||||
|                 //activity.startActivity(localIntent); | ||||
|             } catch (Exception e1) { //否则跳转到应用详情 | ||||
|                 openAppDetailSetting(activity); | ||||
|                 //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|                 //这里有个问题,进入活动后需要再跳一级活动,就检测不到返回结果 | ||||
|                 //activity.startActivity(getAppDetailSettingIntent()); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 索尼,6.0以上的手机非常少,基本没看见 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void Sony(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent(); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             ComponentName comp = new ComponentName("com.sonymobile.cta", "com.sonymobile.cta.SomcCTAMainActivity"); | ||||
|             intent.setComponent(comp); | ||||
|             activity.startActivity(intent); | ||||
|             isAppSettingOpen = false; | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * OPPO | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void OPPO(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent(); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             ComponentName comp = new ComponentName("com.color.safecenter", "com.color.safecenter.permission.PermissionManagerActivity"); | ||||
|             intent.setComponent(comp); | ||||
|             activity.startActivity(intent); | ||||
|             isAppSettingOpen = false; | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * LG经过测试,正常使用 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void LG(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent("android.intent.action.MAIN"); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             ComponentName comp = new ComponentName("com.android.settings", "com.android.settings.Settings$AccessLockSummaryActivity"); | ||||
|             intent.setComponent(comp); | ||||
|             activity.startActivity(intent); | ||||
|             isAppSettingOpen = false; | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 乐视6.0以上很少,基本都可以忽略了,现在乐视手机不多 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void Letv(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent(); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             ComponentName comp = new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.PermissionAndApps"); | ||||
|             intent.setComponent(comp); | ||||
|             activity.startActivity(intent); | ||||
|             isAppSettingOpen = false; | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 只能打开到自带安全软件 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void _360(Activity activity) { | ||||
|         try { | ||||
|             Intent intent = new Intent("android.intent.action.MAIN"); | ||||
|             intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|             intent.putExtra("packageName", activity.getPackageName()); | ||||
|             ComponentName comp = new ComponentName("com.qihoo360.mobilesafe", "com.qihoo360.mobilesafe.ui.index.AppEnterActivity"); | ||||
|             intent.setComponent(comp); | ||||
|             activity.startActivity(intent); | ||||
|         } catch (Exception e) { | ||||
|             openAppDetailSetting(activity); | ||||
|             //activity.startActivityForResult(getAppDetailSettingIntent(activity), PERMISSION_SETTING_FOR_RESULT); | ||||
|         } | ||||
|     } | ||||
|     /** | ||||
|      * 系统设置界面 | ||||
|      * @param activity | ||||
|      */ | ||||
|     public static void SystemConfig(Activity activity) { | ||||
|         Intent intent = new Intent(Settings.ACTION_SETTINGS); | ||||
|         activity.startActivity(intent); | ||||
|     } | ||||
|     /** | ||||
|      * 获取应用详情页面 | ||||
|      * @return | ||||
|      */ | ||||
|     private static Intent getAppDetailSettingIntent(Activity activity) { | ||||
|         Intent localIntent = new Intent(); | ||||
|         localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         //if (Build.VERSION.SDK_INT >= 9) { | ||||
|         localIntent.setAction("android.settings.APPLICATION_DETAILS_SETTINGS"); | ||||
|         localIntent.setData(Uri.fromParts("package", activity.getPackageName(), null)); | ||||
|         /*} else if (Build.VERSION.SDK_INT <= 8) { | ||||
|          localIntent.setAction(Intent.ACTION_VIEW); | ||||
|          localIntent.setClassName("com.android.settings", "com.android.settings.InstalledAppDetails"); | ||||
|          localIntent.putExtra("com.android.settings.ApplicationPkgName", activity.getPackageName()); | ||||
|          }*/ | ||||
|         return localIntent; | ||||
|     } | ||||
|      | ||||
|     public static void openAppDetailSetting(Activity activity) { | ||||
|         activity.startActivityForResult(getAppDetailSettingIntent(activity), ACTIVITY_RESULT_APP_SETTINGS); | ||||
|         isAppSettingOpen = true; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,113 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 文件工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.content.res.AssetManager; | ||||
| import android.net.Uri; | ||||
| import androidx.core.content.FileProvider; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import java.io.File; | ||||
| import java.io.FileInputStream; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.io.OutputStream; | ||||
| import java.io.OutputStreamWriter; | ||||
| import java.nio.charset.StandardCharsets; | ||||
|  | ||||
| public class FileUtil { | ||||
|  | ||||
|     public static final String TAG = "FileUtil"; | ||||
|  | ||||
|     public static void shareJSONFile(Context context, String szConfigFile) { | ||||
|         Uri uri; | ||||
|         File file = new File(szConfigFile); | ||||
|         uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file); | ||||
|         /*if (Build.VERSION.SDK_INT >= 24) {//android 7.0以上 | ||||
|             uri = FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file); | ||||
|         } else { | ||||
|             uri = Uri.fromFile(file); | ||||
|         }*/ | ||||
|         Intent shareIntent = new Intent();     | ||||
|         shareIntent.setAction(Intent.ACTION_SEND);     | ||||
|         shareIntent.putExtra(Intent.EXTRA_STREAM, uri);     | ||||
|         shareIntent.setType("application/json"); | ||||
|  | ||||
|         shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); | ||||
|         /*if (Build.VERSION.SDK_INT >= 24) { | ||||
|             shareIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); | ||||
|         }*/ | ||||
|          | ||||
|         // 设置分享的标题     | ||||
|         context.startActivity(Intent.createChooser(shareIntent, "SHARE JSON"));   | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 把字符串写入文件,指定 UTF-8 编码 | ||||
|     // | ||||
|     public static void writeFile(String filePath, String content) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         FileOutputStream outputStream = new FileOutputStream(file); | ||||
|         OutputStreamWriter writer = new OutputStreamWriter(outputStream, StandardCharsets.UTF_8); | ||||
|         writer.write(content); | ||||
|         writer.close(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取文件到字符串,指定 UTF-8 编码 | ||||
|     // | ||||
|     public static String readFile(String filePath) throws IOException { | ||||
|         File file = new File(filePath); | ||||
|         FileInputStream inputStream = new FileInputStream(file); | ||||
|         InputStreamReader reader = new InputStreamReader(inputStream, StandardCharsets.UTF_8); | ||||
|         StringBuilder content = new StringBuilder(); | ||||
|         int character; | ||||
|         while ((character = reader.read()) != -1) { | ||||
|             content.append((char) character); | ||||
|         } | ||||
|         reader.close(); | ||||
|         return content.toString(); | ||||
|     } | ||||
|      | ||||
|     public static void copyAssetsToSD(Context context, String szSrcAssets, String szDstSD) { | ||||
|         LogUtils.d(TAG, "copyAssetsToSD [" + szSrcAssets + "] to [" + szDstSD + "]"); | ||||
|         AssetManager assetManager = context.getAssets(); | ||||
|         InputStream inputStream = null; | ||||
|         OutputStream outputStream = null; | ||||
|         try { | ||||
|             inputStream = assetManager.open(szSrcAssets); | ||||
|             File outputFile = new File(szDstSD); | ||||
|             outputStream = new FileOutputStream(outputFile); | ||||
|             byte[] buffer = new byte[1024]; | ||||
|             int length = 0; | ||||
|             while ((length = inputStream.read(buffer)) > 0) { | ||||
|                 outputStream.write(buffer, 0, length); | ||||
|             } | ||||
|             outputStream.flush(); | ||||
|             LogUtils.d(TAG, "copyAssetsToSD done."); | ||||
|         } catch (IOException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } finally { | ||||
|             if (inputStream != null) { | ||||
|                 try { | ||||
|                     inputStream.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|             if (outputStream != null) { | ||||
|                 try { | ||||
|                     outputStream.close(); | ||||
|                 } catch (IOException e) { | ||||
|                     LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,168 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用通知栏工具类 | ||||
|  */ | ||||
| import android.app.Notification; | ||||
| import android.app.NotificationChannel; | ||||
| import android.app.NotificationManager; | ||||
| import android.app.PendingIntent; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.graphics.BitmapFactory; | ||||
| import android.graphics.Color; | ||||
| import android.media.RingtoneManager; | ||||
| import android.widget.RemoteViews; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.MainActivity; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.SMSActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.MessageNotificationBean; | ||||
| import cc.winboll.studio.mymessagemanager.services.MainService; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| public class NotificationUtil { | ||||
|  | ||||
|     public static final String TAG = "NotificationUtil"; | ||||
|     public static final int ID_MSG_SERVICE = 10000; | ||||
|  | ||||
|     static final String szSMSChannelID = "1"; | ||||
|  | ||||
|     static final String szServiceChannelID = "0"; | ||||
|  | ||||
|  | ||||
|     //static int mNumSendForegroundNotification = 10000; | ||||
|     //static int mNumSendSMSNotification = 20000; | ||||
|  | ||||
|     public NotificationManager createServiceNotificationChannel(Context context) { | ||||
|         //创建通知渠道ID | ||||
| 		String channelId = szServiceChannelID; | ||||
| 		//创建通知渠道名称 | ||||
| 		String channelName = "Service Message"; | ||||
| 		//创建通知渠道重要性 | ||||
| 		int importance = NotificationManager.IMPORTANCE_MIN; | ||||
| 		NotificationChannel channel = new NotificationChannel(channelId, channelName, importance); | ||||
| 		channel.setSound(null, null); | ||||
| 		NotificationManager notificationManager = (NotificationManager) context.getSystemService( | ||||
| 			Context.NOTIFICATION_SERVICE); | ||||
| 		notificationManager.createNotificationChannel(channel); | ||||
| 		return notificationManager; | ||||
|     } | ||||
|  | ||||
|     public NotificationManager createSMSNotificationChannel(Context context) { | ||||
|         //创建通知渠道ID | ||||
| 		String channelId = szSMSChannelID; | ||||
| 		//创建通知渠道名称 | ||||
| 		String channelName = "SMS Message"; | ||||
| 		//创建通知渠道重要性 | ||||
| 		int importance = NotificationManager.IMPORTANCE_HIGH; | ||||
| 		NotificationChannel channel = new NotificationChannel(channelId, channelName, importance); | ||||
| 		channel.setSound(RingtoneManager.getDefaultUri(RingtoneManager.TYPE_RINGTONE), Notification.AUDIO_ATTRIBUTES_DEFAULT); | ||||
| 		NotificationManager notificationManager = (NotificationManager) context.getSystemService( | ||||
| 			Context.NOTIFICATION_SERVICE); | ||||
| 		notificationManager.createNotificationChannel(channel); | ||||
| 		return notificationManager; | ||||
|     } | ||||
|  | ||||
|     // 创建通知 | ||||
|     // | ||||
|     public void sendForegroundNotification(MainService service, MessageNotificationBean nessageNotificationBean) { | ||||
| 		//创建Notification,传入Context和channelId | ||||
| 		Intent intent = new Intent();//这个intent会传给目标,可以使用getIntent来获取 | ||||
| 		intent.setClass(service, MainActivity.class); | ||||
|  | ||||
| 		//这里放一个count用来区分每一个通知 | ||||
| 		//intent.putExtra("intent", "intent--->" + count);//这里设置一个数据,带过去 | ||||
|  | ||||
| 		//参数1:context 上下文对象 | ||||
| 		//参数2:发送者私有的请求码(Private request code for the sender) | ||||
| 		//参数3:intent 意图对象 | ||||
| 		//参数4:必须为FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,FLAG_UPDATE_CURRENT,中的一个 | ||||
| 		PendingIntent mForegroundPendingIntent = PendingIntent.getActivity(service, nessageNotificationBean.getMessageId(), intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT); | ||||
|  | ||||
| 		Notification mForegroundNotification = new Notification.Builder(service, szServiceChannelID) | ||||
| 			.setAutoCancel(true) | ||||
| 			.setContentTitle(nessageNotificationBean.getTitle()) | ||||
| 			.setContentText(nessageNotificationBean.getContent()) | ||||
| 			.setWhen(System.currentTimeMillis()) | ||||
| 			.setSmallIcon(R.drawable.ic_launcher) | ||||
| 			//设置红色 | ||||
| 			.setColor(Color.parseColor("#F00606")) | ||||
| 			.setLargeIcon(BitmapFactory.decodeResource(service.getResources(), R.drawable.ic_launcher)) | ||||
| 			.setContentIntent(mForegroundPendingIntent) | ||||
| 			.build(); | ||||
|  | ||||
|  | ||||
| 		RemoteViews mrvForegroundNotificationView = new RemoteViews(service.getPackageName(), R.layout.remoteview); | ||||
| 		mrvForegroundNotificationView.setTextViewText(R.id.remoteviewTextView1, nessageNotificationBean.getTitle()); | ||||
| 		mrvForegroundNotificationView.setTextViewText(R.id.remoteviewTextView2, nessageNotificationBean.getContent()); | ||||
| 		mrvForegroundNotificationView.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher); | ||||
| 		mForegroundNotification.contentView = mrvForegroundNotificationView; | ||||
| 		mForegroundNotification.bigContentView = mrvForegroundNotificationView; | ||||
|  | ||||
| 		service.startForeground(nessageNotificationBean.getMessageId(), mForegroundNotification); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void sendSMSNotification(Context context, MessageNotificationBean messageNotificationBean) { | ||||
|         NotificationManager notificationManager = (NotificationManager) context.getSystemService( | ||||
| 			Context.NOTIFICATION_SERVICE); | ||||
| 		/*NotificationManager notificationManager = createSMSNotificationChannel(context); | ||||
| 		 if (notificationManager == null) { | ||||
| 		 LogUtils.d(TAG, "createSMSNotificationChannel failed."); | ||||
| 		 return; | ||||
| 		 }*/ | ||||
|  | ||||
| 		//创建Notification,传入Context和channelId | ||||
| 		Intent intent = new Intent(context, SMSActivity.class); | ||||
| 		intent.putExtra(SMSActivity.EXTRA_PHONE, messageNotificationBean.getPhone()); | ||||
| 		LogUtils.d(TAG, "sendSMSNotification(...) message.getPhone() is : " + messageNotificationBean.getPhone()); | ||||
| 		//Intent intent = new Intent();//这个intent会传给目标,可以使用getIntent来获取 | ||||
| 		//intent.setClass(context, MainActivity.class); | ||||
| 		//这里放一个count用来区分每一个通知 | ||||
| 		//intent.putExtra("intent", "intent--->" + count);//这里设置一个数据,带过去 | ||||
|  | ||||
| 		//参数1:context 上下文对象 | ||||
| 		//参数2:发送者私有的请求码(Private request code for the sender) | ||||
| 		//参数3:intent 意图对象 | ||||
| 		//参数4:必须为FLAG_ONE_SHOT,FLAG_NO_CREATE,FLAG_CANCEL_CURRENT,FLAG_UPDATE_CURRENT,中的一个 | ||||
| 		PendingIntent mRemindPendingIntent = PendingIntent.getActivity(context, messageNotificationBean.getMessageId(), intent, PendingIntent.FLAG_IMMUTABLE | PendingIntent.FLAG_CANCEL_CURRENT); | ||||
| 		Notification mSMSNotification = new Notification.Builder(context, szSMSChannelID) | ||||
| 			.setAutoCancel(true) | ||||
| 			.setContentTitle(messageNotificationBean.getTitle()) | ||||
| 			.setContentText(messageNotificationBean.getContent()) | ||||
| 			.setWhen(System.currentTimeMillis()) | ||||
| 			.setSmallIcon(R.drawable.ic_launcher) | ||||
| 			//设置红色 | ||||
| 			.setColor(Color.parseColor("#F00606")) | ||||
| 			.setLargeIcon(BitmapFactory.decodeResource(context.getResources(), R.drawable.ic_launcher)) | ||||
| 			.setContentIntent(mRemindPendingIntent) | ||||
| 			.build(); | ||||
|  | ||||
| 		RemoteViews mrvSMSNotificationView = new RemoteViews(context.getPackageName(), R.layout.remoteview); | ||||
| 		mrvSMSNotificationView.setTextViewText(R.id.remoteviewTextView1, messageNotificationBean.getTitle()); | ||||
| 		mrvSMSNotificationView.setTextViewText(R.id.remoteviewTextView2, messageNotificationBean.getContent()); | ||||
| 		mrvSMSNotificationView.setImageViewResource(R.id.remoteviewImageView1, R.drawable.ic_launcher); | ||||
| 		mSMSNotification.contentView = mrvSMSNotificationView; | ||||
| 		mSMSNotification.bigContentView = mrvSMSNotificationView; | ||||
| 		notificationManager.notify(messageNotificationBean.getMessageId(), mSMSNotification); | ||||
|         LogUtils.d(TAG, "getMessageId is : " + Integer.toString(messageNotificationBean.getMessageId())); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public void sendSMSReceivedMessage(Context context, int nMessageId, String szPhone, String szBody) { | ||||
|         String szTitle = context.getString(R.string.text_smsfrom)  + "<" + szPhone + ">"; | ||||
|         String szContent = "[ " + szBody + " ]"; | ||||
|         sendSMSNotification(context, new MessageNotificationBean(nMessageId, szPhone, szTitle, szContent)); | ||||
|     } | ||||
|  | ||||
|     public static void cancelNotification(Context context, int notificationId) { | ||||
|         // 获取 NotificationManager 实例 | ||||
|         NotificationManager notificationManager = (NotificationManager) context.getSystemService(Context.NOTIFICATION_SERVICE); | ||||
|         // 撤回指定 ID 的通知栏消息 | ||||
|         notificationManager.cancel(notificationId); | ||||
|     } | ||||
| } | ||||
|  | ||||
|  | ||||
| @@ -0,0 +1,204 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/06/01 13:02:30 | ||||
|  * @Describe 应用权限申请工具类 | ||||
|  */ | ||||
| import android.app.AlertDialog; | ||||
| import android.content.Context; | ||||
| import android.content.DialogInterface; | ||||
| import android.content.Intent; | ||||
| import android.net.Uri; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.BaseActivity; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import com.hjq.permissions.OnPermissionCallback; | ||||
| import com.hjq.permissions.Permission; | ||||
| import com.hjq.permissions.XXPermissions; | ||||
| import java.util.List; | ||||
|  | ||||
| public class PermissionUtil { | ||||
|  | ||||
|     public static final String TAG = "PermissionUtil"; | ||||
|  | ||||
|     public static boolean checkAppPermission(Context context) { | ||||
|         if (!XXPermissions.isGranted(context, Permission.READ_CONTACTS)) { | ||||
|             LogUtils.i(TAG, "Permission.READ_CONTACTS error."); | ||||
|             return false; | ||||
|         } | ||||
|         if (!XXPermissions.isGranted(context, Permission.Group.STORAGE)) { | ||||
|             LogUtils.i(TAG, "Permission.Group.STORAGE error."); | ||||
|             return false; | ||||
|         } | ||||
|         if (!XXPermissions.isGranted(context, Permission.READ_SMS)) { | ||||
|             LogUtils.i(TAG, "Permission.READ_SMS error."); | ||||
|             return false; | ||||
|         } | ||||
|         if (!XXPermissions.isGranted(context, Permission.RECEIVE_SMS)) { | ||||
|             LogUtils.i(TAG, "Permission.RECEIVE_SMS error."); | ||||
|             return false; | ||||
|         } | ||||
|  | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     public static boolean checkAndGetAppPermission(Context context) { | ||||
|         if (!XXPermissions.isGranted(context, Permission.READ_CONTACTS)) { | ||||
|             getAppPermission(context, Permission.READ_CONTACTS); | ||||
|             return false; | ||||
|         } | ||||
|         if (!XXPermissions.isGranted(context, Permission.Group.STORAGE)) { | ||||
|             getAppPermissionsList(context, Permission.Group.STORAGE); | ||||
|             return false; | ||||
|         } | ||||
|         if (!XXPermissions.isGranted(context, Permission.READ_SMS)) { | ||||
|             getAppPermission(context, Permission.READ_SMS); | ||||
|             return false; | ||||
|         } | ||||
|         if (!XXPermissions.isGranted(context, Permission.RECEIVE_SMS)) { | ||||
|             getAppPermission(context, Permission.RECEIVE_SMS); | ||||
|             return false; | ||||
|         } | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 申请多个权限 | ||||
|     // | ||||
|     static void getAppPermissionsList(final Context context, final String[] szPermissionList) { | ||||
|         XXPermissions.with(context) | ||||
|             // 申请多个权限 | ||||
|             .permission(szPermissionList) | ||||
|             // 设置权限请求拦截器(局部设置) | ||||
|             //.interceptor(new PermissionInterceptor()) | ||||
|             // 设置不触发错误检测机制(局部设置) | ||||
|             //.unchecked() | ||||
|             .request(new OnPermissionCallback() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onGranted(List<String> permissions, boolean allGranted) { | ||||
|                     StringBuilder sb = new StringBuilder(); | ||||
|                     for (String sz : permissions) { | ||||
|                         sb.append(sz); | ||||
|                     } | ||||
|                     if (!allGranted) { | ||||
|  | ||||
|                         showPermissionDialog(context, sb.toString()); | ||||
|                         LogUtils.d(TAG, "获取部分权限成功,但部分权限未正常授予"); | ||||
|                         return; | ||||
|                     } | ||||
|                     checkAndGetAppPermission(context); | ||||
|                     LogUtils.d(TAG, "获取权限成功:" + sb.toString()); | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onDenied(List<String> permissions, boolean doNotAskAgain) { | ||||
|                     StringBuilder sb = new StringBuilder(); | ||||
|                     for (String sz : permissions) { | ||||
|                         sb.append(sz); | ||||
|                     } | ||||
|                     if (doNotAskAgain) { | ||||
|                         LogUtils.d(TAG, "被永久拒绝授权,请手动授予应用权限:" + sb.toString()); | ||||
|                         // 如果是被永久拒绝就跳转到应用权限系统设置页面 | ||||
|                         //XXPermissions.startPermissionActivity(context, permissions); | ||||
|                         showPermissionDialog(context, sb.toString()); | ||||
|  | ||||
|                     } else { | ||||
|                         LogUtils.d(TAG, "获取应用权限失败:" + sb.toString()); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 申请单个权限 | ||||
|     // | ||||
|     static void getAppPermission(final Context context, final String szPermission) { | ||||
|         XXPermissions.with(context) | ||||
|             // 申请单个权限 | ||||
|             .permission(szPermission) | ||||
|             // 设置权限请求拦截器(局部设置) | ||||
|             //.interceptor(new PermissionInterceptor()) | ||||
|             // 设置不触发错误检测机制(局部设置) | ||||
|             //.unchecked() | ||||
|             .request(new OnPermissionCallback() { | ||||
|  | ||||
|                 @Override | ||||
|                 public void onGranted(List<String> permissions, boolean allGranted) { | ||||
|                     StringBuilder sb = new StringBuilder(); | ||||
|                     for (String sz : permissions) { | ||||
|                         sb.append(sz); | ||||
|                     } | ||||
|                     if (!allGranted) { | ||||
|                         showPermissionDialog(context, sb.toString()); | ||||
|                         LogUtils.d(TAG, "获取部分权限成功,但部分权限未正常授予"); | ||||
|                         return; | ||||
|                     } | ||||
|                     checkAndGetAppPermission(context); | ||||
|                     LogUtils.d(TAG, "获取权限成功:" + sb.toString()); | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onDenied(List<String> permissions, boolean doNotAskAgain) { | ||||
|                     StringBuilder sb = new StringBuilder(); | ||||
|                     for (String sz : permissions) { | ||||
|                         sb.append(sz); | ||||
|                     } | ||||
|                     if (doNotAskAgain) { | ||||
|                         LogUtils.d(TAG, "被永久拒绝授权,请手动授予应用权限"); | ||||
|                         // 如果是被永久拒绝就跳转到应用权限系统设置页面 | ||||
|                         //XXPermissions.startPermissionActivity(context, permissions); | ||||
|                         showPermissionDialog(context, sb.toString()); | ||||
|  | ||||
|                     } else { | ||||
|                         LogUtils.d(TAG, "获取应用权限失败:" + sb.toString()); | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // | ||||
|     // 打开应用属性设置页 | ||||
|     // | ||||
|     static void openSettingIntent(Context context) { | ||||
|         Intent intent = new Intent("android.settings.APPLICATION_DETAILS_SETTINGS"); | ||||
|         intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); | ||||
|         intent.setData(Uri.parse("package:" + context.getPackageName())); | ||||
|         context.startActivity(intent); | ||||
|     } | ||||
|  | ||||
|     static void showPermissionDialog(final Context context, String szPermissionMessage) { | ||||
|         AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context); | ||||
|         // set title | ||||
|         alertDialogBuilder.setTitle(context.getString(R.string.app_permission_require_info)); | ||||
|  | ||||
|         // set dialog message | ||||
|         alertDialogBuilder | ||||
|             .setMessage(szPermissionMessage) | ||||
|             .setCancelable(false) | ||||
|             .setPositiveButton("Open Permission Dialog", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     // if this button is clicked, close | ||||
|                     // current activity | ||||
|                     //MainActivity.this.finish(); | ||||
|                     AppGoToSettingsUtil appGoToSettingsUtil = new AppGoToSettingsUtil(); | ||||
|                     appGoToSettingsUtil.GoToSetting((BaseActivity)context); | ||||
|                 } | ||||
|             }) | ||||
|             .setNegativeButton("Exit", new DialogInterface.OnClickListener() { | ||||
|                 public void onClick(DialogInterface dialog, int id) { | ||||
|                     // if this button is clicked, just close | ||||
|                     // the dialog box and do nothing | ||||
|                     dialog.cancel(); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         // create alert dialog | ||||
|         AlertDialog alertDialog = alertDialogBuilder.create(); | ||||
|  | ||||
|         // show it | ||||
|         alertDialog.show(); | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,70 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 手机联系人工具类 | ||||
|  */ | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.database.Cursor; | ||||
| import android.net.Uri; | ||||
| import android.provider.ContactsContract; | ||||
| import cc.winboll.studio.mymessagemanager.beans.PhoneBean; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.Comparator; | ||||
| import java.util.List; | ||||
|  | ||||
| public class PhoneUtil { | ||||
|  | ||||
|     public static String TAG = "PhoneUtil"; | ||||
|  | ||||
|     // 号码 | ||||
|     public final static String NUMBER = ContactsContract.CommonDataKinds.Phone.NUMBER; | ||||
|     // 联系人姓名 | ||||
|     public final static String DISPLAY_NAME = ContactsContract.CommonDataKinds.Phone.DISPLAY_NAME; | ||||
|  | ||||
|     // 上下文对象 | ||||
|     Context mContext; | ||||
|     // 联系人提供者的Uri | ||||
|     Uri mUriPhoneContent = ContactsContract.CommonDataKinds.Phone.CONTENT_URI; | ||||
|  | ||||
|     public PhoneUtil(Context context) { | ||||
|         mContext = context; | ||||
|     } | ||||
|  | ||||
|     // 读取所有联系人 | ||||
|     // | ||||
|     public List<PhoneBean> getPhoneList() { | ||||
|         List<PhoneBean> listPhoneBean = new ArrayList<>(); | ||||
|         ContentResolver cr = mContext.getContentResolver(); | ||||
|         Cursor cursor = cr.query(mUriPhoneContent, new String[]{NUMBER, DISPLAY_NAME}, null, null, null); | ||||
|         while (cursor.moveToNext()) { | ||||
| 			PhoneBean phoneBean = new PhoneBean(cursor.getString(1), cursor.getString(0).replaceAll("\\s", "")); | ||||
| 			listPhoneBean.add(phoneBean); | ||||
|  | ||||
|         } | ||||
| 		cursor.close(); | ||||
|  | ||||
|         Collections.sort(listPhoneBean, new Comparator<PhoneBean>() { | ||||
|                 @Override | ||||
|                 public int compare(PhoneBean o1, PhoneBean o2) { | ||||
|                     return o1.getTelPhone().compareTo(o2.getTelPhone()); | ||||
|                 } | ||||
|             }); | ||||
|  | ||||
|         return listPhoneBean; | ||||
|     } | ||||
|  | ||||
|     public boolean isPhoneInContacts(String szPhone) { | ||||
|         List<PhoneBean> listPhoneDto = getPhoneList(); | ||||
|         for (int i = 0; i < listPhoneDto.size(); i++) { | ||||
|             if (listPhoneDto.get(i).getTelPhone().equals(szPhone)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|         return false; | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/12/09 19:00:21 | ||||
|  * @Describe .* 前置预防针 | ||||
|  regex pointer preventive injection | ||||
|  简称 RegexPPi | ||||
|  */ | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| public class RegexPPiUtils { | ||||
|  | ||||
|     public static final String TAG = "RegexPPiUtils"; | ||||
|  | ||||
|     // | ||||
|     // 检验文本是否满足适合正则表达式模式计算 | ||||
|     // | ||||
|     public static boolean isPPiOK(String text) { | ||||
|         //String text = "这里是一些任意的文本内容"; | ||||
|         String regex = ".*"; | ||||
|         Pattern pattern = Pattern.compile(regex); | ||||
|         Matcher matcher = pattern.matcher(text); | ||||
|         /*if (matcher.matches()) { | ||||
|          System.out.println("文本满足该正则表达式模式"); | ||||
|          } else { | ||||
|          System.out.println("文本不满足该正则表达式模式"); | ||||
|          }*/ | ||||
|         return matcher.matches(); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,304 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2023/07/01 05:59:25 | ||||
|  * @Describe 短信接收过滤规则工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.JsonReader; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean_V1; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.text.Collator; | ||||
| import java.util.ArrayList; | ||||
| import java.util.Collections; | ||||
| import java.util.Comparator; | ||||
| import java.util.List; | ||||
| import java.nio.channels.AcceptPendingException; | ||||
|  | ||||
| public class SMSReceiveRuleUtil { | ||||
|  | ||||
|     public static final String TAG = "SMSReceiveRuleUtil"; | ||||
|  | ||||
|     public static final int VALID_MATCHRESULT_POSITION = -1; | ||||
|  | ||||
|  | ||||
|     // 单例模式的实例变量 | ||||
|     static SMSReceiveRuleUtil _mInstance; | ||||
|     // 类实例运行的上下文环境 | ||||
|     Context mContext; | ||||
|     // 当前实例的配置操作数据 | ||||
|     ArrayList<SMSAcceptRuleBean> mDataList; | ||||
|  | ||||
|     // | ||||
|     // ReceiveRule 规则数组匹配结果数据类 | ||||
|     // | ||||
|     public class MatchResult { | ||||
|         // 当前匹配规则的运算结果 | ||||
|         public SMSAcceptRuleBean.RuleType matchRuleType; | ||||
|         // 在规则数组中匹配的位置 | ||||
|         public int matchPositionInRules; | ||||
|          | ||||
|         MatchResult() { | ||||
|             matchRuleType = SMSAcceptRuleBean.RuleType.ACCEPT; | ||||
|             // 在规则数组中匹配的位置 | ||||
|             matchPositionInRules = VALID_MATCHRESULT_POSITION; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 私有的隐藏的实例构造函数 | ||||
|     // | ||||
|     private SMSReceiveRuleUtil(Context context) { | ||||
|         // 保存当前类实例的运行环境 | ||||
|         mContext = context; | ||||
|         //mszConfigPath = context.getExternalFilesDir(TAG) + File.separator + mszConfigFileName; | ||||
|         // 从存储设备加载应用数据 | ||||
|         mDataList = new ArrayList<SMSAcceptRuleBean>(); | ||||
|         loadConfigData(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 为了解决各个窗口数据同步问题, | ||||
|     // 设置数据重加载开关 | ||||
|     // @isReload : 每次取数据实例都从存储设备读取数据 | ||||
|     // | ||||
|     public static SMSReceiveRuleUtil getInstance(Context context, boolean isReload) { | ||||
|         if (_mInstance == null) { | ||||
|             _mInstance = new SMSReceiveRuleUtil(context); | ||||
|         } else if (isReload) { | ||||
|             _mInstance = new SMSReceiveRuleUtil(context); | ||||
|         } | ||||
|  | ||||
|         return _mInstance; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 从存储设备读取数据,添加默认配置,并保存到存储设备。 | ||||
|     // | ||||
|     public void resetConfig() { | ||||
|         String szAssetsFilePath = "GlobalApplication/SMSAcceptRuleBean_List.json"; | ||||
|         SMSAcceptRuleBean beanTemp = new SMSAcceptRuleBean(); | ||||
|         String szConfigFilePath = beanTemp.getBeanListJsonFilePath(mContext); | ||||
|         /*File fConfigFilePath = new File(szConfigFilePath); | ||||
|          if(fConfigFilePath.exists()) { | ||||
|          fConfigFilePath.delete(); | ||||
|          }*/ | ||||
|         FileUtil.copyAssetsToSD(mContext, szAssetsFilePath, szConfigFilePath); | ||||
|         loadConfigData(); | ||||
|     } | ||||
|  | ||||
|     public void cleanConfig() { | ||||
|         mDataList.clear(); | ||||
|         saveConfigData(); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // Rule数据排序 | ||||
|     // @isDesc : 是否降序排列 | ||||
|     // | ||||
|     public static <T extends SMSAcceptRuleBean> void sortListByRuleData(List<T> list, boolean isDesc) { | ||||
|         Collections.sort(list, new SortListByRuleData(isDesc)); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // Rule数据排序比较类定义 | ||||
|     // | ||||
|     static class SortListByRuleData implements Comparator<SMSAcceptRuleBean> { | ||||
|         private boolean mIsDesc = true; | ||||
|         // isDesc 是否降序排列 | ||||
|         public SortListByRuleData(boolean isDesc) { | ||||
|             mIsDesc = isDesc; | ||||
|         } | ||||
|         Collator cmp = Collator.getInstance(java.util.Locale.CHINA); | ||||
|         @Override | ||||
|         public int compare(SMSAcceptRuleBean o1, SMSAcceptRuleBean o2) { | ||||
|             int b0_1 = cmp.compare(o1.getRuleData(), o2.getRuleData()); | ||||
|             if (mIsDesc) { | ||||
|                 return b0_1 > 0 ? -1 : 1; | ||||
|             } else { | ||||
|                 return b0_1 > 0 ? 1 : -1; | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 添加Rule数据现 | ||||
|     // @szRule : Rule数据内容 | ||||
|     // @isEnable : Rule数据启用开关项 | ||||
|     // @@ 返回 :Rule数据添加结果 | ||||
|     // | ||||
|     public boolean addRule(SMSAcceptRuleBean bean) { | ||||
|         loadConfigData(); | ||||
|         mDataList.add(bean); | ||||
|         saveConfigData(); | ||||
|         return true; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 校验短信是否在规则表里 | ||||
|     // | ||||
|     public boolean checkIsSMSAcceptInRule(Context context, String szSMS) { | ||||
|         /*ArrayList<SMSAcceptRuleBean> configData = loadConfigData(); | ||||
|          for (int i = 0; i < configData.size(); i++) { | ||||
|          SMSAcceptRuleBean bean = configData.get(i); | ||||
|          if (bean.isEnable()) { | ||||
|          String regex = bean.getRuleData(); | ||||
|          if (szSMS.matches(regex)) { | ||||
|          if (bean.getRuleType() == SMSAcceptRuleBean.RuleType.REFUSE) { | ||||
|          return false; | ||||
|          } else if (bean.getRuleType() == SMSAcceptRuleBean.RuleType.ACCEPT) { | ||||
|          return true; | ||||
|          } | ||||
|          } | ||||
|          } | ||||
|  | ||||
|          }*/ | ||||
|         MatchResult matchResult = getReceiveRuleMatchResult(context, szSMS); | ||||
|         return matchResult.matchRuleType == SMSAcceptRuleBean.RuleType.ACCEPT; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 校验短信是否在规则表里 | ||||
|     // | ||||
|     public MatchResult getReceiveRuleMatchResult(Context context, String szSMS) { | ||||
|          | ||||
|         MatchResult matchResult = new MatchResult(); | ||||
|         matchResult.matchRuleType = !RegexPPiUtils.isPPiOK(szSMS)? SMSAcceptRuleBean.RuleType.REGEXPPIUTILS_ISPPIOK_FALSE : matchResult.matchRuleType; | ||||
|         //LogUtils.d(TAG, "RegexPPiUtils.isPPiOK(szSMS) " + Boolean.toString(RegexPPiUtils.isPPiOK(szSMS))); | ||||
|          | ||||
|         ArrayList<SMSAcceptRuleBean> configData = loadConfigData(); | ||||
|         for (int i = 0; i < configData.size(); i++) { | ||||
|             SMSAcceptRuleBean bean = configData.get(i); | ||||
|             if (bean.isEnable()) { | ||||
|                 String regex = bean.getRuleData(); | ||||
|                 if (szSMS.matches(regex)) { | ||||
|                     matchResult.matchRuleType = bean.getRuleType(); | ||||
|                     matchResult.matchPositionInRules = i; | ||||
|                     LogUtils.d(TAG, "matchPositionInRules " + Integer.toString(i)); | ||||
|                     return matchResult; | ||||
|                 } | ||||
|             } | ||||
|  | ||||
|         } | ||||
|         return matchResult; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 加载应用配置数据 | ||||
|     // | ||||
|     public ArrayList<SMSAcceptRuleBean> loadConfigData() { | ||||
|         ArrayList<SMSAcceptRuleBean> list = new ArrayList<SMSAcceptRuleBean>(); | ||||
|         SMSAcceptRuleBean.loadBeanList(mContext, list, SMSAcceptRuleBean.class); | ||||
|         for (int i = 0; i < list.size(); i++) { | ||||
|             LogUtils.d(TAG, "loadConfigData isEnable : " + Boolean.toString(list.get(i).isEnable())); | ||||
|         } | ||||
|         mDataList.clear(); | ||||
|         mDataList.addAll(list); | ||||
|         return mDataList; | ||||
|     } | ||||
|  | ||||
|     /*ArrayList<SMSAcceptRuleBean_V1> loadDataFromPath(String szPath) { | ||||
|      File fJson = new File(szPath); | ||||
|      ArrayList<SMSAcceptRuleBean_V1> listTemp = null; | ||||
|      try { | ||||
|      listTemp = readJsonStream(new FileInputStream(fJson)); | ||||
|      } catch (IOException e) { | ||||
|      LogUtils.d(TAG, "IOException : " + e.getMessage()); | ||||
|      } | ||||
|      if (listTemp == null) { | ||||
|      listTemp = new ArrayList<SMSAcceptRuleBean_V1>(); | ||||
|      } | ||||
|      return listTemp; | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件 | ||||
|     // | ||||
|     public ArrayList<SMSAcceptRuleBean_V1> readJsonStream_V1(InputStream in) throws IOException { | ||||
|         JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); | ||||
|         return readJsonArrayList_V1(reader); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件的每一 Json 项 | ||||
|     // | ||||
|     public ArrayList<SMSAcceptRuleBean_V1> readJsonArrayList_V1(JsonReader reader) throws IOException { | ||||
|         ArrayList<SMSAcceptRuleBean_V1> list = new ArrayList<SMSAcceptRuleBean_V1>(); | ||||
|         reader.beginArray(); | ||||
|         while (reader.hasNext()) { | ||||
|             list.add(readBeanItem_V1(reader)); | ||||
|         } | ||||
|         reader.endArray(); | ||||
|         return list; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     public SMSAcceptRuleBean_V1 readBeanItem_V1(JsonReader reader) throws IOException { | ||||
|         SMSAcceptRuleBean_V1 bean = new SMSAcceptRuleBean_V1(); | ||||
|         int nReaderCount = 0; | ||||
|         reader.beginObject(); | ||||
|         while (reader.hasNext()) { | ||||
|             String name = reader.nextName(); | ||||
|             if (name.equals("userID")) { | ||||
|                 bean.setUserID(reader.nextString()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("ruleData")) { | ||||
|                 bean.setRuleData(reader.nextString()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("enable")) { | ||||
|                 bean.setEnable(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } else { | ||||
|                 reader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         reader.endObject(); | ||||
|         return nReaderCount > 0 ? bean : null; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 写入 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     /*public void writeBeanItem(JsonWriter writer, SMSAcceptRuleBean_V1 bean) throws IOException { | ||||
|      writer.beginObject(); | ||||
|      writer.name("userID").value(bean.getUserID()); | ||||
|      writer.name("ruleData").value(bean.getRuleData()); | ||||
|      writer.name("enable").value(bean.isEnable()); | ||||
|      writer.endObject(); | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 保存应用配置数据 | ||||
|     // | ||||
|     public void saveConfigData() { | ||||
|         SMSAcceptRuleBean.saveBeanList(mContext, mDataList, SMSAcceptRuleBean.class); | ||||
|     } | ||||
|  | ||||
|     /*// | ||||
|      // 写入 Json 文件 | ||||
|      // | ||||
|      public void writeJsonStream(OutputStream out, ArrayList<SMSAcceptRuleBean_V1> beanList) throws IOException { | ||||
|      JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8")); | ||||
|      writer.setIndent("  "); | ||||
|      writeJsonArrayList(writer, beanList); | ||||
|      writer.close(); | ||||
|      } | ||||
|  | ||||
|      // | ||||
|      // 记录 Json 文件的某一 Json 项 | ||||
|      // | ||||
|      public void writeJsonArrayList(JsonWriter writer, ArrayList<SMSAcceptRuleBean_V1> beanList) throws IOException { | ||||
|      writer.beginArray(); | ||||
|      for (SMSAcceptRuleBean_V1 bean : beanList) { | ||||
|      writeBeanItem(writer, bean); | ||||
|      } | ||||
|      writer.endArray(); | ||||
|      }*/ | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 19:29:59 | ||||
|  * @Describe 短信回收站工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import cc.winboll.studio.mymessagemanager.GlobalApplication; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSBean; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSRecycleBean; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class SMSRecycleUtil { | ||||
|      | ||||
|     public static final String TAG = "SMSRecycleUtil"; | ||||
|      | ||||
|     public static String getSMSRecycleListDataPath(Context context) { | ||||
|         if(cc.winboll.studio.mymessagemanager.BuildConfig.DEBUG) { | ||||
|             return context.getExternalFilesDir(TAG) + "/mSMSRecycleList.json"; | ||||
|         } else { | ||||
|             return context.getDataDir() + "/home/" + TAG + "/mSMSRecycleList.json"; | ||||
|         } | ||||
|     } | ||||
|      | ||||
|     public static void addSMSRecycleItem(Context context, SMSBean bean) { | ||||
|         ArrayList<SMSRecycleBean> list = new ArrayList<SMSRecycleBean>(); | ||||
|         SMSRecycleBean.loadBeanListFromFile(getSMSRecycleListDataPath(context), list, SMSRecycleBean.class); | ||||
|         SMSRecycleBean smsRecycleBean = new SMSRecycleBean(bean, System.currentTimeMillis()); | ||||
|         list.add(smsRecycleBean); | ||||
|         SMSRecycleBean.saveBeanListToFile(getSMSRecycleListDataPath(context), list); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,387 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用短信管理工具类 | ||||
|  */ | ||||
| import android.app.PendingIntent; | ||||
| import android.content.ContentUris; | ||||
| import android.content.ContentValues; | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.database.Cursor; | ||||
| import android.database.sqlite.SQLiteException; | ||||
| import android.net.Uri; | ||||
| import android.os.Bundle; | ||||
| import android.provider.Telephony; | ||||
| import android.telephony.gsm.SmsManager; | ||||
| import android.telephony.gsm.SmsMessage; | ||||
| import cc.winboll.studio.mymessagemanager.beans.SMSBean; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import com.hjq.toast.ToastUtils; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class SMSUtil { | ||||
|  | ||||
|     public static String TAG = "SMSUtil"; | ||||
|     public static String SENT_SMS_ACTION = SMSUtil.class.getName() + ".SENT_SMS_ACTION"; | ||||
|     public static String DELIVERED_SMS_ACTION = SMSUtil.class.getName() + ".SENT_SMS_ACTION"; | ||||
|  | ||||
|     final static String SMS_URI_ALL = "content://sms/"; // 所有短信 | ||||
|     final static String SMS_URI_INBOX = "content://sms/inbox"; // 收件箱 | ||||
|     final static String SMS_URI_SEND = "content://sms/sent"; // 已发送 | ||||
|     final static String SMS_URI_DRAFT = "content://sms/draft"; // 草稿 | ||||
|     final static String SMS_URI_OUTBOX = "content://sms/outbox"; // 发件箱 | ||||
|     final static String SMS_URI_FAILED = "content://sms/failed"; // 发送失败 | ||||
|     final static String SMS_URI_QUEUED = "content://sms/queued"; // 待发送列表 | ||||
|  | ||||
|     // | ||||
|     // 获得短信内容 | ||||
|     // | ||||
|     public static String getSmsBody(Intent intent) { | ||||
|  | ||||
|         String tempString = ""; | ||||
|         Bundle bundle = intent.getExtras(); | ||||
|         Object messages[] = (Object[]) bundle.get("pdus"); | ||||
|         SmsMessage[] smsMessage = new SmsMessage[messages.length]; | ||||
|         for (int n = 0; n < messages.length; n++) { | ||||
|             smsMessage[n] = SmsMessage.createFromPdu((byte[]) messages[n]); | ||||
|             // 短信有可能因为使用了回车而导致分为多条,所以要加起来接受 | ||||
|             tempString += smsMessage[n].getDisplayMessageBody(); | ||||
|         } | ||||
|         return tempString; | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public static int deleteSMSById(Context context, int nDeleteId) { | ||||
|         //LogUtils.d(TAG, "nDeleteId is " + Integer.toString(nDeleteId)); | ||||
|         int nResult = 0; | ||||
|         //int nTotal = 0; | ||||
|         //Uri uri = Uri.parse(SMS_URI_ALL); | ||||
|         //String[] projection = new String[] { "_id", "address", "person", | ||||
|         //    "body", "date", "type", }; | ||||
|         /*Cursor cursor = context.getContentResolver().query(uri, projection, | ||||
|          "_id = ? ", | ||||
|          new String[] {Integer.toString(nDeleteId)}, | ||||
|          "");*/ | ||||
|         nResult = context.getContentResolver().delete(Uri.parse("content://sms/" + Integer.toString(nDeleteId)), null, null); | ||||
|         /*if (cursor.moveToFirst()) { | ||||
|          do { | ||||
|          //nTotal++; | ||||
|          //int nSMSId = cursor.getInt(0); | ||||
|          //String szType = (SMSBean.Type.values()[cursor.getInt(5)]).toString(); | ||||
|          //LogUtils.d(TAG, "nSMSId is : " + Integer.toString(nSMSId)); | ||||
|          //LogUtils.d(TAG, "szType is : " + szType); | ||||
|          //if (nSMSId == nDeleteId) { | ||||
|          //LogUtils.d(TAG, "nSMSId == nDeleteId"); | ||||
|          //int threadId = cursor.getInt(cursor.getColumnIndex("_id")); | ||||
|          //nResult = context.getContentResolver().delete(Uri.parse("content://sms/" + nSMSId), null, null); | ||||
|          //LogUtils.d(TAG, "getContentResolver delete"); | ||||
|          //} | ||||
|          } while (cursor.moveToNext()); | ||||
|          }*/ | ||||
|  | ||||
|         /*if (!cursor.isClosed()) { | ||||
|          cursor.close(); | ||||
|          cursor = null; | ||||
|          }*/ | ||||
|  | ||||
|         //LogUtils.d(TAG, "nTotal is : " + Integer.toString(nTotal)); | ||||
|         //LogUtils.d(TAG, "nResult is : " + Integer.toString(nResult)); | ||||
|         return nResult; | ||||
|     } | ||||
|  | ||||
|     public static ArrayList<SMSBean> getAllSMSList(Context context) { | ||||
|         ArrayList<SMSBean> returnList = new ArrayList<SMSBean>(); | ||||
|         try { | ||||
|             String szReplaceString = AppConfigUtil.getInstance(context).getPhoneReplaceString(); | ||||
|  | ||||
|             Uri uri = Uri.parse(SMS_URI_ALL); | ||||
|             String[] projection = new String[] { "_id", "address", "person", | ||||
|                 "body", "date", "type", }; | ||||
|             Cursor cur = context.getContentResolver().query(uri, projection, | ||||
|                                                             "", | ||||
|                                                             null, | ||||
|                                                             ""); | ||||
|             // 获取短信中最新的未读短信 | ||||
|             // Cursor cur = getContentResolver().query(uri, projection, | ||||
|             // "read = ?", new String[]{"0"}, "date desc"); | ||||
|             if (cur.moveToFirst()) { | ||||
|                 do { | ||||
|                     SMSBean smsBean = new SMSBean(); | ||||
|                     smsBean.setId(cur.getInt(0)); | ||||
|                     smsBean.setAddress(cur.getString(1).replaceAll(szReplaceString, "")); | ||||
|                     smsBean.setPerson(cur.getInt(2)); | ||||
|                     smsBean.setBody(cur.getString(3)); | ||||
|                     smsBean.setDate(cur.getLong(4)); | ||||
|                     smsBean.setType(SMSBean.Type.values()[cur.getInt(5)]); | ||||
|                     returnList.add(smsBean); | ||||
|                 } while (cur.moveToNext()); | ||||
|  | ||||
|                 // 按时间降序排列 | ||||
|                 SMSBean.sortSMSByDateDesc(returnList, true); | ||||
|  | ||||
|                 // 去除重复 mszAddress 的数据; | ||||
|                 for (int i = returnList.size() - 1; i > -1; i--) { | ||||
|                     String szCheckAddress =returnList.get(i).getAddress(); | ||||
| 					if (szCheckAddress != null) { | ||||
| 						for (int j = i - 1; j > -1; j--) { | ||||
| 							if ((returnList.get(j).getAddress() != null) | ||||
| 								&& (szCheckAddress.equals(returnList.get(j).getAddress()))) { | ||||
| 								returnList.remove(i); | ||||
| 								break; | ||||
| 							} | ||||
| 						} | ||||
| 					} | ||||
|  | ||||
|                 } | ||||
|  | ||||
|                 if (!cur.isClosed()) { | ||||
|                     cur.close(); | ||||
|                     cur = null; | ||||
|                 } | ||||
|             } | ||||
|         } catch (SQLiteException e) { | ||||
|             LogUtils.d(TAG, e.getMessage(), Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return returnList; | ||||
|     } | ||||
|  | ||||
|     public static ArrayList<SMSBean> getSMSListByPhone(Context context, String szPhone) { | ||||
|         ArrayList<SMSBean> returnList = new ArrayList<SMSBean>(); | ||||
|         try { | ||||
|  | ||||
|  | ||||
|             Uri uri = Uri.parse(SMS_URI_ALL); | ||||
|             String[] projection = new String[] { "_id", "address", "person", | ||||
|                 "body", "date", "type", }; | ||||
|             Cursor cursor; | ||||
|             AppConfigUtil configUtil = AppConfigUtil.getInstance(context); | ||||
|             String szPhoneCountryCodePrefix = "\\s"; | ||||
|             if (configUtil.mAppConfigBean.isMergeCountryCodePrefix()) { | ||||
|                 szPhoneCountryCodePrefix = "+" + configUtil.mAppConfigBean.getCountryCode() + szPhone; | ||||
|                 cursor = context.getContentResolver().query(uri, projection, | ||||
|                                                             "address = ? or address = ? ", | ||||
|                                                             new String[] {szPhone, szPhoneCountryCodePrefix}, | ||||
|                                                             ""); | ||||
|             } else { | ||||
|                 cursor = context.getContentResolver().query(uri, projection, | ||||
|                                                             "address = ? ", | ||||
|                                                             new String[] {szPhone}, | ||||
|                                                             ""); | ||||
|             } | ||||
|             // 获取短信中最新的未读短信 | ||||
|             // Cursor cur = getContentResolver().query(uri, projection, | ||||
|             // "read = ?", new String[]{"0"}, "date desc"); | ||||
|             if (cursor.moveToFirst()) { | ||||
|                 do { | ||||
|                     /*int nSMSId = cursor.getInt(0); | ||||
|                      String szType = (SMSBean.Type.values()[cursor.getInt(5)]).toString(); | ||||
|                      LogUtils.d(TAG, "nSMSId is : " + Integer.toString(nSMSId)); | ||||
|                      LogUtils.d(TAG, "szType is : " + szType); | ||||
|                      */ | ||||
|  | ||||
|                     SMSBean smsBean = new SMSBean(); | ||||
|                     smsBean.setId(cursor.getInt(0)); | ||||
|                     smsBean.setAddress(cursor.getString(1)); | ||||
|                     smsBean.setPerson(cursor.getInt(2)); | ||||
|                     smsBean.setBody(cursor.getString(3)); | ||||
|                     smsBean.setDate(cursor.getLong(4)); | ||||
|                     smsBean.setType(SMSBean.Type.values()[cursor.getInt(5)]); | ||||
|                     /*long nDateDefault = Date.parse("2022/01/01"); | ||||
|                      if (smsBean.mnDate < nDateDefault) { | ||||
|                      LogUtils.d(TAG, "smsBean >>> " + smsBean.toString()); | ||||
|                      smsBean.mnDate = nDateDefault; | ||||
|                      }*/ | ||||
|  | ||||
|                     returnList.add(smsBean); | ||||
|                 } while (cursor.moveToNext()); | ||||
|  | ||||
|                 if (!cursor.isClosed()) { | ||||
|                     cursor.close(); | ||||
|                     cursor = null; | ||||
|                 } | ||||
|             } | ||||
|         } catch (SQLiteException e) { | ||||
|             LogUtils.d("SQLiteException : ", e.getMessage()); | ||||
|         } | ||||
|         return returnList; | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // | ||||
|     // 获得短信地址 | ||||
|     // | ||||
|     public static String getSmsAddress(Intent intent) { | ||||
|  | ||||
|         Bundle bundle = intent.getExtras(); | ||||
|         Object messages[] = (Object[]) bundle.get("pdus"); | ||||
|         return SmsMessage.createFromPdu((byte[]) messages[0]) | ||||
|             .getDisplayOriginatingAddress(); | ||||
|     } | ||||
|  | ||||
|     public static int saveReceiveSms(Context context, String phoneNumber, String message, String readState, long time, String folderName) { | ||||
|         int nResultId = -1; | ||||
|         try { | ||||
|             ContentValues values = new ContentValues(); | ||||
|             values.put("address", phoneNumber); | ||||
|             values.put("body", message); | ||||
|             values.put("read", readState); //"0" for have not read sms and "1" for have read sms | ||||
|             values.put("date", Long.toString(time)); | ||||
|             //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | ||||
| 			Uri uri = Telephony.Sms.Sent.CONTENT_URI; | ||||
| 			if (folderName.equals("inbox")) { | ||||
| 				uri = Telephony.Sms.Inbox.CONTENT_URI; | ||||
| 			} | ||||
| 		    // 插入数据 | ||||
|             Uri uriReturn = context.getContentResolver().insert(uri, values); | ||||
|             // 读取插入记录的 id | ||||
|             nResultId = (int)ContentUris.parseId(uriReturn); | ||||
|             /*} else { | ||||
| 			 // folderName  could be inbox or sent | ||||
| 			 context.getContentResolver().insert(Uri.parse("content://sms/" + folderName), values); | ||||
| 			 }*/ | ||||
|             //ToastUtils.show("saveReceiveSms done."); | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return nResultId; | ||||
|     } | ||||
|  | ||||
|     public static long saveSendedSMS(Context context, String phoneNumber, String message) { | ||||
|         SMSBean smsBean = new SMSBean(); | ||||
|         smsBean.setAddress(phoneNumber); | ||||
|         smsBean.setBody(message); | ||||
|         smsBean.setReadStatus(SMSBean.ReadStatus.UNREAD); | ||||
|         smsBean.setDate(System.currentTimeMillis()); | ||||
|  | ||||
|         return saveSendedSMS(context, smsBean); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     public static long saveOldSendedSMS(Context context, SMSBean smsBean) { | ||||
|         long nResultId = 0; | ||||
|         try { | ||||
|             ContentValues values = SMSBean.createOldSendedSMSContentValues(smsBean); | ||||
|             LogUtils.d(TAG, "ContentValues created."); | ||||
|             //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | ||||
|             Uri uri = Telephony.Sms.Sent.CONTENT_URI; | ||||
|             Uri uriReturn = context.getContentResolver().insert(uri, values); | ||||
|             LogUtils.d(TAG, "inserted"); | ||||
|             // 读取插入记录的 id | ||||
|             nResultId = ContentUris.parseId(uriReturn); | ||||
|             /*} else { | ||||
|              // folderName  could be inbox or sent | ||||
|              context.getContentResolver().insert(Uri.parse(SMS_URI_SEND), values); | ||||
|              }*/ | ||||
|             LogUtils.d(TAG, "nResultId : " + Long.toString(nResultId)); | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return nResultId; | ||||
|     } | ||||
|  | ||||
|     public static long saveSendedSMS(Context context, SMSBean smsBean) { | ||||
|         long nResultId = 0; | ||||
|         try { | ||||
|             ContentValues values = SMSBean.createSendedSMSContentValues(smsBean); | ||||
|  | ||||
|             //if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) { | ||||
| 			Uri uri = Telephony.Sms.Sent.CONTENT_URI; | ||||
| 			Uri uriReturn = context.getContentResolver().insert(uri, values); | ||||
|             // 读取插入记录的 id | ||||
|             nResultId = ContentUris.parseId(uriReturn); | ||||
|             /*} else { | ||||
| 			 // folderName  could be inbox or sent | ||||
| 			 context.getContentResolver().insert(Uri.parse(SMS_URI_SEND), values); | ||||
| 			 }*/ | ||||
|             //LogUtils.d(TAG, "nResultId : " + Integer.toString(nResultId)); | ||||
|         } catch (Exception e) { | ||||
|             LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|         } | ||||
|         return nResultId; | ||||
|     } | ||||
|  | ||||
|     // 发送短文本短信 | ||||
|     // phoneNumber:接收号码 | ||||
|     // message:发送内容 | ||||
|     // | ||||
|     /*public static boolean sendSMS(Context context, String phoneNumber, String message) { | ||||
|      //Getting intent and PendingIntent instance | ||||
|      PendingIntent pi = PendingIntent. | ||||
|      getBroadcast(context, 0, new Intent(), PendingIntent.FLAG_IMMUTABLE); | ||||
|      //Get the SmsManager instance and call the sendTextMessage method to send message | ||||
|      SmsManager sms=SmsManager.getDefault(); | ||||
|      sms.sendTextMessage(phoneNumber, null, message, pi, null); | ||||
|      if (SMSUtil.saveSendedSMS(context, phoneNumber, message) != 0) { | ||||
|      Toast.makeText(context, "TO : <" + phoneNumber + "> Sended.", Toast.LENGTH_SHORT).show(); | ||||
|      return true; | ||||
|      } | ||||
|      return false; | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 发送长文本短信,第一种方法发送短信,是将短信分割成多条短信,分别发给接收方。 | ||||
|     // phoneNumber:接收号码 | ||||
|     // message:发送内容 | ||||
|     // | ||||
|     /*public static boolean sendMessageByInterface(Context context, String phoneNumber, String message) { | ||||
|      SmsManager smsManager = SmsManager.getDefault(); | ||||
|      //String message = "这是一条很长的短信,需要分割"; | ||||
|      //int maxLength = SmsManager.getMaxMessageLength(); // 获取最大长度 | ||||
|      int maxLength = 70; | ||||
|      //int remainingChars = maxLength; | ||||
|      List<String> messages = new ArrayList<>(); | ||||
|      for (int i = 0; i < message.length(); i += maxLength) { | ||||
|      if (i + maxLength >= message.length()) { // 如果到达结尾 | ||||
|      messages.add(message.substring(i)); | ||||
|      break; | ||||
|      } else { | ||||
|      messages.add(message.substring(i, i + maxLength)); | ||||
|      } | ||||
|      } | ||||
|  | ||||
|      for (String msg : messages) { | ||||
|      smsManager.sendTextMessage(phoneNumber, null, msg, null, null); | ||||
|      } | ||||
|      ToastUtils.show("TO : <" + phoneNumber + "> Sended."); | ||||
|      if (SMSUtil.saveSendedSMS(context, phoneNumber, message) != 0) { | ||||
|      return true; | ||||
|      } | ||||
|      return false; | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 发送长文本短信,第二种方法是将短信内容一次性发给接收方。在接收方的短信列表中,显示的是一条短信,但是实际上还是按多条短信计费。 | ||||
|     // phoneNumber:接收号码 | ||||
|     // message:发送内容 | ||||
|     // | ||||
|     public static boolean sendMessageByInterface2(Context context, String phoneNumber, String message) { | ||||
|         SmsManager sms = SmsManager.getDefault(); | ||||
|  | ||||
|         Intent sentIntent = new Intent(SENT_SMS_ACTION); | ||||
|         PendingIntent sentPI = PendingIntent.getBroadcast(context, 0, sentIntent, 0); | ||||
|  | ||||
|         Intent deliverIntent = new Intent(DELIVERED_SMS_ACTION); | ||||
|         PendingIntent deliverPI = PendingIntent.getBroadcast(context, 0, deliverIntent, 0); | ||||
|  | ||||
|         if (message.length() > 70) {   | ||||
|             ArrayList<String> msgs = sms.divideMessage(message);   | ||||
|             ArrayList<PendingIntent> sentIntents =  new ArrayList<PendingIntent>(); | ||||
|             for (int i = 0;i < msgs.size();i++) {   | ||||
|                 sentIntents.add(sentPI);   | ||||
|             }   | ||||
|             sms.sendMultipartTextMessage(phoneNumber, null, msgs, sentIntents, null); | ||||
|             LogUtils.d(TAG, "Long SMS TO : <" + phoneNumber + "> Sended."); | ||||
|         } else {   | ||||
|             sms.sendTextMessage(phoneNumber, null, message, sentPI, deliverPI); | ||||
|             LogUtils.d(TAG, "SMS TO : <" + phoneNumber + "> Sended."); | ||||
|         } | ||||
|         if (SMSUtil.saveSendedSMS(context, phoneNumber, message) != 0) { | ||||
|             ToastUtils.show("SMS TO : <" + phoneNumber + "> Sended."); | ||||
|             return true; | ||||
|         } | ||||
|         return false; | ||||
| 	} | ||||
| } | ||||
| @@ -0,0 +1,34 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用服务组件工具类 | ||||
|  */ | ||||
| import android.app.ActivityManager; | ||||
| import android.content.Context; | ||||
| import java.util.List; | ||||
|  | ||||
| public class ServiceUtil { | ||||
|     public final static String TAG = "ServiceUtil"; | ||||
|  | ||||
|     public static boolean isServiceAlive(Context context, String szServiceName) { | ||||
|         // 获取Activity管理者对象 | ||||
|         ActivityManager manager = (ActivityManager) context | ||||
|             .getSystemService(Context.ACTIVITY_SERVICE); | ||||
|         // 获取正在运行的服务(此处设置最多取1000个) | ||||
|         List<ActivityManager.RunningServiceInfo> runningServices = manager | ||||
|             .getRunningServices(1000); | ||||
|         if (runningServices.size() <= 0) { | ||||
|             return false; | ||||
|         } | ||||
|         // 遍历,若存在名字和传入的serviceName的一致则说明存在 | ||||
|         for (ActivityManager.RunningServiceInfo runningServiceInfo : runningServices) { | ||||
|             if (runningServiceInfo.service.getClassName().equals(szServiceName)) { | ||||
|                 return true; | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return false; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,429 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe TTS 语音播放工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.Intent; | ||||
| import android.os.Message; | ||||
| import android.util.JsonReader; | ||||
| import android.widget.Toast; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.activitys.TTSPlayRuleActivity; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSPlayRuleBean; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSPlayRuleBean_V1; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSSpeakTextBean; | ||||
| import cc.winboll.studio.mymessagemanager.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.mymessagemanager.services.TTSPlayService; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import java.io.File; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.InputStreamReader; | ||||
| import java.util.ArrayList; | ||||
| import java.util.regex.Matcher; | ||||
| import java.util.regex.Pattern; | ||||
|  | ||||
| public class TTSPlayRuleUtil { | ||||
|     public static final String TAG = "TTSPlayRuleUtil"; | ||||
|  | ||||
|     TTSPlayRuleActivity mTTSPlayRuleActivity; | ||||
|     static TTSPlayRuleUtil _mTTSPlayRuleUtil; | ||||
| 	Context mContext; | ||||
| 	ArrayList<TTSPlayRuleBean> mConfigData; | ||||
|     public static String mszConfigFileName = TAG + ".json"; | ||||
|     String mszConfigPath_V1 = null; | ||||
|  | ||||
|     TTSPlayRuleUtil(Context context) { | ||||
|         mContext = context; | ||||
| 		mszConfigPath_V1 = context.getExternalFilesDir(TAG) + File.separator + mszConfigFileName; | ||||
| 		mConfigData = new ArrayList<TTSPlayRuleBean>(); | ||||
| 		mConfigData = loadConfigData(); | ||||
|     } | ||||
|  | ||||
|     public static TTSPlayRuleUtil getInstance(Context context) { | ||||
|         if (_mTTSPlayRuleUtil == null) { | ||||
|             _mTTSPlayRuleUtil = new TTSPlayRuleUtil(context); | ||||
|         } | ||||
|         return _mTTSPlayRuleUtil; | ||||
|     } | ||||
|  | ||||
|     public void initTTSPlayRuleActivity(TTSPlayRuleActivity activity) { | ||||
|         mTTSPlayRuleActivity = activity; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 用 TTS 播放语音 | ||||
|     // @szSpeak : 语音内容 | ||||
|     // @nRepeat : 重复次数 | ||||
|     // | ||||
|     public static void speakText(Context context, String szSpeak, int nRepeat) { | ||||
|         speakText(context, szSpeak, 0, nRepeat); | ||||
|     } | ||||
|  | ||||
|  | ||||
|     // | ||||
|     // 用 TTS 播放语音 | ||||
|     // @szSpeak : 语音内容 | ||||
|     // @nTtsPlayDelayTimes : 延迟初始播放时间毫秒数 | ||||
|     // @nRepeat : 重复次数 | ||||
|     // | ||||
|     public static void speakText(Context context, String szSpeak, int nTtsPlayDelayTimes, int nRepeat) { | ||||
|         // 初始化语音数据 | ||||
|         ArrayList<TTSSpeakTextBean> ttsData = new ArrayList<TTSSpeakTextBean>(); | ||||
|         ttsData.add(new TTSSpeakTextBean(nTtsPlayDelayTimes, szSpeak)); | ||||
|         for (int i = 0; i < nRepeat - 1; i++) { | ||||
|             ttsData.add(new TTSSpeakTextBean(3000, szSpeak)); | ||||
|         } | ||||
|         // 调用TTS语音服务 | ||||
|         Intent intent = new Intent(context, TTSPlayService.class); | ||||
|         intent.putExtra(TTSPlayService.EXTRA_SPEAKDATA, ttsData); | ||||
|         context.startService(intent); | ||||
|     } | ||||
|  | ||||
| 	// | ||||
|     // 短信解析模式播放短信的 TTS 语音 | ||||
|     // @context : 上下文 | ||||
|     // @szSMS : 要解析的短信 | ||||
|     // | ||||
|     public int speakTTSAnalyzeModeText(String szSMS) { | ||||
| 		return speakTTSAnalyzeModeText(szSMS, 0); | ||||
| 	} | ||||
|  | ||||
|     // | ||||
|     // 短信解析模式播放短信的 TTS 语音 | ||||
|     // @context : 上下文 | ||||
|     // @szSMS : 要解析的短信 | ||||
|     // @nTtsPlayDelayTimes : 延迟初始播放时间毫秒数 | ||||
|     // | ||||
|     public int speakTTSAnalyzeModeText(String szSMS, int nTtsPlayDelayTimes) { | ||||
|         // 初始化语音数据 | ||||
|         ArrayList<TTSSpeakTextBean> ttsData = new ArrayList<TTSSpeakTextBean>(); | ||||
|         int reault = addTTSAnalyzeModeReply(szSMS, ttsData, nTtsPlayDelayTimes); | ||||
|  | ||||
|         // 调用TTS语音服务 | ||||
|         Intent intent = new Intent(mContext, TTSPlayService.class); | ||||
|         intent.putExtra(TTSPlayService.EXTRA_SPEAKDATA, ttsData); | ||||
|         mContext.startService(intent); | ||||
|  | ||||
|         return reault; | ||||
| 	} | ||||
|  | ||||
| 	public void deleteTTSRuleBean(int position) { | ||||
| 		mConfigData.remove(position); | ||||
|         saveConfigData(); | ||||
| 	} | ||||
|  | ||||
|     // | ||||
|     // 添加语音回复数据 | ||||
|     // @context : 上下文 | ||||
|     // @szSMS : 提供校验的短信 | ||||
|     // @ttsData : 语音数据规则表 | ||||
|     // @nTtsPlayDelayTimes : 延迟初始播放时间毫秒数 | ||||
|     // | ||||
|     int addTTSAnalyzeModeReply(String szSMS, ArrayList<TTSSpeakTextBean> ttsData, int nTtsPlayDelayTimes) { | ||||
|         for (int i = 0; i < mConfigData.size(); i++) { | ||||
| 			if (mConfigData.get(i).isEnable()) { | ||||
| 				String szResult = getRewriteRegExpResult(szSMS, mConfigData.get(i).getPatternText(), mConfigData.get(i).getTtsRuleText()); | ||||
| 				if (!szResult.equals("")) { | ||||
| 					ttsData.add(new TTSSpeakTextBean(nTtsPlayDelayTimes, szResult)); | ||||
| 					return i; | ||||
| 				} | ||||
| 			} | ||||
|         } | ||||
|         return -1; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 添加语音回复数据 | ||||
|     // @context : 上下文 | ||||
|     // @szSMS : 提供校验的短信 | ||||
|     // @ttsData : 语音数据规则表 | ||||
|     // | ||||
|     void addTTSAnalyzeModeReply(String szSMS, ArrayList<TTSSpeakTextBean> ttsData) { | ||||
|         addTTSAnalyzeModeReply(szSMS, ttsData, 0); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 测试语音回复数据 | ||||
|     // @context : 上下文 | ||||
|     // @szSMS : 示例短信 | ||||
|     // @ttsData : 语音数据规则 | ||||
|     // | ||||
|     public String testTTSAnalyzeModeReply(TTSPlayRuleBean bean) { | ||||
|  | ||||
|         String szResult = getRewriteRegExpResult(bean.getDemoSMSText(), bean.getPatternText(), bean.getTtsRuleText()); | ||||
| 		if (szResult.equals("")) { | ||||
| 			szResult += "\nDemoSMSText : " + bean.getDemoSMSText(); | ||||
| 			szResult += "\nPatternText : " + bean.getPatternText(); | ||||
| 			szResult += "\nTTSRuleText : " + bean.getTtsRuleText(); | ||||
| 		} else { | ||||
| 			// 初始化语音数据 | ||||
| 			ArrayList<TTSSpeakTextBean> ttsData = new ArrayList<TTSSpeakTextBean>(); | ||||
| 			ttsData.add(new TTSSpeakTextBean(0, szResult)); | ||||
|  | ||||
| 			// 调用TTS语音服务 | ||||
| 			Intent intent = new Intent(mContext, TTSPlayService.class); | ||||
| 			intent.putExtra(TTSPlayService.EXTRA_SPEAKDATA, ttsData); | ||||
| 			mContext.startService(intent); | ||||
| 		} | ||||
| 		return szResult; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 正则替换函数 | ||||
|     // @szMatchText : 操作字符串 | ||||
|     // @szPattern : 查找模板 | ||||
|     // @szRewrite : 替换模板 | ||||
|     // | ||||
|     String getRewriteRegExpResult(String szMatchText, String szPattern, String szRewrite) { | ||||
|         String szReturn = ""; | ||||
| 		if (!szPattern.equals("") && !szRewrite.equals("")) { | ||||
| 			try { | ||||
| 				Pattern pattern = Pattern.compile(szPattern, Pattern.MULTILINE); | ||||
| 				Matcher matcher = pattern.matcher(szMatchText); | ||||
|                 LogUtils.d(TAG, "szMatchText : " + szMatchText); | ||||
| 				while (matcher.find()) { | ||||
| 					szReturn += matcher.replaceAll(szRewrite); | ||||
| 				} | ||||
| 			} catch (java.lang.IndexOutOfBoundsException ex) { | ||||
| 				LogUtils.d(TAG, "getRewriteRegExpResult(...) IndexOutOfBoundsException : " + ex.getMessage()); | ||||
| 			} | ||||
| 		} | ||||
|  | ||||
|         return szReturn; | ||||
|     } | ||||
|  | ||||
| 	public void addNewTTSRuleBean(TTSPlayRuleBean bean) { | ||||
| 		mConfigData.add(0, bean); | ||||
| 		saveConfigData(); | ||||
| 	} | ||||
|  | ||||
| 	public void changeBeanPosition(int currentPosition, boolean isUp) { | ||||
| 		if (isUp && currentPosition > 0) { | ||||
| 			//LogUtils.d(TAG, "Up"); | ||||
| 			mConfigData.add(currentPosition - 1, mConfigData.get(currentPosition)); | ||||
| 			mConfigData.remove(currentPosition + 1); | ||||
|             saveConfigData(); | ||||
| 			return; | ||||
| 		} | ||||
|  | ||||
| 		if (!isUp && currentPosition < mConfigData.size() - 1) { | ||||
| 			//LogUtils.d(TAG, "Down"); | ||||
| 			mConfigData.add(currentPosition + 2, mConfigData.get(currentPosition)); | ||||
| 			mConfigData.remove(currentPosition); | ||||
|             saveConfigData(); | ||||
| 			return; | ||||
| 		} | ||||
| 	} | ||||
|  | ||||
| 	public void setBeanEnable(int position, boolean isEnable) { | ||||
| 		mConfigData.get(position).setIsEnable(isEnable); | ||||
| 		saveConfigData(); | ||||
| 	} | ||||
|  | ||||
|     /*public String getConfigPath() { | ||||
|      return mszConfigPath_V1; | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 从指定路径的文件读取数据,添加并保存到现有的数据文件。 | ||||
|     // @szPath : 要读取的文件指定的路径 | ||||
|     // @@ 返回 :添加的数据条数 | ||||
|     // | ||||
|     /*public int importConfig(String szPath) { | ||||
|      ArrayList<TTSPlayRuleBean> listBeanImport = loadDataFromPath(szPath); | ||||
|      // 添加更新表到现有操作表 | ||||
|      if (mConfigData == null) { | ||||
|      mConfigData = new ArrayList<TTSPlayRuleBean>(); | ||||
|      } | ||||
|      ArrayList<TTSPlayRuleBean> configData = loadConfigData(); | ||||
|      configData.addAll(listBeanImport); | ||||
|      // 保存操作表数据 | ||||
|      saveConfigData(configData); | ||||
|      return listBeanImport.size(); | ||||
|      }*/ | ||||
|  | ||||
|     /*ArrayList<TTSPlayRuleBean> loadDataFromPath(String szPath) { | ||||
|      File fJson = new File(szPath); | ||||
|      ArrayList<TTSPlayRuleBean> listTemp = null; | ||||
|      try { | ||||
|      listTemp = readJsonStream(new FileInputStream(fJson)); | ||||
|      } catch (IOException e) { | ||||
|      LogUtils.d(TAG, "IOException : " + e.getMessage()); | ||||
|      } | ||||
|      if (listTemp == null) { | ||||
|      listTemp = new ArrayList<TTSPlayRuleBean>(); | ||||
|      } | ||||
|      return listTemp; | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 加载 TTS 配置数据 | ||||
|     // | ||||
|     public ArrayList<TTSPlayRuleBean> loadConfigData() { | ||||
|         TTSPlayRuleBean.loadBeanList(mContext, mConfigData, TTSPlayRuleBean.class); | ||||
|         return mConfigData; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 保存 TTS 配置数据 | ||||
|     // | ||||
|     public void saveConfigData() { | ||||
|         // 设定只能在规则编辑窗口改变规则 | ||||
|         if (mTTSPlayRuleActivity == null) { | ||||
|             LogUtils.i(TAG, "Please edit rules in TTSPlayRuleActivity."); | ||||
|             return; | ||||
|         } | ||||
|  | ||||
|         YesNoAlertDialog.show(mTTSPlayRuleActivity, mContext.getString(R.string.text_ttsrule), "是否更新语音规则?", new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|                 @Override | ||||
|                 public void onYes() { | ||||
|                     TTSPlayRuleBean.saveBeanList(mContext, mConfigData, TTSPlayRuleBean.class); | ||||
|                     Toast.makeText(mTTSPlayRuleActivity, "语音数据已更改。", Toast.LENGTH_SHORT).show(); | ||||
|                      | ||||
|                     Message message = new Message(); | ||||
|                     message.what = TTSPlayRuleActivity.MSG_RELOAD; | ||||
|                     mTTSPlayRuleActivity.sendActivityMessage(message); | ||||
|                 } | ||||
|  | ||||
|                 @Override | ||||
|                 public void onNo() { | ||||
|                     Message message = new Message(); | ||||
|                     message.what = TTSPlayRuleActivity.MSG_RELOAD; | ||||
|                     mTTSPlayRuleActivity.sendActivityMessage(message); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 清空 TTS 配置数据 | ||||
|     // | ||||
|     public void cleanConfig() { | ||||
|         YesNoAlertDialog.show(mTTSPlayRuleActivity, "确定清理", "您确定清理所有语音规则吗?", new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|                 @Override | ||||
|                 public void onYes() { | ||||
|                     mConfigData.clear(); | ||||
|                     TTSPlayRuleBean.saveBeanList(mContext, mConfigData, TTSPlayRuleBean.class); | ||||
|                     Toast.makeText(mTTSPlayRuleActivity, "语音数据已更改。", Toast.LENGTH_SHORT).show(); | ||||
|                      | ||||
|                     Message message = new Message(); | ||||
|                     message.what = TTSPlayRuleActivity.MSG_RELOAD; | ||||
|                     mTTSPlayRuleActivity.sendActivityMessage(message); | ||||
|                 } | ||||
|                 @Override | ||||
|                 public void onNo() { | ||||
|                 } | ||||
|             }); | ||||
| 	} | ||||
|  | ||||
|     // | ||||
|     // 重置默认 TTS 配置数据 | ||||
|     // | ||||
|     public void resetConfig() { | ||||
|         YesNoAlertDialog.show(mTTSPlayRuleActivity, "确定重置", "您确定重置语音规则为默认设置吗?", new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|                 @Override | ||||
|                 public void onYes() { | ||||
|                     String szAssetsFilePath = "GlobalApplication/TTSPlayRuleBean_List.json"; | ||||
|                     TTSPlayRuleBean beanTemp = new TTSPlayRuleBean(); | ||||
|                     String szConfigFilePath = beanTemp.getBeanListJsonFilePath(mContext); | ||||
|                     FileUtil.copyAssetsToSD(mContext, szAssetsFilePath, szConfigFilePath); | ||||
|                     Toast.makeText(mTTSPlayRuleActivity, "语音数据已更改。", Toast.LENGTH_SHORT).show(); | ||||
|                      | ||||
|                     loadConfigData(); | ||||
|                     Message message = new Message(); | ||||
|                     message.what = TTSPlayRuleActivity.MSG_RELOAD; | ||||
|                     mTTSPlayRuleActivity.sendActivityMessage(message); | ||||
|                 } | ||||
|                 @Override | ||||
|                 public void onNo() { | ||||
|                 } | ||||
|             }); | ||||
| 	} | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件 | ||||
|     // | ||||
|     public ArrayList<TTSPlayRuleBean_V1> readJsonStream(InputStream in) throws IOException { | ||||
|         JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); | ||||
|         return readJsonArrayList(reader); | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件的每一 Json 项 | ||||
|     // | ||||
|     public ArrayList<TTSPlayRuleBean_V1> readJsonArrayList(JsonReader reader) throws IOException { | ||||
|         ArrayList<TTSPlayRuleBean_V1> list = new ArrayList<TTSPlayRuleBean_V1>(); | ||||
|         reader.beginArray(); | ||||
|         while (reader.hasNext()) { | ||||
|             list.add(readBeanItem(reader)); | ||||
|         } | ||||
|         reader.endArray(); | ||||
|         return list; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 读取 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     public TTSPlayRuleBean_V1 readBeanItem(JsonReader reader) throws IOException { | ||||
|         TTSPlayRuleBean_V1 bean = new TTSPlayRuleBean_V1(); | ||||
|         int nReaderCount = 0; | ||||
|         reader.beginObject(); | ||||
|         while (reader.hasNext()) { | ||||
|             String name = reader.nextName(); | ||||
|             if (name.equals("DemoSMSText")) { | ||||
|                 bean.setDemoSMSText(reader.nextString()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("PatternText")) { | ||||
|                 bean.setPatternText(reader.nextString()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("TTSRuleText")) { | ||||
|                 bean.setTtsRuleText(reader.nextString()); | ||||
|                 nReaderCount++; | ||||
|             } else if (name.equals("Enable")) { | ||||
|                 bean.setIsEnable(reader.nextBoolean()); | ||||
|                 nReaderCount++; | ||||
|             } else { | ||||
|                 reader.skipValue(); | ||||
|             } | ||||
|         } | ||||
|         reader.endObject(); | ||||
|         return nReaderCount > 0 ? bean : null; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 写入 Json 文件的某一 Json 项 | ||||
|     // | ||||
|     /*public void writeBeanItem(JsonWriter writer, TTSPlayRuleBean bean) throws IOException { | ||||
|      writer.beginObject(); | ||||
|      writer.name("Name").value(bean.getRuleName()); | ||||
|      writer.name("DemoSMSText").value(bean.getDemoSMSText()); | ||||
|      writer.name("PatternText").value(bean.getPatternText()); | ||||
|      writer.name("TTSRuleText").value(bean.getTtsRuleText()); | ||||
|      writer.name("Enable").value(bean.isEnable()); | ||||
|      writer.endObject(); | ||||
|      }*/ | ||||
|  | ||||
|     // | ||||
|     // 写入 Json 文件 | ||||
|     // | ||||
|     /*public void writeJsonStream(OutputStream out, ArrayList<TTSPlayRuleBean> beanList) throws IOException { | ||||
|      JsonWriter writer = new JsonWriter(new OutputStreamWriter(out, "UTF-8")); | ||||
|      writer.setIndent("  "); | ||||
|      writeJsonArrayList(writer, beanList); | ||||
|      writer.close(); | ||||
|      } | ||||
|  | ||||
|      // | ||||
|      // 记录 Json 文件的某一 Json 项 | ||||
|      // | ||||
|      public void writeJsonArrayList(JsonWriter writer, ArrayList<TTSPlayRuleBean> beanList) throws IOException { | ||||
|      writer.beginArray(); | ||||
|      for (TTSPlayRuleBean bean : beanList) { | ||||
|      writeBeanItem(writer, bean); | ||||
|      } | ||||
|      writer.endArray(); | ||||
|      }*/ | ||||
| } | ||||
| @@ -0,0 +1,186 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/03 10:27:46 | ||||
|  * @Describe TTS语音播放工具类 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.graphics.PixelFormat; | ||||
| import android.os.Build; | ||||
| import android.speech.tts.TextToSpeech; | ||||
| import android.speech.tts.UtteranceProgressListener; | ||||
| import android.view.Gravity; | ||||
| import android.view.View; | ||||
| import android.view.WindowManager; | ||||
| import android.widget.LinearLayout; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
| import cc.winboll.studio.mymessagemanager.beans.TTSSpeakTextBean; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
| import java.util.ArrayList; | ||||
|  | ||||
| public class TextToSpeechUtil { | ||||
|  | ||||
|     public static final String TAG = "TextToSpeechUtil"; | ||||
|  | ||||
|     public static final String UNIQUE_ID = "UNIQUE_ID"; | ||||
|  | ||||
|     static TextToSpeechUtil _mTextToSpeechUtil; | ||||
|  | ||||
|     View mView; | ||||
|     WindowManager mWindowManager; | ||||
|     TextToSpeech mTextToSpeech; | ||||
|     Context mContext; | ||||
|     volatile boolean isExist = false; | ||||
|  | ||||
|     TextToSpeechUtil(Context context) { | ||||
|         mContext = context; | ||||
|         // 获取WindowManager | ||||
|         mWindowManager = (WindowManager) mContext.getSystemService(mContext.WINDOW_SERVICE); | ||||
|     } | ||||
|  | ||||
|     public static TextToSpeechUtil getInstance(Context context) { | ||||
|         if (_mTextToSpeechUtil == null) { | ||||
|             _mTextToSpeechUtil = new TextToSpeechUtil(context); | ||||
|         } | ||||
|         return _mTextToSpeechUtil; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 播放 TTS 语音队列 | ||||
|     // | ||||
|     public void speekTTSList(final ArrayList<TTSSpeakTextBean> listTTSSpeakTextBean) { | ||||
|         // 重置播放退出标志位 | ||||
|         isExist = false; | ||||
|  | ||||
|         // 开始播放 | ||||
|         if (mTextToSpeech == null) { | ||||
|             //ToastUtils.show("mTextToSpeech == null"); | ||||
|             // 创建TextToSpeech实例 | ||||
|             mTextToSpeech = new TextToSpeech(mContext, new TextToSpeech.OnInitListener() { | ||||
|                     @Override | ||||
|                     public void onInit(int i) { | ||||
|                         if (i == TextToSpeech.SUCCESS) { | ||||
|                             speekTTSList(listTTSSpeakTextBean); | ||||
|                         } else { | ||||
|                             LogUtils.d(TAG, "TTS init failed : " + Integer.toString(i) + ". The app [https://play.google.com/store/apps/details?id=com.google.android.tts] maybe fix this TTS probrem. "); | ||||
|                         } | ||||
|                     } | ||||
|                 }); | ||||
|             mTextToSpeech.setOnUtteranceProgressListener(mUtteranceProgressListener); | ||||
|         } else { | ||||
|             if (mTextToSpeech != null && listTTSSpeakTextBean != null && listTTSSpeakTextBean.size() > 0) { | ||||
|                 // 清理过期的悬浮窗 | ||||
|                 if (mWindowManager != null && mView != null) { | ||||
|                     try { | ||||
|                         mWindowManager.removeView(mView); | ||||
|                         mView = null; | ||||
|                     } catch(Exception e) { | ||||
|                         LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                     } | ||||
|                 } | ||||
|                  | ||||
|                 // 显示悬浮窗 | ||||
|                 initWindow(); | ||||
|                  | ||||
|                 // 播放 TTS 语音 | ||||
|                 // | ||||
|                 //ToastUtils.show("initWindow done."); | ||||
|                 // 设置延迟间隔 | ||||
|                 int  nDelay = listTTSSpeakTextBean.get(0).mnDelay; | ||||
|                 try { | ||||
|                     Thread.sleep(nDelay); | ||||
|                 } catch (InterruptedException e) { | ||||
|                     LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); | ||||
|                 } | ||||
|                 //ToastUtils.show("Delay done."); | ||||
|                 for (int speakPosition = 0; speakPosition < listTTSSpeakTextBean.size() && !isExist; speakPosition++) { | ||||
|                     // 播放语音 | ||||
|                     String szSpeakContent = listTTSSpeakTextBean.get(speakPosition).mszSpeakContent; | ||||
|                     isExist = (listTTSSpeakTextBean.size() - 2 < speakPosition); | ||||
|                     //ToastUtils.show("for isExist is : " + Boolean.toString(isExist)); | ||||
|                     if (speakPosition == 0) { | ||||
|                         mTextToSpeech.speak(szSpeakContent, TextToSpeech.QUEUE_FLUSH, null, UNIQUE_ID); | ||||
|                     } else { | ||||
|                         mTextToSpeech.speak(szSpeakContent, TextToSpeech.QUEUE_ADD, null, UNIQUE_ID); | ||||
|                     } | ||||
|                     //ToastUtils.show("mTextToSpeech.speak"); | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     UtteranceProgressListener mUtteranceProgressListener = new UtteranceProgressListener() { | ||||
|         @Override | ||||
|         public void onStart(String utteranceId) { | ||||
|             LogUtils.d(TAG, "播放开始"); | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onDone(String utteranceId) { | ||||
|             LogUtils.d(TAG, "播放结束"); | ||||
|             //ToastUtils.show("isExist is : " + Boolean.toString(isExist)); | ||||
|             // 关闭悬浮窗 | ||||
|             if (isExist && mWindowManager != null && mView != null) { | ||||
|                 LogUtils.d(TAG, "关闭悬浮窗"); | ||||
|                 mWindowManager.removeView(mView); | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         @Override | ||||
|         public void onError(String utteranceId) { | ||||
|             LogUtils.d(TAG, "播放出错"); | ||||
|         } | ||||
|     }; | ||||
|  | ||||
|  | ||||
|     // | ||||
|     // 初始化 TTS 悬浮窗 | ||||
|     // | ||||
|     private void initWindow() { | ||||
|         //ToastUtils.show("initWindow"); | ||||
|         // 创建布局参数 | ||||
|         WindowManager.LayoutParams params = new WindowManager.LayoutParams(); | ||||
|         //这里需要进行不同的设置 | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { | ||||
|             params.type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY; | ||||
|         } else { | ||||
|             params.type = WindowManager.LayoutParams.TYPE_PHONE; | ||||
|         } | ||||
|         //设置透明度 | ||||
|         params.alpha = 0.9f; | ||||
|         //设置内部视图对齐方式 | ||||
|         params.gravity = Gravity.RIGHT | Gravity.BOTTOM; | ||||
|         //窗口的右上角角坐标 | ||||
|         params.x = 20; | ||||
|         params.y = 20; | ||||
|         //是指定窗口的像素格式为 RGBA_8888。 | ||||
|         //使用 RGBA_8888 像素格式的窗口可以在保持高质量图像的同时实现透明度效果。 | ||||
|         params.format = PixelFormat.RGBA_8888; | ||||
|         //设置窗口的宽高,这里为自动 | ||||
|         params.width = WindowManager.LayoutParams.WRAP_CONTENT; | ||||
|         params.height = WindowManager.LayoutParams.WRAP_CONTENT; | ||||
|         //这段非常重要,是后续是否穿透点击的关键 | ||||
|         params.flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE  //表示悬浮窗口不需要获取焦点,这样用户点击悬浮窗口以外的区域,就不需要关闭悬浮窗口。 | ||||
|             | WindowManager.LayoutParams.FLAG_NOT_TOUCH_MODAL;//表示悬浮窗口不会阻塞事件传递,即用户点击悬浮窗口以外的区域时,事件会传递给后面的窗口处理。 | ||||
|         //这里的引入布局文件的方式,也可以动态添加控件 | ||||
|         mView = View.inflate(mContext, R.layout.view_tts_back, null); | ||||
|         LinearLayout llMain = mView.findViewById(R.id.viewttsbackLinearLayout1); | ||||
|         llMain.setOnClickListener(new View.OnClickListener(){ | ||||
|  | ||||
|                 @Override | ||||
|                 public void onClick(View view) { | ||||
|                     //ToastUtils.show("onClick"); | ||||
|                     isExist = true; | ||||
|                     if (mTextToSpeech != null) { | ||||
|                         mTextToSpeech.stop(); | ||||
|                     } | ||||
|                     if (mWindowManager != null && mView != null) { | ||||
|                         mWindowManager.removeView(mView); | ||||
|                         mView = null; | ||||
|                     } | ||||
|                 } | ||||
|             }); | ||||
|         mWindowManager.addView(mView, params); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,47 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe 应用主题工具类 | ||||
|  */ | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
|  | ||||
| public class ThemeUtil { | ||||
| /* | ||||
|     public static final String SZ_THEME_TYPE = "SZ_THEME_TYPE"; | ||||
|     public static final String THEME_PREFERENCES = "THEME_PREFERENCES"; | ||||
|  | ||||
|     public enum BaseTheme { DEFAULT(0), SKY(1), GOLDEN(2); | ||||
|         static String[] _mlistName = { "默认主题", "天空主题", "辉煌主题" }; | ||||
|         private int value; | ||||
|         private BaseTheme(int value) { | ||||
|             this.value = value; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static int getThemeID(BaseTheme baseTheme) { | ||||
|         int themeId; | ||||
|         if (baseTheme == BaseTheme.DEFAULT) { | ||||
|             themeId = R.style.AppTheme_Default; | ||||
|         } else  if (baseTheme == BaseTheme.SKY) { | ||||
|             themeId = R.style.AppTheme_Sky; | ||||
|         } else  if (baseTheme == BaseTheme.GOLDEN) { | ||||
|             themeId = R.style.AppTheme_Golden; | ||||
|         } else { | ||||
|             themeId = R.style.AppTheme_Default; | ||||
|         } | ||||
|         return themeId; | ||||
|     } | ||||
|  | ||||
|     public static BaseTheme getTheme(int nThemeID) { | ||||
|         if (nThemeID == R.style.AppTheme_Sky) { | ||||
|             return BaseTheme.SKY; | ||||
|         } else  if (nThemeID ==  R.style.AppTheme_Golden) { | ||||
|             return BaseTheme.GOLDEN; | ||||
|         } else { | ||||
|             return BaseTheme.DEFAULT; | ||||
|         } | ||||
|     } | ||||
|     */ | ||||
| } | ||||
| @@ -0,0 +1,131 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe Uri 资源管理工具类 | ||||
|  */ | ||||
| import android.content.ContentResolver; | ||||
| import android.content.Context; | ||||
| import android.database.Cursor; | ||||
| import android.net.Uri; | ||||
| import android.provider.MediaStore; | ||||
| import java.io.File; | ||||
| import java.io.FileOutputStream; | ||||
| import java.io.IOException; | ||||
| import java.io.InputStream; | ||||
| import java.io.OutputStream; | ||||
|  | ||||
| public class UriUtil { | ||||
|  | ||||
|     public static final String TAG = "UriUtil"; | ||||
|  | ||||
|     // | ||||
|     // 获取真实路径 | ||||
|     // | ||||
|     // @param context | ||||
|     // | ||||
|     public static String getFileFromUri(Context context, Uri uri) { | ||||
|         if (uri == null) { | ||||
|             return null; | ||||
|         } | ||||
|         switch (uri.getScheme()) { | ||||
|             case ContentResolver.SCHEME_CONTENT: | ||||
|                 //Android7.0之后的uri content:// URI | ||||
|                 return getFilePathFromContentUri(context, uri); | ||||
|             case ContentResolver.SCHEME_FILE: | ||||
|             default: | ||||
|                 //Android7.0之前的uri file:// | ||||
|                 return new File(uri.getPath()).getAbsolutePath(); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 从uri获取path | ||||
|     // | ||||
|     // @param uri content://media/external/file/109009 | ||||
|     //            <p> | ||||
|     //            FileProvider适配 | ||||
|     //            content://com.tencent.mobileqq.fileprovider/external_files/storage/emulated/0/Tencent/QQfile_recv/ | ||||
|     //            content://com.tencent.mm.external.fileprovider/external/tencent/MicroMsg/Download/ | ||||
|     // | ||||
|     private static String getFilePathFromContentUri(Context context, Uri uri) { | ||||
|         if (null == uri) return null; | ||||
|         String data = null; | ||||
|  | ||||
|         String[] filePathColumn = {MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.DISPLAY_NAME}; | ||||
|         Cursor cursor = context.getContentResolver().query(uri, filePathColumn, null, null, null); | ||||
|         if (null != cursor) { | ||||
|             if (cursor.moveToFirst()) { | ||||
|                 int index = cursor.getColumnIndex(MediaStore.MediaColumns.DATA); | ||||
|                 if (index > -1) { | ||||
|                     data = cursor.getString(index); | ||||
|                 } else { | ||||
|                     int nameIndex = cursor.getColumnIndex(MediaStore.MediaColumns.DISPLAY_NAME); | ||||
|                     String fileName = cursor.getString(nameIndex); | ||||
|                     data = getPathFromInputStreamUri(context, uri, fileName); | ||||
|                 } | ||||
|             } | ||||
|             cursor.close(); | ||||
|         } | ||||
|         return data; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 用流拷贝文件一份到自己APP私有目录下 | ||||
|     // | ||||
|     // @param context | ||||
|     // @param uri | ||||
|     // @param fileName | ||||
|     // | ||||
|     private static String getPathFromInputStreamUri(Context context, Uri uri, String fileName) { | ||||
|         InputStream inputStream = null; | ||||
|         String filePath = null; | ||||
|  | ||||
|         if (uri.getAuthority() != null) { | ||||
|             try { | ||||
|                 inputStream = context.getContentResolver().openInputStream(uri); | ||||
|                 File file = createTemporalFileFrom(context, inputStream, fileName); | ||||
|                 filePath = file.getPath(); | ||||
|  | ||||
|             } catch (Exception e) { | ||||
|             } finally { | ||||
|                 try { | ||||
|                     if (inputStream != null) { | ||||
|                         inputStream.close(); | ||||
|                     } | ||||
|                 } catch (Exception e) { | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|         return filePath; | ||||
|     } | ||||
|  | ||||
|     private static File createTemporalFileFrom(Context context, InputStream inputStream, String fileName) | ||||
|     throws IOException { | ||||
|         File targetFile = null; | ||||
|         if (inputStream != null) { | ||||
|             int read; | ||||
|             byte[] buffer = new byte[8 * 1024]; | ||||
|             //自己定义拷贝文件路径 | ||||
|             targetFile = new File(context.getExternalCacheDir(), fileName); | ||||
|             if (targetFile.exists()) { | ||||
|                 targetFile.delete(); | ||||
|             } | ||||
|             OutputStream outputStream = new FileOutputStream(targetFile); | ||||
|  | ||||
|             while ((read = inputStream.read(buffer)) != -1) { | ||||
|                 outputStream.write(buffer, 0, read); | ||||
|             } | ||||
|             outputStream.flush(); | ||||
|  | ||||
|             try { | ||||
|                 outputStream.close(); | ||||
|             } catch (IOException e) { | ||||
|                 e.printStackTrace(); | ||||
|             } | ||||
|         } | ||||
|         return targetFile; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,53 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/24 16:20:13 | ||||
|  * @Describe 用户视觉系统保护模式工具集 | ||||
|  */ | ||||
| import java.util.Random; | ||||
|  | ||||
| public class UserVisionSystemProtectModeUtil { | ||||
|  | ||||
|     public static final String TAG = "UserVisionSystemProtectModeUtil"; | ||||
|  | ||||
|     public static final String PreviewShuffleSMS(String szSMSText, String szRefuseChars, String szReplaceChars) { | ||||
|         String szPreview; | ||||
|         // 将字符串转换为字符数组 | ||||
|         char[] charArray = szSMSText.toCharArray(); | ||||
|         // 打乱字符数组 | ||||
|         shuffleArray(charArray); | ||||
|         // 构建新的字符串并打印 | ||||
|         szPreview = new String(charArray); | ||||
|         szPreview = useProtectedCharsRule(szPreview, szRefuseChars, szReplaceChars); | ||||
|         return szPreview; | ||||
|     } | ||||
|  | ||||
|     // | ||||
|     // 打乱字符数组的方法 | ||||
|     // | ||||
|     // @param array 要被打乱的字符数组 | ||||
|     // | ||||
|     public static void shuffleArray(char[] array) { | ||||
|         // 创建随机数生成器 | ||||
|         Random random = new Random(); | ||||
|         for (int i = array.length - 1; i > 0; i--) { | ||||
|             // 生成一个随机索引j,范围在0到i之间(包括i) | ||||
|             int j = random.nextInt(i + 1); | ||||
|  | ||||
|             // 交换array[i]和array[j]的位置 | ||||
|             char temp = array[i]; | ||||
|             array[i] = array[j]; | ||||
|             array[j] = temp; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public static String useProtectedCharsRule(String szContent, String szRefuseChars, String szReplaceChars) { | ||||
|         // 正则表达式模式 (寻找 szProtectChars 其中一个字符) | ||||
|         String pattern = "[" + szRefuseChars + "]";  | ||||
|  | ||||
|         // 替换模式后的字符串 | ||||
|         String szProtectedContent = szContent.replaceAll(pattern, szReplaceChars); | ||||
|         return szProtectedContent; | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,20 @@ | ||||
| package cc.winboll.studio.mymessagemanager.utils; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2024/07/19 14:30:57 | ||||
|  * @Describe Uri 视图元素工具类 | ||||
|  */ | ||||
| import android.widget.ScrollView; | ||||
|  | ||||
| public class ViewUtil { | ||||
|  | ||||
|     public static void scrollScrollView(final ScrollView scrollView) { | ||||
|         scrollView.post(new Runnable() { | ||||
|                 @Override | ||||
|                 public void run() { | ||||
|                     scrollView.fullScroll(ScrollView.FOCUS_DOWN); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,76 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2023/07/25 13:37:55 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.view.View; | ||||
| import android.widget.Switch; | ||||
| import cc.winboll.studio.mymessagemanager.dialogs.YesNoAlertDialog; | ||||
| import cc.winboll.studio.shared.log.LogUtils; | ||||
|  | ||||
| public class ConfirmSwitchView extends Switch { | ||||
|  | ||||
|     public static final String TAG = "SwitchView"; | ||||
|  | ||||
|     Context mContext; | ||||
|  | ||||
|     public ConfirmSwitchView(Context context) { | ||||
|         super(context); | ||||
|         initView(context); | ||||
|     } | ||||
|  | ||||
|     public ConfirmSwitchView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         initView(context); | ||||
|     } | ||||
|  | ||||
|     public ConfirmSwitchView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|         initView(context); | ||||
|     } | ||||
|  | ||||
|     public ConfirmSwitchView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) { | ||||
|         super(context, attrs, defStyleAttr, defStyleRes); | ||||
|         initView(context); | ||||
|     } | ||||
|  | ||||
|     void initView(Context context) { | ||||
|         mContext = context; | ||||
|         /*TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.SMSView, 0, 0); | ||||
|          colorInbox = a.getColor(R.styleable.SMSView_attrSMSViewInboxColor, 0); | ||||
|          colorSend = a.getColor(R.styleable.SMSView_attrSMSViewSendColor, 0); | ||||
|          a.recycle();*/ | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void setOnClickListener(final View.OnClickListener l) { | ||||
|         super.setOnClickListener(new View.OnClickListener() { | ||||
|                 @Override | ||||
|                 public void onClick(View v) { | ||||
|                     final boolean isChecked = isChecked(); | ||||
|                     StringBuilder sbMessage = new StringBuilder("请确定["); | ||||
|                     sbMessage.append(isChecked ?"开启": "关闭"); | ||||
|                     sbMessage.append("]操作。"); | ||||
|                     // 在这里添加您的点击事件响应逻辑 | ||||
|                     YesNoAlertDialog.show(mContext, getText().toString(), sbMessage.toString(), new YesNoAlertDialog.OnDialogResultListener(){ | ||||
|                             @Override | ||||
|                             public void onYes() { | ||||
|                                 LogUtils.d(TAG, "onYes"); | ||||
|                                 setChecked(isChecked); | ||||
|                             } | ||||
|                             @Override | ||||
|                             public void onNo() { | ||||
|                                 LogUtils.d(TAG, "onNo"); | ||||
|                                 setChecked(!isChecked); | ||||
|                             } | ||||
|                         }); | ||||
|                     //Toast.makeText(getContext(), "Switch clicked", Toast.LENGTH_SHORT).show(); | ||||
|                     // 确保调用了父类的onClick()方法 | ||||
|                     l.onClick(v); | ||||
|                 } | ||||
|             }); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,32 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import androidx.appcompat.widget.AppCompatTextView; | ||||
| import java.text.SimpleDateFormat; | ||||
| import java.util.Date; | ||||
| import java.util.Locale; | ||||
|  | ||||
| public class DateAgoTextView extends AppCompatTextView { | ||||
|     long mnDate; | ||||
|  | ||||
|     public DateAgoTextView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public DateAgoTextView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|     } | ||||
|  | ||||
|     public DateAgoTextView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     public void setDate(long nDate) { | ||||
|         SimpleDateFormat dateFormat = new SimpleDateFormat( | ||||
|             "yyyy-MM-dd HH:mm:ss", Locale.getDefault()); | ||||
|         Date d = new Date(nDate); | ||||
|  | ||||
|         setText(dateFormat.format(d)); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,65 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.ListView; | ||||
|  | ||||
| public class PhoneListViewForScrollView extends ListView { | ||||
|  | ||||
|     public PhoneListViewForScrollView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public PhoneListViewForScrollView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|     } | ||||
|  | ||||
|     public PhoneListViewForScrollView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重写onMeasure方法,重新计算高度,达到使ListView适应ScrollView的效果 | ||||
|      * | ||||
|      * @param widthMeasureSpec  宽度测量规则 | ||||
|      * @param heightMeasureSpec 高度测量规则 | ||||
|      */ | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|         /* | ||||
|          // 子控件TextView不换行显示 | ||||
|          ListAdapter listAdapter = this.getAdapter();   | ||||
|          if (listAdapter == null) {  | ||||
|          return;  | ||||
|          } | ||||
|          int maxWidth = 0; | ||||
|          for (int i = 0; i < listAdapter.getCount(); i++) {  | ||||
|          View listItem = listAdapter.getView(i, null, this); | ||||
|          View cb = listItem.findViewById(R.id.listviewfiledataCheckBox1); | ||||
|          View iv = listItem.findViewById(R.id.listviewfiledataImageView1); | ||||
|          View tv = listItem.findViewById(R.id.listviewfiledataTextView1); | ||||
|  | ||||
|          cb.measure(0,0); | ||||
|          iv.measure(0,0); | ||||
|          tv.measure(0,0); | ||||
|  | ||||
|          //listItem.measure(0, 0); | ||||
|          //int width = listItem.getMeasuredWidth(); | ||||
|          int width = cb.getMeasuredWidth() + iv.getMeasuredWidth()+ tv.getMeasuredWidth(); | ||||
|          if(width>maxWidth) maxWidth = width; | ||||
|          } | ||||
|          int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|          int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); | ||||
|          super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); | ||||
|          */ | ||||
|  | ||||
|         // 子控件TextView换行显示 | ||||
|         //Integer.MAX_VALUE:表示int类型能够表示的最大值,值为2的31次方-1 | ||||
|         //>>2:右移N位相当于除以2的N的幂 | ||||
|         //MeasureSpec.AT_MOST:子布局可以根据自己的大小选择任意大小的模式 | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|         //int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,33 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.ListView; | ||||
|  | ||||
| public class SMSAcceptRuleListViewForScrollView extends ListView { | ||||
|  | ||||
|     public SMSAcceptRuleListViewForScrollView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public SMSAcceptRuleListViewForScrollView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|     } | ||||
|  | ||||
|     public SMSAcceptRuleListViewForScrollView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重写onMeasure方法,重新计算高度,达到使ListView适应ScrollView的效果 | ||||
|      * | ||||
|      * @param widthMeasureSpec  宽度测量规则 | ||||
|      * @param heightMeasureSpec 高度测量规则 | ||||
|      */ | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,73 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.ListView; | ||||
|  | ||||
| public class SMSListViewForScrollView extends ListView { | ||||
|     static int nMaxWidth = 0; | ||||
|  | ||||
|     public SMSListViewForScrollView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public SMSListViewForScrollView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public SMSListViewForScrollView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重写onMeasure方法,重新计算高度,达到使ListView适应ScrollView的效果 | ||||
|      * | ||||
|      * @param widthMeasureSpec  宽度测量规则 | ||||
|      * @param heightMeasureSpec 高度测量规则 | ||||
|      */ | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|  | ||||
|         /* | ||||
|          // 子控件TextView不换行显示 | ||||
|          ListAdapter listAdapter = this.getAdapter();   | ||||
|          if (listAdapter == null) {  | ||||
|          return;  | ||||
|          } | ||||
|          int maxWidth = 0; | ||||
|          for (int i = 0; i < listAdapter.getCount(); i++) {  | ||||
|          View listItem = listAdapter.getView(i, null, this); | ||||
|          View cb = listItem.findViewById(R.id.listviewfiledataCheckBox1); | ||||
|          View iv = listItem.findViewById(R.id.listviewfiledataImageView1); | ||||
|          View tv = listItem.findViewById(R.id.listviewfiledataTextView1); | ||||
|  | ||||
|          cb.measure(0,0); | ||||
|          iv.measure(0,0); | ||||
|          tv.measure(0,0); | ||||
|  | ||||
|          //listItem.measure(0, 0); | ||||
|          //int width = listItem.getMeasuredWidth(); | ||||
|          int width = cb.getMeasuredWidth() + iv.getMeasuredWidth()+ tv.getMeasuredWidth(); | ||||
|          if(width>maxWidth) maxWidth = width; | ||||
|          } | ||||
|          int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|          int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); | ||||
|          super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); | ||||
|          */ | ||||
|  | ||||
|         // 子控件TextView换行显示 | ||||
|         //Integer.MAX_VALUE:表示int类型能够表示的最大值,值为2的31次方-1 | ||||
|         //>>2:右移N位相当于除以2的N的幂 | ||||
|         //MeasureSpec.AT_MOST:子布局可以根据自己的大小选择任意大小的模式 | ||||
|  | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         //int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         //int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
|  | ||||
| } | ||||
| @@ -0,0 +1,78 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.content.res.TypedArray; | ||||
| import android.graphics.Canvas; | ||||
| import android.util.AttributeSet; | ||||
| import androidx.cardview.widget.CardView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
|  | ||||
| public class SMSView extends CardView { | ||||
|  | ||||
|     public static final String TAG = "SMSView"; | ||||
|  | ||||
|     Context mContext; | ||||
|     int colorInbox; | ||||
|     int colorSend; | ||||
|     int colorItem; | ||||
|     public enum SMSType { INBOX, SEND } | ||||
|     SMSType mSMSType = SMSType.INBOX; | ||||
|  | ||||
|     public void setSMSType(SMSType smsType) { | ||||
|         this.mSMSType = smsType; | ||||
|         updateViewBackgroundColor(); | ||||
|     } | ||||
|  | ||||
|     public SMSType getCardType() { | ||||
|         return mSMSType; | ||||
|     } | ||||
|  | ||||
|     void updateViewBackgroundColor() { | ||||
|         if (mSMSType == SMSType.INBOX) { | ||||
|             setCardBackgroundColor(colorInbox); | ||||
|         } else if (mSMSType == SMSType.SEND) { | ||||
|             setCardBackgroundColor(colorSend); | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     public SMSView(Context context) { | ||||
|         super(context); | ||||
|         mContext = context; | ||||
|     } | ||||
|  | ||||
|     public SMSView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         mContext = context; | ||||
|  | ||||
|         TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.SMSView, 0, 0); | ||||
|         String szSMSType = a.getString(R.styleable.SMSView_attrSMSType); | ||||
|         if((szSMSType == null)||szSMSType.equals("")) { | ||||
|             mSMSType = SMSType.SEND; | ||||
|         } else { | ||||
|             mSMSType = SMSType.valueOf(szSMSType); | ||||
|         } | ||||
|         colorInbox = a.getColor(R.styleable.SMSView_attrSMSViewInboxColor, 0); | ||||
|         colorSend = a.getColor(R.styleable.SMSView_attrSMSViewSendColor, 0); | ||||
|         a.recycle(); | ||||
|     } | ||||
|  | ||||
|     public SMSView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|         mContext = context; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onDraw(Canvas canvas) { | ||||
|         super.onDraw(canvas); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|         // 子控件TextView换行显示 | ||||
|         //Integer.MAX_VALUE:表示int类型能够表示的最大值,值为2的31次方-1 | ||||
|         //>>2:右移N位相当于除以2的N的幂 | ||||
|         //MeasureSpec.AT_MOST:子布局可以根据自己的大小选择任意大小的模式 | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
| } | ||||
| @@ -0,0 +1,82 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| import android.content.Context; | ||||
| import android.util.AttributeSet; | ||||
| import android.widget.ListView; | ||||
|  | ||||
| public class TTSRuleListViewForScrollView extends ListView { | ||||
|     static int nMaxWidth = 0; | ||||
|  | ||||
|     public TTSRuleListViewForScrollView(Context context) { | ||||
|         super(context); | ||||
|     } | ||||
|  | ||||
|     public TTSRuleListViewForScrollView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|  | ||||
|     } | ||||
|  | ||||
|     public TTSRuleListViewForScrollView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     public void setSelection(int position) { | ||||
|         super.setSelection(position); | ||||
|     } | ||||
|  | ||||
|     /** | ||||
|      * 重写onMeasure方法,重新计算高度,达到使ListView适应ScrollView的效果 | ||||
|      * | ||||
|      * @param widthMeasureSpec  宽度测量规则 | ||||
|      * @param heightMeasureSpec 高度测量规则 | ||||
|      */ | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|  | ||||
|         /* | ||||
|          // 子控件TextView不换行显示 | ||||
|          ListAdapter listAdapter = this.getAdapter();   | ||||
|          if (listAdapter == null) {  | ||||
|          return;  | ||||
|          } | ||||
|          int maxWidth = 0; | ||||
|          for (int i = 0; i < listAdapter.getCount(); i++) {  | ||||
|          View listItem = listAdapter.getView(i, null, this); | ||||
|          View cb = listItem.findViewById(R.id.listviewfiledataCheckBox1); | ||||
|          View iv = listItem.findViewById(R.id.listviewfiledataImageView1); | ||||
|          View tv = listItem.findViewById(R.id.listviewfiledataTextView1); | ||||
|  | ||||
|          cb.measure(0,0); | ||||
|          iv.measure(0,0); | ||||
|          tv.measure(0,0); | ||||
|  | ||||
|          //listItem.measure(0, 0); | ||||
|          //int width = listItem.getMeasuredWidth(); | ||||
|          int width = cb.getMeasuredWidth() + iv.getMeasuredWidth()+ tv.getMeasuredWidth(); | ||||
|          if(width>maxWidth) maxWidth = width; | ||||
|          } | ||||
|          int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|          int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(maxWidth, MeasureSpec.AT_MOST); | ||||
|          super.onMeasure(newWidthMeasureSpec, newHeightMeasureSpec); | ||||
|          */ | ||||
|  | ||||
|         // 子控件TextView换行显示 | ||||
|         //Integer.MAX_VALUE:表示int类型能够表示的最大值,值为2的31次方-1 | ||||
|         //>>2:右移N位相当于除以2的N的幂 | ||||
|         //MeasureSpec.AT_MOST:子布局可以根据自己的大小选择任意大小的模式 | ||||
|  | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         //int newWidthMeasureSpec = MeasureSpec.makeMeasureSpec(widthMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         //int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(heightMeasureSpec, MeasureSpec.AT_MOST); | ||||
|  | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
|  | ||||
| } | ||||
|      | ||||
|      | ||||
|      | ||||
|  | ||||
| @@ -0,0 +1,48 @@ | ||||
| package cc.winboll.studio.mymessagemanager.views; | ||||
|  | ||||
| /** | ||||
|  * @Author ZhanGSKen@QQ.COM | ||||
|  * @Date 2023/07/24 15:08:31 | ||||
|  * @Describe TTS语音规则视图 | ||||
|  */ | ||||
| import android.content.Context; | ||||
| import android.content.res.TypedArray; | ||||
| import android.util.AttributeSet; | ||||
| import androidx.cardview.widget.CardView; | ||||
| import cc.winboll.studio.mymessagemanager.R; | ||||
|  | ||||
| public class TTSRuleView extends CardView { | ||||
|      | ||||
|     public static final String TAG = "TTSRuleView"; | ||||
|      | ||||
|     Context mContext; | ||||
|  | ||||
|     public TTSRuleView(Context context) { | ||||
|         super(context); | ||||
|         mContext = context; | ||||
|     } | ||||
|  | ||||
|     public TTSRuleView(Context context, AttributeSet attrs) { | ||||
|         super(context, attrs); | ||||
|         mContext = context; | ||||
|         TypedArray a = mContext.obtainStyledAttributes(attrs, R.styleable.TTSRuleView, 0, 0); | ||||
|         int colorBackground = a.getColor(R.styleable.TTSRuleView_attrTTSRuleViewBackgroundColor, 0); | ||||
|         a.recycle(); | ||||
|         setCardBackgroundColor(colorBackground); | ||||
|     } | ||||
|  | ||||
|     public TTSRuleView(Context context, AttributeSet attrs, int defStyleAttr) { | ||||
|         super(context, attrs, defStyleAttr); | ||||
|         mContext = context; | ||||
|     } | ||||
|  | ||||
|     @Override | ||||
|     protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { | ||||
|         //Integer.MAX_VALUE:表示int类型能够表示的最大值,值为2的31次方-1 | ||||
|         //>>2:右移N位相当于除以2的N的幂 | ||||
|         //MeasureSpec.AT_MOST:子布局可以根据自己的大小选择任意大小的模式 | ||||
|         int newHeightMeasureSpec = MeasureSpec.makeMeasureSpec(Integer.MAX_VALUE >> 2, MeasureSpec.AT_MOST); | ||||
|         super.onMeasure(widthMeasureSpec, newHeightMeasureSpec); | ||||
|     } | ||||
|      | ||||
| } | ||||
							
								
								
									
										7
									
								
								mymessagemanager/src/main/res/anim/slow_fade_in.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										7
									
								
								mymessagemanager/src/main/res/anim/slow_fade_in.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,7 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <set xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <alpha | ||||
|         android:fromAlpha="0.0" | ||||
|         android:toAlpha="1.0" | ||||
|         android:duration="5000" /> <!-- 持续2秒 --> | ||||
| </set> | ||||
							
								
								
									
										41
									
								
								mymessagemanager/src/main/res/drawable/bg_frame.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								mymessagemanager/src/main/res/drawable/bg_frame.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?>  | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  | ||||
|     <!-- 阴影部分 -->  | ||||
|     <!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->  | ||||
|     <item  | ||||
|         android:left="2dp"  | ||||
|         android:top="2dp"  | ||||
|         android:right="2dp"  | ||||
|         android:bottom="2dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#0F000000"  | ||||
|                 android:startColor="#0F000000" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
|     <!-- 背景部分 -->  | ||||
|     <!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->  | ||||
|     <item  | ||||
|         android:left="3dp"  | ||||
|         android:top="3dp"  | ||||
|         android:right="3dp"  | ||||
|         android:bottom="5dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#0FFFFFFF"  | ||||
|                 android:startColor="#FFFFFFFF" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
| </layer-list> | ||||
							
								
								
									
										41
									
								
								mymessagemanager/src/main/res/drawable/bg_frame_black.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								mymessagemanager/src/main/res/drawable/bg_frame_black.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?>  | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  | ||||
|     <!-- 阴影部分 -->  | ||||
|     <!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->  | ||||
|     <item  | ||||
|         android:left="2dp"  | ||||
|         android:top="2dp"  | ||||
|         android:right="2dp"  | ||||
|         android:bottom="2dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#0F000000"  | ||||
|                 android:startColor="#0F000000" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
|     <!-- 背景部分 -->  | ||||
|     <!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->  | ||||
|     <item  | ||||
|         android:left="3dp"  | ||||
|         android:top="3dp"  | ||||
|         android:right="3dp"  | ||||
|         android:bottom="5dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#AF000000"  | ||||
|                 android:startColor="#AF000000" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
| </layer-list> | ||||
							
								
								
									
										41
									
								
								mymessagemanager/src/main/res/drawable/bg_frame_white.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										41
									
								
								mymessagemanager/src/main/res/drawable/bg_frame_white.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,41 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?>  | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" >  | ||||
|     <!-- 阴影部分 -->  | ||||
|     <!-- 个人觉得更形象的表达:top代表下边的阴影高度,left代表右边的阴影宽度。其实也就是相对应的offset,solid中的颜色是阴影的颜色,也可以设置角度等等 -->  | ||||
|     <item  | ||||
|         android:left="2dp"  | ||||
|         android:top="2dp"  | ||||
|         android:right="2dp"  | ||||
|         android:bottom="2dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#0FFFFFFF"  | ||||
|                 android:startColor="#0FFFFFFF" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
|     <!-- 背景部分 -->  | ||||
|     <!-- 形象的表达:bottom代表背景部分在上边缘超出阴影的高度,right代表背景部分在左边超出阴影的宽度(相对应的offset) -->  | ||||
|     <item  | ||||
|         android:left="3dp"  | ||||
|         android:top="3dp"  | ||||
|         android:right="3dp"  | ||||
|         android:bottom="5dp">  | ||||
|         <shape android:shape="rectangle" >  | ||||
|             <gradient  | ||||
|                 android:angle="270"  | ||||
|                 android:endColor="#CFFFFFFF"  | ||||
|                 android:startColor="#CFFFFFFF" />  | ||||
|             <corners  | ||||
|                 android:bottomLeftRadius="6dip"  | ||||
|                 android:bottomRightRadius="6dip"  | ||||
|                 android:topLeftRadius="6dip"  | ||||
|                 android:topRightRadius="6dip" />  | ||||
|         </shape>  | ||||
|     </item>  | ||||
| </layer-list> | ||||
							
								
								
									
										20
									
								
								mymessagemanager/src/main/res/drawable/cursor_pointer.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								mymessagemanager/src/main/res/drawable/cursor_pointer.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="48dp" | ||||
|     android:height="48dp" | ||||
|     android:viewportWidth="48" | ||||
|     android:viewportHeight="48"> | ||||
|     <path | ||||
|         android:fillColor="#00FFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="2.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M24.17 5.23C34.61 5.23 43.16 13.78 43.16 24.22 43.16 34.66 34.61 43.2 24.17 43.2 13.73 43.2 5.18 34.66 5.18 24.22 5.18 13.78 13.73 5.23 24.17 5.23"/> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="2.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M25.8 20.4C25.8 20.4 26.6 20.6 26.6 20.6 26.6 20.6 31.92 23.77 31.92 23.77 32.81 24.12 33.39 25.17 33.32 26.3 33.32 26.3 33.32 26.5 33.32 26.5 33.32 26.5 33.32 26.7 33.32 26.7 33.32 26.7 32.17 36.04 32.17 36.04 32.09 36.69 31.85 37.3 31.41 37.73 31.01 38.19 30.49 38.42 29.94 38.42 29.94 38.42 21.18 38.42 21.18 38.42 20.55 38.42 19.98 38.14 19.56 37.61 19.56 37.61 11.93 28.5 11.93 28.5 11.93 28.5 13.07 26.97 13.07 26.97 13.38 26.59 13.86 26.38 14.32 26.41 14.32 26.41 14.69 26.41 14.69 26.41 14.69 26.41 19.75 27.74 19.75 27.74 19.75 27.74 19.75 11.72 19.75 11.72 19.75 10.03 20.89 8.66 22.3 8.66 23.7 8.66 24.85 10.03 24.85 11.72 24.85 11.72 24.85 20.4 24.85 20.4 24.85 20.4 25.8 20.4 25.8 20.4 25.8 20.4 25.8 20.4 25.8 20.4"/> | ||||
| </vector> | ||||
							
								
								
									
										11
									
								
								mymessagemanager/src/main/res/drawable/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								mymessagemanager/src/main/res/drawable/ic_launcher.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <layer-list xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:clickable="true"> | ||||
|     <item android:drawable="@drawable/ic_launcher_background"/>  | ||||
|     <item  | ||||
|         android:left="15dp"  | ||||
|         android:top="15dp"  | ||||
|         android:right="15dp"  | ||||
|         android:bottom="15dp" | ||||
|         android:drawable="@drawable/ic_launcher_foreground"/> | ||||
| </layer-list> | ||||
| @@ -0,0 +1,170 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportWidth="108" | ||||
|     android:viewportHeight="108"> | ||||
|     <path | ||||
|         android:fillColor="#3DDC84" | ||||
|         android:pathData="M0,0h108v108h-108z" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M9,0L9,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,0L19,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,0L29,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,0L39,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,0L49,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,0L59,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,0L69,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,0L79,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M89,0L89,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M99,0L99,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,9L108,9" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,19L108,19" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,29L108,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,39L108,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,49L108,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,59L108,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,69L108,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,79L108,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,89L108,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,99L108,99" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,29L89,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,39L89,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,49L89,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,59L89,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,69L89,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,79L89,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,19L29,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,19L39,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,19L49,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,19L59,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,19L69,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,19L79,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
| </vector> | ||||
| @@ -0,0 +1,170 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportWidth="108" | ||||
|     android:viewportHeight="108"> | ||||
|     <path | ||||
|         android:fillColor="#FFDCD93D" | ||||
|         android:pathData="M0,0h108v108h-108z" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M9,0L9,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,0L19,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,0L29,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,0L39,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,0L49,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,0L59,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,0L69,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,0L79,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M89,0L89,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M99,0L99,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,9L108,9" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,19L108,19" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,29L108,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,39L108,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,49L108,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,59L108,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,69L108,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,79L108,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,89L108,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,99L108,99" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,29L89,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,39L89,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,49L89,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,59L89,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,69L89,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,79L89,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,19L29,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,19L39,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,19L49,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,19L59,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,19L69,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,19L79,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
| </vector> | ||||
| @@ -0,0 +1,170 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="108dp" | ||||
|     android:height="108dp" | ||||
|     android:viewportWidth="108" | ||||
|     android:viewportHeight="108"> | ||||
|     <path | ||||
|         android:fillColor="#FF3DC9DC" | ||||
|         android:pathData="M0,0h108v108h-108z" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M9,0L9,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,0L19,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,0L29,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,0L39,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,0L49,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,0L59,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,0L69,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,0L79,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M89,0L89,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M99,0L99,108" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,9L108,9" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,19L108,19" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,29L108,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,39L108,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,49L108,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,59L108,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,69L108,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,79L108,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,89L108,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M0,99L108,99" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,29L89,29" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,39L89,39" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,49L89,49" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,59L89,59" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,69L89,69" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M19,79L89,79" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M29,19L29,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M39,19L39,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M49,19L49,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M59,19L59,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M69,19L69,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
|     <path | ||||
|         android:fillColor="#00000000" | ||||
|         android:pathData="M79,19L79,89" | ||||
|         android:strokeWidth="0.8" | ||||
|         android:strokeColor="#33FFFFFF" /> | ||||
| </vector> | ||||
| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#FFFFFFFF" | ||||
|         android:pathData="M16.61,15.15C16.15,15.15 15.77,14.78 15.77,14.32S16.15,13.5 16.61,13.5H16.61C17.07,13.5 17.45,13.86 17.45,14.32C17.45,14.78 17.07,15.15 16.61,15.15M7.41,15.15C6.95,15.15 6.57,14.78 6.57,14.32C6.57,13.86 6.95,13.5 7.41,13.5H7.41C7.87,13.5 8.24,13.86 8.24,14.32C8.24,14.78 7.87,15.15 7.41,15.15M16.91,10.14L18.58,7.26C18.67,7.09 18.61,6.88 18.45,6.79C18.28,6.69 18.07,6.75 18,6.92L16.29,9.83C14.95,9.22 13.5,8.9 12,8.91C10.47,8.91 9,9.24 7.73,9.82L6.04,6.91C5.95,6.74 5.74,6.68 5.57,6.78C5.4,6.87 5.35,7.08 5.44,7.25L7.1,10.13C4.25,11.69 2.29,14.58 2,18H22C21.72,14.59 19.77,11.7 16.91,10.14H16.91Z"/> | ||||
| </vector> | ||||
							
								
								
									
										20
									
								
								mymessagemanager/src/main/res/drawable/ic_message.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										20
									
								
								mymessagemanager/src/main/res/drawable/ic_message.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,20 @@ | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="48dp" | ||||
|     android:height="48dp" | ||||
|     android:viewportWidth="48" | ||||
|     android:viewportHeight="48"> | ||||
|     <path | ||||
|         android:fillColor="#00FFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="2.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M13.46 15.9C13.46 15.9 40.54 15.9 35.12 15.9 40.54 15.9 40.54 15.9 40.54 19.5 40.54 19.5 40.54 33.87 40.54 33.87 40.54 37.46 40.54 37.46 35.12 37.46 35.12 37.46 13.46 37.46 13.46 37.46 8.05 37.46 8.05 37.46 8.05 33.87 8.05 33.87 8.05 19.5 8.05 19.5 8.05 15.9 8.05 15.9 13.46 15.9"/> | ||||
|     <path | ||||
|         android:fillColor="#00FFFFFF" | ||||
|         android:strokeColor="#FF000000" | ||||
|         android:strokeWidth="2.0" | ||||
|         android:strokeLineCap="round" | ||||
|         android:strokeMiterLimit="10" | ||||
|         android:pathData="M8.86 16.79C11.42 20.07 15.03 25.47 24.19 25.57 33.46 25.67 37.88 18.2 39.86 16.42"/> | ||||
| </vector> | ||||
							
								
								
									
										10
									
								
								mymessagemanager/src/main/res/drawable/shape_gradient.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								mymessagemanager/src/main/res/drawable/shape_gradient.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android"> | ||||
|     <gradient | ||||
|         android:angle="180" | ||||
|         android:endColor="#FFFFFFFF" | ||||
|         android:startColor="#FFFFFFFF" | ||||
|         android:type="linear" /> | ||||
|  | ||||
|     <corners android:radius="10dp" /> | ||||
| </shape> | ||||
							
								
								
									
										11
									
								
								mymessagemanager/src/main/res/drawable/speaker.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								mymessagemanager/src/main/res/drawable/speaker.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,11 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <vector xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:width="24dp" | ||||
|     android:height="24dp" | ||||
|     android:viewportHeight="24" | ||||
|     android:viewportWidth="24"> | ||||
|     <path | ||||
|         android:fillColor="#ff000000" | ||||
|         android:pathData="M14,3.23V5.29C16.89,6.15 19,8.83 19,12C19,15.17 16.89,17.84 14,18.7V20.77C18,19.86 21,16.28 21,12C21,7.72 18,4.14 14,3.23M16.5,12C16.5,10.23 15.5,8.71 14,7.97V16C15.5,15.29 16.5,13.76 16.5,12M3,9V15H7L12,20V4L7,9H3Z"/> | ||||
|  | ||||
| </vector> | ||||
							
								
								
									
										29
									
								
								mymessagemanager/src/main/res/layout/activity_about.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										29
									
								
								mymessagemanager/src/main/res/layout/activity_about.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,29 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
|    <!--<androidx.appcompat.widget.Toolbar | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:id="@+id/activityaboutToolbar1"/>--> | ||||
|  | ||||
|     <cc.winboll.studio.libaes.views.ASupportToolbar | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activityaboutASupportToolbar1"/> | ||||
|  | ||||
|     <cc.winboll.studio.shared.view.AboutView | ||||
|         app:appname="MyMessageManager" | ||||
|         app:appprojectname="MyMessageManager" | ||||
|         app:appdescription="用正则表达式方法自定义短信过滤和语音播报的短信应用。" | ||||
|         app:appicon="@drawable/ic_winboll" | ||||
|         android:layout_width="match_parent" | ||||
|         android:layout_height="match_parent" | ||||
|         android:id="@+id/activityaboutAboutView1"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										248
									
								
								mymessagemanager/src/main/res/layout/activity_appsettings.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										248
									
								
								mymessagemanager/src/main/res/layout/activity_appsettings.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,248 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.AToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activityappsettingsAToolbar1"/> | ||||
|  | ||||
| 	<ScrollView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="0dp" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:padding="5dp"> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:textAppearance="?android:attr/textAppearanceLarge" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="用户视觉系统保护模式设置:" | ||||
| 					android:paddingLeft="5dp"/> | ||||
|  | ||||
| 				<LinearLayout | ||||
| 					android:orientation="vertical" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:gravity="center_vertical"> | ||||
|  | ||||
| 					<Switch | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="48dp" | ||||
| 						android:text="回收站短信保护式预览开关:" | ||||
| 						android:paddingLeft="5dp" | ||||
| 						android:textAppearance="?android:attr/textAppearanceSmall" | ||||
| 						android:id="@+id/activityappsettingsSwitch3"/> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="center_vertical"> | ||||
|  | ||||
| 						<TextView | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="拒绝显示的字符集:"/> | ||||
|  | ||||
| 						<EditText | ||||
| 							android:layout_width="0dp" | ||||
| 							android:ems="10" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:layout_weight="1.0" | ||||
| 							android:id="@+id/activityappsettingsEditText3"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="center_vertical"> | ||||
|  | ||||
| 						<TextView | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="替代字符:"/> | ||||
|  | ||||
| 						<EditText | ||||
| 							android:layout_width="0dp" | ||||
| 							android:ems="10" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:layout_weight="1.0" | ||||
| 							android:id="@+id/activityappsettingsEditText4"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 				</LinearLayout> | ||||
|  | ||||
| 			</LinearLayout> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:textAppearance="?android:attr/textAppearanceLarge" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="短信号码国家代码合并设置:" | ||||
| 					android:paddingLeft="5dp"/> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="如+8612345678901与12345678901合并为12345678901." | ||||
| 					android:textAppearance="?android:attr/textAppearanceSmall" | ||||
| 					android:paddingLeft="5dp"/> | ||||
|  | ||||
| 				<LinearLayout | ||||
| 					android:orientation="horizontal" | ||||
| 					android:layout_width="wrap_content" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:gravity="center_vertical"> | ||||
|  | ||||
| 					<TextView | ||||
| 						android:layout_width="wrap_content" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:text="当前国家代码为:+"/> | ||||
|  | ||||
| 					<EditText | ||||
| 						android:layout_width="80dp" | ||||
| 						android:ems="10" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:inputType="number" | ||||
| 						android:id="@+id/activityappsettingsEditText2"/> | ||||
|  | ||||
| 					<Switch | ||||
| 						android:layout_width="wrap_content" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:id="@+id/activityappsettingsSwitch1"/> | ||||
|  | ||||
| 				</LinearLayout> | ||||
|  | ||||
| 			</LinearLayout> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:textAppearance="?android:attr/textAppearanceLarge" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="TTS 语音设置:" | ||||
| 					android:paddingLeft="5dp"/> | ||||
|  | ||||
| 				<LinearLayout | ||||
| 					android:orientation="horizontal" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:gravity="center_vertical"> | ||||
|  | ||||
| 					<TextView | ||||
| 						android:layout_width="0dp" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:text="@string/text_ttsplaydelaytimes" | ||||
| 						android:layout_weight="1.0" | ||||
| 						android:layout_alignParentLeft="true" | ||||
| 						android:layout_centerVertical="true" | ||||
| 						android:paddingLeft="5dp"/> | ||||
|  | ||||
| 					<EditText | ||||
| 						android:layout_width="50dp" | ||||
| 						android:inputType="number" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:ems="10" | ||||
| 						android:id="@+id/activityappsettingsEditText1" | ||||
| 						android:layout_alignParentRight="true" | ||||
| 						android:layout_centerVertical="true"/> | ||||
|  | ||||
| 				</LinearLayout> | ||||
|  | ||||
| 			</LinearLayout> | ||||
|  | ||||
| 			<LinearLayout | ||||
| 				android:orientation="vertical" | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 				<TextView | ||||
| 					android:textAppearance="?android:attr/textAppearanceLarge" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content" | ||||
| 					android:text="应用权限设置 :" | ||||
| 					android:paddingLeft="5dp"/> | ||||
|  | ||||
| 				<LinearLayout | ||||
| 					android:orientation="vertical" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content"> | ||||
|  | ||||
| 					<Button | ||||
| 						android:layout_width="wrap_content" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:text="打开系统默认应用设置" | ||||
| 						android:onClick="onOpenSystemDefaultAppSettings"/> | ||||
|  | ||||
| 					<Button | ||||
| 						android:layout_width="wrap_content" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:text="检查应用权限" | ||||
| 						android:onClick="onCheckAndGetAppPermission"/> | ||||
|  | ||||
| 				</LinearLayout> | ||||
|  | ||||
| 			</LinearLayout> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</ScrollView> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:padding="10dp" | ||||
| 		android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 		<cc.winboll.studio.libaes.views.AOHPCTCSeekBar | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/activityappsettingsAOHPCTCSeekBar1" | ||||
| 			android:padding="30dp"/> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:gravity="center" | ||||
| 			android:textSize="15sp" | ||||
| 			android:id="@+id/activityappsettingsTextView1" | ||||
| 			android:text="@string/msg_100applysettings"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										71
									
								
								mymessagemanager/src/main/res/layout/activity_composesms.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										71
									
								
								mymessagemanager/src/main/res/layout/activity_composesms.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,71 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.AToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activitycomposesmsASupportToolbar1"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 		<RelativeLayout | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/activitycomposesmsRelativeLayout1"> | ||||
|  | ||||
| 			<TextView | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="SMS TO : " | ||||
| 				android:id="@+id/activitycomposesmsTextView1" | ||||
| 				android:layout_alignParentLeft="true" | ||||
| 				android:layout_marginLeft="10dp" | ||||
| 				android:layout_centerVertical="true"/> | ||||
|  | ||||
| 			<EditText | ||||
| 				android:layout_toRightOf="@id/activitycomposesmsTextView1" | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:inputType="phone" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:ems="10" | ||||
| 				android:id="@+id/activitycomposesmsEditText1" | ||||
| 				android:layout_alignParentRight="true" | ||||
| 				android:layout_marginRight="10dp" | ||||
| 				android:layout_centerVertical="true"/> | ||||
|  | ||||
| 		</RelativeLayout> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<RelativeLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:padding="10dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<ListView | ||||
| 			android:layout_alignParentTop="true" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:layout_above="@+id/activitycomposesmsinclude1" | ||||
| 			android:id="@+id/activitycomposesmsListView1"/> | ||||
|  | ||||
| 		<include | ||||
| 			layout="@layout/view_smssend" | ||||
| 			android:layout_alignParentBottom="true" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/activitycomposesmsinclude1"/> | ||||
|  | ||||
| 	</RelativeLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										82
									
								
								mymessagemanager/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										82
									
								
								mymessagemanager/src/main/res/layout/activity_main.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,82 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.ASupportToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:layout_gravity="center" | ||||
| 		android:id="@+id/activitymainASupportToolbar1"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content"> | ||||
|  | ||||
| 		<cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="60dp" | ||||
| 			android:padding="10dp" | ||||
| 			android:text="@string/text_mainservice" | ||||
| 			android:id="@+id/activitymainSwitchView1"/> | ||||
|  | ||||
| 		<cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="60dp" | ||||
| 			android:padding="10dp" | ||||
| 			android:text="@string/text_onlyreceivecontacts" | ||||
| 			android:id="@+id/activitymainSwitchView2"/> | ||||
|  | ||||
| 		<cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="60dp" | ||||
| 			android:padding="10dp" | ||||
| 			android:text="@string/text_usingtts" | ||||
| 			android:id="@+id/activitymainSwitchView3"/> | ||||
|  | ||||
| 		<cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="60dp" | ||||
| 			android:padding="10dp" | ||||
| 			android:text="@string/text_usingttsrule" | ||||
| 			android:id="@+id/activitymainSwitchView4"/> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/activitymainButton1" | ||||
| 			android:text="@string/text_sendsms"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| 	<com.baoyz.widget.PullRefreshLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/activitymainPullRefreshLayout1"> | ||||
|  | ||||
| 		<ScrollView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="match_parent" | ||||
| 			android:id="@+id/activitymainScrollView1"> | ||||
|  | ||||
| 			<cc.winboll.studio.mymessagemanager.views.PhoneListViewForScrollView | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:id="@+id/activitymainListView1"/> | ||||
|  | ||||
| 		</ScrollView> | ||||
|  | ||||
| 	</com.baoyz.widget.PullRefreshLayout> | ||||
|  | ||||
| 	<cc.winboll.studio.shared.log.LogView | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="120dp" | ||||
| 		android:id="@+id/logview"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -0,0 +1,29 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.AToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activitysharedjsonreceiveASupportToolbar1"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Text" | ||||
| 			android:id="@+id/activitysharedjsonreceiveTextView1" | ||||
| 			android:padding="10dp"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										45
									
								
								mymessagemanager/src/main/res/layout/activity_sms.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								mymessagemanager/src/main/res/layout/activity_sms.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,45 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.AToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activitysmsASupportToolbar1"/> | ||||
|  | ||||
| 	<RelativeLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="match_parent" | ||||
| 		android:paddingBottom="10dp"> | ||||
|  | ||||
| 		<ScrollView | ||||
| 			android:layout_alignParentTop="true" | ||||
| 			android:layout_above="@+id/activitysmsinclude1" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="0dp" | ||||
| 			android:id="@+id/activitysmsinphoneScrollView1" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:isScrollContainer="false"> | ||||
|  | ||||
| 			<cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:id="@+id/activitysmsinphoneListView1"/> | ||||
|  | ||||
| 		</ScrollView> | ||||
|  | ||||
| 		<include | ||||
| 			android:layout_alignParentBottom="true" | ||||
| 			layout="@layout/view_smssend" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:id="@+id/activitysmsinclude1"/> | ||||
|  | ||||
| 	</RelativeLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -0,0 +1,82 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.ASupportToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activitysmsacceptrulesettingASupportToolbar1"/> | ||||
|  | ||||
| 	<com.baoyz.widget.PullRefreshLayout | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/activitysmsacceptrulesettingPullRefreshLayout1"> | ||||
|  | ||||
| 		<androidx.recyclerview.widget.RecyclerView | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:isScrollContainer="true" | ||||
| 			app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||
| 			app:reverseLayout="false" | ||||
| 			android:id="@+id/activitysmsacceptrulesettingRecyclerView1"/> | ||||
|  | ||||
| 	</com.baoyz.widget.PullRefreshLayout> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="center_vertical" | ||||
| 		android:background="@drawable/bg_frame" | ||||
| 		android:padding="10dp"> | ||||
|  | ||||
| 		<EditText | ||||
| 			android:layout_width="0dp" | ||||
| 			android:ems="10" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:singleLine="true" | ||||
| 			android:id="@+id/activitysmsacceptrulesettingEditText1"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content"> | ||||
|  | ||||
| 			<RadioButton | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="Accept" | ||||
| 				android:id="@+id/activitysmsacceptrulesettingRadioButton1" | ||||
| 				android:onClick="onAcceptRuleType"/> | ||||
|  | ||||
| 			<RadioButton | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="Refuse" | ||||
| 				android:id="@+id/activitysmsacceptrulesettingRadioButton2" | ||||
| 				android:onClick="onRefuseRuleType"/> | ||||
|  | ||||
| 			<CheckBox | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="Enable" | ||||
| 				android:id="@+id/activitysmsacceptrulesettingCheckBox1"/> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="+" | ||||
| 				android:id="@+id/activitysmsacceptrulesettingButton1"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										32
									
								
								mymessagemanager/src/main/res/layout/activity_smsrecycle.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										32
									
								
								mymessagemanager/src/main/res/layout/activity_smsrecycle.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,32 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.ASupportToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activitysmsrecycleASupportToolbar1"/> | ||||
|  | ||||
| 	<com.baoyz.widget.PullRefreshLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/activitysmsrecyclePullRefreshLayout1"> | ||||
|  | ||||
|         <androidx.recyclerview.widget.RecyclerView | ||||
|             android:layout_width="match_parent" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:isScrollContainer="true" | ||||
|             app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||
|             app:reverseLayout="false" | ||||
|             android:id="@+id/activitysmsrecycleRecyclerView1"/> | ||||
|  | ||||
| 	</com.baoyz.widget.PullRefreshLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										164
									
								
								mymessagemanager/src/main/res/layout/activity_ttsplayrule.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										164
									
								
								mymessagemanager/src/main/res/layout/activity_ttsplayrule.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,164 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<cc.winboll.studio.libaes.views.ASupportToolbar | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="@dimen/toolbar_height" | ||||
| 		android:id="@+id/activityttsplayruleASupportToolbar1"/> | ||||
|  | ||||
| 	<RelativeLayout | ||||
| 		android:orientation="vertical" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0"> | ||||
|  | ||||
| 		<androidx.recyclerview.widget.RecyclerView | ||||
| 			android:layout_above="@+id/activityttsplayruleLinearLayout2" | ||||
| 			android:layout_alignParentTop="true" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:isScrollContainer="false" | ||||
| 			app:layoutManager="androidx.recyclerview.widget.LinearLayoutManager" | ||||
| 			app:reverseLayout="false" | ||||
| 			android:id="@+id/activityttsplayruleRecyclerView1"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="234dp" | ||||
| 			android:id="@+id/activityttsplayruleLinearLayout1"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:layout_below="@+id/activityttsplayruleLinearLayout1" | ||||
| 			android:background="@drawable/bg_frame" | ||||
| 			android:id="@+id/activityttsplayruleLinearLayout2" | ||||
| 			android:layout_alignParentBottom="true" | ||||
| 			android:padding="10dp"> | ||||
|  | ||||
| 			<ScrollView | ||||
| 				android:layout_width="match_parent" | ||||
| 				android:layout_height="wrap_content"> | ||||
|  | ||||
| 				<LinearLayout | ||||
| 					android:orientation="vertical" | ||||
| 					android:layout_width="match_parent" | ||||
| 					android:layout_height="wrap_content"> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="vertical" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:layout_gravity="center_horizontal"> | ||||
|  | ||||
| 						<RelativeLayout | ||||
| 							android:layout_width="match_parent" | ||||
| 							android:layout_height="wrap_content"> | ||||
|  | ||||
| 							<TextView | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content" | ||||
| 								android:text="测试文本:" | ||||
| 								android:id="@+id/activityttsplayruleTextView1" | ||||
| 								android:layout_centerVertical="true"/> | ||||
|  | ||||
| 							<Button | ||||
| 								android:layout_width="wrap_content" | ||||
| 								android:layout_height="wrap_content" | ||||
| 								android:text="✈" | ||||
| 								android:layout_toRightOf="@id/activityttsplayruleTextView1" | ||||
| 								android:layout_centerVertical="true" | ||||
| 								android:onClick="onScrollToDemoSMSTextMatchingRule"/> | ||||
|  | ||||
| 						</RelativeLayout> | ||||
|  | ||||
| 						<EditText | ||||
| 							android:layout_width="match_parent" | ||||
| 							android:inputType="textMultiLine" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:ems="10" | ||||
| 							android:id="@+id/activityttsplayruleEditText1"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:layout_gravity="center_horizontal"> | ||||
|  | ||||
| 						<TextView | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="搜索字串:"/> | ||||
|  | ||||
| 						<EditText | ||||
| 							android:layout_width="0dp" | ||||
| 							android:inputType="textMultiLine" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:ems="10" | ||||
| 							android:id="@+id/activityttsplayruleEditText2" | ||||
| 							android:layout_weight="1.0"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:layout_gravity="center_horizontal"> | ||||
|  | ||||
| 						<TextView | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:text="语音字串:"/> | ||||
|  | ||||
| 						<EditText | ||||
| 							android:layout_width="0dp" | ||||
| 							android:inputType="textMultiLine" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							android:ems="10" | ||||
| 							android:id="@+id/activityttsplayruleEditText3" | ||||
| 							android:layout_weight="1.0"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 					<LinearLayout | ||||
| 						android:orientation="horizontal" | ||||
| 						android:layout_width="match_parent" | ||||
| 						android:layout_height="wrap_content" | ||||
| 						android:gravity="center"> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							style="?android:attr/buttonStyle" | ||||
| 							android:text="♬" | ||||
| 							android:id="@+id/activityttsplayruleButton1"/> | ||||
|  | ||||
| 						<Button | ||||
| 							android:layout_width="wrap_content" | ||||
| 							android:layout_height="wrap_content" | ||||
| 							style="?android:attr/buttonStyle" | ||||
| 							android:text="√" | ||||
| 							android:id="@+id/activityttsplayruleButton2"/> | ||||
|  | ||||
| 					</LinearLayout> | ||||
|  | ||||
| 				</LinearLayout> | ||||
|  | ||||
| 			</ScrollView> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</RelativeLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										66
									
								
								mymessagemanager/src/main/res/layout/item_ttsplayrule.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								mymessagemanager/src/main/res/layout/item_ttsplayrule.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,66 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="wrap_content"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:padding="10dp" | ||||
| 		android:layout_marginBottom="10dp" | ||||
| 		android:gravity="center_vertical" | ||||
| 		android:id="@+id/itemttsplayruleLinearLayout1"> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content"> | ||||
|  | ||||
| 			<TextView | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="Text" | ||||
| 				android:id="@+id/itemttsplayruleTextView2"/> | ||||
|  | ||||
| 			<CheckBox | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:background="#FFFFFFFF" | ||||
| 				android:id="@+id/itemttsplayruleCheckBox1"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content"> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="△" | ||||
| 				android:id="@+id/itemttsplayruleButton1"/> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="▽" | ||||
| 				android:id="@+id/itemttsplayruleButton2"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="0dp" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Text" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:id="@+id/itemttsplayruleTextView1"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -0,0 +1,66 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="wrap_content"> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:padding="10dp" | ||||
| 		android:layout_marginBottom="10dp" | ||||
| 		android:gravity="center_vertical" | ||||
| 		android:id="@+id/itemttsplayrulesimpleLinearLayout1"> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content"> | ||||
|  | ||||
| 			<TextView | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="Text" | ||||
| 				android:id="@+id/itemttsplayrulesimpleTextView2"/> | ||||
|  | ||||
| 			<CheckBox | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:background="#FFFFFFFF" | ||||
| 				android:id="@+id/itemttsplayrulesimpleCheckBox1"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content"> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="△" | ||||
| 				android:id="@+id/itemttsplayrulesimpleButton1"/> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="▽" | ||||
| 				android:id="@+id/itemttsplayrulesimpleButton2"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="0dp" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Text" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:id="@+id/itemttsplayrulesimpleTextView1"/> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										21
									
								
								mymessagemanager/src/main/res/layout/listview_contracts.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								mymessagemanager/src/main/res/layout/listview_contracts.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="Text" | ||||
| 		android:id="@+id/listviewcontractsTextView1"/> | ||||
|      | ||||
|     <TextView | ||||
|         android:layout_width="wrap_content" | ||||
|         android:layout_height="wrap_content" | ||||
|         android:text="Text" | ||||
|         android:id="@+id/listviewcontractsTextView2"/> | ||||
|      | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										22
									
								
								mymessagemanager/src/main/res/layout/listview_phone.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										22
									
								
								mymessagemanager/src/main/res/layout/listview_phone.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,22 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent" | ||||
| 	android:padding="10dp" | ||||
| 	android:id="@+id/listviewphoneLinearLayout1" | ||||
| 	android:background="@drawable/bg_frame"> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/listviewphoneTextView2"/> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/listviewphoneTextView1"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										38
									
								
								mymessagemanager/src/main/res/layout/listview_sms.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										38
									
								
								mymessagemanager/src/main/res/layout/listview_sms.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,38 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	android:orientation="horizontal" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="wrap_content"> | ||||
|  | ||||
| 	<View | ||||
| 		android:layout_width="32dp" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/listviewsmsView1"/> | ||||
|  | ||||
| 	<cc.winboll.studio.mymessagemanager.views.SMSView | ||||
| 		xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 		android:layout_width="0dp" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		app:cardCornerRadius="12dp" | ||||
| 		app:cardElevation="5dp" | ||||
| 		app:cardUseCompatPadding="true" | ||||
| 		android:elevation="5dp" | ||||
| 		android:translationZ="5dp" | ||||
| 		android:clickable="true" | ||||
| 		android:foreground="?android:attr/selectableItemBackground" | ||||
| 		app:cardBackgroundColor="?attr/colorAccent" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/listviewsmsSMSView1"> | ||||
|  | ||||
| 		<include layout="@layout/listview_sms_part1"/> | ||||
|  | ||||
| 	</cc.winboll.studio.mymessagemanager.views.SMSView> | ||||
|  | ||||
| 	<View | ||||
| 		android:layout_width="32dp" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:id="@+id/listviewsmsView2"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
Some files were not shown because too many files have changed in this diff Show More
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen