Compare commits

...

5 Commits

Author SHA1 Message Date
ZhanGSKen
9ece6778b7 <mymessagemanager>APK 15.3.3 release Publish. 2025-08-28 21:13:38 +08:00
ZhanGSKen
e13c8e7af0 <mymessagemanager>Start New Stage Version. 2025-08-28 16:03:47 +08:00
ZhanGSKen
a4988b5b68 联系人查询发送窗口添加拼音查询功能。 2025-08-28 16:02:41 +08:00
ZhanGSKen
5507126f6b <mymessagemanager>APK 15.3.2 release Publish. 2025-08-23 13:40:21 +08:00
ZhanGSKen
d381c29452 短信发送窗口UI优化 2025-08-23 13:38:20 +08:00
11 changed files with 656 additions and 224 deletions

View File

@@ -55,6 +55,8 @@ dependencies {
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'
api 'com.baoyz.pullrefreshlayout:library:1.2.0' api 'com.baoyz.pullrefreshlayout:library:1.2.0'

View File

@@ -1,8 +1,8 @@
#Created by .winboll/winboll_app_build.gradle #Created by .winboll/winboll_app_build.gradle
#Thu Jul 03 13:50:15 HKT 2025 #Thu Aug 28 21:13:38 HKT 2025
stageCount=2 stageCount=4
libraryProject= libraryProject=
baseVersion=15.3 baseVersion=15.3
publishVersion=15.3.1 publishVersion=15.3.3
buildCount=0 buildCount=0
baseBetaVersion=15.3.2 baseBetaVersion=15.3.4

View File

@@ -35,6 +35,8 @@ public class ComposeSMSActivity extends BaseActivity {
String mszSMSBody; String mszSMSBody;
String mszScheme; String mszScheme;
String mszPhoneTo; String mszPhoneTo;
TextView mtvTOName;
EditText metTONameSearch;
EditText metTO; EditText metTO;
EditText metSMSBody; EditText metSMSBody;
SimpleAdapter mSimpleAdapter; SimpleAdapter mSimpleAdapter;
@@ -59,9 +61,9 @@ public class ComposeSMSActivity extends BaseActivity {
// 初始化视图 // 初始化视图
initView(); initView();
// 设置适配器 // 设置适配器
initAdapter(); initAdapter(null);
// 设置搜索到的匹配位置 // 设置搜索到的匹配位置
setListViewPrePosition(); setListViewPrePositionByPhone();
} }
// //
@@ -76,8 +78,25 @@ public class ComposeSMSActivity extends BaseActivity {
setActionBar(mToolbar); setActionBar(mToolbar);
// 初始化联系人栏目框 // 初始化联系人栏目框
mtvTOName = findViewById(R.id.activitycomposesmsTextView2);
mrlContracts = findViewById(R.id.activitycomposesmsRelativeLayout1); mrlContracts = findViewById(R.id.activitycomposesmsRelativeLayout1);
//mrlContracts.setBackground(drawableFrame); //mrlContracts.setBackground(drawableFrame);
metTONameSearch = findViewById(R.id.activitycomposesmsEditText2);
metTONameSearch.addTextChangedListener(new TextWatcher() {
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
metTO.setText("");
setListViewPrePositionByName();
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void afterTextChanged(Editable s) {
}
});
// 初始化联系人列表 // 初始化联系人列表
mlvContracts = findViewById(R.id.activitycomposesmsListView1); mlvContracts = findViewById(R.id.activitycomposesmsListView1);
@@ -88,7 +107,10 @@ public class ComposeSMSActivity extends BaseActivity {
metTO.addTextChangedListener(new TextWatcher() { metTO.addTextChangedListener(new TextWatcher() {
@Override @Override
public void onTextChanged(CharSequence s, int start, int before, int count) { public void onTextChanged(CharSequence s, int start, int before, int count) {
setListViewPrePosition(); mtvTOName.setText("");
//重新加载数据
initAdapter(null);
setListViewPrePositionByPhone();
} }
@Override @Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) { public void beforeTextChanged(CharSequence s, int start, int count, int after) {
@@ -96,6 +118,7 @@ public class ComposeSMSActivity extends BaseActivity {
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
} }
}); });
@@ -136,18 +159,34 @@ public class ComposeSMSActivity extends BaseActivity {
} }
// //
// 设置搜索到的匹配位置 // 设置号码搜索到的匹配位置
// //
void setListViewPrePosition() { void setListViewPrePositionByPhone() {
int nPrePosition = getContractsDataPrePosition(metTO.getText().toString()); int nPrePosition = getContractsDataPrePositionByPhone(metTO.getText().toString());
PhoneUtil phoneUtils = new PhoneUtil(this);
mtvTOName.setText(phoneUtils.getNameByPhone(metTO.getText().toString()));
mlvContracts.setSelected(false); mlvContracts.setSelected(false);
mlvContracts.setSelection(nPrePosition); mlvContracts.setSelection(nPrePosition);
} }
//
// 设置名称搜索到的匹配位置
//
void setListViewPrePositionByName() {
PhoneUtil phoneUtils = new PhoneUtil(this);
List<PhoneBean> newPhoneData = phoneUtils.getPhonesByName(metTONameSearch.getText().toString());
// 重新绑定数据
initAdapter(newPhoneData);
mlvContracts.setSelected(false);
}
// //
// 返回搜索到的匹配位置 // 返回搜索到的匹配位置
// //
int getContractsDataPrePosition(String szPhone) { int getContractsDataPrePositionByPhone(String szPhone) {
for (int i = 0; i < mListPhoneBeanContracts.size(); i++) { for (int i = 0; i < mListPhoneBeanContracts.size(); i++) {
if (mListPhoneBeanContracts.get(i).getTelPhone().compareTo(szPhone) > -1) { if (mListPhoneBeanContracts.get(i).getTelPhone().compareTo(szPhone) > -1) {
return i; return i;
@@ -157,15 +196,65 @@ public class ComposeSMSActivity extends BaseActivity {
return 0; return 0;
} }
//
// 返回搜索到的匹配位置
//
int getContractsDataPrePositionByName(String szName) {
for (int i = 0; i < mListPhoneBeanContracts.size(); i++) {
if (mListPhoneBeanContracts.get(i).getName().startsWith(szName)) {
return i;
}
}
return 0;
}
// //
// 初始化适配器 // 初始化适配器
// //
void initAdapter() { /*void initAdapter() {
// 初始化联系人数据适配器
mAdapterData = new ArrayList<>();
// 读取联系人数据
final 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
public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
metTO.setText(mAdapterData.get(position).get(MAP_PHONE).toString());
mListPhoneBeanContracts = phoneUtils.getPhoneList();
mtvTOName.setText(phoneUtils.getNameByPhone(metTO.getText().toString()));
}
});
}*/
void initAdapter(List<PhoneBean> initData) {
// 初始化联系人数据适配器 // 初始化联系人数据适配器
mAdapterData = new ArrayList<>(); mAdapterData = new ArrayList<>();
// 读取联系人数据 final PhoneUtil phoneUtils = new PhoneUtil(this);
PhoneUtil phoneUtils = new PhoneUtil(this); if (initData != null) {
mListPhoneBeanContracts = phoneUtils.getPhoneList(); mListPhoneBeanContracts = initData;
} else {
// 读取联系人数据
mListPhoneBeanContracts = phoneUtils.getPhoneList();
}
// 映射联系人数据给适配器数据对象 // 映射联系人数据给适配器数据对象
for (int i = 0;i < mListPhoneBeanContracts.size();i++) { for (int i = 0;i < mListPhoneBeanContracts.size();i++) {
Map<String,Object> map =new HashMap<>(); Map<String,Object> map =new HashMap<>();
@@ -184,7 +273,7 @@ public class ComposeSMSActivity extends BaseActivity {
@Override @Override
public void onItemClick(AdapterView<?> parent, View view, int position, long id) { public void onItemClick(AdapterView<?> parent, View view, int position, long id) {
metTO.setText(mAdapterData.get(position).get(MAP_PHONE).toString()); metTO.setText(mAdapterData.get(position).get(MAP_PHONE).toString());
mtvTOName.setText(phoneUtils.getNameByPhone(metTO.getText().toString()));
} }
}); });
} }

View File

@@ -4,11 +4,16 @@ 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;
@@ -16,19 +21,17 @@ 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;
@@ -36,10 +39,11 @@ public class SMSActivity extends BaseActivity {
Toolbar mToolbar; Toolbar mToolbar;
String mszPhoneTo; String mszPhoneTo;
SMSArrayAdapter mSMSArrayAdapter; SMSArrayAdapter mSMSArrayAdapter;
ScrollView mScrollView; BottomPositionFixedScrollView mScrollView1;
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) {
@@ -47,45 +51,90 @@ 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 { // 监听根布局绘制完成(窗口加载完成的标志)
WeakReference<SMSActivity> mActivity; rootView.getViewTreeObserver().addOnGlobalLayoutListener(new ViewTreeObserver.OnGlobalLayoutListener() {
MyHandler(SMSActivity activity) { @Override
mActivity = new WeakReference<SMSActivity>(activity); public void onGlobalLayout() {
} // 滚动到底部
public void handleMessage(Message msg) { mScrollView1.post(new Runnable() {
SMSActivity theActivity = mActivity.get(); @Override
switch (msg.what) { public void run() {
case MSG_SET_FOCUS: mScrollView1.fullScroll(ScrollView.FOCUS_DOWN);
theActivity.metSMSBody.setFocusable(true); }
theActivity.metSMSBody.requestFocus(); });
break;
default: // 移除监听,避免重复触发
break; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN) {
} rootView.getViewTreeObserver().removeOnGlobalLayoutListener(this);
super.handleMessage(msg); } else {
} 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() {
@@ -94,135 +143,130 @@ 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);
//Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame); metSMSBody.setOnClickListener(new View.OnClickListener() {
metSMSBody = findViewById(R.id.viewsmssendpart1EditText1); @Override
//metSMSBody.setBackground(drawableFrame); public void onClick(View v) {
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( aOHPCTCSeekBar.setOnOHPCListener(new AOHPCTCSeekBar.OnOHPCListener() {
new AOHPCTCSeekBar.OnOHPCListener(){ @Override
@Override public void onOHPCommit() {
public void onOHPCommit() { sendSMS();
//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.activitysmsinphoneListView1); mlvSMS = (SMSListViewForScrollView) findViewById(R.id.activitysmsSMSListViewForScrollView1);
// 准备数据
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(); IntentFilter intentFilter = new IntentFilter(ACTION_NOTIFY_SMS_CHANGED);
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("");
new Handler().postDelayed(new Runnable(){ metSMSBody.clearFocus();
@Override new Handler().postDelayed(new Runnable() {
public void run() { @Override
updateSMSView(); public void run() {
ViewUtil.scrollScrollView(mScrollView); updateSMSView();
} 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) {
switch (intent.getAction()) { if (ACTION_NOTIFY_SMS_CHANGED.equals(intent.getAction())) {
case ACTION_NOTIFY_SMS_CHANGED : updateSMSView();
//Toast.makeText(context, "ACTION_NOTIFY_SMS_CHANGED", Toast.LENGTH_SHORT).show(); ViewUtil.scrollScrollView(mScrollView1);
updateSMSView(); } else {
ViewUtil.scrollScrollView(mScrollView); throw new IllegalStateException("Unexpected value: " + intent.getAction());
//LogUtils.d(TAG, "ACTION_NOTIFY_SMS_CHANGED");
break;
default:
throw new IllegalStateException("Unexpected value: " + intent.getAction());
} }
} }
} }
} }

View File

@@ -5,6 +5,7 @@ package cc.winboll.studio.mymessagemanager.utils;
* @Date 2024/07/19 14:30:57 * @Date 2024/07/19 14:30:57
* @Describe 手机联系人工具类 * @Describe 手机联系人工具类
*/ */
import android.content.ContentResolver; import android.content.ContentResolver;
import android.content.Context; import android.content.Context;
import android.database.Cursor; import android.database.Cursor;
@@ -12,6 +13,12 @@ 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.mymessagemanager.beans.PhoneBean; import cc.winboll.studio.mymessagemanager.beans.PhoneBean;
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;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.Collections; import java.util.Collections;
import java.util.Comparator; import java.util.Comparator;
@@ -38,28 +45,137 @@ 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);
while (cursor.moveToNext()) { if (cursor != null) {
PhoneBean phoneBean = new PhoneBean(cursor.getString(1), cursor.getString(0).replaceAll("\\s", "")); while (cursor.moveToNext()) {
listPhoneBean.add(phoneBean); // 去除号码中的空格
String phone = cursor.getString(0).replaceAll("\\s", "");
String name = cursor.getString(1);
PhoneBean phoneBean = new PhoneBean(name, phone);
listPhoneBean.add(phoneBean);
}
cursor.close();
} }
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()));
@@ -71,22 +187,36 @@ public class PhoneUtil {
return false; return false;
} }
public String getNameByPhone(String szPhone) {
if (szPhone == null || szPhone.equals("")) {
return "";
}
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 "";
}
boolean isTheSamePhoneNumber(String szNum1, String szNum2) { boolean isTheSamePhoneNumber(String szNum1, String szNum2) {
//LogUtils.d(TAG, String.format("szNum1 %s\nszNum2 %s", szNum1, szNum2)); if (szNum1.equals(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;
} }
@@ -96,23 +226,16 @@ public class PhoneUtil {
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

@@ -29,8 +29,14 @@ public class UnitAreaUtils {
public boolean isCurrentUnitAreaNumber(String szPhoneNumer) { public boolean isCurrentUnitAreaNumber(String szPhoneNumer) {
String szUnitArea = getUnitArea(); String szUnitArea = getUnitArea();
LogUtils.d(TAG, String.format("szPhoneNumer.substring(1,3) %s", szPhoneNumer.substring(1,3))); try {
return szPhoneNumer.substring(1,3).equals(szUnitArea); String szPhoneNumerUnitArea = szPhoneNumer.substring(1, 3);
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) {

View File

@@ -0,0 +1,125 @@
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

@@ -21,25 +21,63 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:id="@+id/activitycomposesmsRelativeLayout1"> android:id="@+id/activitycomposesmsRelativeLayout1">
<TextView <LinearLayout
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_marginLeft="10dp"
android:layout_centerVertical="true"/>
<EditText
android:layout_toRightOf="@id/activitycomposesmsTextView1"
android:layout_width="wrap_content"
android:inputType="phone"
android:layout_height="wrap_content"
android:ems="10"
android:id="@+id/activitycomposesmsEditText1"
android:layout_alignParentRight="true" android:layout_alignParentRight="true"
android:layout_marginRight="10dp" android:layout_marginRight="10dp"
android:layout_centerVertical="true"/> android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(拼音搜索):"/>
<EditText
android:layout_width="80dp"
android:ems="10"
android:layout_height="wrap_content"
android:id="@+id/activitycomposesmsEditText2"/>
<TextView
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>
<LinearLayout
android:orientation="horizontal"
android:layout_below="@id/activitycomposesmsLinearLayout1"
android:layout_alignParentRight="true"
android:layout_marginRight="10dp"
android:layout_marginLeft="10dp"
android:layout_alignParentLeft="true"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center_vertical">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="(SMS TO) :"
android:id="@+id/activitycomposesmsTextView1"/>
<EditText
android:layout_width="wrap_content"
android:inputType="phone"
android:layout_height="wrap_content"
android:ems="10"
android:id="@+id/activitycomposesmsEditText1"/>
</LinearLayout>
</RelativeLayout> </RelativeLayout>

View File

@@ -10,36 +10,40 @@
android:layout_height="@dimen/toolbar_height" android:layout_height="@dimen/toolbar_height"
android:id="@+id/activitysmsASupportToolbar1"/> android:id="@+id/activitysmsASupportToolbar1"/>
<RelativeLayout <ScrollView
android:orientation="vertical"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="0dp"
android:paddingBottom="10dp"> android:layout_weight="1.0"
android:id="@+id/activitysmsScrollView2">
<ScrollView <LinearLayout
android:layout_alignParentTop="true" android:orientation="vertical"
android:layout_above="@+id/activitysmsinclude1"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="0dp" android:layout_height="match_parent"
android:id="@+id/activitysmsinphoneScrollView1" android:id="@+id/activitysmsLinearLayout1">
android:layout_weight="1.0"
android:isScrollContainer="false">
<cc.winboll.studio.mymessagemanager.views.SMSListViewForScrollView <cc.winboll.studio.mymessagemanager.views.BottomPositionFixedScrollView
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/activitysmsinphoneListView1"/> android:id="@+id/activitysmsinclude1"/>
</ScrollView> </LinearLayout>
<include </ScrollView>
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,6 +7,18 @@
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"
@@ -17,17 +29,6 @@
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

@@ -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>