目标:在做毕业设计,要实现当手机有未接短信或者未接来电,并且来源号码是特定的一个关注对象时,触发提醒。
一开始是想用BroadcastReceiver,有短信、来电时Android系统会发出广播,我们只要注册一个BroadcastReceiver接收这些广播,在onReceive方法里面判断一些是否来自关注对象即可。
关于BroadcastReceiver,这篇文章讲的很细致 http://www.cnblogs.com/alwaysyouare/archive/2011/11/17/2252397.html
注意的是BroadcastReceiver在onReceive方法里不能进行耗时的操作,Receiver也要在manifest里面注册
BroadcastReceiver的广播事件不仅有系统的事件,还可以应用自定义的广播事件。
以下是我的实现
PhoneBroadcastReceiver.java 文件:
public class PhoneBroadcastReceiver extends BroadcastReceiver { // broadcast intent位于主线程,不能再onReceive执行太多操作,太多操作要开个Service @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub if(intent.getAction().equals(Intent.ACTION_NEW_OUTGOING_CALL)) { // 有电话打出去 } else { // 有电话打进来 // 取得telephony服务 TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE); // 监听电话 MyPhoneStateListener my = new MyPhoneStateListener(); my.mContext = context; telephonyManager.listen(my, PhoneStateListener.LISTEN_CALL_STATE); } } private class MyPhoneStateListener extends PhoneStateListener { Context mContext = null; public void onCallStateChanged(int state,String incomingNumber){ //关注对象的电话号码 String targetPhoneNumber = new Target(this.mContext).getInfo(Target.TargetPhoneNumber); if(state == TelephonyManager.CALL_STATE_RINGING && incomingNumber.equals(targetPhoneNumber)) { // 触发提醒功能,在这里添加代码 } super.onCallStateChanged(state, incomingNumber); } } }
public class SMSBroadcastReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub // 取出所有短信 Object[] pdusData = (Object[])intent.getExtras().get("pdus"); for(int i = 0; i<pdusData.length; ++i) { SmsMessage smsMessage = SmsMessage.createFromPdu((byte[])pdusData[i]); String phoneNumber = smsMessage.getOriginatingAddress(); String targetPhoneNumber = new Target(context).getInfo(Target.TargetPhoneNumber);//关注对象的电话号码 if(phoneNumber != null && phoneNumber.equals(targetPhoneNumber)) { //触发提醒,在这里添加代码 } } } }
<span style="white-space:pre"> </span><receiver android:name="com.example.mytest.SMSBroadcastReceiver" > <intent-filter> <action android:name="android.provider.Telephony.SMS_RECEIVED" /> </intent-filter> </receiver> <receiver android:name="com.example.mytest.PhoneBroadcastReceiver" > <intent-filter> <action android:name="android.intent.action.PHONE_STATE" /> <action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- 定义开机即启动 --> <action android:name="android.intent.action.NEW_OUTGOING_CALL" /> </intent-filter> </receiver>
<uses-permission android:name="android.permission.RECEIVE_SMS" /> <uses-permission android:name="android.permission.READ_PHONE_STATE" /> <uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
知道了来电短信都记录在Android中的数据库中,我们只要关注未接来电、未读短信的数据库有变化时,去检查号码是否为关注对象的即可,这时候用ContentObserver
这里给出监测来电的代码 http://chunpeng.iteye.com/blog/523728
这里关于ContentObserver讲的比较详细 http://www.cnblogs.com/slider/archive/2012/02/14/2351702.html
我的实现是,开启一个Service,在Service中注册ContentObserver,就可以在退出该软件之后仍然监视着。经过我的小米手机实测,当你手动杀掉进程,该Service会被kill掉,即这时候无法监测来电和短信,但是过几分钟后该Service又能够开启
MissedCallOrSMSService.java,为了让Service重新start时又能观察内容,我不断地register和unregister
public class MissedCallOrSMSService extends Service{ private MissedCallContentObserver call; private MissedSMSContentObserver sms; @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); call = new MissedCallContentObserver(this, new Handler()); sms = new MissedSMSContentObserver(this, new Handler()); // 在服务创建的时候注册ContentObserver,之后就会一直存在 this.getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, false, call); // 发现uri为content://sms/inbox无效,true表示同时监听子目录变化 this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, sms); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub this.getContentResolver().unregisterContentObserver(call); this.getContentResolver().unregisterContentObserver(sms); this.getContentResolver().registerContentObserver(CallLog.Calls.CONTENT_URI, false, call); this.getContentResolver().registerContentObserver(Uri.parse("content://sms/"), true, sms); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); this.getContentResolver().unregisterContentObserver(call); this.getContentResolver().unregisterContentObserver(sms); } } //当有call log时,就会对这个类进行回调 class MissedCallContentObserver extends ContentObserver { private Context ctx; private Target target; public MissedCallContentObserver(Context context, Handler handler) { super(handler); ctx = context; target = new Target(ctx); } @Override public void onChange(boolean selfChange) { Cursor csr = ctx.getContentResolver().query(Calls.CONTENT_URI, new String[] {Calls.NUMBER, Calls.TYPE, Calls.NEW}, null, null, Calls.DEFAULT_SORT_ORDER); if (csr != null) { if (csr.moveToFirst()) { int type = csr.getInt(csr.getColumnIndex(Calls.TYPE)); switch (type) { case Calls.MISSED_TYPE: if (csr.getInt(csr.getColumnIndex(Calls.NEW)) == 1 && csr.getString(csr.getColumnIndex(Calls.NUMBER)).equals(target.getInfo(Target.TargetPhoneNumber))) { Log.e("eee", target.getInfo(Target.TargetName) + " 打来未接电话"); Intent intent = new Intent(ctx, RemindService.class); intent.putExtra("remind_kind", "有未接电话啊!"); ctx.startService(intent); } break; case Calls.INCOMING_TYPE: break; case Calls.OUTGOING_TYPE: break; } } // release resource csr.close(); } } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } } class MissedSMSContentObserver extends ContentObserver { private Context ctx; private Target target; public MissedSMSContentObserver(Context context, Handler handler) { super(handler); ctx = context; target = new Target(ctx); } @Override public void onChange(boolean selfChange) { // select _id, address, read from Uri where read = 0, 0 是未读 Cursor csr = ctx.getContentResolver().query(Uri.parse("content://sms/inbox"), new String[]{"_id", "address", "read"}, "read=?", new String[]{"0"}, "date desc"); if (csr != null) { if (csr.moveToFirst()) { if(csr.getString(csr.getColumnIndex("address")).equals(target.getInfo(Target.TargetPhoneNumber))){ Log.e("eee", target.getInfo(Target.TargetName) + " 发来短信"); // 提醒响铃 Intent intent =new Intent(ctx, RemindService.class); intent.putExtra("remind_kind", "有未接短信啊!"); ctx.startService(intent); } } // release resource csr.close(); } } @Override public boolean deliverSelfNotifications() { return super.deliverSelfNotifications(); } }
<service android:name="com.example.mytest.MissedCallOrSMSService"/>
<uses-permission android:name="android.permission.READ_CALL_LOG"/> <uses-permission android:name="android.permission.READ_SMS"/>这时候效果能够与我们想要的一样了。
还是感谢一开始想错方向,学到了不少BroadcastReceiver的东西