Compare commits

..

41 Commits

Author SHA1 Message Date
ZhanGSKen
48623a2805 更新说明书 2025-09-01 23:23:18 +08:00
ZhanGSKen
2739627aff <timestamp>APK 15.1.3 release Publish. 2025-07-28 11:36:51 +08:00
ZhanGSKen
58e0be9cf4 添加开机启动功能。 2025-07-28 11:35:30 +08:00
ZhanGSKen
8bb80ef575 <timestamp>APK 15.1.2 release Publish. 2025-07-24 15:25:52 +08:00
ZhanGSKen
c1e6e32809 在主界面添加时间戳截取按钮 2025-07-24 15:22:18 +08:00
ZhanGSKen
23920a7ff1 Merge remote-tracking branch 'origin/aes' into appbase 2025-07-24 08:25:21 +08:00
ZhanGSKen
17c373c490 <appbase>APK 15.9.1 release Publish. 2025-07-17 11:39:14 +08:00
ZhanGSKen
5f7c94b349 <appbase>APK 15.9.0 release Publish. 2025-07-17 11:24:17 +08:00
ZhanGSKen
c2b739d345 提升版本 2025-07-17 11:23:30 +08:00
ZhanGSKen
67a05cd457 <appbase>Start New Stage Version. 2025-07-17 11:21:04 +08:00
ZhanGSKen
554ab758bf 编译测试 2025-07-17 11:17:58 +08:00
ZhanGSKen
20e118cd34 Merge remote-tracking branch 'origin/contacts' into appbase 2025-07-17 11:15:51 +08:00
ZhanGSKen
f370ae8ffb <contacts>APK 15.3.11 release Publish. 2025-07-17 09:57:24 +08:00
ZhanGSKen
c92c874ea1 区分防御层数量级差异,区分量级给出相应提示。 2025-07-17 09:54:47 +08:00
ZhanGSKen
90a6116c0a <contacts>APK 15.3.10 release Publish. 2025-07-17 04:06:42 +08:00
ZhanGSKen
45208ecbb1 添加应用效果提示 2025-07-17 04:05:01 +08:00
ZhanGSKen
c28d655fe3 <contacts>APK 15.3.9 release Publish. 2025-07-06 16:18:59 +08:00
ZhanGSKen
4b5905f74e 命名重构 2025-07-06 16:17:09 +08:00
ZhanGSKen
6bd01780ec 联系人号码添加复制功能 2025-07-06 16:14:16 +08:00
ZhanGSKen
a6699262f8 通话记录号码添加复制功能 2025-07-06 16:02:45 +08:00
ZhanGSKen
ea2d38defc <contacts>APK 15.3.8 release Publish. 2025-07-05 12:43:15 +08:00
ZhanGSKen
e430b7abe4 添加清空 BoBullToon 数据功能,更新默认 BoBullToon 数据地址。 2025-07-05 12:41:14 +08:00
ZhanGSKen
6c8b0dcfa5 <contacts>APK 15.3.7 release Publish. 2025-06-28 19:57:09 +08:00
ZhanGSKen
7de8a4f084 规则编辑列表显示优化 2025-06-28 19:54:58 +08:00
ZhanGSKen
219c6614be <contacts>APK 15.3.6 release Publish. 2025-06-28 13:20:38 +08:00
ZhanGSKen
0f5bb020b9 <contacts/>Start New Stage Version. 2025-06-28 13:17:42 +08:00
ZhanGSKen
7794ff80ec 更新应用描述 2025-06-28 13:16:18 +08:00
ZhanGSKen
7463ad3352 更新应用介绍页 2025-06-28 13:08:24 +08:00
ZhanGSKen
753032efed <libaes>Library Release 15.9.2 2025-06-28 12:59:55 +08:00
ZhanGSKen
2b4c43c9af <aes>APK 15.9.2 release Publish. 2025-06-28 12:59:30 +08:00
ZhanGSKen
711c98d556 应用介绍页更新 2025-06-28 12:42:52 +08:00
ZhanGSKen
202205588a 更新按钮文字描述 2025-06-28 12:21:55 +08:00
ZhanGSKen
42c4978b44 添加应用使用方法提示 2025-06-28 12:11:26 +08:00
ZhanGSKen
1a2b7b862d Merge remote-tracking branch 'origin/appbase' into contacts 2025-06-28 12:04:27 +08:00
ZhanGSKen
eb253b374f 更新说明书 2025-06-28 01:03:45 +08:00
ZhanGSKen
ac1c008035 <contacts>APK 15.3.5 release Publish. 2025-06-14 18:43:41 +08:00
ZhanGSKen
b124487cb1 Merge remote-tracking branch 'origin/appbase' into contacts 2025-06-14 17:59:39 +08:00
ZhanGSKen
9621d35f79 <contacts>APK 15.3.4 release Publish. 2025-06-14 17:58:55 +08:00
ZhanGSKen
17de0832a6 检验拨不通号码群排在查询通讯录联系人前面 2025-06-14 17:49:16 +08:00
ZhanGSKen
89dac91cc6 <contacts>APK 15.3.3 release Publish. 2025-06-04 00:08:54 +08:00
ZhanGSKen
3809c1bcab 编译调试 2025-06-04 00:04:20 +08:00
54 changed files with 952 additions and 1190 deletions

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jun 19 20:42:40 HKT 2025 #Sat Jun 28 12:59:51 HKT 2025
stageCount=2 stageCount=3
libraryProject=libaes libraryProject=libaes
baseVersion=15.9 baseVersion=15.9
publishVersion=15.9.1 publishVersion=15.9.2
buildCount=0 buildCount=0
baseBetaVersion=15.9.2 baseBetaVersion=15.9.3

View File

@@ -83,7 +83,7 @@ public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity
appInfo.setAppGitOwner("Studio"); appInfo.setAppGitOwner("Studio");
appInfo.setAppGitAPPBranch(szBranchName); appInfo.setAppGitAPPBranch(szBranchName);
appInfo.setAppGitAPPSubProjectFolder(szBranchName); appInfo.setAppGitAPPSubProjectFolder(szBranchName);
appInfo.setAppHomePage("https://discuz.winboll.cc/forum.php?mod=viewthread&tid=2&fromuid=1"); appInfo.setAppHomePage("https://discuz.winboll.cc/forum.php?mod=viewthread&tid=3&extra=page%3D1");
appInfo.setAppAPKName("AES"); appInfo.setAppAPKName("AES");
appInfo.setAppAPKFolderName("AES"); appInfo.setAppAPKFolderName("AES");
//appInfo.setIsAddDebugTools(false); //appInfo.setIsAddDebugTools(false);

View File

@@ -30,7 +30,7 @@ android {
// versionName 更新后需要手动设置 // versionName 更新后需要手动设置
// .winboll/winbollBuildProps.properties 文件的 stageCount=0 // .winboll/winbollBuildProps.properties 文件的 stageCount=0
// Gradle编译环境下合起来的 versionName 就是 "${versionName}.0" // Gradle编译环境下合起来的 versionName 就是 "${versionName}.0"
versionName "15.8" versionName "15.9"
if(true) { if(true) {
versionName = genVersionName("${versionName}") versionName = genVersionName("${versionName}")
} }

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Mon Jun 09 09:38:19 HKT 2025 #Thu Jul 17 11:39:14 HKT 2025
stageCount=9 stageCount=2
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.8 baseVersion=15.9
publishVersion=15.8.8 publishVersion=15.9.1
buildCount=0 buildCount=0
baseBetaVersion=15.8.9 baseBetaVersion=15.9.2

View File

@@ -3,7 +3,7 @@
https://github.com/aJIEw/PhoneCallApp.git https://github.com/aJIEw/PhoneCallApp.git
#### 介绍 #### 介绍
通讯录与拨号 这是可以根据正则表达式匹配拦截骚扰电话的手机拨号应用。
#### 软件架构 #### 软件架构
适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。 适配安卓应用 [AIDE Pro] 的 Gradle 编译结构。

View File

@@ -45,9 +45,9 @@ android {
dependencies { dependencies {
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
api 'cc.winboll.studio:libaes:15.8.0' api 'cc.winboll.studio:libaes:15.9.2'
api 'cc.winboll.studio:libapputils:15.8.1' api 'cc.winboll.studio:libapputils:15.8.4'
api 'cc.winboll.studio:libappbase:15.8.1' api 'cc.winboll.studio:libappbase:15.8.4'
// 权限请求框架https://github.com/getActivity/XXPermissions // 权限请求框架https://github.com/getActivity/XXPermissions
api 'com.github.getActivity:XXPermissions:18.63' api 'com.github.getActivity:XXPermissions:18.63'

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Tue May 20 13:02:18 HKT 2025 #Thu Jul 17 09:57:24 HKT 2025
stageCount=3 stageCount=12
libraryProject= libraryProject=
baseVersion=15.3 baseVersion=15.3
publishVersion=15.3.2 publishVersion=15.3.11
buildCount=0 buildCount=0
baseBetaVersion=15.3.3 baseBetaVersion=15.3.12

View File

@@ -79,12 +79,12 @@ public class AboutActivity extends AppCompatActivity implements IWinBoLLActivity
APPInfo appInfo = new APPInfo(); APPInfo appInfo = new APPInfo();
appInfo.setAppName("Contacts"); appInfo.setAppName("Contacts");
appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll); appInfo.setAppIcon(cc.winboll.studio.libaes.R.drawable.ic_winboll);
appInfo.setAppDescription("通讯录与拨号"); appInfo.setAppDescription("这是可以根据正则表达式匹配拦截骚扰电话的手机拨号应用。");
appInfo.setAppGitName("APP"); appInfo.setAppGitName("APPBase");
appInfo.setAppGitOwner("Studio"); appInfo.setAppGitOwner("Studio");
appInfo.setAppGitAPPBranch(szBranchName); appInfo.setAppGitAPPBranch(szBranchName);
appInfo.setAppGitAPPSubProjectFolder(szBranchName); appInfo.setAppGitAPPSubProjectFolder(szBranchName);
appInfo.setAppHomePage("https://www.winboll.cc/studio/details.php?app=Contacts"); appInfo.setAppHomePage("https://discuz.winboll.cc/forum.php?mod=viewthread&tid=4&extra=page%3D1");
appInfo.setAppAPKName("Contacts"); appInfo.setAppAPKName("Contacts");
appInfo.setAppAPKFolderName("Contacts"); appInfo.setAppAPKFolderName("Contacts");
return new AboutView(mContext, appInfo); return new AboutView(mContext, appInfo);

View File

@@ -198,6 +198,9 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
settingsModel.setDunTotalCount(Integer.parseInt(etDunTotalCount.getText().toString())); settingsModel.setDunTotalCount(Integer.parseInt(etDunTotalCount.getText().toString()));
settingsModel.setDunResumeSecondCount(Integer.parseInt(etDunResumeSecondCount.getText().toString())); settingsModel.setDunResumeSecondCount(Integer.parseInt(etDunResumeSecondCount.getText().toString()));
settingsModel.setDunResumeCount(Integer.parseInt(etDunResumeCount.getText().toString())); settingsModel.setDunResumeCount(Integer.parseInt(etDunResumeCount.getText().toString()));
// 应用效果提示
ToastUtils.show((settingsModel.getDunTotalCount() == 1)?"电话骚扰防御力几乎为0。":String.format("以下设置将在连拨%d次后接通电话。", settingsModel.getDunTotalCount()));
} }
settingsModel.setIsEnableDun(isEnableDun); settingsModel.setIsEnableDun(isEnableDun);
Rules.getInstance(this).saveDun(); Rules.getInstance(this).saveDun();
@@ -207,6 +210,7 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
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()));
} }
void updateStreamVolumeTextView() { void updateStreamVolumeTextView() {
@@ -243,6 +247,9 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
Rules.getInstance(this).resetDefaultBoBullToonURL(); Rules.getInstance(this).resetDefaultBoBullToonURL();
EditText etBoBullToonURL = findViewById(R.id.bobulltoonurl_et); EditText etBoBullToonURL = findViewById(R.id.bobulltoonurl_et);
etBoBullToonURL.setText(Rules.getInstance(this).getBoBullToonURL()); etBoBullToonURL.setText(Rules.getInstance(this).getBoBullToonURL());
final TomCat tomCat = TomCat.getInstance(this);
tomCat.cleanBoBullToon();
} }
public void onDownloadBoBullToon(View view) { public void onDownloadBoBullToon(View view) {
@@ -330,4 +337,8 @@ public class SettingsActivity extends AppCompatActivity implements IWinBoLLActiv
public void onAbout(View view) { public void onAbout(View view) {
App.getWinBoLLActivityManager().startWinBoLLActivity(this, AboutActivity.class); App.getWinBoLLActivityManager().startWinBoLLActivity(this, AboutActivity.class);
} }
public void onLogView(View view) {
App.getWinBoLLActivityManager().startLogActivity(this);
}
} }

View File

@@ -5,13 +5,18 @@ package cc.winboll.studio.contacts.adapters;
* @Date 2025/02/26 13:09:32 * @Date 2025/02/26 13:09:32
* @Describe CallLogAdapter * @Describe CallLogAdapter
*/ */
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context; import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
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;
@@ -47,6 +52,38 @@ public class CallLogAdapter extends RecyclerView.Adapter<CallLogAdapter.CallLogV
public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) { public void onBindViewHolder(@NonNull CallLogViewHolder holder, int position) {
final CallLogModel callLog = callLogList.get(position); final CallLogModel callLog = callLogList.get(position);
holder.phoneNumber.setText(callLog.getPhoneNumber() + "" + mContactUtils.getContactsName(callLog.getPhoneNumber())); holder.phoneNumber.setText(callLog.getPhoneNumber() + "" + mContactUtils.getContactsName(callLog.getPhoneNumber()));
holder.phoneNumber.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View p1) {
// 弹出复制菜单
PopupMenu menu = new PopupMenu(mContext, holder.phoneNumber);
//加载菜单资源
menu.getMenuInflater().inflate(R.menu.toolbar_calllog_phonenumber, menu.getMenu());
//设置点击事件的响应
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
int nItemId = menuItem.getItemId();
if (nItemId == R.id.item_calllog_phonenumber_copy) {
// Gets a handle to the clipboard service.
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
// Creates a new text clip to put on the clipboard
ClipData clip = ClipData.newPlainText("simple text", callLog.getPhoneNumber());
// Set the clipboard's primary clip.
clipboard.setPrimaryClip(clip);
Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
}
return true;
}
});
//一定要调用show()来显示弹出式菜单
menu.show();
return true;
}
});
holder.callStatus.setText(callLog.getCallStatus()); holder.callStatus.setText(callLog.getCallStatus());
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
holder.callDate.setText(dateFormat.format(callLog.getCallDate())); holder.callDate.setText(dateFormat.format(callLog.getCallDate()));

View File

@@ -5,19 +5,25 @@ package cc.winboll.studio.contacts.adapters;
* @Date 2025/02/26 13:35:44 * @Date 2025/02/26 13:35:44
* @Describe ContactAdapter * @Describe ContactAdapter
*/ */
import android.content.ClipData;
import android.content.ClipboardManager;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MenuItem;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.LinearLayout;
import android.widget.PopupMenu;
import android.widget.TextView; import android.widget.TextView;
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.beans.ContactModel; import cc.winboll.studio.contacts.beans.ContactModel;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import java.util.List; import java.util.List;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> { public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactViewHolder> {
@@ -26,8 +32,10 @@ public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactV
private static final int REQUEST_CALL_PHONE = 1; private static final int REQUEST_CALL_PHONE = 1;
private List<ContactModel> contactList; private List<ContactModel> contactList;
Context mContext;
public ContactAdapter(List<ContactModel> contactList) { public ContactAdapter(Context context, List<ContactModel> contactList) {
mContext = context;
this.contactList = contactList; this.contactList = contactList;
} }
@@ -41,6 +49,37 @@ public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactV
@Override @Override
public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) { public void onBindViewHolder(@NonNull ContactViewHolder holder, int position) {
final ContactModel contact = contactList.get(position); final ContactModel contact = contactList.get(position);
holder.llPhoneNumberMain.setOnLongClickListener(new View.OnLongClickListener() {
@Override
public boolean onLongClick(View p1) {
// 弹出复制菜单
PopupMenu menu = new PopupMenu(mContext, holder.llPhoneNumberMain);
//加载菜单资源
menu.getMenuInflater().inflate(R.menu.toolbar_contact_phonenumber, menu.getMenu());
//设置点击事件的响应
menu.setOnMenuItemClickListener(new PopupMenu.OnMenuItemClickListener() {
@Override
public boolean onMenuItemClick(MenuItem menuItem) {
int nItemId = menuItem.getItemId();
if (nItemId == R.id.item_contact_phonenumber_copy) {
// Gets a handle to the clipboard service.
ClipboardManager clipboard = (ClipboardManager) mContext.getSystemService(Context.CLIPBOARD_SERVICE);
// Creates a new text clip to put on the clipboard
ClipData clip = ClipData.newPlainText("simple text", contact.getNumber());
// Set the clipboard's primary clip.
clipboard.setPrimaryClip(clip);
Toast.makeText(mContext, "Copy to clipboard.", Toast.LENGTH_SHORT).show();
}
return true;
}
});
//一定要调用show()来显示弹出式菜单
menu.show();
return true;
}
});
holder.contactName.setText(contact.getName()); holder.contactName.setText(contact.getName());
holder.contactNumber.setText(contact.getNumber()); holder.contactNumber.setText(contact.getNumber());
@@ -69,12 +108,14 @@ public class ContactAdapter extends RecyclerView.Adapter<ContactAdapter.ContactV
} }
public class ContactViewHolder extends RecyclerView.ViewHolder { public class ContactViewHolder extends RecyclerView.ViewHolder {
LinearLayout llPhoneNumberMain;
TextView contactName; TextView contactName;
TextView contactNumber; TextView contactNumber;
AOHPCTCSeekBar dialAOHPCTCSeekBar; AOHPCTCSeekBar dialAOHPCTCSeekBar;
public ContactViewHolder(@NonNull View itemView) { public ContactViewHolder(@NonNull View itemView) {
super(itemView); super(itemView);
llPhoneNumberMain = itemView.findViewById(R.id.itemcontactLinearLayout1);
contactName = itemView.findViewById(R.id.contact_name); contactName = itemView.findViewById(R.id.contact_name);
contactNumber = itemView.findViewById(R.id.contact_number); contactNumber = itemView.findViewById(R.id.contact_number);
dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial); dialAOHPCTCSeekBar = itemView.findViewById(R.id.aohpctcseekbar_dial);

View File

@@ -7,6 +7,7 @@ package cc.winboll.studio.contacts.adapters;
*/ */
import android.content.Context; import android.content.Context;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button; import android.widget.Button;
@@ -20,6 +21,7 @@ import cc.winboll.studio.contacts.R;
import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel; import cc.winboll.studio.contacts.beans.PhoneConnectRuleModel;
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.libappbase.LogUtils;
import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog; import cc.winboll.studio.libappbase.dialogs.YesNoAlertDialog;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import java.util.ArrayList; import java.util.ArrayList;
@@ -60,6 +62,10 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
final SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder; final SimpleViewHolder simpleViewHolder = (SimpleViewHolder) holder;
String szView = model.getRuleText().trim().equals("") ?"[NULL]": model.getRuleText(); String szView = model.getRuleText().trim().equals("") ?"[NULL]": model.getRuleText();
simpleViewHolder.tvRuleText.setText(szView); simpleViewHolder.tvRuleText.setText(szView);
simpleViewHolder.checkBoxAllow.setChecked(model.isAllowConnection());
simpleViewHolder.checkBoxAllow.setEnabled(false);
simpleViewHolder.checkBoxEnable.setChecked(model.isEnable());
simpleViewHolder.checkBoxEnable.setEnabled(false);
simpleViewHolder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener(){ simpleViewHolder.scrollView.setOnActionListener(new LeftScrollView.OnActionListener(){
@Override @Override
@@ -215,16 +221,22 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
private final LeftScrollView scrollView; private final LeftScrollView scrollView;
private final TextView tvRuleText; private final TextView tvRuleText;
CheckBox checkBoxAllow;
CheckBox checkBoxEnable;
public SimpleViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) { public SimpleViewHolder(@NonNull ViewGroup parent, @NonNull View itemView) {
super(itemView); super(itemView);
scrollView = itemView.findViewById(R.id.scrollView); scrollView = itemView.findViewById(R.id.scrollView);
//tvRuleText = itemView.findViewById(R.id.ruletext_tv); LayoutInflater inflater = LayoutInflater.from(itemView.getContext());
tvRuleText = new TextView(itemView.getContext()); View viewContent = inflater.inflate(R.layout.view_phone_connect_rule_simple_content, parent, false);
tvRuleText = viewContent.findViewById(R.id.ruletext_tv);
checkBoxAllow = viewContent.findViewById(R.id.checkbox_allow);
checkBoxEnable = viewContent.findViewById(R.id.checkbox_enable);
//tvRuleText = new TextView(itemView.getContext());
scrollView.setContentWidth(parent.getWidth()); scrollView.setContentWidth(parent.getWidth());
//scrollView.setContentWidth(600); //scrollView.setContentWidth(600);
scrollView.addContentLayout(tvRuleText); scrollView.addContentLayout(viewContent);
} }
} }
@@ -243,5 +255,9 @@ public class PhoneConnectRuleAdapter extends RecyclerView.Adapter<RecyclerView.V
buttonConfirm = itemView.findViewById(R.id.button_confirm); buttonConfirm = itemView.findViewById(R.id.button_confirm);
} }
} }
private void setCheckBoxTouchListener(CheckBox checkBox) {
}
} }

View File

@@ -44,7 +44,7 @@ public class TomCat {
} }
return _TomCat; return _TomCat;
} }
public String getDefaultBobulltoonUrl() { public String getDefaultBobulltoonUrl() {
return mContext.getString(R.string.default_bobulltoon_url); return mContext.getString(R.string.default_bobulltoon_url);
} }
@@ -123,7 +123,7 @@ public class TomCat {
} }
// 更新新文件 // 更新新文件
if(downloadAndExtractZip(zipUrl, destinationFolder)) { if (downloadAndExtractZip(zipUrl, destinationFolder)) {
LogUtils.d(TAG, "ZIP 文件下载并解压成功。"); LogUtils.d(TAG, "ZIP 文件下载并解压成功。");
return true; return true;
} }
@@ -155,6 +155,19 @@ public class TomCat {
return mContext.getExternalFilesDir(TAG); return mContext.getExternalFilesDir(TAG);
} }
public void cleanBoBullToon() {
String destinationFolder = getWorkingFolder().getPath(); // 替换为实际的目标文件夹路径
// 删除旧文件
File fOldFolder = new File(destinationFolder);
if (fOldFolder.exists()) {
deleteFolderRecursive(fOldFolder);
fOldFolder.mkdirs();
}
ToastUtils.show("已清空 BoBullToon 数据!");
LogUtils.d(TAG, "已清空 BoBullToon 数据");
}
public boolean loadPhoneBoBullToon() { public boolean loadPhoneBoBullToon() {
listPhoneBoBullToon.clear(); listPhoneBoBullToon.clear();
File fBoBullToon = new File(getWorkingFolder(), "bobulltoon"); File fBoBullToon = new File(getWorkingFolder(), "bobulltoon");

View File

@@ -145,6 +145,14 @@ public class Rules {
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect)); LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
} }
// 检验拨不通号码群
if (!isDefend && MainService.isPhoneInBoBullToon(phoneNumber)) {
LogUtils.d(TAG, String.format("PhoneNumber %s\n Is In BoBullToon", phoneNumber));
isDefend = true;
isConnect = false;
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
}
// 查询通讯录是否有该联系人 // 查询通讯录是否有该联系人
boolean isPhoneInContacts = ContactUtils.getInstance(mContext).isPhoneInContacts(mContext, phoneNumber); boolean isPhoneInContacts = ContactUtils.getInstance(mContext).isPhoneInContacts(mContext, phoneNumber);
if (!isDefend) { if (!isDefend) {
@@ -158,14 +166,6 @@ public class Rules {
} }
} }
// 检验拨不通号码群
if (!isDefend && MainService.isPhoneInBoBullToon(phoneNumber)) {
LogUtils.d(TAG, String.format("PhoneNumber %s\n Is In BoBullToon", phoneNumber));
isDefend = true;
isConnect = false;
LogUtils.d(TAG, String.format("isDefend == %s\nisConnect == %s", isDefend, isConnect));
}
// 正则匹配规则名单校验 // 正则匹配规则名单校验
if (!isDefend) { if (!isDefend) {
for (int i = 0; i < _PhoneConnectRuleModelList.size(); i++) { for (int i = 0; i < _PhoneConnectRuleModelList.size(); i++) {

View File

@@ -73,7 +73,7 @@ public class ContactsFragment extends Fragment {
super.onViewCreated(view, savedInstanceState); super.onViewCreated(view, savedInstanceState);
recyclerView = view.findViewById(R.id.contacts_recycler_view); recyclerView = view.findViewById(R.id.contacts_recycler_view);
recyclerView.setLayoutManager(new LinearLayoutManager(getContext())); recyclerView.setLayoutManager(new LinearLayoutManager(getContext()));
contactAdapter = new ContactAdapter(contactList); contactAdapter = new ContactAdapter(getContext(), contactList);
recyclerView.setAdapter(contactAdapter); recyclerView.setAdapter(contactAdapter);
searchEditText = view.findViewById(R.id.search_edit_text); searchEditText = view.findViewById(R.id.search_edit_text);

View File

@@ -47,8 +47,8 @@ public class LeftScrollView extends HorizontalScrollView {
init(); init();
} }
public void addContentLayout(TextView textView) { public void addContentLayout(View viewContent) {
contentLayout.addView(textView, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT); contentLayout.addView(viewContent, LinearLayout.LayoutParams.MATCH_PARENT, LinearLayout.LayoutParams.MATCH_PARENT);
} }
public void setContentWidth(int contentWidth) { public void setContentWidth(int contentWidth) {

View File

@@ -269,6 +269,19 @@
</LinearLayout> </LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_horizontal">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="&lt;&lt;==向左拉动列表项可编辑内容"/>
</LinearLayout>
<androidx.recyclerview.widget.RecyclerView <androidx.recyclerview.widget.RecyclerView
android:id="@+id/recycler_view" android:id="@+id/recycler_view"
android:layout_width="match_parent" android:layout_width="match_parent"
@@ -287,6 +300,12 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:gravity="right"> android:gravity="right">
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="LogView"
android:onClick="onLogView"/>
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"

View File

@@ -15,8 +15,10 @@
<Button <Button
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Test Main" android:text="Add Demo Rules(While size is 0) and Test"
android:onClick="onTestMain"/> android:onClick="onTestMain"
android:textSize="10sp"
android:textAllCaps="false"/>
</LinearLayout> </LinearLayout>
@@ -43,7 +45,8 @@
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="Test Phone" android:text="Test Phone"
android:onClick="onTestPhone"/> android:onClick="onTestPhone"
android:textAllCaps="false"/>
</LinearLayout> </LinearLayout>

View File

@@ -9,7 +9,8 @@
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content"> android:layout_height="wrap_content"
android:id="@+id/itemcontactLinearLayout1">
<TextView <TextView
android:id="@+id/contact_number" android:id="@+id/contact_number"

View File

@@ -23,7 +23,7 @@
android:id="@+id/checkbox_allow" android:id="@+id/checkbox_allow"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="允许连接"/> android:text="连接"/>
<CheckBox <CheckBox
android:id="@+id/checkbox_enable" android:id="@+id/checkbox_enable"

View File

@@ -1,55 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<HorizontalScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:scrollbars="none"
android:id="@+id/scrollView">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal">
<!-- 内容区域 -->
<LinearLayout
android:id="@+id/content_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="16dp"
android:background="@color/white">
<!-- 这里放置你的列表项内容 -->
<TextView
android:id="@+id/text_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:textSize="16sp"/>
</LinearLayout>
<!-- 操作按钮 -->
<LinearLayout
android:id="@+id/action_layout"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:orientation="horizontal"
android:background="@color/lightgray">
<Button
android:id="@+id/edit_btn"
android:layout_width="80dp"
android:layout_height="match_parent"
android:text="编辑"
android:background="@color/blue" />
<Button
android:id="@+id/delete_btn"
android:layout_width="80dp"
android:layout_height="match_parent"
android:text="删除"
android:background="@color/red" />
</LinearLayout>
</LinearLayout>
</HorizontalScrollView>

View File

@@ -0,0 +1,35 @@
<?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:layout_gravity="center_vertical"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:layout_weight="1.0"
android:id="@+id/ruletext_tv"/>
<CheckBox
android:id="@+id/checkbox_allow"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="连接"
android:clickable="false"
android:focusable="false"/>
<CheckBox
android:id="@+id/checkbox_enable"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="启用"
android:clickable="false"
android:focusable="false"/>
</LinearLayout>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_calllog_phonenumber_copy"
android:title="Copy"/>
</menu>

View File

@@ -0,0 +1,9 @@
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<item
android:id="@+id/item_contact_phonenumber_copy"
android:title="Copy"/>
</menu>

View File

@@ -2,6 +2,6 @@
<resources> <resources>
<string name="app_name">Contacts</string> <string name="app_name">Contacts</string>
<string name="default_bobulltoon_url">http://10.8.0.12:3000/Studio/BoBullToon/archive/main.zip</string> <string name="default_bobulltoon_url">https://gitea.winboll.cc/Studio/BoBullToon/archive/main.zip</string>
</resources> </resources>

View File

@@ -21,8 +21,8 @@ android {
dependencies { dependencies {
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
api 'cc.winboll.studio:libapputils:15.8.2' api 'cc.winboll.studio:libapputils:15.8.4'
api 'cc.winboll.studio:libappbase:15.8.2' api 'cc.winboll.studio:libappbase:15.8.4'
// 吐司类库 // 吐司类库
api 'com.github.getActivity:ToastUtils:10.5' api 'com.github.getActivity:ToastUtils:10.5'

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jun 19 20:42:26 HKT 2025 #Sat Jun 28 12:59:30 HKT 2025
stageCount=2 stageCount=3
libraryProject=libaes libraryProject=libaes
baseVersion=15.9 baseVersion=15.9
publishVersion=15.9.1 publishVersion=15.9.2
buildCount=0 buildCount=0
baseBetaVersion=15.9.2 baseBetaVersion=15.9.3

View File

@@ -107,7 +107,7 @@ public class AboutView extends LinearLayout {
mszAppDescription = mAPPInfo.getAppDescription(); mszAppDescription = mAPPInfo.getAppDescription();
mnAppIcon = mAPPInfo.getAppIcon(); mnAppIcon = mAPPInfo.getAppIcon();
mszWinBoLLServerHost = GlobalApplication.isDebuging() ? "https://dev.winboll.cc": "https://www.winboll.cc"; mszWinBoLLServerHost = GlobalApplication.isDebuging() ? "https://yun-preivew.winboll.cc": "https://yun.winboll.cc";
try { try {
mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName; mszAppVersionName = mContext.getPackageManager().getPackageInfo(mContext.getPackageName(), 0).versionName;

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Mon Jun 09 09:38:19 HKT 2025 #Thu Jul 17 11:39:14 HKT 2025
stageCount=9 stageCount=2
libraryProject=libappbase libraryProject=libappbase
baseVersion=15.8 baseVersion=15.9
publishVersion=15.8.8 publishVersion=15.9.1
buildCount=0 buildCount=0
baseBetaVersion=15.8.9 baseBetaVersion=15.9.2

View File

@@ -45,17 +45,15 @@ android {
dependencies { dependencies {
api fileTree(dir: 'libs', include: ['*.jar']) api fileTree(dir: 'libs', include: ['*.jar'])
api 'cc.winboll.studio:libaes:15.9.3' api 'cc.winboll.studio:libaes:15.9.2'
api 'cc.winboll.studio:libapputils:15.8.6' api 'cc.winboll.studio:libapputils:15.8.4'
api 'cc.winboll.studio:libappbase:15.9.5' api 'cc.winboll.studio:libappbase:15.8.4'
api 'io.github.medyo:android-about-page:2.0.0' api 'io.github.medyo:android-about-page:2.0.0'
api 'com.github.getActivity:ToastUtils:10.5' api 'com.github.getActivity:ToastUtils:10.5'
api 'com.jcraft:jsch:0.1.55' api 'com.jcraft:jsch:0.1.55'
api 'org.jsoup:jsoup:1.13.1' api 'org.jsoup:jsoup:1.13.1'
api 'com.squareup.okhttp3:okhttp:4.4.1' api 'com.squareup.okhttp3:okhttp:4.4.1'
api 'com.belerweb:pinyin4j:2.5.1'
// 权限请求框架https://github.com/getActivity/XXPermissions // 权限请求框架https://github.com/getActivity/XXPermissions
api 'com.github.getActivity:XXPermissions:18.63' api 'com.github.getActivity:XXPermissions:18.63'

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Sat Sep 06 01:57:20 HKT 2025 #Thu Jul 03 13:50:15 HKT 2025
stageCount=9 stageCount=2
libraryProject= libraryProject=
baseVersion=15.3 baseVersion=15.3
publishVersion=15.3.8 publishVersion=15.3.1
buildCount=0 buildCount=0
baseBetaVersion=15.3.9 baseBetaVersion=15.3.2

View File

@@ -1,10 +1,5 @@
package cc.winboll.studio.mymessagemanager.activitys; package cc.winboll.studio.mymessagemanager.activitys;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@188.com>
* @Date 2025/08/30 14:32
* @Describe 联系人查询与短信发送窗口
*/
import android.os.Bundle; import android.os.Bundle;
import android.text.Editable; import android.text.Editable;
import android.text.TextWatcher; import android.text.TextWatcher;
@@ -16,17 +11,13 @@ import android.widget.RelativeLayout;
import android.widget.SimpleAdapter; import android.widget.SimpleAdapter;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toolbar; import android.widget.Toolbar;
import android.content.Intent;
import android.graphics.drawable.Drawable;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
import cc.winboll.studio.mymessagemanager.R; import cc.winboll.studio.mymessagemanager.R;
import cc.winboll.studio.mymessagemanager.activitys.ComposeSMSActivity;
import cc.winboll.studio.mymessagemanager.beans.PhoneBean; import cc.winboll.studio.mymessagemanager.beans.PhoneBean;
import cc.winboll.studio.mymessagemanager.utils.PhoneUtil; import cc.winboll.studio.mymessagemanager.utils.PhoneUtil;
import cc.winboll.studio.mymessagemanager.utils.SMSUtil; import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import cc.winboll.studio.libappbase.LogUtils;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.HashMap; import java.util.HashMap;
import java.util.List; import java.util.List;
@@ -35,331 +26,166 @@ import java.util.Map;
public class ComposeSMSActivity extends BaseActivity { public class ComposeSMSActivity extends BaseActivity {
public static String TAG = "ComposeSMSActivity"; public static String TAG = "ComposeSMSActivity";
public static String EXTRA_SMSBODY = "sms_body";
private static final String MAP_NAME = "NAME";
private static final String MAP_PHONE = "PHONE";
private String mszSMSBody; public static String EXTRA_SMSBODY = "sms_body";
private String mszScheme;
private String mszPhoneTo; static String MAP_NAME = "NAME";
private TextView mtvTOName; static String MAP_PHONE = "PHONE";
private EditText metTONameSearch;
private EditText metTO; String mszSMSBody;
private EditText metSMSBody; String mszScheme;
private SimpleAdapter mSimpleAdapter; String mszPhoneTo;
private List<Map<String, Object>> mAdapterData = new ArrayList<Map<String, Object>>(); EditText metTO;
private ListView mlvContracts; EditText metSMSBody;
private List<PhoneBean> mListPhoneBeanContracts; SimpleAdapter mSimpleAdapter;
private Toolbar mToolbar; List<Map<String,Object>> mAdapterData = new ArrayList<>();
private AOHPCTCSeekBar mAOHPCTCSeekBar; ListView mlvContracts;
private RelativeLayout mrlContracts; List<PhoneBean> mListPhoneBeanContracts;
Toolbar mToolbar;
AOHPCTCSeekBar mAOHPCTCSeekBar;
RelativeLayout mrlContracts;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
LogUtils.d(TAG, "onCreate");
setContentView(R.layout.activity_composesms); setContentView(R.layout.activity_composesms);
mszSMSBody = getIntent().getStringExtra(EXTRA_SMSBODY);
// 初始化Intent数据增加空判断避免NullPointerException mszScheme = getIntent().getData().getScheme();
Intent intent = getIntent(); mszPhoneTo = getIntent().getData().getSchemeSpecificPart();
if (intent != null) { if (!mszScheme.equals("smsto")) {
mszSMSBody = intent.getStringExtra(EXTRA_SMSBODY); // 其他方式未支持就退出
if (intent.getData() != null) {
mszScheme = intent.getData().getScheme();
mszPhoneTo = intent.getData().getSchemeSpecificPart();
}
}
// 校验启动方式非smsto则退出
if (mszScheme == null || !"smsto".equals(mszScheme)) {
ToastUtils.show("不支持的启动方式");
finish(); finish();
return;
} }
// 初始化视图
initView(); initView();
initAdapter(null); // 初始加载所有联系人 // 设置适配器
setListViewPrePositionByPhone(); initAdapter();
// 设置搜索到的匹配位置
setListViewPrePosition();
} }
private void initView() { //
// 初始化视图
//
void initView() {
//Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame);
// 初始化标题栏 // 初始化标题栏
mToolbar = (Toolbar) findViewById(R.id.activitycomposesmsASupportToolbar1); mToolbar = findViewById(R.id.activitycomposesmsASupportToolbar1);
mToolbar.setSubtitle(getString(R.string.activity_name_composesms)); mToolbar.setSubtitle(getString(R.string.activity_name_composesms));
setActionBar(mToolbar); setActionBar(mToolbar);
// 初始化联系人姓名显示和搜索 // 初始化联系人栏目框
mtvTOName = (TextView) findViewById(R.id.activitycomposesmsTextView2); mrlContracts = findViewById(R.id.activitycomposesmsRelativeLayout1);
mrlContracts = (RelativeLayout) findViewById(R.id.activitycomposesmsRelativeLayout1); //mrlContracts.setBackground(drawableFrame);
metTONameSearch = (EditText) findViewById(R.id.activitycomposesmsEditText2);
// 姓名搜索框文本变化监听 // 初始化联系人列表
metTONameSearch.addTextChangedListener(new TextWatcher() { mlvContracts = findViewById(R.id.activitycomposesmsListView1);
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
metTO.setText(""); // 清空号码输入框,避免冲突
String input = s == null ? "" : s.toString().trim();
if (input.isEmpty()) {
initAdapter(null); // 空搜索时显示所有联系人
} else {
setListViewPrePositionByName(); // 按姓名搜索
}
}
@Override // 初始化联系人输入框
public void beforeTextChanged(CharSequence s, int start, int count, int after) { metTO = findViewById(R.id.activitycomposesmsEditText1);
// 无操作 metTO.setText(mszPhoneTo);
} metTO.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
setListViewPrePosition();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
// 无操作 }
} });
});
// 初始化联系人列表(关键:设置单选模式,确保选中状态生效) // 初始化发送拉动控件
mlvContracts = (ListView) findViewById(R.id.activitycomposesmsListView1); mAOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
mlvContracts.setChoiceMode(ListView.CHOICE_MODE_SINGLE); // 开启单选,与布局中一致 mAOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message));
// 初始化号码输入框(核心:优化文本变化监听逻辑)
metTO = (EditText) findViewById(R.id.activitycomposesmsEditText1);
if (mszPhoneTo != null) {
metTO.setText(mszPhoneTo);
}
metTO.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
mtvTOName.setText(""); // 清空姓名显示
String inputPhone = s == null ? "" : s.toString().trim();
if (inputPhone.isEmpty()) {
// 输入为空时,显示所有联系人
initAdapter(null);
} else {
// 输入非空时,按号码搜索并更新列表(无结果则清空)
filterListByPhone(inputPhone);
}
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// 无操作
}
@Override
public void afterTextChanged(Editable s) {
// 无操作
}
});
// 初始化发送控件
mAOHPCTCSeekBar = (AOHPCTCSeekBar) findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
Drawable thumbDrawable = getResources().getDrawable(R.drawable.ic_message); // Java 7兼容写法
mAOHPCTCSeekBar.setThumb(thumbDrawable);
mAOHPCTCSeekBar.setThumbOffset(20); mAOHPCTCSeekBar.setThumbOffset(20);
mAOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() { mAOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
@Override @Override
public void onOHPCommit() { public void onOHPCommit() {
sendSMS(); // 空号码不发送
} mszPhoneTo = metTO.getText().toString();
if (mszPhoneTo.trim().equals("")) {
ToastUtils.show("没有设置接收号码。");
return;
}
// 空消息不发送
mszSMSBody = metSMSBody.getText().toString();
if (mszSMSBody.equals("")) {
ToastUtils.show("没有消息内容可发送。");
return;
}
// 发送消息
if (SMSUtil.sendMessageByInterface2(ComposeSMSActivity.this, mszPhoneTo, mszSMSBody)) {
ComposeSMSActivity.this.finish();
}
}
}); });
// 初始化短信内容输入 // 初始化提示
TextView tvAOHPCTCSeekBarMSG = (TextView) findViewById(R.id.viewsmssendpart1TextView1); TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1);
tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg); tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg);
metSMSBody = (EditText) findViewById(R.id.viewsmssendpart1EditText1);
if (mszSMSBody != null) { // 初始化发送消息框
metSMSBody.setText(mszSMSBody); metSMSBody = findViewById(R.id.viewsmssendpart1EditText1);
} //metSMSBody.setBackground(drawableFrame);
metSMSBody.setText(mszSMSBody);
} }
// 核心优化:根据输入号码筛选列表(无结果则显示空列表,优化选中逻辑) //
private void filterListByPhone(String inputPhone) { // 设置搜索到的匹配位置
PhoneUtil phoneUtil = new PhoneUtil(this); //
List<PhoneBean> allContacts = phoneUtil.getPhoneList(); void setListViewPrePosition() {
List<PhoneBean> matchedContacts = new ArrayList<PhoneBean>(); int nPrePosition = getContractsDataPrePosition(metTO.getText().toString());
mlvContracts.setSelected(false);
mlvContracts.setSelection(nPrePosition);
}
// 遍历所有联系人,匹配包含输入号码的联系人 //
for (PhoneBean contact : allContacts) { // 返回搜索到的匹配位置
if (contact.getTelPhone().contains(inputPhone) //
|| phoneUtil.isTheSamePhoneNumber(contact.getTelPhone(), inputPhone)) { int getContractsDataPrePosition(String szPhone) {
matchedContacts.add(contact); for (int i = 0; i < mListPhoneBeanContracts.size(); i++) {
if (mListPhoneBeanContracts.get(i).getTelPhone().compareTo(szPhone) > -1) {
return i;
} }
} }
return 0;
}
LogUtils.d(TAG, "号码搜索:输入'" + inputPhone + "', 匹配" + matchedContacts.size() + "个结果"); //
// 初始化适配器
//
void initAdapter() {
// 初始化联系人数据适配器
mAdapterData = new ArrayList<>();
// 读取联系人数据
PhoneUtil phoneUtils = new PhoneUtil(this);
mListPhoneBeanContracts = phoneUtils.getPhoneList();
// 映射联系人数据给适配器数据对象
for (int i = 0;i < mListPhoneBeanContracts.size();i++) {
Map<String,Object> map =new HashMap<>();
map.put(MAP_NAME, mListPhoneBeanContracts.get(i).getName());
map.put(MAP_PHONE, mListPhoneBeanContracts.get(i).getTelPhone());
mAdapterData.add(map);
}
// 绑定适配器与数据
mSimpleAdapter = new SimpleAdapter(ComposeSMSActivity.this, mAdapterData, R.layout.listview_contracts
, new String[]{MAP_NAME, MAP_PHONE}
, new int[]{R.id.listviewcontractsTextView1, R.id.listviewcontractsTextView2});
mSimpleAdapter.setDropDownViewResource(R.layout.listview_contracts);
mlvContracts.setAdapter(mSimpleAdapter);
mlvContracts.setOnItemClickListener(new ListView.OnItemClickListener() {
// 用筛选结果更新列表(无结果则传入空列表) @Override
initAdapter(matchedContacts.isEmpty() ? new ArrayList<PhoneBean>() : matchedContacts); public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
metTO.setText(mAdapterData.get(position).get(MAP_PHONE).toString());
// 定位并选中匹配项(如果有)
if (!matchedContacts.isEmpty()) {
boolean isFound = false;
for (int i = 0; i < matchedContacts.size(); i++) {
PhoneBean item = matchedContacts.get(i);
// 精确匹配号码(兼容区域码格式)
if (phoneUtil.isTheSamePhoneNumber(item.getTelPhone(), inputPhone)) {
mtvTOName.setText(item.getName());
// 关键:先滚动到目标位置,再设置选中状态
mlvContracts.setSelection(i);
// 主动设置选中(确保样式生效,兼容部分系统)
mlvContracts.setItemChecked(i, true);
LogUtils.d(TAG, String.format("%s 匹配 %s选中位置%d", inputPhone, item.getTelPhone(), i));
isFound = true;
break;
} }
} });
// 若未精确匹配,选中第一个结果
/*if (!isFound) {
mlvContracts.setSelection(0);
mlvContracts.setItemChecked(0, true);
mtvTOName.setText(matchedContacts.get(0).getName());
}*/
} else {
mtvTOName.setText(""); // 无结果时清空姓名显示
}
}
// 根据姓名搜索联系人
private void setListViewPrePositionByName() {
String searchName = metTONameSearch.getText().toString().trim();
PhoneUtil phoneUtil = new PhoneUtil(this);
List<PhoneBean> matchedContacts = phoneUtil.getPhonesByName(searchName);
initAdapter(matchedContacts);
if (!matchedContacts.isEmpty()) {
// 选中第一个结果并设置样式
mlvContracts.setSelection(0);
mlvContracts.setItemChecked(0, true);
}
}
// 初始定位号码对应的联系人
private void setListViewPrePositionByPhone() {
String inputPhone = metTO.getText().toString().trim();
if (inputPhone.isEmpty()) {
return;
}
filterListByPhone(inputPhone); // 复用筛选逻辑
}
// 获取号码匹配的位置(兼容旧逻辑)
private int getContractsDataPrePositionByPhone(String szPhone) {
if (mListPhoneBeanContracts == null || mListPhoneBeanContracts.isEmpty()) {
return 0;
}
for (int i = 0; i < mListPhoneBeanContracts.size(); i++) {
PhoneBean bean = mListPhoneBeanContracts.get(i);
if (bean.getTelPhone().compareTo(szPhone) >= 0) {
return i;
}
}
return 0;
}
// 获取姓名匹配的位置(兼容旧逻辑)
private int getContractsDataPrePositionByName(String szName) {
if (mListPhoneBeanContracts == null || mListPhoneBeanContracts.isEmpty()) {
return 0;
}
for (int i = 0; i < mListPhoneBeanContracts.size(); i++) {
if (mListPhoneBeanContracts.get(i).getName().startsWith(szName)) {
return i;
}
}
return 0;
}
// 初始化或更新列表适配器
private void initAdapter(List<PhoneBean> initData) {
mAdapterData.clear(); // 清空旧数据
final PhoneUtil phoneUtil = new PhoneUtil(this);
// 确定数据源:传入的筛选数据或所有联系人
if (initData != null) {
mListPhoneBeanContracts = initData;
} else {
mListPhoneBeanContracts = phoneUtil.getPhoneList();
}
// 转换数据为SimpleAdapter所需格式
if (mListPhoneBeanContracts != null) {
for (PhoneBean bean : mListPhoneBeanContracts) {
Map<String, Object> map = new HashMap<String, Object>();
map.put(MAP_NAME, bean.getName());
map.put(MAP_PHONE, bean.getTelPhone());
mAdapterData.add(map);
}
}
// 初始化或更新适配器
if (mSimpleAdapter == null) {
mSimpleAdapter = new SimpleAdapter(
ComposeSMSActivity.this,
mAdapterData,
R.layout.listview_contracts,
new String[]{MAP_NAME, MAP_PHONE},
new int[]{R.id.listviewcontractsTextView1, R.id.listviewcontractsTextView2}
);
mSimpleAdapter.setDropDownViewResource(R.layout.listview_contracts);
mlvContracts.setAdapter(mSimpleAdapter);
// 列表项点击事件:点击时主动设置选中状态,确保样式突显
mlvContracts.setOnItemClickListener(new AdapterView.OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
if (position < mAdapterData.size()) {
// 1. 主动设置当前项为选中状态
mlvContracts.setItemChecked(position, true);
// 2. 更新号码输入框和姓名显示
String phone = mAdapterData.get(position).get(MAP_PHONE).toString();
metTO.setText(phone);
mtvTOName.setText(phoneUtil.getNameByPhone(phone));
// 3. 滚动到点击位置(确保可见)
mlvContracts.setSelection(position);
}
}
});
// 列表项选中状态变化监听(可选,增强选中反馈)
mlvContracts.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
// 选中时可添加额外反馈(如改变文本颜色,可选)
if (view != null) {
TextView tvName = (TextView) view.findViewById(R.id.listviewcontractsTextView1);
TextView tvPhone = (TextView) view.findViewById(R.id.listviewcontractsTextView2);
if (tvName != null) tvName.setTextColor(getResources().getColor(R.color.white));
if (tvPhone != null) tvPhone.setTextColor(getResources().getColor(R.color.white));
}
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
// 未选中时无操作
}
});
} else {
// 数据更新时,先取消所有旧选中状态,再通知适配器刷新
mlvContracts.clearChoices();
mSimpleAdapter.notifyDataSetChanged();
}
}
// 发送短信逻辑
private void sendSMS() {
String phoneTo = metTO.getText().toString().trim();
if (phoneTo.isEmpty()) {
ToastUtils.show("没有设置接收号码。");
return;
}
String smsBody = metSMSBody.getText().toString().trim();
if (smsBody.isEmpty()) {
ToastUtils.show("没有消息内容可发送。");
return;
}
if (SMSUtil.sendMessageByInterface2(ComposeSMSActivity.this, phoneTo, smsBody)) {
finish();
}
} }
} }

View File

@@ -4,16 +4,11 @@ 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 android.os.Build;
import android.os.Bundle; import android.os.Bundle;
import android.os.Handler; import android.os.Handler;
import android.os.Message; import android.os.Message;
import android.view.View;
import android.view.ViewTreeObserver;
import android.view.inputmethod.InputMethodManager;
import android.widget.AbsListView; import android.widget.AbsListView;
import android.widget.EditText; import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.ScrollView; import android.widget.ScrollView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
@@ -21,17 +16,19 @@ import android.widget.Toolbar;
import androidx.localbroadcastmanager.content.LocalBroadcastManager; import androidx.localbroadcastmanager.content.LocalBroadcastManager;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar; import cc.winboll.studio.libaes.views.AOHPCTCSeekBar;
import cc.winboll.studio.mymessagemanager.R; import cc.winboll.studio.mymessagemanager.R;
import cc.winboll.studio.mymessagemanager.activitys.SMSActivity;
import cc.winboll.studio.mymessagemanager.adapters.SMSArrayAdapter; import cc.winboll.studio.mymessagemanager.adapters.SMSArrayAdapter;
import cc.winboll.studio.mymessagemanager.utils.AddressUtils; import cc.winboll.studio.mymessagemanager.utils.AddressUtils;
import cc.winboll.studio.mymessagemanager.utils.SMSUtil; import cc.winboll.studio.mymessagemanager.utils.SMSUtil;
import cc.winboll.studio.mymessagemanager.utils.ViewUtil; import cc.winboll.studio.mymessagemanager.utils.ViewUtil;
import cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView;
import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView; import cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView;
import java.lang.ref.WeakReference; import java.lang.ref.WeakReference;
public class SMSActivity extends BaseActivity { public class SMSActivity extends BaseActivity {
public static String TAG = "SMSActivity"; public static String TAG = "SMSActivity";
public static final String ACTION_NOTIFY_SMS_CHANGED = "cc.winboll.studio.mymessagemanager.activitys.SMSActivity.ACTION_NOTIFY_SMS_CHANGED"; public static final String ACTION_NOTIFY_SMS_CHANGED = "cc.winboll.studio.mymessagemanager.activitys.SMSActivity.ACTION_NOTIFY_SMS_CHANGED";
public static final String EXTRA_PHONE = "Phone"; public static final String EXTRA_PHONE = "Phone";
final static int MSG_SET_FOCUS = 0; final static int MSG_SET_FOCUS = 0;
@@ -39,11 +36,10 @@ public class SMSActivity extends BaseActivity {
Toolbar mToolbar; Toolbar mToolbar;
String mszPhoneTo; String mszPhoneTo;
SMSArrayAdapter mSMSArrayAdapter; SMSArrayAdapter mSMSArrayAdapter;
BottomPositionFixedScrollView mScrollView1; ScrollView mScrollView;
EditText metSMSBody; EditText metSMSBody;
SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver; SMSActivityBroadcastReceiver mSMSActivityBroadcastReceiver;
Handler mSetFocusHandler; Handler mSetFocusHandler;
private boolean isImeVisible = false;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
@@ -51,90 +47,45 @@ public class SMSActivity extends BaseActivity {
setContentView(R.layout.activity_sms); setContentView(R.layout.activity_sms);
initView(); initView();
mSetFocusHandler = new MyHandler(SMSActivity.this);
scrollScrollView(); scrollScrollView();
setupImeStatusListener();
// 新增监听窗口加载完成触发mScrollView1滚动到底部 // 每隔一定时间设置输入框获得焦点
setupScrollToBottomAfterWindowLoaded(); //
new Thread() {
@Override
public void run() {
while (true) {
try {
Thread.sleep(1500);
} catch (InterruptedException e) {}
Message message = mSetFocusHandler.obtainMessage(MSG_SET_FOCUS);
mSetFocusHandler.sendMessage(message);
}
}}.start();
} }
// 新增窗口加载完成后让mScrollView1滚动到底部 //
private void setupScrollToBottomAfterWindowLoaded() { // 设置输入框获得焦点的类
final View rootView = findViewById(android.R.id.content); //
// 监听根布局绘制完成(窗口加载完成的标志) static class MyHandler extends Handler {
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() { WeakReference<SMSActivity> mActivity;
@Override MyHandler(SMSActivity activity) {
public void onGlobalLayout() { mActivity = new WeakReference<SMSActivity>(activity);
// 滚动到底部 }
mScrollView1.post(new Runnable() { public void handleMessage(Message msg) {
@Override SMSActivity theActivity = mActivity.get();
public void run() { switch (msg.what) {
mScrollView1.fullScroll(ScrollView.FOCUS_DOWN); case MSG_SET_FOCUS:
} theActivity.metSMSBody.setFocusable(true);
}); theActivity.metSMSBody.requestFocus();
break;
// 移除监听,避免重复触发 default:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) { break;
rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this); }
} else { super.handleMessage(msg);
rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this); }
} }
}
});
}
private void setupImeStatusListener() {
final View rootView = findViewById(android.R.id.content);
rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
int rootViewHeight = rootView.getHeight();
int screenHeight = getResources().getDisplayMetrics().heightPixels;
int imeThreshold = dp2px(200);
boolean currentImeVisible = (screenHeight - rootViewHeight) > imeThreshold;
if (currentImeVisible != isImeVisible) {
isImeVisible = currentImeVisible;
setupScrollView1Height();
if (!isImeVisible) {
metSMSBody.clearFocus();
}
}
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
} else {
rootView.getViewTreeObserver().removeGlobalOnLayoutListener(this);
}
setupImeStatusListener();
}
});
}
private int dp2px(int dp) {
return (int) (dp * getResources().getDisplayMetrics().density + 0.5f);
}
/*static class MyHandler extends Handler {
WeakReference<SMSActivity> mActivity;
MyHandler(SMSActivity activity) {
mActivity = new WeakReference<SMSActivity>(activity);
}
public void handleMessage(Message msg) {
SMSActivity theActivity = mActivity.get();
switch (msg.what) {
case MSG_SET_FOCUS:
theActivity.metSMSBody.setFocusable(true);
theActivity.metSMSBody.requestFocus();
theActivity.setupScrollView1Height();
break;
default:
break;
}
super.handleMessage(msg);
}
}*/
@Override @Override
protected void onDestroy() { protected void onDestroy() {
@@ -143,130 +94,135 @@ public class SMSActivity extends BaseActivity {
} }
void initView() { void initView() {
// 发送端空号码退出
mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE); mszPhoneTo = getIntent().getStringExtra(EXTRA_PHONE);
if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) { if (mszPhoneTo == null || mszPhoneTo.trim().equals("")) {
finish(); finish();
} }
mToolbar = (Toolbar) findViewById(R.id.activitysmsASupportToolbar1); // 初始化标题栏
mToolbar = findViewById(R.id.activitysmsASupportToolbar1);
mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + AddressUtils.getFormattedAddress(mszPhoneTo) + " >"); mToolbar.setSubtitle(getString(R.string.activity_name_smsinphone) + " < Phone : " + AddressUtils.getFormattedAddress(mszPhoneTo) + " >");
setActionBar(mToolbar); setActionBar(mToolbar);
mScrollView1 = (BottomPositionFixedScrollView) findViewById(R.id.activitysmsScrollView1); // 初始化滚动窗口
mScrollView = findViewById(R.id.activitysmsinphoneScrollView1);
metSMSBody = (EditText) findViewById(R.id.viewsmssendpart1EditText1); // 初始化发送消息框
metSMSBody.setOnClickListener(new View.OnClickListener() { //Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame);
@Override metSMSBody = findViewById(R.id.viewsmssendpart1EditText1);
public void onClick(View v) { //metSMSBody.setBackground(drawableFrame);
setupScrollView1Height();
}
});
metSMSBody.setOnFocusChangeListener(new View.OnFocusChangeListener() {
@Override
public void onFocusChange(View v, boolean hasFocus) {
setupScrollView1Height();
}
});
final AOHPCTCSeekBar aOHPCTCSeekBar = (AOHPCTCSeekBar) findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1); // 初始化发送拉动控件
final AOHPCTCSeekBar aOHPCTCSeekBar = findViewById(R.id.viewsmssendpart1AOHPCTCSeekBar1);
aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message)); aOHPCTCSeekBar.setThumb(getDrawable(R.drawable.ic_message));
aOHPCTCSeekBar.setThumbOffset(20); aOHPCTCSeekBar.setThumbOffset(20);
aOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() { aOHPCTCSeekBar.setOnOHPCListener(
@Override new AOHPCTCSeekBar.OnOHPCListener(){
public void onOHPCommit() { @Override
sendSMS(); public void onOHPCommit() {
} //Toast.makeText(getApplication(), "Send", Toast.LENGTH_SHORT).show();
}); sendSMS();
}
});
TextView tvAOHPCTCSeekBarMSG = (TextView) findViewById(R.id.viewsmssendpart1TextView1); // 初始化提示框
TextView tvAOHPCTCSeekBarMSG = findViewById(R.id.viewsmssendpart1TextView1);
tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg); tvAOHPCTCSeekBarMSG.setText(R.string.msg_100sendmsg);
mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsSMSListViewForScrollView1); mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsinphoneListView1);
// 准备数据
mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo); mSMSArrayAdapter = new SMSArrayAdapter(SMSActivity.this, mszPhoneTo);
mlvSMS.setAdapter(mSMSArrayAdapter); mlvSMS.setAdapter(mSMSArrayAdapter);
// 设置短信列表滚动到底部就取消已发送的通知消息
//
mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() { mlvSMS.setOnScrollListener(new AbsListView.OnScrollListener() {
@Override @Override
public void onScrollStateChanged(AbsListView view, int scrollState) {} public void onScrollStateChanged(AbsListView view, int scrollState) {
}
@Override @Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) { if (firstVisibleItem + visibleItemCount == totalItemCount && totalItemCount > 0) {
mSMSArrayAdapter.cancelMessageNotification(); // 滑动到了底部
} mSMSArrayAdapter.cancelMessageNotification();
} }
}); }
});
mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver(); mSMSActivityBroadcastReceiver = new SMSActivityBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter(ACTION_NOTIFY_SMS_CHANGED); IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(ACTION_NOTIFY_SMS_CHANGED);
LocalBroadcastManager.getInstance(this).registerReceiver(mSMSActivityBroadcastReceiver, intentFilter); LocalBroadcastManager.getInstance(this).registerReceiver(mSMSActivityBroadcastReceiver, intentFilter);
/*SMSView mSMSView = findViewById(R.id.viewsmssendSMSView1);
mSMSView.setSMSType(SMSView.SMSType.SEND);*/
} }
private void setupScrollView1Height() { //
mScrollView1.postDelayed(new Runnable() { // 更新信息列表
@Override //
public void run() {
final ScrollView scrollView2 = (ScrollView) findViewById(R.id.activitysmsScrollView2);
final BottomPositionFixedScrollView scrollView1 = (BottomPositionFixedScrollView) findViewById(R.id.activitysmsScrollView1);
final View includeView = findViewById(R.id.activitysmsinclude1);
scrollView2.post(new Runnable() {
@Override
public void run() {
int scrollView2Height = scrollView2.getHeight();
int includeHeight = includeView.getHeight();
int targetHeight = Math.max(scrollView2Height - includeHeight, 0);
LinearLayout.LayoutParams params = (LinearLayout.LayoutParams) scrollView1.getLayoutParams();
params.height = targetHeight;
scrollView1.setLayoutParams(params);
}
});
}
}, 100);
}
public void updateSMSView() { public void updateSMSView() {
mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo); mSMSArrayAdapter.reLoadSMSList(SMSActivity.this, mszPhoneTo);
mSMSArrayAdapter.notifyDataSetChanged(); mSMSArrayAdapter.notifyDataSetChanged();
} }
//
// 滚动消息文本框
//
void scrollScrollView() { void scrollScrollView() {
ViewUtil.scrollScrollView(mScrollView1);
ViewUtil.scrollScrollView(mScrollView);
} }
//
// 发送短信
//
void sendSMS() { void sendSMS() {
// 空消息不发送
String szSMSBody = metSMSBody.getText().toString(); String szSMSBody = metSMSBody.getText().toString();
if (szSMSBody.equals("")) { if (szSMSBody.equals("")) {
Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show(); Toast.makeText(getApplication(), "没有消息内容可发送。", Toast.LENGTH_SHORT).show();
return; return;
} }
// 发送短信
if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) { if (SMSUtil.sendMessageByInterface2(this, mszPhoneTo, szSMSBody)) {
metSMSBody.setText(""); metSMSBody.setText("");
metSMSBody.clearFocus(); new Handler().postDelayed(new Runnable(){
new Handler().postDelayed(new Runnable() { @Override
@Override public void run() {
public void run() { updateSMSView();
updateSMSView(); ViewUtil.scrollScrollView(mScrollView);
ViewUtil.scrollScrollView(mScrollView1); }
} }, 1000);
}, 1000);
} }
} }
class SMSActivityBroadcastReceiver extends BroadcastReceiver { class SMSActivityBroadcastReceiver extends BroadcastReceiver {
public SMSActivityBroadcastReceiver() {}
public SMSActivityBroadcastReceiver() {
//LogUtils.d(TAG, "SMSActivityBroadcastReceiver()");
}
@Override @Override
public void onReceive(Context context, Intent intent) { public void onReceive(Context context, Intent intent) {
if (ACTION_NOTIFY_SMS_CHANGED.equals(intent.getAction())) { switch (intent.getAction()) {
updateSMSView(); case ACTION_NOTIFY_SMS_CHANGED :
ViewUtil.scrollScrollView(mScrollView1); //Toast.makeText(context, "ACTION_NOTIFY_SMS_CHANGED", Toast.LENGTH_SHORT).show();
} else { updateSMSView();
throw new IllegalStateException("Unexpected value: " + intent.getAction()); ViewUtil.scrollScrollView(mScrollView);
//LogUtils.d(TAG, "ACTION_NOTIFY_SMS_CHANGED");
break;
default:
throw new IllegalStateException("Unexpected value: " + intent.getAction());
} }
}
}
}
}
}
}

View File

@@ -1,8 +1,8 @@
package cc.winboll.studio.mymessagemanager.utils; package cc.winboll.studio.mymessagemanager.utils;
/** /**
* @Author ZhanGSKen&豆包大模型<zhangsken@188.com> * @Author ZhanGSKen<zhangsken@188.com>
* @Date 2025/08/30 14:32 * @Date 2024/07/19 14:30:57
* @Describe 手机联系人工具类 * @Describe 手机联系人工具类
*/ */
import android.content.ContentResolver; import android.content.ContentResolver;
@@ -11,7 +11,6 @@ import android.database.Cursor;
import android.net.Uri; import android.net.Uri;
import android.provider.ContactsContract; import android.provider.ContactsContract;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libapputils.utils.RegexPPiUtils;
import cc.winboll.studio.mymessagemanager.beans.PhoneBean; import cc.winboll.studio.mymessagemanager.beans.PhoneBean;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
@@ -19,11 +18,6 @@ import java.util.Comparator;
import java.util.List; import java.util.List;
import java.util.regex.Matcher; import java.util.regex.Matcher;
import java.util.regex.Pattern; import java.util.regex.Pattern;
import net.sourceforge.pinyin4j.PinyinHelper;
import net.sourceforge.pinyin4j.format.HanyuPinyinCaseType;
import net.sourceforge.pinyin4j.format.HanyuPinyinOutputFormat;
import net.sourceforge.pinyin4j.format.HanyuPinyinToneType;
import net.sourceforge.pinyin4j.format.exception.BadHanyuPinyinOutputFormatCombination;
public class PhoneUtil { public class PhoneUtil {
@@ -44,137 +38,28 @@ public class PhoneUtil {
} }
// 读取所有联系人 // 读取所有联系人
//
public List<PhoneBean> getPhoneList() { public List<PhoneBean> getPhoneList() {
List<PhoneBean> listPhoneBean = new ArrayList<>(); List<PhoneBean> listPhoneBean = new ArrayList<>();
ContentResolver cr = mContext.getContentResolver(); ContentResolver cr = mContext.getContentResolver();
Cursor cursor = cr.query(mUriPhoneContent, new String[]{NUMBER, DISPLAY_NAME}, null, null, null); Cursor cursor = cr.query(mUriPhoneContent, new String[]{NUMBER, DISPLAY_NAME}, null, null, null);
if (cursor != null) { while (cursor.moveToNext()) {
while (cursor.moveToNext()) { PhoneBean phoneBean = new PhoneBean(cursor.getString(1), cursor.getString(0).replaceAll("\\s", ""));
// 去除号码中的空格 listPhoneBean.add(phoneBean);
String phone = cursor.getString(0).replaceAll("\\s", "");
String name = cursor.getString(1); }
PhoneBean phoneBean = new PhoneBean(name, phone); cursor.close();
listPhoneBean.add(phoneBean);
}
cursor.close();
}
// 按电话号码排序
Collections.sort(listPhoneBean, new Comparator<PhoneBean>() { Collections.sort(listPhoneBean, new Comparator<PhoneBean>() {
@Override @Override
public int compare(PhoneBean o1, PhoneBean o2) { public int compare(PhoneBean o1, PhoneBean o2) {
return o1.getTelPhone().compareTo(o2.getTelPhone()); return o1.getTelPhone().compareTo(o2.getTelPhone());
} }
}); });
return listPhoneBean; return listPhoneBean;
} }
/**
* 根据联系人名称查询号码(兼容拼音查询)
* @param keyword 搜索关键词(支持汉字、拼音、拼音首字母)
* @return 匹配的联系人列表(包含姓名和号码)
*/
public List<PhoneBean> getPhonesByName(String keyword) {
List<PhoneBean> result = new ArrayList<>();
if (keyword == null || keyword.trim().isEmpty()) {
return result; // 关键词为空,返回空列表
}
// 获取所有联系人
List<PhoneBean> allContacts = getPhoneList();
// 统一转为小写,忽略大小写
String keywordLower = keyword.trim().toLowerCase();
for (PhoneBean contact : allContacts) {
String name = contact.getName();
if (name == null || name.isEmpty()) {
continue;
}
// 1. 直接匹配姓名(包含关键词)
if (name.toLowerCase().contains(keywordLower)) {
result.add(contact);
continue;
}
// 2. 匹配姓名的全拼(包含关键词)
String namePinyin = getPinyin(name).toLowerCase();
if (namePinyin.contains(keywordLower)) {
result.add(contact);
continue;
}
// 3. 匹配姓名的拼音首字母(包含关键词)
String namePinyinFirstLetter = getPinyinFirstLetter(name).toLowerCase();
if (namePinyinFirstLetter.contains(keywordLower)) {
result.add(contact);
continue;
}
}
return result;
}
/**
* 将汉字转为全拼(不带声调,小写)
* 例如:"张三" → "zhangsan"
*/
private String getPinyin(String chinese) {
StringBuilder pinyin = new StringBuilder();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE); // 小写
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE); // 不带声调
char[] chars = chinese.toCharArray();
for (char c : chars) {
// 如果是汉字,转换为拼音;否则直接拼接(如字母、数字、符号)
if (Character.toString(c).matches("[\\u4e00-\\u9fa5]")) {
try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (pinyinArray != null && pinyinArray.length > 0) {
pinyin.append(pinyinArray[0]); // 取第一个拼音(多音字默认取第一个)
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
LogUtils.e(TAG, "拼音转换失败:" + e.getMessage());
}
} else {
pinyin.append(c);
}
}
return pinyin.toString();
}
/**
* 将汉字转为拼音首字母(小写)
* 例如:"张三" → "zs"
*/
private String getPinyinFirstLetter(String chinese) {
StringBuilder firstLetters = new StringBuilder();
HanyuPinyinOutputFormat format = new HanyuPinyinOutputFormat();
format.setCaseType(HanyuPinyinCaseType.LOWERCASE);
format.setToneType(HanyuPinyinToneType.WITHOUT_TONE);
char[] chars = chinese.toCharArray();
for (char c : chars) {
if (Character.toString(c).matches("[\\u4e00-\\u9fa5]")) {
try {
String[] pinyinArray = PinyinHelper.toHanyuPinyinStringArray(c, format);
if (pinyinArray != null && pinyinArray.length > 0) {
// 取拼音首字母(如"zhang" → "z"
firstLetters.append(pinyinArray[0].charAt(0));
}
} catch (BadHanyuPinyinOutputFormatCombination e) {
LogUtils.e(TAG, "拼音首字母转换失败:" + e.getMessage());
}
} else {
// 非汉字直接拼接首字符(如"李3" → "l3"
firstLetters.append(c);
}
}
return firstLetters.toString();
}
public boolean isPhoneInContacts(String szPhone) { public boolean isPhoneInContacts(String szPhone) {
List<PhoneBean> listPhoneDto = getPhoneList(); List<PhoneBean> listPhoneDto = getPhoneList();
LogUtils.d(TAG, String.format("isPhoneInContacts(...) listPhoneDto.size() %d", listPhoneDto.size())); LogUtils.d(TAG, String.format("isPhoneInContacts(...) listPhoneDto.size() %d", listPhoneDto.size()));
@@ -185,56 +70,49 @@ public class PhoneUtil {
} }
return false; return false;
} }
public String getNameByPhone(String szPhone) { boolean isTheSamePhoneNumber(String szNum1, String szNum2) {
if (szPhone == null || szPhone.equals("")) { //LogUtils.d(TAG, String.format("szNum1 %s\nszNum2 %s", szNum1, szNum2));
return ""; if(szNum1.equals(szNum2)) {
}
List<PhoneBean> listPhoneDto = getPhoneList();
LogUtils.d(TAG, String.format("getNameByPhone(...) listPhoneDto.size() %d", listPhoneDto.size()));
for (int i = 0; i < listPhoneDto.size(); i++) {
if (isTheSamePhoneNumber(listPhoneDto.get(i).getTelPhone(), szPhone)) {
return listPhoneDto.get(i).getName();
}
}
return "";
}
public boolean isTheSamePhoneNumber(String szNum1, String szNum2) {
if (szNum1.equals(szNum2)) {
LogUtils.d(TAG, "szNum1.equals(szNum2)"); LogUtils.d(TAG, "szNum1.equals(szNum2)");
return true; return true;
} }
if (UnitAreaUtils.getInstance(mContext).isCurrentUnitAreaNumber(szNum1)) { if(UnitAreaUtils.getInstance(mContext).isCurrentUnitAreaNumber(szNum1)) {
if (szNum1.equals(UnitAreaUtils.getInstance(mContext).genCurrentUnitAreaNumber(szNum2))) { if(szNum1.equals(UnitAreaUtils.getInstance(mContext).genCurrentUnitAreaNumber(szNum2))) {
LogUtils.d(TAG, "szNum1.equals(UnitAreaUtils.genCurrentUnitAreaNumber(szNum2))"); LogUtils.d(TAG, "szNum1.equals(UnitAreaUtils.genCurrentUnitAreaNumber(szNum2))");
return true; return true;
} }
} }
if (UnitAreaUtils.getInstance(mContext).isCurrentUnitAreaNumber(szNum2)) { if(UnitAreaUtils.getInstance(mContext).isCurrentUnitAreaNumber(szNum2)) {
if (szNum2.equals(UnitAreaUtils.getInstance(mContext).genCurrentUnitAreaNumber(szNum1))) { if(szNum2.equals(UnitAreaUtils.getInstance(mContext).genCurrentUnitAreaNumber(szNum1))) {
LogUtils.d(TAG, "szNum2.equals(UnitAreaUtils.genCurrentUnitAreaNumber(szNum1))"); LogUtils.d(TAG, "szNum2.equals(UnitAreaUtils.genCurrentUnitAreaNumber(szNum1))");
return true; return true;
} }
} }
LogUtils.d(TAG, "isTheSamePhoneNumber(...) return false;"); LogUtils.d(TAG, "isTheSamePhoneNumber(...) return false;");
return false; return false;
} }
//
// 检验电话号码是否是数字 // 检验电话号码是否是数字
//
public static boolean isPhoneByDigit(String szPhone) { public static boolean isPhoneByDigit(String szPhone) {
if (!RegexPPiUtils.isPPiOK(szPhone)) { if(!RegexPPiUtils.isPPiOK(szPhone)) {
return false; return false;
} }
//String text = "这里是一些任意的文本内容";
String regex = "[+]?\\d+"; String regex = "[+]?\\d+";
Pattern pattern = Pattern.compile(regex); Pattern pattern = Pattern.compile(regex);
Matcher matcher = pattern.matcher(szPhone); Matcher matcher = pattern.matcher(szPhone);
LogUtils.d(TAG, String.format("matcher.matches() : %s", matcher.matches())); LogUtils.d(TAG, String.format("matcher.matches() : %s", matcher.matches()));
/*if (matcher.matches()) {
System.out.println("文本满足该正则表达式模式");
} else {
System.out.println("文本不满足该正则表达式模式");
}*/
return matcher.matches(); return matcher.matches();
} }
} }

View File

@@ -0,0 +1,32 @@
package cc.winboll.studio.mymessagemanager.utils;
/**
* @Author ZhanGSKen<zhangsken@188.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();
}
}

View File

@@ -8,7 +8,6 @@ package cc.winboll.studio.mymessagemanager.utils;
import android.content.Context; import android.content.Context;
import android.util.JsonReader; import android.util.JsonReader;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.libapputils.utils.RegexPPiUtils;
import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean; import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean;
import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean_V1; import cc.winboll.studio.mymessagemanager.beans.SMSAcceptRuleBean_V1;
import java.io.IOException; import java.io.IOException;

View File

@@ -10,9 +10,9 @@ import cc.winboll.studio.mymessagemanager.beans.AppConfigBean;
import android.content.Context; import android.content.Context;
public class UnitAreaUtils { public class UnitAreaUtils {
public static final String TAG = "UnitAreaUtils"; public static final String TAG = "UnitAreaUtils";
static UnitAreaUtils _UnitAreaUtils; static UnitAreaUtils _UnitAreaUtils;
Context mContext; Context mContext;
@@ -26,25 +26,19 @@ public class UnitAreaUtils {
} }
return _UnitAreaUtils; return _UnitAreaUtils;
} }
public boolean isCurrentUnitAreaNumber(String szPhoneNumer) { public boolean isCurrentUnitAreaNumber(String szPhoneNumer) {
String szUnitArea = getUnitArea(); String szUnitArea = getUnitArea();
try { LogUtils.d(TAG, String.format("szPhoneNumer.substring(1,3) %s", szPhoneNumer.substring(1,3)));
String szPhoneNumerUnitArea = szPhoneNumer.substring(1, 3); return szPhoneNumer.substring(1,3).equals(szUnitArea);
LogUtils.d(TAG, String.format("szPhoneNumerUnitArea %s", szPhoneNumerUnitArea));
return szPhoneNumerUnitArea.equals(szUnitArea);
} catch (StringIndexOutOfBoundsException e) {
LogUtils.d(TAG, e, Thread.currentThread().getStackTrace());
}
return false;
} }
public String genCurrentUnitAreaNumber(String szPhoneNumer) { public String genCurrentUnitAreaNumber(String szPhoneNumer) {
String szUnitArea = getUnitArea(); String szUnitArea = getUnitArea();
LogUtils.d(TAG, String.format("szUnitArea %s", szUnitArea)); LogUtils.d(TAG, String.format("szUnitArea %s", szUnitArea));
return "+" + szUnitArea + szPhoneNumer; return "+" + szUnitArea + szPhoneNumer;
} }
String getUnitArea() { String getUnitArea() {
String szUnitArea = AppConfigUtil.getInstance(mContext).mAppConfigBean.getCountryCode(); String szUnitArea = AppConfigUtil.getInstance(mContext).mAppConfigBean.getCountryCode();
LogUtils.d(TAG, String.format("szUnitArea %s", szUnitArea)); LogUtils.d(TAG, String.format("szUnitArea %s", szUnitArea));

View File

@@ -1,125 +0,0 @@
package cc.winboll.studio.mymessagemanager.views;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@188.com>
* @Date 2025/08/23 00:39
* @Describe 多级拉动响应自定义控件
*/
import android.content.Context;
import android.util.AttributeSet;
import android.view.ViewTreeObserver;
import android.widget.ScrollView;
public class BottomPositionFixedScrollView extends ScrollView {
public static final String TAG = "BottomPositionFixedScrollView";
// 记录底部对应的内容绝对位置即底部位置在内容中的y坐标该位置需始终保持在视图底部
private int mBottomContentY = 0;
// 标记是否是首次布局(避免初始加载误触发)
private boolean isFirstLayout = true;
public BottomPositionFixedScrollView(Context context) {
super(context);
init();
}
public BottomPositionFixedScrollView(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public BottomPositionFixedScrollView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init();
}
private void init() {
// 监听布局变化(高度改变时触发)
getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
@Override
public void onGlobalLayout() {
if (isFirstLayout) {
isFirstLayout = false;
return;
}
// 布局变化后,恢复底部位置
restoreBottomPosition();
}
});
}
/**
* 重写滚动事件,记录“底部对应的内容绝对位置”
* 即当前视图底部边缘对应的内容y坐标该坐标需始终保持在视图底部
*/
@Override
protected void onScrollChanged(int l, int t, int oldl, int oldt) {
super.onScrollChanged(l, t, oldl, oldt);
if (getChildCount() == 0) {
mBottomContentY = 0;
return;
}
// 内容总高度
int contentHeight = getChildAt(0).getMeasuredHeight();
// 视图可视高度(自身高度)
int scrollViewHeight = getMeasuredHeight();
// 当前视图底部边缘对应的内容y坐标 = 顶部滚动距离(t) + 可视高度
// (该坐标就是“底部内容的绝对位置”,需始终保持在视图底部)
mBottomContentY = t + scrollViewHeight;
// 避免超过内容总高度(比如内容不足一屏时,底部最多到内容底部)
if (mBottomContentY > contentHeight) {
mBottomContentY = contentHeight;
}
}
/**
* 恢复底部位置:让原记录的“底部内容绝对位置”仍保持在视图底部
*/
private void restoreBottomPosition() {
if (getChildCount() == 0) {
return;
}
// 新的内容总高度
int newContentHeight = getChildAt(0).getMeasuredHeight();
// 新的视图可视高度
int newScrollViewHeight = getMeasuredHeight();
// 目标让原mBottomContentY底部内容绝对位置仍位于视图底部
// 此时需要的顶部滚动距离 = mBottomContentY - 新的可视高度
int targetScrollY = mBottomContentY - newScrollViewHeight;
// 边界修正:
// 1. 不能小于0避免滚动到负数位置
// 2. 不能大于“最大可滚动距离”(内容高度 - 可视高度,避免超出内容范围)
int maxScrollY = Math.max(newContentHeight - newScrollViewHeight, 0);
targetScrollY = Math.max(targetScrollY, 0);
targetScrollY = Math.min(targetScrollY, maxScrollY);
// 滚动到目标位置,保持底部内容位置不变
smoothScrollTo(0, targetScrollY);
}
/**
* 外部手动设置底部内容绝对位置(可选)
*/
public void setBottomContentY(int bottomContentY) {
if (getChildCount() == 0) {
mBottomContentY = bottomContentY;
return;
}
// 限制不超过内容总高度
int contentHeight = getChildAt(0).getMeasuredHeight();
mBottomContentY = Math.min(bottomContentY, contentHeight);
restoreBottomPosition();
}
/**
* 获取当前底部内容绝对位置(可选)
*/
public int getBottomContentY() {
return mBottomContentY;
}
}

View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">
<!-- 选中状态:深灰色背景(可根据需求调整颜色) -->
<item android:state_selected="true" android:drawable="@color/list_item_selected"/>
<!-- 按压状态:浅灰色背景 -->
<item android:state_pressed="true" android:drawable="@color/list_item_pressed"/>
<!-- 默认状态:透明背景 -->
<item android:drawable="@android:color/transparent"/>
</selector>

View File

@@ -1,112 +1,71 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
android:orientation="vertical" android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent"> android:layout_height="match_parent">
<cc.winboll.studio.libaes.views.AToolbar <cc.winboll.studio.libaes.views.AToolbar
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="@dimen/toolbar_height" android:layout_height="@dimen/toolbar_height"
android:id="@+id/activitycomposesmsASupportToolbar1"/> android:id="@+id/activitycomposesmsASupportToolbar1"/>
<LinearLayout <LinearLayout
android:orientation="horizontal" android:orientation="horizontal"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:background="@drawable/bg_frame"> android:background="@drawable/bg_frame">
<RelativeLayout <RelativeLayout
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitycomposesmsRelativeLayout1"> android:id="@+id/activitycomposesmsRelativeLayout1">
<LinearLayout <TextView
android:orientation="horizontal" android:layout_width="wrap_content"
android:layout_width="wrap_content" android:layout_height="wrap_content"
android:layout_height="wrap_content" android:text="SMS TO : "
android:id="@+id/activitycomposesmsLinearLayout1" android:id="@+id/activitycomposesmsTextView1"
android:gravity="center_vertical" android:layout_alignParentLeft="true"
android:layout_alignParentRight="true" android:layout_marginLeft="10dp"
android:layout_marginRight="10dp" android:layout_centerVertical="true"/>
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true">
<TextView <EditText
android:layout_width="wrap_content" android:layout_toRightOf="@id/activitycomposesmsTextView1"
android:layout_height="wrap_content" android:layout_width="wrap_content"
android:text="(拼音搜索):"/> android:inputType="phone"
android:layout_height="wrap_content"
android:ems="10"
android:id="@+id/activitycomposesmsEditText1"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_centerVertical="true"/>
<EditText </RelativeLayout>
android:layout_width="80dp"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/activitycomposesmsEditText2"/>
<TextView </LinearLayout>
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentTop="true"
android:layout_toRightOf="@id/activitycomposesmsEditText2"
android:id="@+id/activitycomposesmsTextView2"
android:layout_weight="1.0"/>
</LinearLayout> <RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="10dp"
android:layout_weight="1.0">
<LinearLayout <ListView
android:orientation="horizontal" android:layout_alignParentTop="true"
android:layout_below="@id/activitycomposesmsLinearLayout1" android:layout_width="match_parent"
android:layout_alignParentRight="true" android:layout_height="wrap_content"
android:layout_marginRight="10dp" android:layout_above="@+id/activitycomposesmsinclude1"
android:layout_marginLeft="10dp" android:id="@+id/activitycomposesmsListView1"/>
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView <include
android:layout_width="wrap_content" layout="@layout/view_smssend"
android:layout_height="wrap_content" android:layout_alignParentBottom="true"
android:text="(SMS TO) :" android:layout_width="match_parent"
android:id="@+id/activitycomposesmsTextView1"/> android:layout_height="wrap_content"
android:id="@+id/activitycomposesmsinclude1"/>
<EditText </RelativeLayout>
android:layout_width="wrap_content"
android:inputType="phone"
android:layout_height="wrap_content"
android:ems="10"
android:id="@+id/activitycomposesmsEditText1"/>
</LinearLayout>
</RelativeLayout>
</LinearLayout>
<RelativeLayout
android:layout_width="match_parent"
android:layout_height="0dp"
android:padding="10dp"
android:layout_weight="1.0">
<!-- 关键修改:添加 listSelector 属性,关联选中样式 -->
<ListView
android:layout_alignParentTop="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_above="@+id/activitycomposesmsinclude1"
android:id="@+id/activitycomposesmsListView1"
android:listSelector="@drawable/listview_item_selector"
android:choiceMode="singleChoice"/> <!-- 开启单选模式,确保选中状态唯一 -->
<include
layout="@layout/view_smssend"
android:layout_alignParentBottom="true"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitycomposesmsinclude1"/>
</RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@@ -27,7 +27,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="60dp" android:layout_height="60dp"
android:padding="10dp" android:padding="10dp"
android:text="@string/text_norulesreceivecontacts" android:text="@string/text_onlyreceivecontacts"
android:id="@+id/activitymainSwitchView2"/> android:id="@+id/activitymainSwitchView2"/>
<cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView <cc.winboll.studio.mymessagemanager.views.ConfirmSwitchView

View File

@@ -10,40 +10,36 @@
android:layout_height="@dimen/toolbar_height" android:layout_height="@dimen/toolbar_height"
android:id="@+id/activitysmsASupportToolbar1"/> android:id="@+id/activitysmsASupportToolbar1"/>
<ScrollView <RelativeLayout
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
android:layout_weight="1.0" android:paddingBottom="10dp">
android:id="@+id/activitysmsScrollView2">
<LinearLayout <ScrollView
android:orientation="vertical" android:layout_alignParentTop="true"
android:layout_above="@+id/activitysmsinclude1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="0dp"
android:id="@+id/activitysmsLinearLayout1"> android:id="@+id/activitysmsinphoneScrollView1"
android:layout_weight="1.0"
android:isScrollContainer="false">
<cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView <cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView
android:layout_width="match_parent"
android:layout_height="520dp"
android:isScrollContainer="false"
android:id="@+id/activitysmsScrollView1">
<cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitysmsSMSListViewForScrollView1"/>
</cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView>
<include
layout="@layout/view_smssend"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitysmsinclude1"/> android:id="@+id/activitysmsinphoneListView1"/>
</LinearLayout>
</ScrollView> </ScrollView>
<include
android:layout_alignParentBottom="true"
layout="@layout/view_smssend"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/activitysmsinclude1"/>
</RelativeLayout>
</LinearLayout> </LinearLayout>

View File

@@ -7,18 +7,6 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:padding="10dp"> android:padding="10dp">
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="20sp"
android:id="@+id/viewsmssendpart1TextView1"/>
<cc.winboll.studio.libaes.views.AOHPCTCSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/viewsmssendpart1AOHPCTCSeekBar1"/>
<EditText <EditText
android:scrollbars="vertical" android:scrollbars="vertical"
android:maxHeight="150dp" android:maxHeight="150dp"
@@ -29,6 +17,17 @@
android:id="@+id/viewsmssendpart1EditText1" android:id="@+id/viewsmssendpart1EditText1"
android:background="@drawable/bg_frame"/> android:background="@drawable/bg_frame"/>
<cc.winboll.studio.libaes.views.AOHPCTCSeekBar
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:id="@+id/viewsmssendpart1AOHPCTCSeekBar1"/>
<TextView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:textSize="20sp"
android:id="@+id/viewsmssendpart1TextView1"/>
</LinearLayout> </LinearLayout>

View File

@@ -32,7 +32,7 @@
<string name="text_item_rule_clean">清理设置</string> <string name="text_item_rule_clean">清理设置</string>
<string name="text_sendsms">发送短信</string> <string name="text_sendsms">发送短信</string>
<string name="text_mainservice">短信服务管理总开关</string> <string name="text_mainservice">短信服务管理总开关</string>
<string name="text_norulesreceivecontacts">无限制接收联系人短信</string> <string name="text_onlyreceivecontacts">接收联系人短信</string>
<string name="text_usingtts">使用TTS语音播报</string> <string name="text_usingtts">使用TTS语音播报</string>
<string name="text_usingttsrule">使用TTS语音自定义规则</string> <string name="text_usingttsrule">使用TTS语音自定义规则</string>
<string name="text_iamhere">短信管理服务已启动。</string> <string name="text_iamhere">短信管理服务已启动。</string>
@@ -41,6 +41,6 @@
<string name="text_appsettings">应用设置</string> <string name="text_appsettings">应用设置</string>
<string name="text_ttsplaydelaytimes">TTS播放延迟时间</string> <string name="text_ttsplaydelaytimes">TTS播放延迟时间</string>
<string name="msg_newsms">接收到新的消息。</string> <string name="msg_newsms">接收到新的消息。</string>
<string name="msg_100sendmsg">&gt;&gt;&gt;拉动到100%可发信息&gt;&gt;&gt;</string> <string name="msg_100sendmsg">&gt;&gt;&gt;图标动到 100% 以发送信息&gt;&gt;&gt;</string>
<string name="msg_100applysettings">&gt;&gt;&gt;拉动到100%应用设置&gt;&gt;&gt;</string> <string name="msg_100applysettings">&gt;&gt;&gt;图标动到 100% 应用设置&gt;&gt;&gt;</string>
</resources> </resources>

View File

@@ -1,8 +1,5 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<resources> <resources>
<color name="white">#FFFFFFFF</color>
<color name="colorSMSSendColor">#FFDCDA3D</color> <color name="colorSMSSendColor">#FFDCDA3D</color>
<color name="colorSMSInboxColor">#FF3DDC84</color> <color name="colorSMSInboxColor">#FF3DDC84</color>
<color name="colorTTSRuleViewBackgroundColor">#FFDCDA3D</color> <color name="colorTTSRuleViewBackgroundColor">#FFDCDA3D</color>
@@ -10,11 +7,11 @@
<color name="colorSMSSendColorDepth">#FFA28BFF</color> <color name="colorSMSSendColorDepth">#FFA28BFF</color>
<color name="colorSMSInboxColorDepth">#FF8BAEFF</color> <color name="colorSMSInboxColorDepth">#FF8BAEFF</color>
<color name="colorTTSRuleViewBackgroundColorDepth">#FFA28BFF</color> <color name="colorTTSRuleViewBackgroundColorDepth">#FFA28BFF</color>
<color name="colorSMSSendColorSky">#FFFFEB8C</color> <color name="colorSMSSendColorSky">#FFFFEB8C</color>
<color name="colorSMSInboxColorSky">#FF8CD9FF</color> <color name="colorSMSInboxColorSky">#FF8CD9FF</color>
<color name="colorTTSRuleViewBackgroundColorSky">#FFFFEB8C</color> <color name="colorTTSRuleViewBackgroundColorSky">#FFFFEB8C</color>
<color name="colorSMSSendColorGolden">#FF78BDFF</color> <color name="colorSMSSendColorGolden">#FF78BDFF</color>
<color name="colorSMSInboxColorGolden">#FFFFED78</color> <color name="colorSMSInboxColorGolden">#FFFFED78</color>
<color name="colorTTSRuleViewBackgroundColorGolden">#FF78BDFF</color> <color name="colorTTSRuleViewBackgroundColorGolden">#FF78BDFF</color>
@@ -22,13 +19,9 @@
<color name="colorSMSSendColorMemor">#FF5AEB53</color> <color name="colorSMSSendColorMemor">#FF5AEB53</color>
<color name="colorSMSInboxColorMemor">#FFE653EB</color> <color name="colorSMSInboxColorMemor">#FFE653EB</color>
<color name="colorTTSRuleViewBackgroundColorMemor">#FF5AEB53</color> <color name="colorTTSRuleViewBackgroundColorMemor">#FF5AEB53</color>
<color name="colorSMSSendColorTao">#FFB4B4B4</color> <color name="colorSMSSendColorTao">#FFB4B4B4</color>
<color name="colorSMSInboxColorTao">#FFD9D9D9</color> <color name="colorSMSInboxColorTao">#FFD9D9D9</color>
<color name="colorTTSRuleViewBackgroundColorTao">#FFB4B4B4</color> <color name="colorTTSRuleViewBackgroundColorTao">#FFB4B4B4</color>
<!-- 列表项选中颜色(深灰) -->
<color name="list_item_selected">#FF696969</color>
<!-- 列表项按压颜色(浅灰) -->
<color name="list_item_pressed">#FFE0E0E0</color>
</resources> </resources>

View File

@@ -34,7 +34,7 @@
<string name="text_item_rule_clean">Clean Setting</string> <string name="text_item_rule_clean">Clean Setting</string>
<string name="text_sendsms">Send SMS</string> <string name="text_sendsms">Send SMS</string>
<string name="text_mainservice">Main Service</string> <string name="text_mainservice">Main Service</string>
<string name="text_norulesreceivecontacts">No rules Receive Contacts</string> <string name="text_onlyreceivecontacts">Only Receive Contacts</string>
<string name="text_usingtts">Using TTS</string> <string name="text_usingtts">Using TTS</string>
<string name="text_usingttsrule">Using TTS Rule</string> <string name="text_usingttsrule">Using TTS Rule</string>
<string name="text_iamhere">The main service is start.</string> <string name="text_iamhere">The main service is start.</string>

View File

@@ -1,5 +1,7 @@
## TimpStamp ## TimpStamp
## 时间戳工具集
#### 介绍
时间戳工具集。常驻工具栏快捷拷贝一份时间戳到剪贴板的工具。
## 使用要点: ## 使用要点:
1。常驻通知栏按钮的正常使用 1。常驻通知栏按钮的正常使用

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Wed May 07 15:07:02 HKT 2025 #Mon Jul 28 11:36:51 HKT 2025
stageCount=2 stageCount=4
libraryProject= libraryProject=
baseVersion=15.1 baseVersion=15.1
publishVersion=15.1.1 publishVersion=15.1.3
buildCount=0 buildCount=0
baseBetaVersion=15.1.2 baseBetaVersion=15.1.4

View File

@@ -3,6 +3,9 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
package="cc.winboll.studio.timestamp"> package="cc.winboll.studio.timestamp">
<!-- 开机启动 -->
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>
<!-- 运行前台服务 --> <!-- 运行前台服务 -->
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/> <uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
@@ -45,6 +48,20 @@
<service android:name=".AssistantService"/> <service android:name=".AssistantService"/>
<receiver
android:name=".receivers.MainReceiver"
android:enabled="true"
android:exported="false"
android:directBootAware="true">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
</application> </application>
</manifest> </manifest>

View File

@@ -5,6 +5,7 @@ import android.view.View;
import android.widget.EditText; import android.widget.EditText;
import android.widget.Switch; import android.widget.Switch;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import androidx.appcompat.app.AppCompatActivity; import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.Toolbar; import androidx.appcompat.widget.Toolbar;
import cc.winboll.studio.libappbase.LogUtils; import cc.winboll.studio.libappbase.LogUtils;
@@ -12,6 +13,8 @@ import cc.winboll.studio.libappbase.LogView;
import cc.winboll.studio.timestamp.MainService; import cc.winboll.studio.timestamp.MainService;
import cc.winboll.studio.timestamp.R; import cc.winboll.studio.timestamp.R;
import cc.winboll.studio.timestamp.utils.AppConfigsUtil; import cc.winboll.studio.timestamp.utils.AppConfigsUtil;
import cc.winboll.studio.timestamp.utils.ClipboardUtil;
import cc.winboll.studio.timestamp.utils.TimeStampUtil;
import com.hjq.toast.ToastUtils; import com.hjq.toast.ToastUtils;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
@@ -97,4 +100,22 @@ public class MainActivity extends AppCompatActivity {
} }
return false; return false;
} }
public void onTimeStamp(View view) {
// 在这里编写按钮点击后要执行的代码
TimeStampUtil.getInstance(this).genTimeStamp();
String formattedDateTime = TimeStampUtil.getInstance(this).getTimeStampCopyString();
ClipboardUtil.copyTextToClipboard(this, formattedDateTime);
// 更新时间戳文本框显示内容
EditText etTimeStamp = findViewById(R.id.et_timestamp);
etTimeStamp.setText(formattedDateTime);
// 输出一个提示音
TimeStampUtil.getInstance(this).playNotifyMusic(this);
// 比如显示一个 Toast
Toast.makeText(this, "时间戳:\n" + TimeStampUtil.getInstance(this).getTimeStampCopyString() + "\n已拷贝到剪贴板。", Toast.LENGTH_SHORT).show();
MainService.updateCopiedTimeStamp();
}
} }

View File

@@ -0,0 +1,40 @@
package cc.winboll.studio.timestamp.receivers;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.timestamp.MainService;
import cc.winboll.studio.timestamp.models.AppConfigsModel;
import cc.winboll.studio.timestamp.utils.AppConfigsUtil;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@188.com>
* @Date 2025/07/28 11:15
* @Describe MainReceiver
*/
public class MainReceiver extends BroadcastReceiver {
public static final String TAG = "MainReceiver";
static final String ACTION_BOOT_COMPLETED = "android.intent.action.BOOT_COMPLETED";
AppConfigsUtil mAppConfigsUtil;
@Override
public void onReceive(Context context, Intent intent) {
String szAction = intent.getAction();
if (szAction.equals(ACTION_BOOT_COMPLETED)) {
AppConfigsModel appConfigs = AppConfigsUtil.getInstance(context).loadAppConfigs();
boolean isEnable = appConfigs.isEnableService();
AppConfigsUtil.getInstance(context).saveAppConfigs();
Intent intentMainService = new Intent(context, MainService.class);
if (isEnable) {
context.startService(intentMainService);
}
LogUtils.i(TAG, "System Boot And Start ManagerService Completed!");
}
}
}

View File

@@ -130,16 +130,10 @@ public class NotificationHelper {
mForegroundNotification.bigContentView = remoteViews; mForegroundNotification.bigContentView = remoteViews;
service.startForeground(ID_MSG_SERVICE, mForegroundNotification); service.startForeground(ID_MSG_SERVICE, mForegroundNotification);
// 播放默认短信铃声 TimeStampUtil.getInstance(service).playNotifyMusic(service);
Uri defaultSmsRingtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
AudioPlayerUriUtil.playAudio(service, defaultSmsRingtoneUri);
// 播放应用铃声
// 获取MP3文件的Uri
Uri soundUri = Uri.parse("android.resource://" + service.getPackageName() + "/" + R.raw.diweiyi);
AudioPlayerUriUtil.playAudio(service, soundUri);
} }

View File

@@ -6,6 +6,8 @@ package cc.winboll.studio.timestamp.utils;
* @Describe TimeStampUtil * @Describe TimeStampUtil
*/ */
import android.content.Context; import android.content.Context;
import android.net.Uri;
import cc.winboll.studio.timestamp.R;
import java.time.Instant; import java.time.Instant;
import java.time.LocalDateTime; import java.time.LocalDateTime;
import java.time.ZoneId; import java.time.ZoneId;
@@ -55,4 +57,19 @@ public class TimeStampUtil {
String formattedDateTime = ldt.format(formatter); String formattedDateTime = ldt.format(formatter);
return formattedDateTime; return formattedDateTime;
} }
//
// 播放时间戳确定时的提示音乐
//
public static void playNotifyMusic(Context context) {
// 播放默认短信铃声
//Uri defaultSmsRingtoneUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
//AudioPlayerUriUtil.playAudio(context, defaultSmsRingtoneUri);
// 播放应用铃声
// 获取MP3文件的Uri
Uri soundUri = Uri.parse("android.resource://" + context.getPackageName() + "/" + R.raw.diweiyi);
AudioPlayerUriUtil.playAudio(context, soundUri);
}
} }

View File

@@ -1,144 +1,180 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<LinearLayout <LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android" 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_width="wrap_content"
android:layout_height="match_parent" android:layout_height="wrap_content">
android:orientation="vertical">
<com.google.android.material.appbar.AppBarLayout <ScrollView
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<Switch
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启用时间戳常驻通知栏"
android:id="@+id/activitymainSwitch1"
android:onClick="onSetMainServiceStatus"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Format Preview:"
android:paddingRight="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/tv_timestampformatstring"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<EditText
android:layout_width="0dp"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/et_timestampformatstring"
android:layout_weight="1.0"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ApplyShow"
android:id="@+id/btn_saveformatstring"
android:textAllCaps="false"
android:onClick="onSaveFormatString"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Copy Format Preview:"
android:paddingRight="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/tv_timestampcopyformatstring"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<EditText
android:layout_width="0dp"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/et_timestampcopyformatstring"
android:layout_weight="1.0"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ApplyCopy"
android:id="@+id/btn_savecopyformatstring"
android:textAllCaps="false"
android:onClick="onSaveCopyFormatString"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1.0"
android:gravity="center_vertical|center_horizontal">
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="0dp"
android:layout_weight="1.0"> android:layout_weight="1.0">
<cc.winboll.studio.libappbase.LogView <LinearLayout
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:id="@+id/logview"/> android:orientation="vertical">
</LinearLayout> <com.google.android.material.appbar.AppBarLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar">
<androidx.appcompat.widget.Toolbar
android:id="@+id/toolbar"
android:layout_width="match_parent"
android:layout_height="?attr/actionBarSize"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</com.google.android.material.appbar.AppBarLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<Switch
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="启用时间戳常驻通知栏"
android:id="@+id/activitymainSwitch1"
android:onClick="onSetMainServiceStatus"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Show Format Preview:"
android:paddingRight="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/tv_timestampformatstring"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<EditText
android:layout_width="0dp"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/et_timestampformatstring"
android:layout_weight="1.0"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ApplyShow"
android:id="@+id/btn_saveformatstring"
android:textAllCaps="false"
android:onClick="onSaveFormatString"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Copy Format Preview:"
android:paddingRight="10dp"/>
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Text"
android:id="@+id/tv_timestampcopyformatstring"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:padding="10dp">
<EditText
android:layout_width="0dp"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/et_timestampcopyformatstring"
android:layout_weight="1.0"/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="ApplyCopy"
android:id="@+id/btn_savecopyformatstring"
android:textAllCaps="false"
android:onClick="onSaveCopyFormatString"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="当前截取的时间戳为:"/>
</LinearLayout>
<LinearLayout
android:orientation="vertical"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center_vertical|center_horizontal">
<ImageButton
android:layout_width="100dp"
android:layout_height="100dp"
android:onClick="onTimeStamp"
android:background="@drawable/ic_timestamp"/>
</LinearLayout>
<LinearLayout
android:orientation="horizontal"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<EditText
android:layout_width="match_parent"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/et_timestamp"/>
</LinearLayout>
</LinearLayout>
</ScrollView>
<cc.winboll.studio.libappbase.LogView
android:layout_width="match_parent"
android:layout_height="200dp"
android:id="@+id/logview"/>
</LinearLayout> </LinearLayout>