@@ -1,5 +1,10 @@
package cc.winboll.studio.mymessagemanager.activitys ;
/**
* @Author ZhanGSKen&豆包大模型<zhangsken@188.com>
* @Date 2025/08/30 14:32
* @Describe 联系人查询与短信发送窗口
*/
import android.os.Bundle ;
import android.text.Editable ;
import android.text.TextWatcher ;
@@ -11,13 +16,17 @@ import android.widget.RelativeLayout;
import android.widget.SimpleAdapter ;
import android.widget.TextView ;
import android.widget.Toolbar ;
import android.content.Intent ;
import android.graphics.drawable.Drawable ;
import cc.winboll.studio.libaes.views.AOHPCTCSeekBar ;
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.utils.PhoneUtil ;
import cc.winboll.studio.mymessagemanager.utils.SMSUtil ;
import com.hjq.toast.ToastUtils ;
import cc.winboll.studio.libappbase.LogUtils ;
import java.util.ArrayList ;
import java.util.HashMap ;
import java.util.List ;
@@ -26,255 +35,282 @@ import java.util.Map;
public class ComposeSMSActivity extends BaseActivity {
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 " ;
static String MAP_NAME = " NAME " ;
static String MAP_PHONE = " PHONE " ;
String mszSMSBody ;
String mszScheme ;
String mszPhoneTo ;
TextView mtvTOName ;
EditText metTONameSearch ;
EditText metTO ;
EditText metSMSBody ;
SimpleAdapter mSimpleAdapter ;
List < Map < String , Object > > mAdapterData = new ArrayList < > ( ) ;
ListView mlvContracts ;
List < PhoneBean > mListPhoneBean Contracts;
Toolbar mToolbar ;
AOHPCTCSeekBar mAOHPCTCSeekBar ;
RelativeLayout mrlContracts ;
private String mszSMSBody ;
private String mszScheme ;
private String mszPhoneTo ;
private TextView mtvTOName ;
private EditText metTONameSearch ;
private EditText metTO ;
private EditText metSMSBody ;
private SimpleAdapter mSimpleAdapter ;
private List < Map < String , Object > > mAdapterData = new ArrayList < Map < String , Object > > ( ) ;
private ListView mlvContracts ;
private List < PhoneBean > mListPhoneBeanContracts ;
private Toolbar mToolbar ;
private AOHPCTCSeekBar mAOHPCTCSeekBar ;
private RelativeLayout mrl Contracts;
@Override
protected void onCreate ( Bundle savedInstanceState ) {
super . onCreate ( savedInstanceState ) ;
setContentView ( R . layout . activity_composesms ) ;
mszSMSBody = getIntent ( ) . getStringExtra ( EXTRA_SMSBODY ) ;
mszScheme = getIntent ( ) . getData ( ) . getScheme ( ) ;
mszPhoneTo = getIntent ( ) . getData ( ) . getSchemeSpecificPart ( ) ;
if ( ! mszScheme . equals ( " smsto " ) ) {
// 其他方式未支持就退出
finish ( ) ;
// 初始化Intent数据( 增加空判断, 避免NullPointerException)
Intent intent = getIntent ( ) ;
if ( intent ! = null ) {
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 ( ) ;
return ;
}
initView ( ) ;
// 设置适配器
initAdapter ( null ) ;
// 设置搜索到的匹配位置
initAdapter ( null ) ; // 初始加载所有联系人
setListViewPrePositionByPhone ( ) ;
}
//
// 初始化视图
//
void initView ( ) {
//Drawable drawableFrame = AppCompatResources.getDrawable(this, R.drawable.bg_frame);
private void initView ( ) {
// 初始化标题栏
mToolbar = findViewById ( R . id . activitycomposesmsASupportToolbar1 ) ;
mToolbar = ( Toolbar ) findViewById ( R . id . activitycomposesmsASupportToolbar1 ) ;
mToolbar . setSubtitle ( getString ( R . string . activity_name_composesms ) ) ;
setActionBar ( mToolbar ) ;
// 初始化联系人栏目框
mtvTOName = findViewById ( R . id . activitycomposesmsTextView2 ) ;
mrlContracts = findViewById ( R . id . activitycomposesmsRelativeLayout1 ) ;
//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 ) {
}
// 初始化联系人姓名显示和搜索 栏
mtvTOName = ( TextView ) findViewById ( R . id . activitycomposesmsTextView2 ) ;
mrlContracts = ( RelativeLayout ) findViewById ( R . id . activitycomposesmsRelativeLayout1 ) ;
metTONameSearch = ( EditText ) findViewById ( R . id . activitycomposesmsEditText2 ) ;
@Override
public void afterTextChanged ( Editable s ) {
// 姓名搜索框文本变化监听
metTONameSearch . addTextChangedListener ( new TextWatcher ( ) {
@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 ) {
// 无操作
}
// 初始化联系人列表
mlvContracts = findViewById ( R . id . activitycomposesmsListView1 ) ;
// 初始化联系人输入框
metTO = findViewById ( R . id . activitycomposesmsEditText1 ) ;
metTO . setText ( mszPhoneTo ) ;
metTO . addTextChangedListener ( new TextWatcher ( ) {
@Override
public void onTextChanged ( CharSequence s , int start , int before , int count ) {
mtvTOName . setText ( " " ) ;
//重新加载数据
initAdapter ( null ) ;
setListViewPrePositionByPhone ( ) ;
}
@Override
public void beforeTextChanged ( CharSequence s , int start , int count , int after ) {
}
@Override
public void afterTextChanged ( Editable s ) {
}
} ) ;
// 初始化发送拉动控件
mAOHPCTCSeekBar = findViewById ( R . id . viewsmssendpart1AOHPCTCSeekBar1 ) ;
mAOHPCTCSeekBar . setThumb ( getDrawable ( R . drawable . ic_message ) ) ;
mAOHPCTCSeekBar . setThumbOffset ( 20 ) ;
mAOHPCTCSeekBar . setOnOHPCListener ( new AOHPCTCSeekBar . OnOHPCListener ( ) {
@Override
public void onOHPCommit ( ) {
// 空号码不发送
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 ( ) ;
}
}
@Override
public void afterTextChanged ( Editable s ) {
// 无操作
}
} ) ;
// 初始化提示框
TextView tvAOHPCTCSeekBarMSG = findViewById ( R . id . viewsmssendpart1Tex tView1) ;
// 初始化联系人列表
mlvContracts = ( ListView ) findViewById ( R . id . activitycomposesmsLis tView1) ;
// 初始化号码输入框(核心:优化文本变化监听逻辑)
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 . setOnOHPCListener ( new AOHPCTCSeekBar . OnOHPCListener ( ) {
@Override
public void onOHPCommit ( ) {
sendSMS ( ) ;
}
} ) ;
// 初始化短信内容输入框
TextView tvAOHPCTCSeekBarMSG = ( TextView ) findViewById ( R . id . viewsmssendpart1TextView1 ) ;
tvAOHPCTCSeekBarMSG . setText ( R . string . msg_100sendmsg ) ;
// 初始化发送消息框
metSMSBody = findViewById ( R . id . viewsmssendpart1EditText1 ) ;
//metSMSBody.setBackground(drawableFrame);
metSMSBody . setText ( mszSMSBody ) ;
metSMSBody = ( EditText ) findViewById ( R . id . viewsmssendpart1EditText1 ) ;
if ( mszSMSBody ! = null ) {
metSMSBody . setText ( mszSMSBody ) ;
}
}
//
// 设置号码搜索到的匹配位置
//
void setListViewPrePositionBy Phone ( ) {
int nPrePosition = get Contr actsDataPrePositionByPhone ( metTO . getText ( ) . toString ( ) ) ;
// 核心优化:根据输入号码筛选列表(无结果则显示空列表)
private void filterListByPhone ( String inputPhone ) {
PhoneUtil phoneUtil = new PhoneUtil ( this ) ;
List < PhoneBean > allContacts = phoneUtil . get PhoneList ( ) ;
List < PhoneBean > matched Contacts = new ArrayList < PhoneBean > ( ) ;
PhoneUtil phoneUtils = new PhoneUtil ( this ) ;
mtvTOName . setText ( p honeUtils . getNameByPhone ( metTO . getText ( ) . toString ( ) ) ) ;
// 遍历所有联系人,匹配包含输入号码的联系人
for ( P honeBean contact : allContacts ) {
if ( contact . getTelPhone ( ) . contains ( inputPhone )
| | phoneUtil . isTheSamePhoneNumber ( contact . getTelPhone ( ) , inputPhone ) ) {
matchedContacts . add ( contact ) ;
}
}
mlv Contr acts. setSelected ( false ) ;
mlvContracts . setSelection ( nPrePosition ) ;
LogUtils . d ( TAG , " 号码搜索:输入' " + inputPhone + " ', 匹配 " + matched Contacts. size ( ) + " 个结果 " ) ;
// 用筛选结果更新列表(无结果则传入空列表)
initAdapter ( matchedContacts . isEmpty ( ) ? new ArrayList < PhoneBean > ( ) : matchedContacts ) ;
// 定位到第一个匹配项(如果有)
if ( ! matchedContacts . isEmpty ( ) ) {
mlvContracts . setSelection ( 0 ) ;
mtvTOName . setText ( matchedContacts . get ( 0 ) . getName ( ) ) ;
} else {
mtvTOName . setText ( " " ) ; // 无结果时清空姓名显示
}
}
//
// 设置名称搜索到的匹配位置
//
void setListViewPrePosition ByName ( ) {
PhoneUtil phoneUtils = new PhoneUtil ( thi s) ;
List < PhoneBean > newPhoneData = phoneUtils . getPhonesByName ( metTONameSearch . getText ( ) . toString ( ) ) ;
// 重新绑定数据
initAdapter ( newPhoneData ) ;
mlvContracts . setSelected ( false ) ;
// 根据姓名搜索联系人
private void setListViewPrePositionByName ( ) {
String searchName = metTONameSearch . getText ( ) . toString ( ) . trim ( ) ;
PhoneUtil phoneUtil = new PhoneUtil ( this ) ;
List < PhoneBean > matchedContacts = phoneUtil . getPhones ByName ( searchName ) ;
initAdapter ( matchedContact s) ;
if ( ! matchedContacts . isEmpty ( ) ) {
mlvContracts . setSelection ( 0 ) ;
}
}
//
// 返回搜索到的匹配位置
//
int getContractsDataPrePositionByPhone ( String szPhone ) {
// 初始定位号码对应的联系人
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 + + ) {
if ( mListPhoneBeanContracts . get ( i ) . getTelPhone ( ) . compareTo ( szPhone ) > - 1 ) {
PhoneBean bean = mListPhoneBeanContracts . get ( i ) ;
if ( bean . getTelPhone ( ) . compareTo ( szPhone ) > = 0 ) {
return i ;
}
}
return 0 ;
}
//
// 返回搜索到的匹配位置
//
int getContractsDataPrePositionByName ( String szName ) {
// 获取姓名匹配的位置(兼容旧逻辑)
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 ;
}
//
// 初始化适配器
//
/*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() {
// 初始化或更新列表适配器
private void initAdapter ( List < PhoneBean > initData ) {
mAdapterData . clear ( ) ; // 清空旧数据
final PhoneUtil phoneUtil = new PhoneUtil ( this ) ;
@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 < > ( ) ;
final PhoneUtil phoneUtils = new PhoneUtil ( this ) ;
// 确定数据源:传入的筛选数据或所有联系人
if ( initData ! = null ) {
mListPhoneBeanContracts = initData ;
} else {
// 读取联系人数据
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 ) ;
mListPhoneBeanContracts = initData ;
} else {
mListPhoneBeanContracts = phoneUtil . getPhoneList ( ) ;
}
// 绑定适配器与数据
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 ( ) ) ;
mtvTOName . setText ( phoneUtils . getNameByPhone ( metTO . getText ( ) . toString ( ) ) ) ;
}
} ) ;
// 转换数据为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 ( ) ) {
String phone = mAdapterData . get ( position ) . get ( MAP_PHONE ) . toString ( ) ;
metTO . setText ( phone ) ;
mtvTOName . setText ( phoneUtil . getNameByPhone ( phone ) ) ;
}
}
} ) ;
} else {
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 ( ) ;
}
}
}