diff --git a/mymessagemanager/.gitignore b/mymessagemanager/.gitignore new file mode 100644 index 0000000..796b96d --- /dev/null +++ b/mymessagemanager/.gitignore @@ -0,0 +1 @@ +/build diff --git a/mymessagemanager/README.md b/mymessagemanager/README.md new file mode 100644 index 0000000..75856f4 --- /dev/null +++ b/mymessagemanager/README.md @@ -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 diff --git a/mymessagemanager/app_update_description.txt b/mymessagemanager/app_update_description.txt new file mode 100644 index 0000000..8b13789 --- /dev/null +++ b/mymessagemanager/app_update_description.txt @@ -0,0 +1 @@ + diff --git a/mymessagemanager/build.gradle b/mymessagemanager/build.gradle new file mode 100644 index 0000000..7f9a2d1 --- /dev/null +++ b/mymessagemanager/build.gradle @@ -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']) +} diff --git a/mymessagemanager/build.properties b/mymessagemanager/build.properties new file mode 100644 index 0000000..2414519 --- /dev/null +++ b/mymessagemanager/build.properties @@ -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 diff --git a/mymessagemanager/proguard-rules.pro b/mymessagemanager/proguard-rules.pro new file mode 100644 index 0000000..233bad2 --- /dev/null +++ b/mymessagemanager/proguard-rules.pro @@ -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 *; +#} diff --git a/mymessagemanager/src/beta/AndroidManifest.xml b/mymessagemanager/src/beta/AndroidManifest.xml new file mode 100644 index 0000000..522ecec --- /dev/null +++ b/mymessagemanager/src/beta/AndroidManifest.xml @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/beta/res/values-zh/strings.xml b/mymessagemanager/src/beta/res/values-zh/strings.xml new file mode 100644 index 0000000..ffbc3e5 --- /dev/null +++ b/mymessagemanager/src/beta/res/values-zh/strings.xml @@ -0,0 +1,6 @@ + + + + 我的短信管家 ☆ + + diff --git a/mymessagemanager/src/beta/res/values/strings.xml b/mymessagemanager/src/beta/res/values/strings.xml new file mode 100644 index 0000000..085d3ca --- /dev/null +++ b/mymessagemanager/src/beta/res/values/strings.xml @@ -0,0 +1,6 @@ + + + + My Message Manager + + + diff --git a/mymessagemanager/src/main/AndroidManifest.xml b/mymessagemanager/src/main/AndroidManifest.xml new file mode 100644 index 0000000..c1e89fa --- /dev/null +++ b/mymessagemanager/src/main/AndroidManifest.xml @@ -0,0 +1,231 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/assets/GlobalApplication/SMSAcceptRuleBean_List.json b/mymessagemanager/src/main/assets/GlobalApplication/SMSAcceptRuleBean_List.json new file mode 100644 index 0000000..b7fdefe --- /dev/null +++ b/mymessagemanager/src/main/assets/GlobalApplication/SMSAcceptRuleBean_List.json @@ -0,0 +1,7 @@ +[ + { + "userId": -1, + "ruleData": ".*", + "isEnable": true + } +] \ No newline at end of file diff --git a/mymessagemanager/src/main/assets/GlobalApplication/TTSPlayRuleBean_List.json b/mymessagemanager/src/main/assets/GlobalApplication/TTSPlayRuleBean_List.json new file mode 100644 index 0000000..8c9f761 --- /dev/null +++ b/mymessagemanager/src/main/assets/GlobalApplication/TTSPlayRuleBean_List.json @@ -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 + } +] \ No newline at end of file diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/GlobalApplication.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/GlobalApplication.java new file mode 100644 index 0000000..a14351e --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/GlobalApplication.java @@ -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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/AboutActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/AboutActivity.java new file mode 100644 index 0000000..51750d6 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/AboutActivity.java @@ -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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/AppSettingsActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/AppSettingsActivity.java new file mode 100644 index 0000000..2704fe6 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/AppSettingsActivity.java @@ -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(); + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/BaseActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/BaseActivity.java new file mode 100644 index 0000000..233f18a --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/BaseActivity.java @@ -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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/ComposeSMSActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/ComposeSMSActivity.java new file mode 100644 index 0000000..03a7a3c --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/ComposeSMSActivity.java @@ -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> mAdapterData = new ArrayList<>(); + ListView mlvContracts; + List 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 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()); + + } + }); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/MainActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/MainActivity.java new file mode 100644 index 0000000..a2bdbd8 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/MainActivity.java @@ -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 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中可能这样定义: + /*/ + + + Tab 1 + Tab 2 + Tab 3 + + + */ + // 现在你可以遍历这个数组来访问每个元素 + 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); + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSActivity.java new file mode 100644 index 0000000..9f354fe --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSActivity.java @@ -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 mActivity; + MyHandler(SMSActivity activity) { + mActivity = new WeakReference(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()); + } + + } + + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSReceiveRuleActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSReceiveRuleActivity.java new file mode 100644 index 0000000..c043091 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSReceiveRuleActivity.java @@ -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(); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSRecycleActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSRecycleActivity.java new file mode 100644 index 0000000..1c61a0a --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SMSRecycleActivity.java @@ -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(); + } + }; +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SharedJSONReceiveActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SharedJSONReceiveActivity.java new file mode 100644 index 0000000..945da3c --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/SharedJSONReceiveActivity.java @@ -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 beanList = new ArrayList(); + 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 beanListShare = new ArrayList(); + SMSAcceptRuleBean.loadBeanListFromFile(szSrcJSON, beanListShare, SMSAcceptRuleBean.class); + ArrayList beanListApp = new ArrayList(); + 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 beanList = new ArrayList(); + 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 beanListShare = new ArrayList(); + TTSPlayRuleBean.loadBeanListFromFile(szSrcJSON, beanListShare, TTSPlayRuleBean.class); + ArrayList beanListApp = new ArrayList(); + 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(); + } + })); + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/TTSPlayRuleActivity.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/TTSPlayRuleActivity.java new file mode 100644 index 0000000..8ecdd29 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/activitys/TTSPlayRuleActivity.java @@ -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; + } + }; +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/PhoneArrayAdapter.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/PhoneArrayAdapter.java new file mode 100644 index 0000000..b8b9454 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/PhoneArrayAdapter.java @@ -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 mData; + List mlistContacts; + PhoneUtil mPhoneUtil; + + public PhoneArrayAdapter(Context context) { + mContext = context; + mData = new ArrayList(); + } + + public void loadData() { + ArrayList 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; + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSAcceptRuleArrayAdapter.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSAcceptRuleArrayAdapter.java new file mode 100644 index 0000000..992bf08 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSAcceptRuleArrayAdapter.java @@ -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 { + + public static final String TAG = "SMSAcceptRuleArrayAdapter"; + + Context mContext; + ArrayList 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); + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSArrayAdapter.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSArrayAdapter.java new file mode 100644 index 0000000..4671ae4 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSArrayAdapter.java @@ -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 mData; + + public SMSArrayAdapter(Context context, String szPhone) { + mContext = context; + mszPhone = szPhone; + mData = new ArrayList(); + mData = loadSMSList(context, szPhone); + } + + ArrayList loadSMSList(Context context, String szPhone) { + ArrayList 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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSRecycleAdapter.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSRecycleAdapter.java new file mode 100644 index 0000000..1f6e71d --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/SMSRecycleAdapter.java @@ -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 { + + public static final String TAG = "SMSRecycleAdapter"; + + Context mContext; + ArrayList mDataList; + String mszSMSRecycleListDataPath; + AppConfigUtil mAppConfigUtil; + + public SMSRecycleAdapter(Context context) { + mContext = context; + mAppConfigUtil = AppConfigUtil.getInstance(mContext); + mszSMSRecycleListDataPath = SMSRecycleUtil.getSMSRecycleListDataPath(mContext); + mDataList = new ArrayList(); + mDataList = loadSMSRecycleList(); + } + + public ArrayList loadSMSRecycleList() { + ArrayList list = new ArrayList(); + 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); + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/TTSRuleBeanRecyclerViewAdapter.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/TTSRuleBeanRecyclerViewAdapter.java new file mode 100644 index 0000000..075abb7 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/adapters/TTSRuleBeanRecyclerViewAdapter.java @@ -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 { + + public static final String TAG = "TTSRuleBeanRecyclerViewAdapter"; + + Context mContext; + ArrayList 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); + + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/AppConfigBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/AppConfigBean.java new file mode 100644 index 0000000..364e942 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/AppConfigBean.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/AppConfigBean_V1.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/AppConfigBean_V1.java new file mode 100644 index 0000000..f712c84 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/AppConfigBean_V1.java @@ -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; + }*/ + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/ContractsBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/ContractsBean.java new file mode 100644 index 0000000..0a1cf81 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/ContractsBean.java @@ -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; + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/MessageNotificationBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/MessageNotificationBean.java new file mode 100644 index 0000000..5088b6c --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/MessageNotificationBean.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/PhoneBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/PhoneBean.java new file mode 100644 index 0000000..ca37ff0 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/PhoneBean.java @@ -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; + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSAcceptRuleBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSAcceptRuleBean.java new file mode 100644 index 0000000..cd145eb --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSAcceptRuleBean.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSAcceptRuleBean_V1.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSAcceptRuleBean_V1.java new file mode 100644 index 0000000..0c32443 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSAcceptRuleBean_V1.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSBean.java new file mode 100644 index 0000000..7534844 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSBean.java @@ -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 list, boolean isDesc) { + Collections.sort(list, new SortSMSByDateDesc(isDesc)); + + } + + private static class SortSMSByDateDesc implements Comparator { + 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; + } + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSRecycleBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSRecycleBean.java new file mode 100644 index 0000000..7da594b --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/SMSRecycleBean.java @@ -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 list, boolean isDesc) { + Collections.sort(list, new SortSMSByDeleteDateDesc(isDesc)); + } + + private static class SortSMSByDeleteDateDesc implements Comparator { + 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; + } + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSPlayRuleBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSPlayRuleBean.java new file mode 100644 index 0000000..41ce4f0 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSPlayRuleBean.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSPlayRuleBean_V1.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSPlayRuleBean_V1.java new file mode 100644 index 0000000..b4e2c95 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSPlayRuleBean_V1.java @@ -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 parseBeanList(String beanList) { + try { + StringReader stringReader = new StringReader(beanList); + JsonReader jsonReader = new JsonReader(stringReader); + ArrayList list = new ArrayList(); + 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 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 loadBeanList(Context context) { + return loadBeanListFromFile(getBeanListJsonFilePath(context)); + }*/ + + public static ArrayList loadBeanListFromFile(String szFilePath) { + ArrayList 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 beanList) { + return saveBeanListToFile(getBeanListJsonFilePath(context), beanList); + } + + public static boolean saveBeanListToFile(String szFilePath, ArrayList 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; + }*/ +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSSpeakTextBean.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSSpeakTextBean.java new file mode 100644 index 0000000..149db9a --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/beans/TTSSpeakTextBean.java @@ -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; + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/dialogs/YesNoAlertDialog.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/dialogs/YesNoAlertDialog.java new file mode 100644 index 0000000..7296109 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/dialogs/YesNoAlertDialog.java @@ -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(); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/receivers/MainReceiver.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/receivers/MainReceiver.java new file mode 100644 index 0000000..254039d --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/receivers/MainReceiver.java @@ -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!"); + } + } + + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/receivers/SMSRecevier.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/receivers/SMSRecevier.java new file mode 100644 index 0000000..b5255c2 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/receivers/SMSRecevier.java @@ -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); + } + } + + + + } + + +} + + + + diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/AssistantService.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/AssistantService.java new file mode 100644 index 0000000..efd81f3 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/AssistantService.java @@ -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(); + } + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/DefaultSMSManagerService.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/DefaultSMSManagerService.java new file mode 100644 index 0000000..bcdf546 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/DefaultSMSManagerService.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/MainService.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/MainService.java new file mode 100644 index 0000000..3b8b4ce --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/MainService.java @@ -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); + } + } + + + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/TTSPlayService.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/TTSPlayService.java new file mode 100644 index 0000000..607546b --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/services/TTSPlayService.java @@ -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 listTTSSpeakTextBean = (ArrayList)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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppConfigUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppConfigUtil.java new file mode 100644 index 0000000..627ce6a --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppConfigUtil.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppConfigUtil_V1.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppConfigUtil_V1.java new file mode 100644 index 0000000..6404807 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppConfigUtil_V1.java @@ -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 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 readJsonStream(InputStream in) throws IOException { + JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); + return readJsonArrayList(reader); + } + + // + // 读取 Json 文件的每一 Json 项 + // + public ArrayList readJsonArrayList(JsonReader reader) throws IOException { + ArrayList list = new ArrayList(); + 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 list = new ArrayList(); + 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 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 beanList) throws IOException { + writer.beginArray(); + for (AppConfigBean bean : beanList) { + writeBeanItem(writer, bean); + } + writer.endArray(); + }*/ +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppGoToSettingsUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppGoToSettingsUtil.java new file mode 100644 index 0000000..9d169ce --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/AppGoToSettingsUtil.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/FileUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/FileUtil.java new file mode 100644 index 0000000..49fa200 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/FileUtil.java @@ -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()); + } + } + } + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/NotificationUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/NotificationUtil.java new file mode 100644 index 0000000..1c94e56 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/NotificationUtil.java @@ -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); + } +} + + diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/PermissionUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/PermissionUtil.java new file mode 100644 index 0000000..ea0cf52 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/PermissionUtil.java @@ -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 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 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 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 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(); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/PhoneUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/PhoneUtil.java new file mode 100644 index 0000000..7001c12 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/PhoneUtil.java @@ -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 getPhoneList() { + List 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() { + @Override + public int compare(PhoneBean o1, PhoneBean o2) { + return o1.getTelPhone().compareTo(o2.getTelPhone()); + } + }); + + return listPhoneBean; + } + + public boolean isPhoneInContacts(String szPhone) { + List listPhoneDto = getPhoneList(); + for (int i = 0; i < listPhoneDto.size(); i++) { + if (listPhoneDto.get(i).getTelPhone().equals(szPhone)) { + return true; + } + } + return false; + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/RegexPPiUtils.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/RegexPPiUtils.java new file mode 100644 index 0000000..8387f39 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/RegexPPiUtils.java @@ -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(); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSReceiveRuleUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSReceiveRuleUtil.java new file mode 100644 index 0000000..1c8949b --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSReceiveRuleUtil.java @@ -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 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(); + 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 void sortListByRuleData(List list, boolean isDesc) { + Collections.sort(list, new SortListByRuleData(isDesc)); + } + + // + // Rule数据排序比较类定义 + // + static class SortListByRuleData implements Comparator { + 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 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 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 loadConfigData() { + ArrayList list = new ArrayList(); + 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 loadDataFromPath(String szPath) { + File fJson = new File(szPath); + ArrayList listTemp = null; + try { + listTemp = readJsonStream(new FileInputStream(fJson)); + } catch (IOException e) { + LogUtils.d(TAG, "IOException : " + e.getMessage()); + } + if (listTemp == null) { + listTemp = new ArrayList(); + } + return listTemp; + }*/ + + // + // 读取 Json 文件 + // + public ArrayList readJsonStream_V1(InputStream in) throws IOException { + JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); + return readJsonArrayList_V1(reader); + } + + // + // 读取 Json 文件的每一 Json 项 + // + public ArrayList readJsonArrayList_V1(JsonReader reader) throws IOException { + ArrayList list = new ArrayList(); + 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 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 beanList) throws IOException { + writer.beginArray(); + for (SMSAcceptRuleBean_V1 bean : beanList) { + writeBeanItem(writer, bean); + } + writer.endArray(); + }*/ +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSRecycleUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSRecycleUtil.java new file mode 100644 index 0000000..01012ef --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSRecycleUtil.java @@ -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 list = new ArrayList(); + SMSRecycleBean.loadBeanListFromFile(getSMSRecycleListDataPath(context), list, SMSRecycleBean.class); + SMSRecycleBean smsRecycleBean = new SMSRecycleBean(bean, System.currentTimeMillis()); + list.add(smsRecycleBean); + SMSRecycleBean.saveBeanListToFile(getSMSRecycleListDataPath(context), list); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSUtil.java new file mode 100644 index 0000000..0cf09f1 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/SMSUtil.java @@ -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 getAllSMSList(Context context) { + ArrayList returnList = new ArrayList(); + 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 getSMSListByPhone(Context context, String szPhone) { + ArrayList returnList = new ArrayList(); + 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 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 msgs = sms.divideMessage(message); + ArrayList sentIntents = new ArrayList(); + 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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ServiceUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ServiceUtil.java new file mode 100644 index 0000000..68957f6 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ServiceUtil.java @@ -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 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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/TTSPlayRuleUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/TTSPlayRuleUtil.java new file mode 100644 index 0000000..c954dbd --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/TTSPlayRuleUtil.java @@ -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 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(); + 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 ttsData = new ArrayList(); + 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 ttsData = new ArrayList(); + 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 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 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 ttsData = new ArrayList(); + 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 listBeanImport = loadDataFromPath(szPath); + // 添加更新表到现有操作表 + if (mConfigData == null) { + mConfigData = new ArrayList(); + } + ArrayList configData = loadConfigData(); + configData.addAll(listBeanImport); + // 保存操作表数据 + saveConfigData(configData); + return listBeanImport.size(); + }*/ + + /*ArrayList loadDataFromPath(String szPath) { + File fJson = new File(szPath); + ArrayList listTemp = null; + try { + listTemp = readJsonStream(new FileInputStream(fJson)); + } catch (IOException e) { + LogUtils.d(TAG, "IOException : " + e.getMessage()); + } + if (listTemp == null) { + listTemp = new ArrayList(); + } + return listTemp; + }*/ + + // + // 加载 TTS 配置数据 + // + public ArrayList 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 readJsonStream(InputStream in) throws IOException { + JsonReader reader = new JsonReader(new InputStreamReader(in, "UTF-8")); + return readJsonArrayList(reader); + } + + // + // 读取 Json 文件的每一 Json 项 + // + public ArrayList readJsonArrayList(JsonReader reader) throws IOException { + ArrayList list = new ArrayList(); + 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 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 beanList) throws IOException { + writer.beginArray(); + for (TTSPlayRuleBean bean : beanList) { + writeBeanItem(writer, bean); + } + writer.endArray(); + }*/ +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/TextToSpeechUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/TextToSpeechUtil.java new file mode 100644 index 0000000..a0f62b5 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/TextToSpeechUtil.java @@ -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 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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ThemeUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ThemeUtil.java new file mode 100644 index 0000000..22f0243 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ThemeUtil.java @@ -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; + } + } + */ +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/UriUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/UriUtil.java new file mode 100644 index 0000000..f80a892 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/UriUtil.java @@ -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 + //

+ // 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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/UserVisionSystemProtectModeUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/UserVisionSystemProtectModeUtil.java new file mode 100644 index 0000000..2aa9d61 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/UserVisionSystemProtectModeUtil.java @@ -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; + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ViewUtil.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ViewUtil.java new file mode 100644 index 0000000..1b56d0b --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/utils/ViewUtil.java @@ -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); + } + }); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/ConfirmSwitchView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/ConfirmSwitchView.java new file mode 100644 index 0000000..6c9ebb6 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/ConfirmSwitchView.java @@ -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); + } + }); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/DateAgoTextView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/DateAgoTextView.java new file mode 100644 index 0000000..e813885 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/DateAgoTextView.java @@ -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)); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/PhoneListViewForScrollView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/PhoneListViewForScrollView.java new file mode 100644 index 0000000..b7d5b43 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/PhoneListViewForScrollView.java @@ -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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSAcceptRuleListViewForScrollView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSAcceptRuleListViewForScrollView.java new file mode 100644 index 0000000..d60d8f6 --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSAcceptRuleListViewForScrollView.java @@ -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); + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSListViewForScrollView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSListViewForScrollView.java new file mode 100644 index 0000000..296882e --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSListViewForScrollView.java @@ -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); + } + +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSView.java new file mode 100644 index 0000000..9ce0bbe --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/SMSView.java @@ -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); + } +} diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/TTSRuleListViewForScrollView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/TTSRuleListViewForScrollView.java new file mode 100644 index 0000000..be676cb --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/TTSRuleListViewForScrollView.java @@ -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); + } + +} + + + + diff --git a/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/TTSRuleView.java b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/TTSRuleView.java new file mode 100644 index 0000000..60104ce --- /dev/null +++ b/mymessagemanager/src/main/java/cc/winboll/studio/mymessagemanager/views/TTSRuleView.java @@ -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); + } + +} diff --git a/mymessagemanager/src/main/res/anim/slow_fade_in.xml b/mymessagemanager/src/main/res/anim/slow_fade_in.xml new file mode 100644 index 0000000..fa73170 --- /dev/null +++ b/mymessagemanager/src/main/res/anim/slow_fade_in.xml @@ -0,0 +1,7 @@ + + + + diff --git a/mymessagemanager/src/main/res/drawable/bg_frame.xml b/mymessagemanager/src/main/res/drawable/bg_frame.xml new file mode 100644 index 0000000..75b2b94 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/bg_frame.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/bg_frame_black.xml b/mymessagemanager/src/main/res/drawable/bg_frame_black.xml new file mode 100644 index 0000000..cfe4379 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/bg_frame_black.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/bg_frame_white.xml b/mymessagemanager/src/main/res/drawable/bg_frame_white.xml new file mode 100644 index 0000000..002ffe1 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/bg_frame_white.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/cursor_pointer.xml b/mymessagemanager/src/main/res/drawable/cursor_pointer.xml new file mode 100644 index 0000000..e828063 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/cursor_pointer.xml @@ -0,0 +1,20 @@ + + + + diff --git a/mymessagemanager/src/main/res/drawable/ic_launcher.xml b/mymessagemanager/src/main/res/drawable/ic_launcher.xml new file mode 100644 index 0000000..d4d1eaf --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/ic_launcher.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/mymessagemanager/src/main/res/drawable/ic_launcher_background.xml b/mymessagemanager/src/main/res/drawable/ic_launcher_background.xml new file mode 100644 index 0000000..a4f78de --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/ic_launcher_background.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/ic_launcher_background_golden.xml b/mymessagemanager/src/main/res/drawable/ic_launcher_background_golden.xml new file mode 100644 index 0000000..804236c --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/ic_launcher_background_golden.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/ic_launcher_background_sky.xml b/mymessagemanager/src/main/res/drawable/ic_launcher_background_sky.xml new file mode 100644 index 0000000..1ff84d4 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/ic_launcher_background_sky.xml @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/ic_launcher_foreground.xml b/mymessagemanager/src/main/res/drawable/ic_launcher_foreground.xml new file mode 100644 index 0000000..872b04e --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/ic_launcher_foreground.xml @@ -0,0 +1,10 @@ + + + + diff --git a/mymessagemanager/src/main/res/drawable/ic_message.xml b/mymessagemanager/src/main/res/drawable/ic_message.xml new file mode 100644 index 0000000..70f1497 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/ic_message.xml @@ -0,0 +1,20 @@ + + + + diff --git a/mymessagemanager/src/main/res/drawable/shape_gradient.xml b/mymessagemanager/src/main/res/drawable/shape_gradient.xml new file mode 100644 index 0000000..c164fe9 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/shape_gradient.xml @@ -0,0 +1,10 @@ + + + + + + diff --git a/mymessagemanager/src/main/res/drawable/speaker.xml b/mymessagemanager/src/main/res/drawable/speaker.xml new file mode 100644 index 0000000..53e00c1 --- /dev/null +++ b/mymessagemanager/src/main/res/drawable/speaker.xml @@ -0,0 +1,11 @@ + + + + + diff --git a/mymessagemanager/src/main/res/layout/activity_about.xml b/mymessagemanager/src/main/res/layout/activity_about.xml new file mode 100644 index 0000000..a2dcf3f --- /dev/null +++ b/mymessagemanager/src/main/res/layout/activity_about.xml @@ -0,0 +1,29 @@ + + + + + + + + + + + diff --git a/mymessagemanager/src/main/res/layout/activity_appsettings.xml b/mymessagemanager/src/main/res/layout/activity_appsettings.xml new file mode 100644 index 0000000..2664de4 --- /dev/null +++ b/mymessagemanager/src/main/res/layout/activity_appsettings.xml @@ -0,0 +1,248 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +