diff --git a/contacts/build.gradle b/contacts/build.gradle index 55ef8d2..7efb0a9 100644 --- a/contacts/build.gradle +++ b/contacts/build.gradle @@ -51,6 +51,8 @@ android { dependencies { implementation fileTree(dir: 'libs', include: ['*.jar']) + implementation 'com.squareup.okhttp3:okhttp:4.4.1' + // https://mvnrepository.com/artifact/com.github.open-android/pinyin4j implementation 'com.github.open-android:pinyin4j:2.5.0' diff --git a/contacts/build.properties b/contacts/build.properties index 9cd1345..3feb87e 100644 --- a/contacts/build.properties +++ b/contacts/build.properties @@ -1,8 +1,8 @@ #Created by .winboll/winboll_app_build.gradle -#Wed Feb 26 19:10:28 HKT 2025 +#Sun Mar 02 10:24:46 GMT 2025 stageCount=5 libraryProject= baseVersion=1.0 publishVersion=1.0.4 -buildCount=0 +buildCount=40 baseBetaVersion=1.0.5 diff --git a/contacts/src/main/AndroidManifest.xml b/contacts/src/main/AndroidManifest.xml index 3b27a29..f92009a 100644 --- a/contacts/src/main/AndroidManifest.xml +++ b/contacts/src/main/AndroidManifest.xml @@ -183,6 +183,8 @@ + + - + \ No newline at end of file diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/App.java b/contacts/src/main/java/cc/winboll/studio/contacts/App.java index 6f482d5..9c2044a 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/App.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/App.java @@ -8,6 +8,7 @@ package cc.winboll.studio.contacts; import cc.winboll.studio.libappbase.GlobalApplication; import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libapputils.app.WinBollActivityManager; +import com.hjq.toast.ToastUtils; public class App extends GlobalApplication { @@ -23,6 +24,8 @@ public class App extends GlobalApplication { WinBollActivityManager.getInstance(this).setWinBollUI_TYPE(WinBollActivityManager.WinBollUI_TYPE.Aplication); LogUtils.d(TAG, "onCreate"); + + ToastUtils.init(this); } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java index 4525b54..f60dde8 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/activities/SettingsActivity.java @@ -4,7 +4,6 @@ package cc.winboll.studio.contacts.activities; * @Author ZhanGSKen@AliYun.Com * @Date 2025/02/21 05:37:42 */ -import android.app.NotificationManager; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; @@ -15,21 +14,29 @@ import android.os.Bundle; import android.provider.Settings; import android.view.View; import android.view.WindowManager; +import android.widget.EditText; +import android.widget.SeekBar; import android.widget.Switch; +import android.widget.TextView; import android.widget.Toast; import androidx.appcompat.app.AlertDialog; import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.widget.Toolbar; +import androidx.recyclerview.widget.LinearLayoutManager; +import androidx.recyclerview.widget.RecyclerView; import cc.winboll.studio.contacts.R; +import cc.winboll.studio.contacts.adapters.PhoneConnectRuleAdapter; +import cc.winboll.studio.contacts.beans.MainServiceBean; +import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel; import cc.winboll.studio.contacts.beans.RingTongBean; +import cc.winboll.studio.contacts.bobulltoon.TomCat; +import cc.winboll.studio.contacts.dun.Rules; +import cc.winboll.studio.contacts.services.MainService; import cc.winboll.studio.libappbase.IWinBollActivity; import cc.winboll.studio.libappbase.bean.APPInfo; import com.hjq.toast.ToastUtils; import java.lang.reflect.Field; -import android.widget.SeekBar; -import android.widget.TextView; -import cc.winboll.studio.contacts.beans.MainServiceBean; -import cc.winboll.studio.contacts.services.MainService; +import java.util.List; public class SettingsActivity extends AppCompatActivity implements IWinBollActivity { @@ -43,7 +50,10 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv int mnStreamVolume; Switch mswMainService; - + private RecyclerView recyclerView; + private PhoneConnectRuleAdapter adapter; + private List ruleList; + @Override public APPInfo getAppInfo() { return null; @@ -146,12 +156,26 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv // 当停止拖动SeekBar时的操作 } }); + + + recyclerView = findViewById(R.id.recycler_view); + recyclerView.setLayoutManager(new LinearLayoutManager(this)); + + ruleList = Rules.getInstance(this).getPhoneBlacRuleBeanList(); + + adapter = new PhoneConnectRuleAdapter(this, ruleList); + recyclerView.setAdapter(adapter); } void updateStreamVolumeTextView() { mtvVolume.setText(String.format("%d/%d", mnStreamVolume, mnStreamMaxVolume)); } + public void onUnitTest(View view) { + Intent intent = new Intent(this, UnitTestActivity.class); + startActivity(intent); + } + public void onDefaultPhone(View view) { Intent intent = new Intent(Settings.ACTION_MANAGE_DEFAULT_APPS_SETTINGS); startActivity(intent); @@ -167,6 +191,34 @@ public class SettingsActivity extends AppCompatActivity implements IWinBollActiv } } + public void onDownloadBoBullToon(View view) { + final TomCat tomCat = TomCat.getInstance(this); + new Thread(new Runnable() { + @Override + public void run() { + if (tomCat.downloadBoBullToon()) { + ToastUtils.show("BoBullToon downlaod OK!"); + } + } + }).start(); + } + + public void onSearchBoBullToonPhone(View view) { + TomCat tomCat = TomCat.getInstance(this); + EditText etPhone = findViewById(R.id.activitysettingsEditText1); + String phone = etPhone.getText().toString().trim(); + if (tomCat.loadPhoneBoBullToon()) { + if (tomCat.isPhoneBoBullToon(phone)) { + ToastUtils.show("It is a BoBullToon Phone!"); + } else { + ToastUtils.show("Not in BoBullToon."); + } + } else { + ToastUtils.show("没有下载 BoBullToon。"); + } + + } + private void askForDrawOverlay() { AlertDialog alertDialog = new AlertDialog.Builder(this) .setTitle("允许显示悬浮框") diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/activities/UnitTestActivity.java b/contacts/src/main/java/cc/winboll/studio/contacts/activities/UnitTestActivity.java new file mode 100644 index 0000000..7088462 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/activities/UnitTestActivity.java @@ -0,0 +1,81 @@ +package cc.winboll.studio.contacts.activities; + +import android.app.Activity; +import android.os.Bundle; +import android.view.View; +import cc.winboll.studio.contacts.R; +import cc.winboll.studio.contacts.dun.Rules; +import cc.winboll.studio.libappbase.LogUtils; +import cc.winboll.studio.libappbase.LogView; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/03/02 16:07:04 + */ +public class UnitTestActivity extends Activity { + + public static final String TAG = "UnitTestActivity"; + + LogView logView; + + @Override + protected void onCreate(Bundle savedInstanceState) { + super.onCreate(savedInstanceState); + setContentView(R.layout.activity_unittest); + logView = findViewById(R.id.logview); + logView.start(); + } + + public void onTestMain(View view) { + Rules rules = Rules.getInstance(this); + + // 如果没有规则就添加测试规则 + if (rules.getPhoneBlacRuleBeanList().size() == 0) { + // 手机号码允许 + // 中国手机号码正则表达式,以1开头,第二位可以是3、4、5、6、7、8、9,后面跟9位数字 + String regex = "^1[3-9]\\d{9}$"; + rules.add(regex, true, true); + + // 指定区号号码允许 + regex = "^0660\\d+$"; + rules.add(regex, true, true); + + // 指定区号号码允许 + regex = "^020\\d+$"; + rules.add(regex, true, true); + + // 添加默认拒接规则 + regex = ".*"; + rules.add(regex, false, true); + + // 保存规则到文件 + rules.saveRules(); + } + + // 开始测试数据 + String phone = "16769764848"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "16856582777"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "17519703124"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "0205658955"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "0108965253"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "+8616769764848"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "4005816769764848"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + phone = "95566"; + LogUtils.d(TAG, String.format("Test phone : %s\n%s", phone, rules.isAllowed(phone))); + + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter2.java b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter2.java deleted file mode 100644 index 104f516..0000000 --- a/contacts/src/main/java/cc/winboll/studio/contacts/adapters/MyPagerAdapter2.java +++ /dev/null @@ -1,42 +0,0 @@ -package cc.winboll.studio.contacts.adapters; - -/** - * @Author ZhanGSKen@AliYun.Com - * @Date 2025/02/20 13:33:04 - * @Describe MyPagerAdapter - */ -import androidx.annotation.NonNull; -import androidx.fragment.app.Fragment; -import androidx.fragment.app.FragmentManager; -import androidx.fragment.app.FragmentPagerAdapter; -import cc.winboll.studio.contacts.fragments.CallLogFragment; -import cc.winboll.studio.contacts.fragments.ContactsFragment; -import cc.winboll.studio.contacts.fragments.LogFragment; - -public class MyPagerAdapter2 extends FragmentPagerAdapter { - public static final String TAG = "MyPagerAdapter"; - - private static final int PAGE_COUNT = 3; - - public MyPagerAdapter2(@NonNull FragmentManager fm) { - super(fm, BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT); - } - - @NonNull - @Override - public Fragment getItem(int position) { - if(position == 1) { - return ContactsFragment.newInstance(position); - } else if(position == 2) { - return LogFragment.newInstance(position); - } else { - return CallLogFragment.newInstance(position); - } - } - - @Override - public int getCount() { - return PAGE_COUNT; - } -} - diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/adapters/PhoneConnectRuleAdapter.java b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/PhoneConnectRuleAdapter.java new file mode 100644 index 0000000..93d1165 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/adapters/PhoneConnectRuleAdapter.java @@ -0,0 +1,123 @@ +package cc.winboll.studio.contacts.adapters; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/03/02 17:27:41 + * @Describe PhoneConnectRuleAdapter + */ +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.TextView; +import android.widget.Toast; +import androidx.annotation.NonNull; +import androidx.recyclerview.widget.RecyclerView; +import cc.winboll.studio.contacts.R; +import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel; +import cc.winboll.studio.contacts.dun.Rules; +import java.util.List; + +public class PhoneConnectRuleAdapter extends RecyclerView.Adapter { + + public static final String TAG = "PhoneConnectRuleAdapter"; + + private static final int VIEW_TYPE_SIMPLE = 0; + private static final int VIEW_TYPE_EDIT = 1; + + private Context context; + private List ruleList; + + public PhoneConnectRuleAdapter(Context context, List ruleList) { + this.context = context; + this.ruleList = ruleList; + } + + @NonNull + @Override + public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + LayoutInflater inflater = LayoutInflater.from(context); + if (viewType == VIEW_TYPE_SIMPLE) { + View view = inflater.inflate(R.layout.view_phone_connect_rule_simple, parent, false); + return new SimpleViewHolder(view); + } else { + View view = inflater.inflate(R.layout.view_phone_connect_rule, parent, false); + return new EditViewHolder(view); + } + } + + @Override + public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, final int position) { + final PhoneConnectRuleModel model = ruleList.get(position); + if (holder instanceof SimpleViewHolder) { + SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder; + simpleViewHolder.textView.setText(model.getRuleText()); + simpleViewHolder.button.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + model.setIsSimpleView(false); + notifyItemChanged(position); + } + }); + } else if (holder instanceof EditViewHolder) { + final EditViewHolder editViewHolder = (EditViewHolder) holder; + editViewHolder.editText.setText(model.getRuleText()); + editViewHolder.checkBoxAllow.setChecked(model.isAllowConnection()); + editViewHolder.checkBoxEnable.setChecked(model.isEnable()); + editViewHolder.buttonConfirm.setOnClickListener(new View.OnClickListener() { + @Override + public void onClick(View v) { + model.setRuleText(editViewHolder.editText.getText().toString()); + model.setIsAllowConnection(editViewHolder.checkBoxAllow.isChecked()); + model.setIsEnable(editViewHolder.checkBoxEnable.isChecked()); + model.setIsSimpleView(true); + Rules.getInstance(context).saveRules(); + notifyItemChanged(position); + Toast.makeText(context, "保存成功", Toast.LENGTH_SHORT).show(); + } + }); + } + } + + @Override + public int getItemCount() { + return ruleList.size(); + } + + @Override + public int getItemViewType(int position) { + PhoneConnectRuleModel model = ruleList.get(position); + // 这里可以根据模型的状态来决定视图类型,简单起见,假设点击按钮后进入编辑视图 + return model.isSimpleView() ? VIEW_TYPE_SIMPLE : VIEW_TYPE_EDIT; + } + + static class SimpleViewHolder extends RecyclerView.ViewHolder { + TextView textView; + Button button; + + public SimpleViewHolder(@NonNull View itemView) { + super(itemView); + textView = itemView.findViewById(R.id.text_view); + button = itemView.findViewById(R.id.button); + } + } + + static class EditViewHolder extends RecyclerView.ViewHolder { + EditText editText; + CheckBox checkBoxAllow; + CheckBox checkBoxEnable; + Button buttonConfirm; + + public EditViewHolder(@NonNull View itemView) { + super(itemView); + editText = itemView.findViewById(R.id.edit_text); + checkBoxAllow = itemView.findViewById(R.id.checkbox_allow); + checkBoxEnable = itemView.findViewById(R.id.checkbox_enable); + buttonConfirm = itemView.findViewById(R.id.button_confirm); + } + } +} + diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/beans/PhoneBlackRuleBean.java b/contacts/src/main/java/cc/winboll/studio/contacts/beans/PhoneConnectRuleModel.java similarity index 64% rename from contacts/src/main/java/cc/winboll/studio/contacts/beans/PhoneBlackRuleBean.java rename to contacts/src/main/java/cc/winboll/studio/contacts/beans/PhoneConnectRuleModel.java index 69550cc..3975902 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/beans/PhoneBlackRuleBean.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/beans/PhoneConnectRuleModel.java @@ -10,21 +10,35 @@ import android.util.JsonWriter; import cc.winboll.studio.libappbase.BaseBean; import java.io.IOException; -public class PhoneBlackRuleBean extends BaseBean { - - public static final String TAG = "PhoneBlackRuleBean"; - +public class PhoneConnectRuleModel extends BaseBean { + + public static final String TAG = "PhoneConnectRuleModel"; + String ruleText; + boolean isAllowConnection; boolean isEnable; - - public PhoneBlackRuleBean() { + boolean isSimpleView; + + public PhoneConnectRuleModel() { this.ruleText = ""; + this.isAllowConnection = false; this.isEnable = false; + this.isSimpleView = true; } - public PhoneBlackRuleBean(String ruleText, boolean isEnable) { + 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) { @@ -35,6 +49,14 @@ public class PhoneBlackRuleBean extends BaseBean { return ruleText; } + public void setIsAllowConnection(boolean isAllowConnection) { + this.isAllowConnection = isAllowConnection; + } + + public boolean isAllowConnection() { + return isAllowConnection; + } + public void setIsEnable(boolean isEnable) { this.isEnable = isEnable; } @@ -43,17 +65,19 @@ public class PhoneBlackRuleBean extends BaseBean { return isEnable; } + + @Override public String getName() { - return PhoneBlackRuleBean.class.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 @@ -61,6 +85,8 @@ public class PhoneBlackRuleBean extends BaseBean { 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 { @@ -83,6 +109,6 @@ public class PhoneBlackRuleBean extends BaseBean { jsonReader.endObject(); return this; } - - + + } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/bobulltoon/TomCat.java b/contacts/src/main/java/cc/winboll/studio/contacts/bobulltoon/TomCat.java new file mode 100644 index 0000000..81affee --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/bobulltoon/TomCat.java @@ -0,0 +1,142 @@ +package cc.winboll.studio.contacts.bobulltoon; + +/** + * @Author ZhanGSKen@AliYun.Com + * @Date 2025/03/02 13:47:48 + * @Describe 汤姆猫管家 :使用 BoBullToon 项目,对通讯地址进行筛选判断的好朋友。 + */ +import android.content.Context; +import cc.winboll.studio.libappbase.LogUtils; +import com.hjq.toast.ToastUtils; +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.List; +import java.util.zip.ZipEntry; +import java.util.zip.ZipInputStream; +import okhttp3.OkHttpClient; +import okhttp3.Request; +import okhttp3.Response; + +public class TomCat { + + public static final String TAG = "TomCat"; + + List listPhoneBoBullToon = new ArrayList(); + + static volatile TomCat _TomCat; + Context mContext; + TomCat(Context context) { + mContext = context; + } + + public static synchronized TomCat getInstance(Context context) { + if (_TomCat == null) { + _TomCat = new TomCat(context); + } + return _TomCat; + } + + void downloadAndExtractZip(String zipUrl, String destinationFolder) throws IOException { + OkHttpClient client = new OkHttpClient(); + Request request = new Request.Builder() + .url(zipUrl) + .build(); + + try (Response response = client.newCall(request).execute()) { + if (!response.isSuccessful()) { + throw new IOException("Unexpected code " + response); + } + + // 下载 ZIP 文件到临时位置 + File tempZipFile = File.createTempFile("temp", ".zip"); + try (InputStream inputStream = response.body().byteStream(); + FileOutputStream outputStream = new FileOutputStream(tempZipFile)) { + byte[] buffer = new byte[1024]; + int length; + while ((length = inputStream.read(buffer)) > 0) { + outputStream.write(buffer, 0, length); + } + } + + // 解压 ZIP 文件到指定文件夹 + try (ZipInputStream zipInputStream = new ZipInputStream(Files.newInputStream(tempZipFile.toPath()))) { + ZipEntry zipEntry; + while ((zipEntry = zipInputStream.getNextEntry()) != null) { + Path targetFilePath = Paths.get(destinationFolder, zipEntry.getName()); + if (zipEntry.isDirectory()) { + Files.createDirectories(targetFilePath); + } else { + Files.createDirectories(targetFilePath.getParent()); + try (FileOutputStream fos = new FileOutputStream(targetFilePath.toFile())) { + byte[] buffer = new byte[1024]; + int len; + while ((len = zipInputStream.read(buffer)) > 0) { + fos.write(buffer, 0, len); + } + } + } + zipInputStream.closeEntry(); + } + } + + // 删除临时 ZIP 文件 + tempZipFile.delete(); + } + } + + public boolean downloadBoBullToon() { + String zipUrl = "https://gitea.winboll.cc//Studio/BoBullToon/archive/main.zip"; // 替换为实际的 ZIP 文件 URL + String destinationFolder = getWorkingFolder().getPath(); // 替换为实际的目标文件夹路径 + try { + downloadAndExtractZip(zipUrl, destinationFolder); + LogUtils.d(TAG, "ZIP 文件下载并解压成功。"); + return true; + } catch (IOException e) { + LogUtils.d(TAG, e, Thread.currentThread().getStackTrace()); + } + return false; + } + + File getWorkingFolder() { + return mContext.getExternalFilesDir(TAG); + } + + public boolean loadPhoneBoBullToon() { + listPhoneBoBullToon.clear(); + File fBoBullToon = new File(getWorkingFolder(), "bobulltoon"); + if (fBoBullToon.exists()) { + LogUtils.d(TAG, String.format("getWorkingFolder() %s", getWorkingFolder())); + for (File userFolder : fBoBullToon.listFiles()) { + if (userFolder.isDirectory()) { + for (File recordFile : userFolder.listFiles()) { + listPhoneBoBullToon.add(recordFile.getName()); + } + } + } + + for (int i = 0; i < listPhoneBoBullToon.size(); i++) { + LogUtils.d(TAG, String.format("listPhoneBoBullToon add : %s", listPhoneBoBullToon.get(i))); + } + return true; + } else { + LogUtils.d(TAG, "fBoBullToon not exists。"); + } + return false; + } + + public boolean isPhoneBoBullToon(String phone) { + for (int i = 0; i < listPhoneBoBullToon.size(); i++) { + LogUtils.d(TAG, String.format("isPhoneBoBullToon(...) get(i) phone : %s", listPhoneBoBullToon.get(i))); + if (listPhoneBoBullToon.get(i).equals(phone)) { + return true; + } + } + return false; + } +} diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/dun/Rules.java b/contacts/src/main/java/cc/winboll/studio/contacts/dun/Rules.java index a4f9a1e..cc729db 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/dun/Rules.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/dun/Rules.java @@ -5,25 +5,28 @@ package cc.winboll.studio.contacts.dun; * @Date 2025/02/21 06:15:10 * @Describe 云盾防御规则 */ -import cc.winboll.studio.contacts.beans.PhoneBlackRuleBean; +import android.content.Context; +import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel; +import cc.winboll.studio.contacts.services.MainService; +import cc.winboll.studio.contacts.utils.RegexPPiUtils; +import cc.winboll.studio.libappbase.LogUtils; import java.util.ArrayList; import java.util.regex.Pattern; -import android.content.Context; public class Rules { public static final String TAG = "Rules"; - ArrayList _PhoneBlacRuleBeanList; + ArrayList _PhoneConnectRuleModelList; static volatile Rules _Rules; Context mContext; Rules(Context context) { mContext = context; - _PhoneBlacRuleBeanList = new ArrayList(); - PhoneBlackRuleBean.loadBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class); - + _PhoneConnectRuleModelList = new ArrayList(); + loadRules(); } + public static synchronized Rules getInstance(Context context) { if (_Rules == null) { _Rules = new Rules(context); @@ -31,46 +34,47 @@ public class Rules { return _Rules; } + public void loadRules() { + _PhoneConnectRuleModelList.clear(); + PhoneConnectRuleModel.loadBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class); + } + + public void saveRules() { + PhoneConnectRuleModel.saveBeanList(mContext, _PhoneConnectRuleModelList, PhoneConnectRuleModel.class); + } + public boolean isAllowed(String phoneNumber) { - // 黑名单拒接 - for (int i = 0; i < _PhoneBlacRuleBeanList.size(); i++) { - if (_PhoneBlacRuleBeanList.get(i).isEnable()) { - String regex = _PhoneBlacRuleBeanList.get(i).getRuleText(); + // 正则运算预防针 + if (!RegexPPiUtils.isPPiOK(phoneNumber)) { + LogUtils.d(TAG, "RegexPPiUtils.isPPiOK return false."); + return false; + } + // 检验拨不通号码群 + if (MainService.isPhoneInBoBullToon(phoneNumber)) { + LogUtils.d(TAG, String.format("PhoneNumber %s\n Is In BoBullToon", phoneNumber)); + return false; + } + + // 正则匹配规则名单校验 + for (int i = 0; i < _PhoneConnectRuleModelList.size(); i++) { + if (_PhoneConnectRuleModelList.get(i).isEnable()) { + String regex = _PhoneConnectRuleModelList.get(i).getRuleText(); if (Pattern.matches(regex, phoneNumber)) { - return false; + LogUtils.d(TAG, String.format("phoneNumber :%s \nisAllowConnection %s By Rule : %s", phoneNumber, _PhoneConnectRuleModelList.get(i).isAllowConnection(), _PhoneConnectRuleModelList.get(i))); + return _PhoneConnectRuleModelList.get(i).isAllowConnection(); } } } - // 手机号码允许 - // 中国手机号码正则表达式,以1开头,第二位可以是3、4、5、6、7、8、9,后面跟9位数字 - String regex = "^1[3-9]\\d{9}$"; - if (Pattern.matches(regex, phoneNumber)) { - return true; - } - - // 指定区号号码允许 - regex = "^0660\\d+$"; - if (Pattern.matches(regex, phoneNumber)) { - return true; - } - - // 指定区号号码允许 - regex = "^020\\d+$"; - if (Pattern.matches(regex, phoneNumber)) { - return true; - } - - // 其他拒接 - return false; + // 其他默认接收 + return true; } - public void add(String phoneRuleBlack, boolean isEnable) { - _PhoneBlacRuleBeanList.add(new PhoneBlackRuleBean(phoneRuleBlack, isEnable)); - PhoneBlackRuleBean.saveBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class); + public void add(String szPhoneConnectRule, boolean isAllowConnection, boolean isEnable) { + _PhoneConnectRuleModelList.add(new PhoneConnectRuleModel(szPhoneConnectRule, isAllowConnection, isEnable)); } - public ArrayList getPhoneBlacRuleBeanList() { - return _PhoneBlacRuleBeanList; + public ArrayList getPhoneBlacRuleBeanList() { + return _PhoneConnectRuleModelList; } } diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java index 0206a1d..356201e 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/fragments/ContactsFragment.java @@ -104,6 +104,7 @@ public class ContactsFragment extends Fragment { public void onClick(View p1) { String phoneNumber = searchEditText.getText().toString().replaceAll("\\s", ""); + //phoneNumber = "+8616769764848"; ToastUtils.show(phoneNumber); Intent intent = new Intent(Intent.ACTION_CALL); intent.setData(android.net.Uri.parse("tel:" + phoneNumber)); diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java index d2c39b3..5c1eb9d 100644 --- a/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java +++ b/contacts/src/main/java/cc/winboll/studio/contacts/services/MainService.java @@ -31,6 +31,7 @@ import cc.winboll.studio.libappbase.SOS; import cc.winboll.studio.libappbase.bean.APPSOSBean; import java.util.Timer; import java.util.TimerTask; +import cc.winboll.studio.contacts.bobulltoon.TomCat; public class MainService extends Service { @@ -50,6 +51,7 @@ public class MainService extends Service { boolean isBound = false; MainReceiver mMainReceiver; Timer mStreamVolumeCheckTimer; + static volatile TomCat _TomCat; @Override public IBinder onBind(Intent intent) { @@ -128,6 +130,12 @@ public class MainService extends Service { // 召唤 WinBoll APP 绑定本服务 SOS.bindToAPPService(this, new APPSOSBean(getPackageName(), MainService.class.getName())); + // 初始化服务运行参数 + _TomCat = TomCat.getInstance(this); + if (!_TomCat.loadPhoneBoBullToon()) { + LogUtils.d(TAG, "没有下载 BoBullToon 数据。BoBullToon 参数无法加载。"); + } + if (mMainReceiver == null) { // 注册广播接收器 mMainReceiver = new MainReceiver(this); @@ -135,8 +143,6 @@ public class MainService extends Service { } Rules.getInstance(this); - //Rules.getInstance(this).add("18888888888", true); - //Rules.getInstance(this).add("16769764848", true); startPhoneCallListener(); @@ -146,6 +152,14 @@ public class MainService extends Service { } } + public static boolean isPhoneInBoBullToon(String phone) { + if (_TomCat != null) { + return _TomCat.isPhoneBoBullToon(phone); + } + return false; + } + + // 唤醒和绑定守护进程 // void wakeupAndBindAssistant() { diff --git a/contacts/src/main/java/cc/winboll/studio/contacts/utils/RegexPPiUtils.java b/contacts/src/main/java/cc/winboll/studio/contacts/utils/RegexPPiUtils.java new file mode 100644 index 0000000..c00a9f2 --- /dev/null +++ b/contacts/src/main/java/cc/winboll/studio/contacts/utils/RegexPPiUtils.java @@ -0,0 +1,32 @@ +package cc.winboll.studio.contacts.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/contacts/src/main/res/drawable/recycler_view_border.xml b/contacts/src/main/res/drawable/recycler_view_border.xml new file mode 100644 index 0000000..d538cab --- /dev/null +++ b/contacts/src/main/res/drawable/recycler_view_border.xml @@ -0,0 +1,9 @@ + + + + + + diff --git a/contacts/src/main/res/layout/activity_settings.xml b/contacts/src/main/res/layout/activity_settings.xml index c68fcc2..c5a7085 100644 --- a/contacts/src/main/res/layout/activity_settings.xml +++ b/contacts/src/main/res/layout/activity_settings.xml @@ -90,6 +90,86 @@ + + + + +