feat: 新增云盾查询Fragment替换日志Fragment

- 新增 DunQueryFragment 和 DunQueryView 控件
- 主界面第三个标签页从应用日志改为云盾查询
- 移除 LogFragment 及相关布局文件
- 移除 SettingsActivity 中的 DunQueryView 控件
This commit is contained in:
MiMo
2026-07-19 05:07:03 +08:00
parent 1d0322252e
commit d5d230c1bb
8 changed files with 229 additions and 133 deletions
+2 -2
View File
@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle
#Sun Jul 19 04:13:23 CST 2026
#Sun Jul 19 05:01:46 CST 2026
stageCount=11
libraryProject=
baseVersion=15.20
publishVersion=15.20.10
buildCount=12
buildCount=17
baseBetaVersion=15.20.11
@@ -31,14 +31,13 @@ import cc.winboll.studio.contacts.activities.WinBollActivity;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.contacts.fragments.CallLogFragment;
import cc.winboll.studio.contacts.fragments.ContactsFragment;
import cc.winboll.studio.contacts.fragments.LogFragment;
import cc.winboll.studio.contacts.fragments.DunQueryFragment;
import cc.winboll.studio.contacts.model.MainServiceBean;
import cc.winboll.studio.contacts.services.MainService;
import cc.winboll.studio.contacts.utils.PermissionUtils;
import cc.winboll.studio.contacts.views.DunTemperatureView;
import cc.winboll.studio.libaes.interfaces.IWinBoLLActivity;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
import com.google.android.material.tabs.TabLayout;
import java.util.ArrayList;
import java.util.List;
@@ -75,7 +74,6 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
private final String[] REQUIRED_PERMISSIONS = PermissionUtils.BASE_PERMISSIONS;
// ====================== 4. UI控件成员区 ======================
private LogView mLogView;
private Toolbar mToolbar;
private CheckBox cbMainService;
private TabLayout tabLayout;
@@ -320,10 +318,10 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
// 添加Fragment实例(仅创建对象,不初始化业务逻辑)
fragmentList.add(CallLogFragment.newInstance(0));
fragmentList.add(ContactsFragment.newInstance(1));
fragmentList.add(LogFragment.newInstance(2));
fragmentList.add(DunQueryFragment.newInstance(2));
tabTitleList.add("通话记录");
tabTitleList.add("联系人");
tabTitleList.add("应用日志");
tabTitleList.add("云盾查询");
// 初始化懒加载标记数组(默认均未初始化)
int fragmentCount = fragmentList.size();
@@ -367,8 +365,8 @@ public final class MainActivity extends WinBollActivity implements IWinBoLLActiv
((CallLogFragment) targetFragment).initData();
} else if (targetFragment instanceof ContactsFragment) {
((ContactsFragment) targetFragment).initData();
} else if (targetFragment instanceof LogFragment) {
((LogFragment) targetFragment).initData();
} else if (targetFragment instanceof DunQueryFragment) {
((DunQueryFragment) targetFragment).initData();
}
// 标记为已初始化
isFragmentInit[position] = true;
@@ -0,0 +1,76 @@
package cc.winboll.studio.contacts.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2026/07/19
* @Describe 云盾查询区域视图(支持懒加载,仅切换到当前页才加载)
*/
public class DunQueryFragment extends Fragment {
public static final String TAG = "DunQueryFragment";
private static final String ARG_PAGE = "ARG_PAGE";
private int mPage;
private boolean isViewInitialized = false;
private boolean isLazyInitCompleted = false;
public static DunQueryFragment newInstance(int page) {
LogUtils.d(TAG, "newInstance: 创建云盾查询Fragment实例,页码=" + page);
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
DunQueryFragment fragment = new DunQueryFragment();
fragment.setArguments(args);
return fragment;
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtils.d(TAG, "onCreate: Fragment创建开始");
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
LogUtils.d(TAG, "onCreate: 读取页面参数,mPage=" + mPage);
}
LogUtils.d(TAG, "onCreate: Fragment创建完成");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreateView: 加载Fragment布局");
View view = inflater.inflate(R.layout.fragment_dun_query, container, false);
isViewInitialized = true;
LogUtils.d(TAG, "onCreateView: Fragment布局加载完成");
return view;
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy: Fragment开始销毁");
isViewInitialized = false;
isLazyInitCompleted = false;
LogUtils.d(TAG, "onDestroy: Fragment销毁完成");
}
public void initData() {
if (isLazyInitCompleted || !isViewInitialized || getContext() == null) {
LogUtils.d(TAG, "initData: 懒加载已完成/视图未就绪,跳过");
return;
}
LogUtils.d(TAG, "initData: 开始懒加载初始化");
isLazyInitCompleted = true;
LogUtils.d(TAG, "initData: 懒加载初始化完成");
}
}
@@ -1,118 +0,0 @@
package cc.winboll.studio.contacts.fragments;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.fragment.app.Fragment;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libappbase.LogView;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
* @Date 2025/02/20 12:58:15
* @Describe 应用日志区域视图(支持懒加载,仅切换到当前页才启动日志)
*/
public class LogFragment extends Fragment {
// ====================== 常量定义区 ======================
public static final String TAG = "LogFragment";
private static final String ARG_PAGE = "ARG_PAGE";
// ====================== 页面参数区 ======================
private int mPage;
// ====================== UI控件区 ======================
private LogView mLogView;
// ====================== 懒加载标记区 ======================
private boolean isViewInitialized = false; // 视图控件绑定完成标记
private boolean isLazyInitCompleted = false; // 懒加载总流程完成标记
private boolean isLogViewStarted = false; // LogView启动状态标记
// ====================== 实例化函数区 ======================
public static LogFragment newInstance(int page) {
LogUtils.d(TAG, "newInstance: 创建日志Fragment实例,页码=" + page);
Bundle args = new Bundle();
args.putInt(ARG_PAGE, page);
LogFragment fragment = new LogFragment();
fragment.setArguments(args);
return fragment;
}
// ====================== 生命周期函数区 ======================
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LogUtils.d(TAG, "onCreate: Fragment创建开始");
if (getArguments() != null) {
mPage = getArguments().getInt(ARG_PAGE);
LogUtils.d(TAG, "onCreate: 读取页面参数,mPage=" + mPage);
}
LogUtils.d(TAG, "onCreate: Fragment创建完成");
}
@Nullable
@Override
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
@Nullable Bundle savedInstanceState) {
LogUtils.d(TAG, "onCreateView: 加载Fragment布局");
View view = inflater.inflate(R.layout.fragment_log, container, false);
// Java7 适配:添加强制类型转换,仅初始化LogView控件(不启动)
mLogView = (LogView) view.findViewById(R.id.logview);
LogUtils.d(TAG, "onCreateView: LogView控件初始化完成(未启动)");
// 标记视图控件绑定完成
isViewInitialized = true;
return view;
}
@Override
public void onResume() {
super.onResume();
LogUtils.d(TAG, "onResume: Fragment进入前台");
// 已完成懒加载 → 仅重启LogView(切回页面时恢复日志显示)
if (isLazyInitCompleted && mLogView != null && !isLogViewStarted) {
mLogView.start();
isLogViewStarted = true;
LogUtils.d(TAG, "onResume: LogView已重启,恢复日志显示");
}
// 未完成懒加载 → 不操作(等待MainActivity调用initData触发)
}
@Override
public void onDestroy() {
super.onDestroy();
LogUtils.d(TAG, "onDestroy: Fragment开始销毁");
if (mLogView != null) {
// 若LogView有停止方法,必须调用(避免后台持续占用资源,根据实际API调整)
// mLogView.stop(); // 关键:释放LogView资源,防止内存泄漏
LogUtils.d(TAG, "onDestroy: LogView资源已释放");
}
// 重置所有标记,避免重建时状态异常
mLogView = null;
isViewInitialized = false;
isLazyInitCompleted = false;
isLogViewStarted = false;
LogUtils.d(TAG, "onDestroy: Fragment销毁完成");
}
// ====================== 懒加载核心方法(供MainActivity调用) ======================
public void initData() {
// 双重防护:避免重复初始化(标记+视图就绪+控件非空)
if (isLazyInitCompleted || !isViewInitialized || mLogView == null || getContext() == null) {
LogUtils.d(TAG, "initData: 懒加载已完成/视图未就绪,跳过");
return;
}
LogUtils.d(TAG, "initData: 开始懒加载初始化,启动LogView");
// 核心:启动LogView(原onCreateView中的start逻辑迁移至此)
mLogView.start();
isLogViewStarted = true;
// 标记懒加载总流程完成(仅执行一次)
isLazyInitCompleted = true;
LogUtils.d(TAG, "initData: 懒加载初始化完成,LogView正常启动");
}
}
@@ -0,0 +1,103 @@
package cc.winboll.studio.contacts.views;
import android.content.Context;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.LayoutInflater;
import android.view.View;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.TextView;
import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.dun.Rules;
import cc.winboll.studio.libappbase.LogUtils;
/**
* @Author ZhanGSKen<zhangsken@qq.com>
* @Date 2026/07/19
* @Describe 云盾拦截查询视图控件:实时查询电话号码的云盾拦截状态
*/
public class DunQueryView extends LinearLayout {
private static final String TAG = "DunQueryView";
private Context mContext;
private EditText mEtPhone;
private TextView mTvResult;
public DunQueryView(Context context) {
super(context);
initView(context);
}
public DunQueryView(Context context, AttributeSet attrs) {
super(context, attrs);
initView(context);
}
public DunQueryView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
initView(context);
}
private void initView(Context context) {
LogUtils.d(TAG, "initView: 初始化云盾查询视图");
this.mContext = context;
setOrientation(VERTICAL);
LayoutInflater.from(context).inflate(R.layout.view_dun_query, this, true);
initViews();
initListeners();
LogUtils.d(TAG, "initView: 云盾查询视图初始化完成");
}
private void initViews() {
mEtPhone = (EditText) findViewById(R.id.et_dun_query_phone);
mTvResult = (TextView) findViewById(R.id.tv_dun_query_result);
}
private void initListeners() {
mEtPhone.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
queryDunStatus(s.toString().trim());
}
});
}
private void queryDunStatus(String phoneNumber) {
if (phoneNumber.isEmpty()) {
mTvResult.setText("请输入电话号码");
mTvResult.setTextColor(mContext.getResources().getColor(R.color.gray_500));
LogUtils.d(TAG, "queryDunStatus: 输入为空,显示默认提示");
return;
}
Rules rules = Rules.getInstance(mContext);
if (rules == null) {
mTvResult.setText("云盾规则未初始化");
mTvResult.setTextColor(mContext.getResources().getColor(R.color.gray_500));
LogUtils.e(TAG, "queryDunStatus: Rules实例获取失败");
return;
}
boolean isAllowed = rules.isAllowed(phoneNumber, true);
if (isAllowed) {
mTvResult.setText("允许接通");
mTvResult.setTextColor(mContext.getResources().getColor(R.color.green_normal));
LogUtils.d(TAG, "queryDunStatus: 号码" + phoneNumber + " 允许接通");
} else {
mTvResult.setText("拦截");
mTvResult.setTextColor(mContext.getResources().getColor(R.color.red_normal));
LogUtils.d(TAG, "queryDunStatus: 号码" + phoneNumber + " 被拦截");
}
}
}
@@ -59,7 +59,6 @@
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
@@ -1,12 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="match_parent">
<cc.winboll.studio.libappbase.LogView
android:layout_height="match_parent"
<cc.winboll.studio.contacts.views.DunQueryView
android:layout_width="match_parent"
android:id="@+id/logview"/>
android:layout_height="wrap_content"/>
</LinearLayout>
@@ -0,0 +1,38 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:layout_marginBottom="8dp"
android:padding="12dp"
android:background="@drawable/recycler_view_border">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="云盾拦截查询"
android:textSize="16sp"
android:textStyle="bold"
android:textColor="@color/red_normal"
android:layout_marginBottom="8dp"/>
<EditText
android:id="@+id/et_dun_query_phone"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="输入电话号码查询拦截状态"
android:inputType="phone"
android:textSize="14sp"
android:layout_marginBottom="8dp"/>
<TextView
android:id="@+id/tv_dun_query_result"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="请输入电话号码"
android:textSize="14sp"
android:textColor="@color/gray_500"/>
</LinearLayout>