我的Android心得(4)--监听电话和短信是否来自关注对象--contentObserver

目标:在做毕业设计,要实现当手机有未接短信或者未接来电,并且来源号码是特定的一个关注对象时,触发提醒。


一开始是想用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);
	        }
	        
	    }
}

SMSBroadcastReceiver.java


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))
			{
				//触发提醒,在这里添加代码
			}
		}
		
	}

}

AndroidManifest.xml要注册Receiver

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

要用到的permission

    <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" />

这样实现的结果是一有短信或者一有电话,就触发提醒,所以有时候来电话响铃了,我已经准备接了,但它还提醒,我不得不关了提醒才能接电话。我要的是我有电话忘记接了,而且这来电是关注对象的,软件才要提醒我。所以BroadcastReceiver实现是不够完美的。


知道了来电短信都记录在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();   
			    }   
}  

在Manifest里面注册

        <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的东西

你可能感兴趣的:(我的Android心得(4)--监听电话和短信是否来自关注对象--contentObserver)