完成电话连接规则的编辑和保存
This commit is contained in:
		| @@ -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' | ||||
|  | ||||
|   | ||||
| @@ -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 | ||||
|   | ||||
| @@ -183,6 +183,8 @@ | ||||
|  | ||||
|         </provider> | ||||
|  | ||||
|         <activity android:name="cc.winboll.studio.contacts.activities.UnitTestActivity"/> | ||||
|  | ||||
|     </application> | ||||
|  | ||||
| </manifest> | ||||
| </manifest> | ||||
| @@ -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); | ||||
|     } | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -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<PhoneConnectRuleModel> 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("允许显示悬浮框") | ||||
|   | ||||
| @@ -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))); | ||||
|  | ||||
|     } | ||||
| } | ||||
| @@ -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; | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -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<RecyclerView.ViewHolder> { | ||||
|  | ||||
|     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<PhoneConnectRuleModel> ruleList; | ||||
|  | ||||
|     public PhoneConnectRuleAdapter(Context context, List<PhoneConnectRuleModel> 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); | ||||
|         } | ||||
|     } | ||||
| } | ||||
|  | ||||
| @@ -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; | ||||
|     } | ||||
|      | ||||
|      | ||||
| 
 | ||||
| 
 | ||||
| } | ||||
| @@ -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<String> listPhoneBoBullToon = new ArrayList<String>(); | ||||
|  | ||||
|     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; | ||||
|     } | ||||
| } | ||||
| @@ -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<PhoneBlackRuleBean> _PhoneBlacRuleBeanList; | ||||
|     ArrayList<PhoneConnectRuleModel> _PhoneConnectRuleModelList; | ||||
|     static volatile Rules _Rules; | ||||
|     Context mContext; | ||||
|  | ||||
|     Rules(Context context) { | ||||
|         mContext = context; | ||||
|         _PhoneBlacRuleBeanList = new ArrayList<PhoneBlackRuleBean>(); | ||||
|         PhoneBlackRuleBean.loadBeanList(mContext, _PhoneBlacRuleBeanList, PhoneBlackRuleBean.class); | ||||
|  | ||||
|         _PhoneConnectRuleModelList = new ArrayList<PhoneConnectRuleModel>(); | ||||
|         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<PhoneBlackRuleBean> getPhoneBlacRuleBeanList() { | ||||
|         return _PhoneBlacRuleBeanList; | ||||
|     public ArrayList<PhoneConnectRuleModel> getPhoneBlacRuleBeanList() { | ||||
|         return _PhoneConnectRuleModelList; | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -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)); | ||||
|   | ||||
| @@ -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() { | ||||
|   | ||||
| @@ -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(); | ||||
|     } | ||||
| } | ||||
							
								
								
									
										9
									
								
								contacts/src/main/res/drawable/recycler_view_border.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										9
									
								
								contacts/src/main/res/drawable/recycler_view_border.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,9 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <shape xmlns:android="http://schemas.android.com/apk/res/android" | ||||
|     android:shape="rectangle"> | ||||
|     <stroke | ||||
|         android:width="1dp" | ||||
|         android:color="#000000" /> <!-- 设置边框宽度和颜色,这里是黑色 1dp 边框 --> | ||||
|     <solid android:color="#ffffff" /> <!-- 设置背景颜色,这里是白色 --> | ||||
| </shape> | ||||
|  | ||||
| @@ -90,6 +90,86 @@ | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="拨不通电话记录查询:"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="vertical" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:gravity="right" | ||||
| 			android:layout_margin="10dp"> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="下载 BoBullToon" | ||||
| 				android:onClick="onDownloadBoBullToon"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="horizontal" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:gravity="right|center_vertical" | ||||
| 			android:layout_margin="10dp"> | ||||
|  | ||||
| 			<TextView | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="查询电话:"/> | ||||
|  | ||||
| 			<EditText | ||||
| 				android:layout_width="0dp" | ||||
| 				android:inputType="phone" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:ems="10" | ||||
| 				android:layout_weight="1.0" | ||||
| 				android:id="@+id/activitysettingsEditText1"/> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="查询记录" | ||||
| 				android:onClick="onSearchBoBullToonPhone"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Phone Connect Rule :"/> | ||||
|  | ||||
| 		<androidx.recyclerview.widget.RecyclerView | ||||
| 			android:id="@+id/recycler_view" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="0dp" | ||||
| 			android:layout_weight="1.0" | ||||
| 			android:background="@drawable/recycler_view_border" | ||||
| 			android:layout_margin="5dp"/> | ||||
|  | ||||
| 		<TextView | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="单元测试:"/> | ||||
|  | ||||
| 		<LinearLayout | ||||
| 			android:orientation="horizontal" | ||||
| 			android:layout_width="match_parent" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:gravity="right"> | ||||
|  | ||||
| 			<Button | ||||
| 				android:layout_width="wrap_content" | ||||
| 				android:layout_height="wrap_content" | ||||
| 				android:text="Unit Test" | ||||
| 				android:onClick="onUnitTest"/> | ||||
|  | ||||
| 		</LinearLayout> | ||||
|  | ||||
| 	</LinearLayout> | ||||
|  | ||||
| </LinearLayout> | ||||
|   | ||||
							
								
								
									
										28
									
								
								contacts/src/main/res/layout/activity_unittest.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										28
									
								
								contacts/src/main/res/layout/activity_unittest.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,28 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="match_parent"> | ||||
|  | ||||
| 	<HorizontalScrollView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content"> | ||||
|  | ||||
| 		<Button | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="Test Main" | ||||
| 			android:onClick="onTestMain"/> | ||||
|  | ||||
| 	</HorizontalScrollView> | ||||
|  | ||||
| 	<cc.winboll.studio.libappbase.LogView | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="0dp" | ||||
| 		android:layout_weight="1.0" | ||||
| 		android:id="@+id/logview"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
							
								
								
									
										44
									
								
								contacts/src/main/res/layout/view_phone_connect_rule.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								contacts/src/main/res/layout/view_phone_connect_rule.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="vertical" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="wrap_content" | ||||
| 	android:padding="16dp"> | ||||
|  | ||||
| 	<EditText | ||||
| 		android:id="@+id/edit_text" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:hint="请输入规则文本"/> | ||||
|  | ||||
| 	<LinearLayout | ||||
| 		android:orientation="horizontal" | ||||
| 		android:layout_width="match_parent" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:gravity="right|center_vertical"> | ||||
|  | ||||
| 		<CheckBox | ||||
| 			android:id="@+id/checkbox_allow" | ||||
| 			android:layout_width="wrap_content" | ||||
| 			android:layout_height="wrap_content" | ||||
| 			android:text="允许连接"/> | ||||
|  | ||||
|         <CheckBox | ||||
|             android:id="@+id/checkbox_enable" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="启用"/> | ||||
|  | ||||
|         <Button | ||||
|             android:id="@+id/button_confirm" | ||||
|             android:layout_width="wrap_content" | ||||
|             android:layout_height="wrap_content" | ||||
|             android:text="确定"/> | ||||
|          | ||||
| 	</LinearLayout> | ||||
|  | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
| @@ -0,0 +1,25 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <LinearLayout | ||||
| 	xmlns:android="http://schemas.android.com/apk/res/android" | ||||
| 	xmlns:app="http://schemas.android.com/apk/res-auto" | ||||
| 	android:orientation="horizontal" | ||||
| 	android:layout_width="match_parent" | ||||
| 	android:layout_height="wrap_content" | ||||
| 	android:padding="16dp" | ||||
| 	android:gravity="center_vertical"> | ||||
|  | ||||
| 	<TextView | ||||
| 		android:id="@+id/text_view" | ||||
| 		android:layout_width="0dp" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:layout_weight="1" | ||||
| 		android:textSize="16sp"/> | ||||
|  | ||||
| 	<Button | ||||
| 		android:id="@+id/button" | ||||
| 		android:layout_width="wrap_content" | ||||
| 		android:layout_height="wrap_content" | ||||
| 		android:text="编辑"/> | ||||
|  | ||||
| </LinearLayout> | ||||
|  | ||||
		Reference in New Issue
	
	Block a user
	 ZhanGSKen
					ZhanGSKen