今天搞了个小程序,可以修改你自己android手机的任何一条短信。
直接进入正题,先放两张效果图:
主界面就是四个按钮加一个显示短信的listview:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/linearlayout"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnAll"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="所有短信"
/>
<Button
android:id="@+id/btnInbox"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="收件箱短信"
/>
</LinearLayout>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnSend"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="发件箱短信"
/>
<Button
android:id="@+id/btnDraft"
android:layout_weight="1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="草稿箱短信"
/>
</LinearLayout>
<ListView
android:id="@+id/listview"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:clickable="true"
/>
</LinearLayout>
还有一个StaticValues类放置一些常量
package com.jackchan.sms;
public class StaticValues {
//android系统短信数据库的字段
public static final String _ID = "_id";
public static final String PERSON = "person";
public static final String BODY = "body";
public static final String ADDRESS = "address";
public static final String DATE = "date";
public static final String TYPE = "type";
}
主类代码如下,重点在getSmsInPhone()这个方法,通过ContentResolver分别传入收件箱、发件箱、草稿的Uri获取你想要的字段,
sms相关的字段如下:
_id 一个自增字段,从1开始 ,每条短信_id都不一样,根据这个唯一性可以修改短信
thread_id 序号,同一发信人的id相同
address 发件人手机号码
person 联系人列表里的序号,陌生人为null
date 发件日期
protocol 协议,分为: 0 SMS_RPOTO, 1 MMS_PROTO
read 是否阅读 0未读, 1已读
status 状态 -1接收,0 complete, 64 pending, 128 failed
type
ALL = 0;
INBOX = 1;
SENT = 2;
DRAFT = 3;
OUTBOX = 4;
FAILED = 5;
QUEUED = 6;
body 短信内容
service_center 短信服务中心号码编号
subject 短信的主题
reply_path_present TP-Reply-Path
package com.jackchan.sms;
import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import com.jackchan.sms.ChangeSMSWindow.onOkClick;
import android.app.Activity;
import android.content.ContentResolver;
import android.database.Cursor;
import android.database.sqlite.SQLiteException;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import android.view.Gravity;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.AdapterView;
import android.widget.AdapterView.OnItemClickListener;
import android.widget.Button;
import android.widget.ListView;
public class SMS extends Activity {
private List<Map<String, Object>> list = new ArrayList<Map<String,Object>>(); //已发送信息列表
private SMSAdapter adapter;
private Button btnAll;
private Button btnInbox;
private Button btnSend;
private Button btnDraft;
public static String url;
private ListView listView;
private final String SMS_URI_ALL = "content://sms/";
private final String SMS_URI_INBOX = "content://sms/inbox";
private final String SMS_URI_SEND = "content://sms/sent";
private final String SMS_URI_DRAFT = "content://sms/draft";
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
initComponet();
setBtnClick();
url = SMS_URI_ALL;//默认获取全部短信
adapter = new SMSAdapter(this, getSmsInPhone());
listView.setAdapter(adapter);
listView.setOnItemClickListener(new OnItemClickListener() {
@Override
public void onItemClick(AdapterView<?> arg0, View arg1, int arg2,
long arg3) {
// TODO Auto-generated method stub
ChangeSMSWindow change = new ChangeSMSWindow(SMS.this, list.get(arg2).get(StaticValues.BODY).toString(),
(Long) list.get(arg2).get(StaticValues._ID));
change.setOkClick(new onOkClick() {
@Override
public void dataChange() {
listChange();
}
});
change.showAtLocation(listView,
//LayoutInflater.from(context).inflate(R.layout.main, null),
Gravity.CENTER_HORIZONTAL|Gravity.CENTER_VERTICAL,
0, 0);
}
});
}
private void initComponet(){
listView = (ListView)findViewById(R.id.listview);
btnAll = (Button)findViewById(R.id.btnAll);
btnInbox = (Button)findViewById(R.id.btnInbox);
btnSend = (Button)findViewById(R.id.btnSend);
btnDraft = (Button)findViewById(R.id.btnDraft);
}
private void setBtnClick(){
btnAll.setOnClickListener(click);
btnInbox.setOnClickListener(click);
btnSend.setOnClickListener(click);
btnDraft.setOnClickListener(click);
}
/*
* listview数据发生改变
*/
private void listChange(){
adapter.clearList();
adapter.changeList(getSmsInPhone());
adapter.notifyDataSetChanged();
}
private btnClick click = new btnClick();
private class btnClick implements OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v == btnAll){
url = SMS_URI_ALL;
}
else if(v == btnInbox){
url = SMS_URI_INBOX;
}
else if(v == btnSend){
url = SMS_URI_SEND;
}
else if(v == btnDraft){
url = SMS_URI_DRAFT;
}
listChange();
}
}
/*
* 获取指定类型短信
*/
public List<Map<String, Object>> getSmsInPhone()
{
try{
ContentResolver cr = getContentResolver();
String[] projection = new String[]{"_id", "address", "person",
"body", "date", "type"};
Uri uri = Uri.parse(url);
Cursor cur = cr.query(uri, projection, null, null, "date desc");
if (cur.moveToFirst()) {
long id;
String name;
String phoneNumber;
String smsbody;
String date;
String type;
int idColumn = cur.getColumnIndex(StaticValues._ID);
int nameColumn = cur.getColumnIndex(StaticValues.PERSON);
int phoneNumberColumn = cur.getColumnIndex(StaticValues.ADDRESS);
int smsbodyColumn = cur.getColumnIndex(StaticValues.BODY);
int dateColumn = cur.getColumnIndex(StaticValues.DATE);
int typeColumn = cur.getColumnIndex(StaticValues.TYPE);
do{
id = cur.getLong(idColumn);
name = cur.getString(nameColumn);
phoneNumber = cur.getString(phoneNumberColumn);
smsbody = cur.getString(smsbodyColumn);
SimpleDateFormat dateFormat = new SimpleDateFormat(
"yyyy-MM-dd hh:mm:ss");
Date d = new Date(Long.parseLong(cur.getString(dateColumn)));
date = dateFormat.format(d);
int typeId = cur.getInt(typeColumn);
if(typeId == 1){
type = "接收";
} else if(typeId == 2){
type = "发送";
}else if(typeId == 3){
type = "草稿";
} else {
type = "";
}
if(smsbody == null)
smsbody = "";
Map<String, Object> map = new HashMap<String, Object>();
map.put(StaticValues._ID, id);
map.put(StaticValues.PERSON, name);
map.put(StaticValues.ADDRESS, phoneNumber);
map.put(StaticValues.BODY, smsbody);
map.put(StaticValues.DATE, date);
map.put(StaticValues.TYPE, type);
list.add(map);
}while(cur.moveToNext());
cur.close();
}
} catch(SQLiteException ex) {
Log.d("SQLiteException in getSmsInPhone", ex.getMessage());
}
return list;
}
}
listview中item.xml的布局文件如下:
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical" >
<TextView
android:id="@+id/person"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="姓名:"
/>
<TextView
android:id="@+id/address"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="地址:"
/>
<TextView
android:id="@+id/body"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="内容:"
/>
<TextView
android:id="@+id/date"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="日期:"
/>
<TextView
android:id="@+id/type"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="类型:"
/>
</LinearLayout>
然后还有一个类用来适配主界面的listview
package com.jackchan.sms;
import java.util.List;
import java.util.Map;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.TextView;
public class SMSAdapter extends BaseAdapter{
private Context context;//当前上下文内容
private List<Map<String, Object>> list; //已发送信息列表
private class ViewHolder{
TextView person;
TextView address;
TextView body;
TextView date;
TextView type;
}
public SMSAdapter(Context context, List<Map<String, Object>> list) {
super();
this.context = context;
this.list = list;
}
public void changeList(List<Map<String, Object>> list){
this.list = list;
}
public void clearList(){
list.clear();
}
@Override
public int getCount() {
// TODO Auto-generated method stub
return list.size();
}
@Override
public Object getItem(int arg0) {
// TODO Auto-generated method stub
return null;
}
@Override
public long getItemId(int arg0) {
// TODO Auto-generated method stub
return 0;
}
@Override
public View getView(int position, View convertView, ViewGroup parent) {
ViewHolder viewHolder = null;
if(convertView == null){
viewHolder = new ViewHolder();
convertView = LayoutInflater.from(context).inflate(R.layout.item, null);
viewHolder.person = (TextView)convertView.findViewById(R.id.person);
viewHolder.address = (TextView)convertView.findViewById(R.id.address);
viewHolder.body = (TextView)convertView.findViewById(R.id.body);
viewHolder.date = (TextView)convertView.findViewById(R.id.date);
viewHolder.type = (TextView)convertView.findViewById(R.id.type);
convertView.setTag(viewHolder);
}
else{
viewHolder = (ViewHolder)convertView.getTag();
}
//获取短信基本信息
viewHolder.person.setText("姓名:" + list.get(position).get(StaticValues.PERSON));
viewHolder.address.setText("号码:" + list.get(position).get(StaticValues.ADDRESS));
viewHolder.body.setText("内容:" + list.get(position).get(StaticValues.BODY));
viewHolder.date.setText("日期:" + list.get(position).get(StaticValues.DATE));
viewHolder.type.setText("类型:" + list.get(position).get(StaticValues.TYPE));
return convertView;
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@drawable/bg_popupwindow"
android:orientation="vertical" >
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="输入修改后的内容:"
android:textColor="#000000"
android:textSize="20sp"
/>
<EditText
android:id="@+id/edittext"
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:selectAllOnFocus="true"
/>
<LinearLayout
android:layout_width="fill_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
>
<Button
android:id="@+id/btnOk"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="确认"
/>
<Button
android:id="@+id/btnCancel"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:text="取消"
/>
</LinearLayout>
</LinearLayout>
弹出界面背景bg_popupwindow.xml
<?xml version="1.0" encoding="utf-8"?>
<shape
xmlns:android="http://schemas.android.com/apk/res/android"
android:shape="rectangle"
><!-- android:shape="" 表示是圆角矩形还是椭圆等等 -->
<solid android:color="#FFFF00"/>
<!-- 四个角的弧度 -->
<corners android:radius="4dip"/>
<!-- padding 表示内部空间距离背景图片内部边距 的距离 -->
</shape>
弹出界面实现代码
package com.jackchan.sms;
import android.content.ContentValues;
import android.content.Context;
import android.net.Uri;
import android.view.LayoutInflater;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import android.widget.PopupWindow;
/*
* 修改短信内容弹出框
* @author:jack chan
*/
public class ChangeSMSWindow extends PopupWindow{
private Context context;
private EditText editText;
private Button btnOk;
private Button btnCancel;
private ContentValues cv = new ContentValues(); //存放修改信息
private String body = null;//短信内容
private long id = -1;//短信编号
public ChangeSMSWindow(Context context, String body, long id) {
super(context);
this.context = context;
this.body = body;
this.id = id;
LayoutInflater inflater = LayoutInflater.from(context);
View view = inflater.inflate(R.layout.dialog, null);
setContentView(view);
this.setFocusable(true);
this.setOutsideTouchable(true);
editText = (EditText)view.findViewById(R.id.edittext);
btnOk = (Button)view.findViewById(R.id.btnOk);
btnCancel = (Button)view.findViewById(R.id.btnCancel);
this.setWidth(LinearLayout.LayoutParams.WRAP_CONTENT);
this.setHeight(LinearLayout.LayoutParams.WRAP_CONTENT);
editText.setText(body);
btnClick click = new btnClick();
btnOk.setOnClickListener(click);
btnCancel.setOnClickListener(click);
}
private class btnClick implements OnClickListener{
@Override
public void onClick(View v) {
// TODO Auto-generated method stub
if(v.getId() == R.id.btnOk){
cv.put(StaticValues.BODY, editText.getText().toString());
context.getContentResolver().update(Uri.parse(SMS.url),
cv, StaticValues._ID + "=?", new String[]{id+""});
if(okClick != null)
okClick.dataChange();
}
if(isShowing())
dismiss();
}
}
public interface onOkClick{
void dataChange();
}
private onOkClick okClick;
public void setOkClick(onOkClick okClick) {
this.okClick = okClick;
}
}
最后在Mainfiest里添加读写权限
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.WRITE_SMS" />
大功告成,现在就完成需求了。