源码整理

This commit is contained in:
2025-12-12 13:40:13 +08:00
parent be52292203
commit 2dafa7bf9f
13 changed files with 629 additions and 413 deletions

View File

@@ -23,9 +23,9 @@ import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter; import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter;
import cc.winboll.studio.contacts.model.MainServiceBean; import cc.winboll.studio.contacts.model.MainServiceBean;
import cc.winboll.studio.contacts.model.PhoneConnectRuleModel; import cc.winboll.studio.contacts.model.PhoneConnectRuleBean;
import cc.winboll.studio.contacts.model.RingTongBean; import cc.winboll.studio.contacts.model.RingTongBean;
import cc.winboll.studio.contacts.model.SettingsModel; import cc.winboll.studio.contacts.model.SettingsBean;
import cc.winboll.studio.contacts.bobulltoon.TomCat; import cc.winboll.studio.contacts.bobulltoon.TomCat;
import cc.winboll.studio.contacts.dun.Rules; import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.contacts.services.MainService;
@@ -68,7 +68,7 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
private int mnStreamMaxVolume; private int mnStreamMaxVolume;
private int mnStreamVolume; private int mnStreamVolume;
private PhoneConnectRuleAdapter adapter; private PhoneConnectRuleAdapter adapter;
private List<PhoneConnectRuleModel> ruleList; private List<PhoneConnectRuleBean> ruleList;
// ====================== 接口实现区 ====================== // ====================== 接口实现区 ======================
@Override @Override
@@ -206,7 +206,7 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
etDunResumeCount = (EditText) findViewById(R.id.et_DunResumeCount); etDunResumeCount = (EditText) findViewById(R.id.et_DunResumeCount);
swIsEnableDun = (Switch) findViewById(R.id.sw_IsEnableDun); swIsEnableDun = (Switch) findViewById(R.id.sw_IsEnableDun);
SettingsModel settingsModel = Rules.getInstance(this).getSettingsModel(); SettingsBean settingsModel = Rules.getInstance(this).getSettingsModel();
etDunTotalCount.setText(Integer.toString(settingsModel.getDunTotalCount())); etDunTotalCount.setText(Integer.toString(settingsModel.getDunTotalCount()));
etDunResumeSecondCount.setText(Integer.toString(settingsModel.getDunResumeSecondCount())); etDunResumeSecondCount.setText(Integer.toString(settingsModel.getDunResumeSecondCount()));
etDunResumeCount.setText(Integer.toString(settingsModel.getDunResumeCount())); etDunResumeCount.setText(Integer.toString(settingsModel.getDunResumeCount()));
@@ -248,7 +248,7 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
etDunResumeSecondCount.setEnabled(!isEnableDun); etDunResumeSecondCount.setEnabled(!isEnableDun);
etDunResumeCount.setEnabled(!isEnableDun); etDunResumeCount.setEnabled(!isEnableDun);
SettingsModel settingsModel = Rules.getInstance(this).getSettingsModel(); SettingsBean settingsModel = Rules.getInstance(this).getSettingsModel();
if (isEnableDun) { if (isEnableDun) {
try { try {
int totalCount = Integer.parseInt(etDunTotalCount.getText().toString()); int totalCount = Integer.parseInt(etDunTotalCount.getText().toString());
@@ -284,7 +284,7 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
public void onAddNewConnectionRule(View view) { public void onAddNewConnectionRule(View view) {
LogUtils.d(TAG, "onAddNewConnectionRule: 添加新的连接规则"); LogUtils.d(TAG, "onAddNewConnectionRule: 添加新的连接规则");
Rules.getInstance(this).getPhoneBlacRuleBeanList().add(new PhoneConnectRuleModel()); Rules.getInstance(this).getPhoneBlacRuleBeanList().add(new PhoneConnectRuleBean());
Rules.getInstance(this).saveRules(); Rules.getInstance(this).saveRules();
adapter.notifyDataSetChanged(); adapter.notifyDataSetChanged();
} }

View File

@@ -12,7 +12,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import cc.winboll.studio.contacts.R; import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.model.PhoneConnectRuleModel; import cc.winboll.studio.contacts.model.PhoneConnectRuleBean;
import cc.winboll.studio.contacts.dun.Rules; import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.views.LeftScrollView; import cc.winboll.studio.contacts.views.LeftScrollView;
import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog; import cc.winboll.studio.libaes.dialogs.YesNoAlertDialog;
@@ -36,10 +36,10 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
// ====================== 成员变量区 ====================== // ====================== 成员变量区 ======================
private Context mContext; private Context mContext;
private List<PhoneConnectRuleModel> mRuleList; private List<PhoneConnectRuleBean> mRuleList;
// ====================== 构造函数区 ====================== // ====================== 构造函数区 ======================
public PhoneConnectRuleAdapter(Context context, List<PhoneConnectRuleModel> ruleList) { public PhoneConnectRuleAdapter(Context context, List<PhoneConnectRuleBean> ruleList) {
LogUtils.d(TAG, "PhoneConnectRuleAdapter: 初始化适配器,规则数量=" + ruleList.size()); LogUtils.d(TAG, "PhoneConnectRuleAdapter: 初始化适配器,规则数量=" + ruleList.size());
this.mContext = context; this.mContext = context;
this.mRuleList = ruleList; this.mRuleList = ruleList;
@@ -63,7 +63,7 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
@Override @Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) { public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) {
final PhoneConnectRuleModel model = mRuleList.get(position); final PhoneConnectRuleBean model = mRuleList.get(position);
LogUtils.d(TAG, "onBindViewHolder: 绑定规则数据position=" + position + ",视图类型=" + getItemViewType(position)); LogUtils.d(TAG, "onBindViewHolder: 绑定规则数据position=" + position + ",视图类型=" + getItemViewType(position));
if (holder instanceof SimpleViewHolder) { if (holder instanceof SimpleViewHolder) {
@@ -87,7 +87,7 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
/** /**
* 绑定简单视图数据 * 绑定简单视图数据
*/ */
private void bindSimpleViewHolder(final SimpleViewHolder holder, final PhoneConnectRuleModel model, final int position) { private void bindSimpleViewHolder(final SimpleViewHolder holder, final PhoneConnectRuleBean model, final int position) {
// 绑定规则文本,空值显示[NULL] // 绑定规则文本,空值显示[NULL]
String ruleText = model.getRuleText().trim().isEmpty() ? NULL_RULE_TEXT : model.getRuleText().trim(); String ruleText = model.getRuleText().trim().isEmpty() ? NULL_RULE_TEXT : model.getRuleText().trim();
holder.tvRuleText.setText(ruleText); holder.tvRuleText.setText(ruleText);
@@ -132,7 +132,7 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
/** /**
* 绑定编辑视图数据 * 绑定编辑视图数据
*/ */
private void bindEditViewHolder(final EditViewHolder holder, final PhoneConnectRuleModel model, final int position) { private void bindEditViewHolder(final EditViewHolder holder, final PhoneConnectRuleBean model, final int position) {
// 绑定规则文本到输入框 // 绑定规则文本到输入框
holder.editText.setText(model.getRuleText()); holder.editText.setText(model.getRuleText());
// 绑定复选框状态 // 绑定复选框状态
@@ -167,7 +167,7 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
ToastUtils.show("已到顶部,无法上移"); ToastUtils.show("已到顶部,无法上移");
return; return;
} }
ArrayList<PhoneConnectRuleModel> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList(); ArrayList<PhoneConnectRuleBean> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList();
swapRulePosition(ruleList, position, position - 1); swapRulePosition(ruleList, position, position - 1);
} }
@@ -175,7 +175,7 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
* 规则下移 * 规则下移
*/ */
private void moveRuleDown(int position) { private void moveRuleDown(int position) {
ArrayList<PhoneConnectRuleModel> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList(); ArrayList<PhoneConnectRuleBean> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList();
if (position >= ruleList.size() - 1) { if (position >= ruleList.size() - 1) {
ToastUtils.show("已到底部,无法下移"); ToastUtils.show("已到底部,无法下移");
return; return;
@@ -186,8 +186,8 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
/** /**
* 交换规则位置 * 交换规则位置
*/ */
private void swapRulePosition(ArrayList<PhoneConnectRuleModel> list, int fromPos, int toPos) { private void swapRulePosition(ArrayList<PhoneConnectRuleBean> list, int fromPos, int toPos) {
PhoneConnectRuleModel temp = list.get(fromPos); PhoneConnectRuleBean temp = list.get(fromPos);
list.set(fromPos, list.get(toPos)); list.set(fromPos, list.get(toPos));
list.set(toPos, temp); list.set(toPos, temp);
Rules.getInstance(mContext).saveRules(); Rules.getInstance(mContext).saveRules();
@@ -198,11 +198,11 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
/** /**
* 显示删除确认弹窗 * 显示删除确认弹窗
*/ */
private void showDeleteConfirmDialog(Context dialogContext, final PhoneConnectRuleModel model, final int position) { private void showDeleteConfirmDialog(Context dialogContext, final PhoneConnectRuleBean model, final int position) {
YesNoAlertDialog.show(dialogContext, "删除确认", "是否删除该通话规则?", new YesNoAlertDialog.OnDialogResultListener() { YesNoAlertDialog.show(dialogContext, "删除确认", "是否删除该通话规则?", new YesNoAlertDialog.OnDialogResultListener() {
@Override @Override
public void onYes() { public void onYes() {
ArrayList<PhoneConnectRuleModel> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList(); ArrayList<PhoneConnectRuleBean> ruleList = Rules.getInstance(mContext).getPhoneBlacRuleBeanList();
ruleList.remove(position); ruleList.remove(position);
Rules.getInstance(mContext).saveRules(); Rules.getInstance(mContext).saveRules();
notifyDataSetChanged(); notifyDataSetChanged();

View File

@@ -7,8 +7,8 @@ package cc.winboll.studio.contacts.dun;
*/ */
import android.content.Context; import android.content.Context;
import cc.winboll.studio.contacts.activities.SettingsActivity; import cc.winboll.studio.contacts.activities.SettingsActivity;
import cc.winboll.studio.contacts.model.PhoneConnectRuleModel; import cc.winboll.studio.contacts.model.PhoneConnectRuleBean;
import cc.winboll.studio.contacts.model.SettingsModel; import cc.winboll.studio.contacts.model.SettingsBean;
import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.contacts.utils.ContactUtils; import cc.winboll.studio.contacts.utils.ContactUtils;
import cc.winboll.studio.contacts.utils.IntUtils; import cc.winboll.studio.contacts.utils.IntUtils;
@@ -24,15 +24,15 @@ public class Rules {
public static final String TAG = "Rules"; public static final String TAG = "Rules";
ArrayList<PhoneConnectRuleModel> _PhoneConnectRuleModelList; ArrayList<PhoneConnectRuleBean> _PhoneConnectRuleModelList;
static volatile Rules _Rules; static volatile Rules _Rules;
Context mContext; Context mContext;
SettingsModel mSettingsModel; SettingsBean mSettingsModel;
Timer mDunResumeTimer; Timer mDunResumeTimer;
Rules(Context context) { Rules(Context context) {
mContext = context; mContext = context;
_PhoneConnectRuleModelList = new ArrayList<PhoneConnectRuleModel>(); _PhoneConnectRuleModelList = new ArrayList<PhoneConnectRuleBean>();
reload(); reload();
} }
@@ -57,7 +57,7 @@ public class Rules {
// 盾牌恢复定时器 // 盾牌恢复定时器
mDunResumeTimer = new Timer(); mDunResumeTimer = new Timer();
int ss = IntUtils.getIntInRange(mSettingsModel.getDunResumeSecondCount() * 1000, SettingsModel.MIN_INTRANGE, SettingsModel.MAX_INTRANGE); int ss = IntUtils.getIntInRange(mSettingsModel.getDunResumeSecondCount() * 1000, SettingsBean.MIN_INTRANGE, SettingsBean.MAX_INTRANGE);
mDunResumeTimer.schedule(new TimerTask() { mDunResumeTimer.schedule(new TimerTask() {
@Override @Override
public void run() { public void run() {
@@ -77,12 +77,12 @@ public class Rules {
public void loadRules() { public void loadRules() {
_PhoneConnectRuleModelList.clear(); _PhoneConnectRuleModelList.clear();
PhoneConnectRuleModel.loadBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class); PhoneConnectRuleBean.loadBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleBean.class);
} }
public void saveRules() { public void saveRules() {
LogUtils.d(TAG, String.format("saveRules()")); LogUtils.d(TAG, String.format("saveRules()"));
PhoneConnectRuleModel.saveBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class); PhoneConnectRuleBean.saveBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleBean.class);
} }
public void resetDefaultBoBullToonURL() { public void resetDefaultBoBullToonURL() {
@@ -100,16 +100,16 @@ public class Rules {
} }
public void loadDun() { public void loadDun() {
mSettingsModel = SettingsModel.loadBean(mContext, SettingsModel.class); mSettingsModel = SettingsBean.loadBean(mContext, SettingsBean.class);
if (mSettingsModel == null) { if (mSettingsModel == null) {
mSettingsModel = new SettingsModel(); mSettingsModel = new SettingsBean();
SettingsModel.saveBean(mContext, mSettingsModel); SettingsBean.saveBean(mContext, mSettingsModel);
} }
} }
public void saveDun() { public void saveDun() {
LogUtils.d(TAG, String.format("saveDun()")); LogUtils.d(TAG, String.format("saveDun()"));
SettingsModel.saveBean(mContext, mSettingsModel); SettingsBean.saveBean(mContext, mSettingsModel);
} }
public boolean isAllowed(String phoneNumber) { public boolean isAllowed(String phoneNumber) {
@@ -215,14 +215,14 @@ public class Rules {
} }
public void add(String szPhoneConnectRule, boolean isAllowConnection, boolean isEnable) { public void add(String szPhoneConnectRule, boolean isAllowConnection, boolean isEnable) {
_PhoneConnectRuleModelList.add(new PhoneConnectRuleModel(szPhoneConnectRule, isAllowConnection, isEnable)); _PhoneConnectRuleModelList.add(new PhoneConnectRuleBean(szPhoneConnectRule, isAllowConnection, isEnable));
} }
public ArrayList<PhoneConnectRuleModel> getPhoneBlacRuleBeanList() { public ArrayList<PhoneConnectRuleBean> getPhoneBlacRuleBeanList() {
return _PhoneConnectRuleModelList; return _PhoneConnectRuleModelList;
} }
public SettingsModel getSettingsModel() { public SettingsBean getSettingsModel() {
return mSettingsModel; return mSettingsModel;
} }
} }

View File

@@ -1,26 +1,34 @@
package cc.winboll.studio.contacts.model; package cc.winboll.studio.contacts.model;
/** import cc.winboll.studio.libappbase.LogUtils;
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/26 13:10:57
* @Describe CallLogModel
*/
import java.util.Date; import java.util.Date;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/26 13:10:57
* @Describe 通话记录数据模型
*/
public class CallLogModel { public class CallLogModel {
// ====================== 常量定义区 ======================
public static final String TAG = "CallLogModel"; public static final String TAG = "CallLogModel";
// ====================== 成员变量区 ======================
private String phoneNumber; private String phoneNumber;
private String callStatus; private String callStatus;
private Date callDate; private Date callDate;
// ====================== 构造函数区 ======================
public CallLogModel(String phoneNumber, String callStatus, Date callDate) { public CallLogModel(String phoneNumber, String callStatus, Date callDate) {
// 去除号码中的空格并初始化
this.phoneNumber = phoneNumber.replaceAll("\\s", ""); this.phoneNumber = phoneNumber.replaceAll("\\s", "");
this.callStatus = callStatus; this.callStatus = callStatus;
this.callDate = callDate; this.callDate = callDate;
LogUtils.d(TAG, "CallLogModel: 初始化通话记录模型 | 号码=" + this.phoneNumber
+ " | 状态=" + this.callStatus + " | 时间=" + this.callDate);
} }
// ====================== Getter 方法区 ======================
public String getPhoneNumber() { public String getPhoneNumber() {
return phoneNumber; return phoneNumber;
} }
@@ -33,4 +41,3 @@ public class CallLogModel {
return callDate; return callDate;
} }
} }

View File

@@ -1,92 +1,121 @@
package cc.winboll.studio.contacts.model; package cc.winboll.studio.contacts.model;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/08/30 14:32
* @Describe 联系人信息数据模型
*/
import net.sourceforge.pinyin4j.PinyinHelper; import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType; import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat; import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType; import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination; import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/08/30 14:32
* @Describe 联系人信息数据模型,支持姓名转全拼和拼音首字母
*/
public class ContactModel { public class ContactModel {
// ====================== 常量定义区 ======================
public static final String TAG = "ContactModel"; public static final String TAG = "ContactModel";
// 汉字匹配正则常量,避免重复创建
private static final String CHINESE_CHAR_REGEX = "[\\u4e00-\\u9fa5]";
// ====================== 成员变量区 ======================
private String name; private String name;
private String number; private String number;
private String pinyin; private String pinyin;
// 新增:存储姓名的拼音首字母(如"啊牛"→"an"
private String pinyinFirstLetter; private String pinyinFirstLetter;
// ====================== 构造函数区 ======================
public ContactModel(String name, String number) { public ContactModel(String name, String number) {
this.name = name; LogUtils.d(TAG, "ContactModel: 开始初始化联系人模型");
this.number = number.replaceAll("\\s", ""); this.name = name == null ? "" : name;
this.pinyin = convertToPinyin(name); // 去除号码空格,空值处理为""
// 初始化时生成拼音首字母 this.number = number == null ? "" : number.replaceAll("\\s", "");
this.pinyinFirstLetter = convertToPinyinFirstLetter(name); // 初始化拼音和拼音首字母
this.pinyin = convertToPinyin(this.name);
this.pinyinFirstLetter = convertToPinyinFirstLetter(this.name);
LogUtils.d(TAG, "ContactModel: 联系人初始化完成 | 姓名=" + this.name
+ " | 号码=" + this.number + " | 全拼=" + this.pinyin
+ " | 拼音首字母=" + this.pinyinFirstLetter);
} }
// 原方法:转换为全拼(如"啊牛"→"aniu" // ====================== 拼音转换工具方法区 ======================
/**
* 姓名转为全拼(多音字默认取首个拼音)
*/
private String convertToPinyin(String chinese) { private String convertToPinyin(String chinese) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); LogUtils.d(TAG, "convertToPinyin: 开始转换姓名为全拼,姓名=" + chinese);
format.setCaseType(HanyuPinyinCaseType.LOWERCASE); HanyuPinyinOutputFormat format = getPinyinOutputFormat();
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); StringBuilder pinyinSb = new StringBuilder();
StringBuilder pinyin = new StringBuilder();
for (int i = 0; i < chinese.length(); i++) { for (int i = 0; i < chinese.length(); i++) {
char ch = chinese.charAt(i); char ch = chinese.charAt(i);
if (Character.toString(ch).matches("[\\u4e00-\\u9fa5]")) { // 仅处理汉字 // 仅处理汉字
if (Character.toString(ch).matches(CHINESE_CHAR_REGEX)) {
try { try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format); String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
if (pinyinArray != null && pinyinArray.length > 0) { if (pinyinArray != null && pinyinArray.length > 0) {
pinyin.append(pinyinArray[0]); // 取第一个拼音(多音字默认首选项) pinyinSb.append(pinyinArray[0]);
LogUtils.v(TAG, "convertToPinyin: 字符[" + ch + "]转为拼音[" + pinyinArray[0] + "]");
} }
} catch (BadHanyuPinyinOutputFormatCombination e) { } catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace(); LogUtils.e(TAG, "convertToPinyin: 拼音转换异常,字符=" + ch, e);
} }
} else { } else {
pinyin.append(ch); // 非汉字直接拼接(如字母、数字、符号) pinyinSb.append(ch);
LogUtils.v(TAG, "convertToPinyin: 非汉字字符直接拼接,字符=" + ch);
} }
} }
return pinyin.toString();
String result = pinyinSb.toString();
LogUtils.d(TAG, "convertToPinyin: 全拼转换完成,结果=" + result);
return result;
} }
// 新增:转换为拼音首字母(如"啊牛"→"an" /**
* 姓名转为拼音首字母(多音字默认取首个拼音首字母)
*/
private String convertToPinyinFirstLetter(String chinese) { private String convertToPinyinFirstLetter(String chinese) {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat(); LogUtils.d(TAG, "convertToPinyinFirstLetter: 开始转换姓名为拼音首字母,姓名=" + chinese);
format.setCaseType(HanyuPinyinCaseType.LOWERCASE); HanyuPinyinOutputFormat format = getPinyinOutputFormat();
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); StringBuilder firstLetterSb = new StringBuilder();
StringBuilder firstLetters = new StringBuilder();
for (int i = 0; i < chinese.length(); i++) { for (int i = 0; i < chinese.length(); i++) {
char ch = chinese.charAt(i); char ch = chinese.charAt(i);
if (Character.toString(ch).matches("[\\u4e00-\\u9fa5]")) { // 仅处理汉字 if (Character.toString(ch).matches(CHINESE_CHAR_REGEX)) {
try { try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format); String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(ch, format);
if (pinyinArray != null && pinyinArray.length > 0) { if (pinyinArray != null && pinyinArray.length > 0) {
// 取拼音的第一个字母(如"a"、"niu"→"a"、"n" char firstChar = pinyinArray[0].charAt(0);
firstLetters.append(pinyinArray[0].charAt(0)); firstLetterSb.append(firstChar);
LogUtils.v(TAG, "convertToPinyinFirstLetter: 字符[" + ch + "]转为首字母[" + firstChar + "]");
} }
} catch (BadHanyuPinyinOutputFormatCombination e) { } catch (BadHanyuPinyinOutputFormatCombination e) {
e.printStackTrace(); LogUtils.e(TAG, "convertToPinyinFirstLetter: 拼音首字母转换异常,字符=" + ch, e);
} }
} else { } else {
// 非汉字可根据需求处理:此处保留原字符(如"李3"→"l3""张A"→"za" firstLetterSb.append(ch);
firstLetters.append(ch); LogUtils.v(TAG, "convertToPinyinFirstLetter: 非汉字字符直接拼接,字符=" + ch);
} }
} }
return firstLetters.toString();
String result = firstLetterSb.toString();
LogUtils.d(TAG, "convertToPinyinFirstLetter: 拼音首字母转换完成,结果=" + result);
return result;
} }
// 新增:获取拼音首字母 /**
public String getPinyinFirstLetter() { * 获取统一的拼音输出格式(小写、无音调)
return pinyinFirstLetter; * 抽离为公共方法,避免重复创建对象
*/
private HanyuPinyinOutputFormat getPinyinOutputFormat() {
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
return format;
} }
// 原有getter方法 // ====================== Getter 方法区 ======================
public String getName() { public String getName() {
return name; return name;
} }
@@ -98,5 +127,9 @@ public class ContactModel {
public String getPinyin() { public String getPinyin() {
return pinyin; return pinyin;
} }
public String getPinyinFirstLetter() {
return pinyinFirstLetter;
}
} }

View File

@@ -1,25 +1,34 @@
package cc.winboll.studio.contacts.model; package cc.winboll.studio.contacts.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/13 07:06:13
*/
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter; import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean; import cc.winboll.studio.libappbase.BaseBean;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.IOException; import java.io.IOException;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/13 07:06:13
* @Describe 主服务配置实体类支持JSON序列化与反序列化
*/
public class MainServiceBean extends BaseBean { public class MainServiceBean extends BaseBean {
// ====================== 常量定义区 ======================
public static final String TAG = "MainServiceBean"; public static final String TAG = "MainServiceBean";
private static final String JSON_KEY_IS_ENABLE = "isEnable";
boolean isEnable; // ====================== 成员变量区 ======================
private boolean isEnable;
// ====================== 构造函数区 ======================
public MainServiceBean() { public MainServiceBean() {
this.isEnable = false; this.isEnable = false;
LogUtils.d(TAG, "MainServiceBean: 初始化实体类,默认状态为禁用");
} }
// ====================== Getter & Setter 方法区 ======================
public void setIsEnable(boolean isEnable) { public void setIsEnable(boolean isEnable) {
LogUtils.d(TAG, "setIsEnable: 服务状态设置为" + isEnable);
this.isEnable = isEnable; this.isEnable = isEnable;
} }
@@ -27,42 +36,56 @@ public class MainServiceBean extends BaseBean {
return isEnable; return isEnable;
} }
// ====================== 重写 BaseBean 抽象方法区 ======================
@Override @Override
public String getName() { public String getName() {
return MainServiceBean.class.getName(); String className = MainServiceBean.class.getName();
LogUtils.v(TAG, "getName: 获取类名=" + className);
return className;
} }
@Override @Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
LogUtils.d(TAG, "writeThisToJsonWriter: 开始将实体类写入JSON");
super.writeThisToJsonWriter(jsonWriter); super.writeThisToJsonWriter(jsonWriter);
MainServiceBean bean = this; // 写入服务启用状态字段
jsonWriter.name("isEnable").value(bean.isEnable()); jsonWriter.name(JSON_KEY_IS_ENABLE).value(this.isEnable);
LogUtils.d(TAG, "writeThisToJsonWriter: JSON写入完成isEnable=" + this.isEnable);
} }
@Override @Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { // 优先调用父类方法处理通用字段
if (name.equals("isEnable")) { if (super.initObjectsFromJsonReader(jsonReader, name)) {
setIsEnable(jsonReader.nextBoolean()); LogUtils.v(TAG, "initObjectsFromJsonReader: 父类已处理字段=" + name);
} else { return true;
return false;
}
} }
return true;
// 处理当前类专属字段
if (JSON_KEY_IS_ENABLE.equals(name)) {
this.isEnable = jsonReader.nextBoolean();
LogUtils.d(TAG, "initObjectsFromJsonReader: 读取字段[" + name + "]值=" + this.isEnable);
return true;
}
LogUtils.w(TAG, "initObjectsFromJsonReader: 未识别字段=" + name);
return false;
} }
@Override @Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
LogUtils.d(TAG, "readBeanFromJsonReader: 开始从JSON读取实体类数据");
jsonReader.beginObject(); jsonReader.beginObject();
while (jsonReader.hasNext()) { while (jsonReader.hasNext()) {
String name = jsonReader.nextName(); String name = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) { if (!initObjectsFromJsonReader(jsonReader, name)) {
LogUtils.w(TAG, "readBeanFromJsonReader: 跳过未识别字段=" + name);
jsonReader.skipValue(); jsonReader.skipValue();
} }
} }
// 结束 JSON 对象
jsonReader.endObject(); jsonReader.endObject();
LogUtils.d(TAG, "readBeanFromJsonReader: JSON读取完成当前实体状态=" + this.isEnable);
return this; return this;
} }
} }

View File

@@ -0,0 +1,148 @@
package cc.winboll.studio.contacts.model;
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.IOException;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/21 09:52:10
* @Describe 电话黑名单规则实体类支持JSON序列化与反序列化
*/
public class PhoneConnectRuleBean extends BaseBean {
// ====================== 常量定义区 ======================
public static final String TAG = "PhoneConnectRuleModel";
// JSON字段名常量避免硬编码错误
private static final String JSON_KEY_RULE_TEXT = "ruleText";
private static final String JSON_KEY_ALLOW_CONNECTION = "isAllowConnection";
private static final String JSON_KEY_IS_ENABLE = "isEnable";
// ====================== 成员变量区 ======================
private String ruleText;
private boolean isAllowConnection;
private boolean isEnable;
private boolean isSimpleView;
// ====================== 构造函数区 ======================
/**
* 默认构造,初始化默认值
*/
public PhoneConnectRuleBean() {
this.ruleText = "";
this.isAllowConnection = false;
this.isEnable = false;
this.isSimpleView = true;
LogUtils.d(TAG, "PhoneConnectRuleModel: 默认构造初始化完成 | 规则文本空串,默认禁用状态");
}
/**
* 带参构造,初始化核心规则参数
*/
public PhoneConnectRuleBean(String ruleText, boolean isAllowConnection, boolean isEnable) {
this.ruleText = ruleText == null ? "" : ruleText;
this.isAllowConnection = isAllowConnection;
this.isEnable = isEnable;
this.isSimpleView = true;
LogUtils.d(TAG, "PhoneConnectRuleModel: 带参构造初始化完成 | 规则文本=" + this.ruleText
+ " | 允许连接=" + this.isAllowConnection + " | 规则启用=" + this.isEnable);
}
// ====================== Getter & Setter 方法区 ======================
public String getRuleText() {
return ruleText;
}
public void setRuleText(String ruleText) {
String oldValue = this.ruleText;
this.ruleText = ruleText == null ? "" : ruleText;
LogUtils.d(TAG, "setRuleText: 规则文本更新 | 旧值=" + oldValue + " | 新值=" + this.ruleText);
}
public boolean isAllowConnection() {
return isAllowConnection;
}
public void setIsAllowConnection(boolean isAllowConnection) {
LogUtils.d(TAG, "setIsAllowConnection: 允许连接状态更新为" + isAllowConnection);
this.isAllowConnection = isAllowConnection;
}
public boolean isEnable() {
return isEnable;
}
public void setIsEnable(boolean isEnable) {
LogUtils.d(TAG, "setIsEnable: 规则启用状态更新为" + isEnable);
this.isEnable = isEnable;
}
public boolean isSimpleView() {
return isSimpleView;
}
public void setIsSimpleView(boolean isSimpleView) {
LogUtils.d(TAG, "setIsSimpleView: 视图模式更新 | 简洁模式=" + isSimpleView);
this.isSimpleView = isSimpleView;
}
// ====================== 重写 BaseBean 抽象方法区 ======================
@Override
public String getName() {
String className = PhoneConnectRuleBean.class.getName();
LogUtils.v(TAG, "getName: 获取当前类名=" + className);
return className;
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
LogUtils.d(TAG, "writeThisToJsonWriter: 开始JSON序列化规则数据");
super.writeThisToJsonWriter(jsonWriter);
// 序列化核心字段
jsonWriter.name(JSON_KEY_RULE_TEXT).value(getRuleText());
jsonWriter.name(JSON_KEY_ALLOW_CONNECTION).value(isAllowConnection());
jsonWriter.name(JSON_KEY_IS_ENABLE).value(isEnable());
LogUtils.d(TAG, "writeThisToJsonWriter: JSON序列化完成");
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
// 优先让父类处理通用字段
if (super.initObjectsFromJsonReader(jsonReader, name)) {
LogUtils.v(TAG, "initObjectsFromJsonReader: 父类已处理字段=" + name);
return true;
}
// 处理当前类专属字段
if (JSON_KEY_RULE_TEXT.equals(name)) {
setRuleText(jsonReader.nextString());
} else if (JSON_KEY_ALLOW_CONNECTION.equals(name)) {
setIsAllowConnection(jsonReader.nextBoolean());
} else if (JSON_KEY_IS_ENABLE.equals(name)) {
setIsEnable(jsonReader.nextBoolean());
} else {
LogUtils.w(TAG, "initObjectsFromJsonReader: 未识别的JSON字段=" + name);
return false;
}
LogUtils.v(TAG, "initObjectsFromJsonReader: 成功解析字段=" + name);
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
LogUtils.d(TAG, "readBeanFromJsonReader: 开始从JSON解析规则数据");
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String fieldName = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, fieldName)) {
LogUtils.w(TAG, "readBeanFromJsonReader: 跳过未识别字段=" + fieldName);
jsonReader.skipValue();
}
}
jsonReader.endObject();
LogUtils.d(TAG, "readBeanFromJsonReader: JSON解析完成 | 解析后规则=" + getRuleText());
return this;
}
}

View File

@@ -1,114 +0,0 @@
package cc.winboll.studio.contacts.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/21 09:52:10
* @Describe 电话黑名单规则
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
public class PhoneConnectRuleModel extends BaseBean {
public static final String TAG = "PhoneConnectRuleModel";
String ruleText;
boolean isAllowConnection;
boolean isEnable;
boolean isSimpleView;
public PhoneConnectRuleModel() {
this.ruleText = "";
this.isAllowConnection = false;
this.isEnable = false;
this.isSimpleView = true;
}
public PhoneConnectRuleModel(String ruleText, boolean isAllowConnection, boolean isEnable) {
this.ruleText = ruleText;
this.isAllowConnection = isAllowConnection;
this.isEnable = isEnable;
this.isSimpleView = true;
}
public void setIsSimpleView(boolean isSimpleView) {
this.isSimpleView = isSimpleView;
}
public boolean isSimpleView() {
return isSimpleView;
}
public void setRuleText(String ruleText) {
this.ruleText = ruleText;
}
public String getRuleText() {
return ruleText;
}
public void setIsAllowConnection(boolean isAllowConnection) {
this.isAllowConnection = isAllowConnection;
}
public boolean isAllowConnection() {
return isAllowConnection;
}
public void setIsEnable(boolean isEnable) {
this.isEnable = isEnable;
}
public boolean isEnable() {
return isEnable;
}
@Override
public String getName() {
return PhoneConnectRuleModel.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("ruleText").value(getRuleText());
jsonWriter.name("isAllowConnection").value(isAllowConnection());
jsonWriter.name("isEnable").value(isEnable());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("ruleText")) {
setRuleText(jsonReader.nextString());
} else if (name.equals("isAllowConnection")) {
setIsAllowConnection(jsonReader.nextBoolean());
} else if (name.equals("isEnable")) {
setIsEnable(jsonReader.nextBoolean());
} 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;
}
}

View File

@@ -1,74 +1,107 @@
package cc.winboll.studio.contacts.model; package cc.winboll.studio.contacts.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/24 18:47:11
* @Describe 手机铃声设置参数类
*/
import cc.winboll.studio.libappbase.BaseBean;
import android.util.JsonWriter;
import java.io.IOException;
import android.media.AudioManager;
import android.util.JsonReader; import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import cc.winboll.studio.libappbase.LogUtils;
import java.io.IOException;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/24 18:47:11
* @Describe 手机铃声设置参数类支持JSON序列化与反序列化
*/
public class RingTongBean extends BaseBean { public class RingTongBean extends BaseBean {
// ====================== 常量定义区 ======================
public static final String TAG = "AudioRingTongBean"; public static final String TAG = "AudioRingTongBean";
private static final String JSON_KEY_STREAM_VOLUME = "streamVolume";
// 铃声音量范围常量参考AudioManager标准
private static final int VOLUME_MIN = 0;
private static final int VOLUME_MAX = 100;
// 铃声音量 // ====================== 成员变量区 ======================
int streamVolume; private int streamVolume;
// ====================== 构造函数区 ======================
/**
* 默认构造,铃声音量初始化为最大值
*/
public RingTongBean() { public RingTongBean() {
this.streamVolume = 100; this.streamVolume = VOLUME_MAX;
LogUtils.d(TAG, "RingTongBean: 默认构造初始化 | 铃声音量=" + this.streamVolume);
} }
/**
* 带参构造,初始化指定铃声音量
*/
public RingTongBean(int streamVolume) { public RingTongBean(int streamVolume) {
this.streamVolume = streamVolume; // 音量值范围校验,避免非法值
} this.streamVolume = Math.max(VOLUME_MIN, Math.min(VOLUME_MAX, streamVolume));
LogUtils.d(TAG, "RingTongBean: 带参构造初始化 | 原始音量=" + streamVolume + " | 校正后=" + this.streamVolume);
public void setStreamVolume(int streamVolume) {
this.streamVolume = streamVolume;
} }
// ====================== Getter & Setter 方法区 ======================
public int getStreamVolume() { public int getStreamVolume() {
return streamVolume; return streamVolume;
} }
public void setStreamVolume(int streamVolume) {
int oldVolume = this.streamVolume;
// 音量值范围校验
this.streamVolume = Math.max(VOLUME_MIN, Math.min(VOLUME_MAX, streamVolume));
LogUtils.d(TAG, "setStreamVolume: 铃声音量更新 | 旧值=" + oldVolume + " | 新值=" + this.streamVolume);
}
// ====================== 重写 BaseBean 抽象方法区 ======================
@Override @Override
public String getName() { public String getName() {
return RingTongBean.class.getName(); String className = RingTongBean.class.getName();
LogUtils.v(TAG, "getName: 获取当前类名=" + className);
return className;
} }
@Override @Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException { public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
LogUtils.d(TAG, "writeThisToJsonWriter: 开始JSON序列化铃声音量参数");
super.writeThisToJsonWriter(jsonWriter); super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("streamVolume").value(getStreamVolume()); jsonWriter.name(JSON_KEY_STREAM_VOLUME).value(getStreamVolume());
LogUtils.d(TAG, "writeThisToJsonWriter: JSON序列化完成 | 音量值=" + getStreamVolume());
} }
@Override @Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException { public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else { // 优先调用父类处理通用字段
if (name.equals("streamVolume")) { if (super.initObjectsFromJsonReader(jsonReader, name)) {
setStreamVolume(jsonReader.nextInt()); LogUtils.v(TAG, "initObjectsFromJsonReader: 父类已处理字段=" + name);
} else { return true;
return false;
}
} }
return true;
// 处理当前类专属字段
if (JSON_KEY_STREAM_VOLUME.equals(name)) {
setStreamVolume(jsonReader.nextInt());
LogUtils.v(TAG, "initObjectsFromJsonReader: 解析字段[" + name + "]值=" + this.streamVolume);
return true;
}
LogUtils.w(TAG, "initObjectsFromJsonReader: 未识别的JSON字段=" + name);
return false;
} }
@Override @Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException { public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
LogUtils.d(TAG, "readBeanFromJsonReader: 开始从JSON解析铃声音量参数");
jsonReader.beginObject(); jsonReader.beginObject();
while (jsonReader.hasNext()) { while (jsonReader.hasNext()) {
String name = jsonReader.nextName(); String fieldName = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, name)) { if (!initObjectsFromJsonReader(jsonReader, fieldName)) {
LogUtils.w(TAG, "readBeanFromJsonReader: 跳过未识别字段=" + fieldName);
jsonReader.skipValue(); jsonReader.skipValue();
} }
} }
// 结束 JSON 对象
jsonReader.endObject(); jsonReader.endObject();
LogUtils.d(TAG, "readBeanFromJsonReader: JSON解析完成 | 最终音量值=" + this.streamVolume);
return this; return this;
} }
} }

View File

@@ -0,0 +1,216 @@
package cc.winboll.studio.contacts.model;
import android.util.JsonReader;
import android.util.JsonWriter;
import java.io.IOException;
import cc.winboll.studio.contacts.utils.IntUtils;
import cc.winboll.studio.libappbase.BaseBean;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/03/02 19:51:40
* @Describe 应用设置数据模型支持云盾防御配置与JSON序列化
*/
public class SettingsBean extends BaseBean {
// ====================== 常量定义区 ======================
public static final String TAG = "SettingsModel";
// 数值范围常量
public static final int MAX_INTRANGE = 666666;
public static final int MIN_INTRANGE = 1;
// JSON字段名常量消除硬编码
private static final String JSON_KEY_DUN_TOTAL = "dunTotalCount";
private static final String JSON_KEY_DUN_CURRENT = "dunCurrentCount";
private static final String JSON_KEY_DUN_RESUME_SECOND = "dunResumeSecondCount";
private static final String JSON_KEY_DUN_RESUME_COUNT = "dunResumeCount";
private static final String JSON_KEY_DUN_ENABLE = "isEnableDun";
private static final String JSON_KEY_URL = "szBoBullToon_URL";
// ====================== 成员变量区 ======================
// 云盾防御层数量
private int dunTotalCount;
// 当前云盾防御层
private int dunCurrentCount;
// 防御层恢复时间间隔(秒钟)
private int dunResumeSecondCount;
// 每次恢复防御层数
private int dunResumeCount;
// 是否启用云盾
private boolean isEnableDun;
// BoBullToon 应用模块数据请求地址
private String szBoBullToon_URL;
// ====================== 构造函数区 ======================
/**
* 默认构造,初始化默认配置
*/
public SettingsBean() {
this.dunTotalCount = 6;
this.dunCurrentCount = 6;
this.dunResumeSecondCount = 60;
this.dunResumeCount = 1;
this.isEnableDun = false;
this.szBoBullToon_URL = "";
LogUtils.d(TAG, "SettingsModel: 默认构造初始化完成 | 云盾默认配置加载完毕");
}
/**
* 带参构造,初始化自定义配置并校验数值范围
*/
public SettingsBean(int dunTotalCount, int dunCurrentCount, int dunResumeSecondCount,
int dunResumeCount, boolean isEnableDun, String szBoBullToon_URL) {
this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
this.isEnableDun = isEnableDun;
this.szBoBullToon_URL = szBoBullToon_URL == null ? "" : szBoBullToon_URL;
LogUtils.d(TAG, "SettingsModel: 带参构造初始化完成 | 总层数=" + this.dunTotalCount
+ " | 当前层数=" + this.dunCurrentCount + " | 恢复间隔=" + this.dunResumeSecondCount
+ " | 恢复层数=" + this.dunResumeCount + " | 云盾启用=" + this.isEnableDun);
}
// ====================== 私有工具方法区 ======================
/**
* 数值范围校验,确保参数在 MIN~MAX 区间内
*/
private int getSettingsModelRangeInt(int origin) {
int result = IntUtils.getIntInRange(origin, MIN_INTRANGE, MAX_INTRANGE);
if (result != origin) {
LogUtils.w(TAG, "getSettingsModelRangeInt: 数值校正 | 原始值=" + origin + " | 校正后=" + result);
}
return result;
}
// ====================== Getter & Setter 方法区 ======================
public int getDunTotalCount() {
return dunTotalCount;
}
public void setDunTotalCount(int dunTotalCount) {
int oldValue = this.dunTotalCount;
this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
LogUtils.d(TAG, "setDunTotalCount: 总防御层数更新 | 旧值=" + oldValue + " | 新值=" + this.dunTotalCount);
}
public int getDunCurrentCount() {
return dunCurrentCount;
}
public void setDunCurrentCount(int dunCurrentCount) {
int oldValue = this.dunCurrentCount;
this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
LogUtils.d(TAG, "setDunCurrentCount: 当前防御层数更新 | 旧值=" + oldValue + " | 新值=" + this.dunCurrentCount);
}
public int getDunResumeSecondCount() {
return dunResumeSecondCount;
}
public void setDunResumeSecondCount(int dunResumeSecondCount) {
int oldValue = this.dunResumeSecondCount;
this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
LogUtils.d(TAG, "setDunResumeSecondCount: 恢复间隔更新 | 旧值=" + oldValue + " | 新值=" + this.dunResumeSecondCount);
}
public int getDunResumeCount() {
return dunResumeCount;
}
public void setDunResumeCount(int dunResumeCount) {
int oldValue = this.dunResumeCount;
this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
LogUtils.d(TAG, "setDunResumeCount: 恢复层数更新 | 旧值=" + oldValue + " | 新值=" + this.dunResumeCount);
}
public boolean isEnableDun() {
return isEnableDun;
}
public void setIsEnableDun(boolean isEnableDun) {
LogUtils.d(TAG, "setIsEnableDun: 云盾启用状态更新为" + isEnableDun);
this.isEnableDun = isEnableDun;
}
public String getBoBullToon_URL() {
return szBoBullToon_URL;
}
public void setBoBullToon_URL(String boBullToon_URL) {
String oldValue = this.szBoBullToon_URL;
this.szBoBullToon_URL = boBullToon_URL == null ? "" : boBullToon_URL;
LogUtils.d(TAG, "setBoBullToon_URL: 请求地址更新 | 旧值=" + oldValue + " | 新值=" + this.szBoBullToon_URL);
}
// ====================== 重写 BaseBean 抽象方法区 ======================
@Override
public String getName() {
String className = SettingsBean.class.getName();
LogUtils.v(TAG, "getName: 获取当前类名=" + className);
return className;
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
LogUtils.d(TAG, "writeThisToJsonWriter: 开始JSON序列化设置数据");
super.writeThisToJsonWriter(jsonWriter);
// 写入所有配置字段
jsonWriter.name(JSON_KEY_DUN_TOTAL).value(getDunTotalCount());
jsonWriter.name(JSON_KEY_DUN_CURRENT).value(getDunCurrentCount());
jsonWriter.name(JSON_KEY_DUN_RESUME_SECOND).value(getDunResumeSecondCount());
jsonWriter.name(JSON_KEY_DUN_RESUME_COUNT).value(getDunResumeCount());
jsonWriter.name(JSON_KEY_DUN_ENABLE).value(isEnableDun());
jsonWriter.name(JSON_KEY_URL).value(getBoBullToon_URL());
LogUtils.d(TAG, "writeThisToJsonWriter: JSON序列化完成");
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
// 优先调用父类处理通用字段
if (super.initObjectsFromJsonReader(jsonReader, name)) {
LogUtils.v(TAG, "initObjectsFromJsonReader: 父类已处理字段=" + name);
return true;
}
// 处理当前类专属配置字段
if (JSON_KEY_DUN_TOTAL.equals(name)) {
setDunTotalCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (JSON_KEY_DUN_CURRENT.equals(name)) {
setDunCurrentCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (JSON_KEY_DUN_RESUME_SECOND.equals(name)) {
setDunResumeSecondCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (JSON_KEY_DUN_RESUME_COUNT.equals(name)) {
setDunResumeCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (JSON_KEY_DUN_ENABLE.equals(name)) {
setIsEnableDun(jsonReader.nextBoolean());
} else if (JSON_KEY_URL.equals(name)) {
setBoBullToon_URL(jsonReader.nextString());
} else {
LogUtils.w(TAG, "initObjectsFromJsonReader: 未识别的JSON字段=" + name);
return false;
}
LogUtils.v(TAG, "initObjectsFromJsonReader: 成功解析字段=" + name);
return true;
}
@Override
public BaseBean readBeanFromJsonReader(JsonReader jsonReader) throws IOException {
LogUtils.d(TAG, "readBeanFromJsonReader: 开始从JSON解析设置数据");
jsonReader.beginObject();
while (jsonReader.hasNext()) {
String fieldName = jsonReader.nextName();
if (!initObjectsFromJsonReader(jsonReader, fieldName)) {
LogUtils.w(TAG, "readBeanFromJsonReader: 跳过未识别字段=" + fieldName);
jsonReader.skipValue();
}
}
jsonReader.endObject();
LogUtils.d(TAG, "readBeanFromJsonReader: JSON解析完成 | 云盾配置加载完毕");
return this;
}
}

View File

@@ -1,157 +0,0 @@
package cc.winboll.studio.contacts.model;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/03/02 19:51:40
* @Describe SettingsModel
*/
import android.util.JsonReader;
import android.util.JsonWriter;
import cc.winboll.studio.libappbase.BaseBean;
import java.io.IOException;
import cc.winboll.studio.contacts.utils.IntUtils;
public class SettingsModel extends BaseBean {
public static final String TAG = "SettingsModel";
public static final int MAX_INTRANGE = 666666;
public static final int MIN_INTRANGE = 1;
// 云盾防御层数量
int dunTotalCount;
// 当前云盾防御层
int dunCurrentCount;
// 防御层恢复时间间隔(秒钟)
int dunResumeSecondCount;
// 每次恢复防御层数
int dunResumeCount;
// 是否启用云盾
boolean isEnableDun;
// BoBullToon 应用模块数据请求地址
String szBoBullToon_URL;
public SettingsModel() {
this.dunTotalCount = 6;
this.dunCurrentCount = 6;
this.dunResumeSecondCount = 60;
this.dunResumeCount = 1;
this.isEnableDun = false;
this.szBoBullToon_URL = "";
}
public SettingsModel(int dunTotalCount, int dunCurrentCount, int dunResumeSecondCount, int dunResumeCount, boolean isEnableDun, String szBoBullToon_URL) {
this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
this.isEnableDun = isEnableDun;
this.szBoBullToon_URL = szBoBullToon_URL;
}
public void setBoBullToon_URL(String boBullToon_URL) {
this.szBoBullToon_URL = boBullToon_URL;
}
public String getBoBullToon_URL() {
return szBoBullToon_URL;
}
public void setDunTotalCount(int dunTotalCount) {
this.dunTotalCount = getSettingsModelRangeInt(dunTotalCount);
}
public int getDunTotalCount() {
return dunTotalCount;
}
public void setDunCurrentCount(int dunCurrentCount) {
this.dunCurrentCount = getSettingsModelRangeInt(dunCurrentCount);
}
public int getDunCurrentCount() {
return dunCurrentCount;
}
public void setDunResumeSecondCount(int dunResumeSecondCount) {
this.dunResumeSecondCount = getSettingsModelRangeInt(dunResumeSecondCount);
}
public int getDunResumeSecondCount() {
return dunResumeSecondCount;
}
public void setDunResumeCount(int dunResumeCount) {
this.dunResumeCount = getSettingsModelRangeInt(dunResumeCount);
}
public int getDunResumeCount() {
return dunResumeCount;
}
public void setIsEnableDun(boolean isEnableDun) {
this.isEnableDun = isEnableDun;
}
public boolean isEnableDun() {
return isEnableDun;
}
int getSettingsModelRangeInt(int origin) {
return IntUtils.getIntInRange(origin, MIN_INTRANGE, MAX_INTRANGE);
}
@Override
public String getName() {
return SettingsModel.class.getName();
}
@Override
public void writeThisToJsonWriter(JsonWriter jsonWriter) throws IOException {
super.writeThisToJsonWriter(jsonWriter);
jsonWriter.name("dunTotalCount").value(getDunTotalCount());
jsonWriter.name("dunCurrentCount").value(getDunCurrentCount());
jsonWriter.name("dunResumeSecondCount").value(getDunResumeSecondCount());
jsonWriter.name("dunResumeCount").value(getDunResumeCount());
jsonWriter.name("isEnableDun").value(isEnableDun());
jsonWriter.name("szBoBullToon_URL").value(getBoBullToon_URL());
}
@Override
public boolean initObjectsFromJsonReader(JsonReader jsonReader, String name) throws IOException {
if (super.initObjectsFromJsonReader(jsonReader, name)) { return true; } else {
if (name.equals("dunTotalCount")) {
setDunTotalCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("dunCurrentCount")) {
setDunCurrentCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("dunResumeSecondCount")) {
setDunResumeSecondCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("dunResumeCount")) {
setDunResumeCount(getSettingsModelRangeInt(jsonReader.nextInt()));
} else if (name.equals("isEnableDun")) {
setIsEnableDun(jsonReader.nextBoolean());
} else if (name.equals("szBoBullToon_URL")) {
setBoBullToon_URL(jsonReader.nextString());
} 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;
}
}

View File

@@ -1,45 +1,72 @@
package cc.winboll.studio.contacts.receivers; package cc.winboll.studio.contacts.receivers;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2025/02/13 06:58:04
* @Describe 主要广播接收器
*/
import android.content.BroadcastReceiver; import android.content.BroadcastReceiver;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.IntentFilter; import android.content.IntentFilter;
import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.ToastUtils; import cc.winboll.studio.libappbase.ToastUtils;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/13 06:58:04
* @Describe 主要广播接收器,监听系统开机广播并启动主服务
*/
public class MainReceiver extends BroadcastReceiver { public class MainReceiver extends BroadcastReceiver {
// ====================== 常量定义区 ======================
public static final String TAG = "MainReceiver"; public static final String TAG = "MainReceiver";
public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED"; public static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
WeakReference<MainService> mwrService;
// ====================== 成员变量区 ======================
private WeakReference<MainService> mwrService;
// ====================== 构造函数区 ======================
public MainReceiver(MainService service) { public MainReceiver(MainService service) {
mwrService = new WeakReference<MainService>(service); this.mwrService = new WeakReference<MainService>(service);
LogUtils.d(TAG, "MainReceiver: 初始化广播接收器关联MainService");
} }
// ====================== 重写 BroadcastReceiver 方法区 ======================
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
String szAction = intent.getAction(); if (intent == null || intent.getAction() == null) {
if (szAction.equals(ACTION_BOOT_COMPLETED)) { LogUtils.w(TAG, "onReceive: 接收到空Intent或空Action");
return;
}
String action = intent.getAction();
LogUtils.d(TAG, "onReceive: 接收到广播Action=" + action);
if (ACTION_BOOT_COMPLETED.equals(action)) {
LogUtils.d(TAG, "onReceive: 监听到开机广播启动MainService");
ToastUtils.show("ACTION_BOOT_COMPLETED"); ToastUtils.show("ACTION_BOOT_COMPLETED");
MainService.startMainService(context); MainService.startMainService(context);
} else { } else {
ToastUtils.show(szAction); LogUtils.i(TAG, "onReceive: 接收到未知广播Action=" + action);
ToastUtils.show(action);
} }
} }
// 注册 Receiver // ====================== 公共方法区 ======================
// /**
* 注册广播接收器,监听指定系统广播
*/
public void registerAction(Context context) { public void registerAction(Context context) {
IntentFilter filter=new IntentFilter(); if (context == null) {
LogUtils.e(TAG, "registerAction: 上下文对象为null注册失败");
return;
}
IntentFilter filter = new IntentFilter();
filter.addAction(ACTION_BOOT_COMPLETED); filter.addAction(ACTION_BOOT_COMPLETED);
//filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION); // 原注释的铃声模式变更广播可按需启用
// filter.addAction(AudioManager.RINGER_MODE_CHANGED_ACTION);
context.registerReceiver(this, filter); context.registerReceiver(this, filter);
LogUtils.d(TAG, "registerAction: 广播接收器注册成功监听Action=" + ACTION_BOOT_COMPLETED);
} }
} }

View File

@@ -9,7 +9,7 @@ import android.content.Context;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.widget.TextView; import android.widget.TextView;
import cc.winboll.studio.contacts.model.SettingsModel; import cc.winboll.studio.contacts.model.SettingsBean;
import cc.winboll.studio.contacts.dun.Rules; import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
@@ -45,7 +45,7 @@ public class DuInfoTextView extends TextView {
void updateInfo() { void updateInfo() {
LogUtils.d(TAG, "updateInfo()"); LogUtils.d(TAG, "updateInfo()");
SettingsModel settingsModel = Rules.getInstance(mContext).getSettingsModel(); SettingsBean settingsModel = Rules.getInstance(mContext).getSettingsModel();
String info = String.format("(云盾防御值【%d/%d】)", settingsModel.getDunCurrentCount(), settingsModel.getDunTotalCount()); String info = String.format("(云盾防御值【%d/%d】)", settingsModel.getDunCurrentCount(), settingsModel.getDunTotalCount());
setText(info); setText(info);
} }