編輯:關於Android編程
上面四節,已經實現了界面設計,黑名單(白名單的添加與刪除與黑名單同理,不再贅述),啟用監聽開關,定時攔截開關,及攔截模式選擇等功能,下面就要實現來電管家最核心的功能,也就是攔截功能。
主要思路:
1. 制定攔截模式,這裡主要有兩個,一個是黑名單模式,也就是只攔截在黑名單中的號碼;另一個就是白名單模式,攔截除了白名單以外的號碼。
2. 根據用戶自定義設置信息,制定正則表達式,判斷攔截的標准。
3. 使用對應的類實現掛斷電話的功能。
監聽模塊主要是利用service實現功能,為了實現電話掛斷功能,這裡需要調用遠程的AIDL Service,大多數書上都介紹要將Android源代碼中如下兩個文件復制到項目的相應位置:
com.android.internal.telephony包下的ITelephony.aidl
android.telephony包下的NeighboringCellinfo.aidl
但是下載源碼需要翻牆,有點麻煩,其實做這些的目的就是為了在根目錄下自動生成ITelephony.java源文件,因此沒有源碼也可以,具體做法如下:
1)在項目的src目錄下,新建package:com.android.internal.telephony
2) 在剛新建的package下,新建一個名為ITelephony.aidl的文件。
3) 將以下代碼拷到剛新建的文件中。
package com.android.internal.telephony; interface ITelephony{ boolean endCall(); void answerRingingCall(); }
這樣,ADT會在根目錄下自動生成ITelephony.java源文件了。
service的整個代碼如下,裡面也有解釋:
ListenService.java
package com.example.callmanager; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.text.SimpleDateFormat; import java.util.Date; import android.app.Activity; import android.app.Service; import android.content.Context; import android.content.Intent; import android.content.SharedPreferences; import android.database.Cursor; import android.database.sqlite.SQLiteDatabase; import android.media.AudioManager; import android.net.Uri; import android.os.IBinder; import android.os.RemoteException; import android.provider.ContactsContract.PhoneLookup; import android.telephony.PhoneStateListener; import android.telephony.TelephonyManager; import android.widget.Toast; import com.android.internal.telephony.ITelephony; public class ListenService extends Service { TelephonyManager tManager; private SQLiteDatabase db; private SharedPreferences spf; private CustomPhoneCallListener callListener; @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); System.out.println("create"); } @Override public int onStartCommand(Intent intent, int flags, int startId) { // TODO Auto-generated method stub tManager = (TelephonyManager)getSystemService(TELEPHONY_SERVICE); callListener = new CustomPhoneCallListener(); spf = this.getSharedPreferences("setting", Activity.MODE_PRIVATE); tManager.listen(callListener, PhoneStateListener.LISTEN_CALL_STATE); System.out.println("start"); return super.onStartCommand(intent, flags, startId); } @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); callListener = null; tManager = null; System.out.println("destory"); stopSelf(); } @Override public boolean onUnbind(Intent intent) { // TODO Auto-generated method stub return super.onUnbind(intent); } //創建或打開數據庫 public void create_db(){ //創建或打開數據庫 db = SQLiteDatabase.openOrCreateDatabase(ListenService.this.getFilesDir().toString()+"/list.db3", null); if(db == null){ Toast.makeText(ListenService.this,"數據庫創建不成功",Toast.LENGTH_LONG).show(); } else{ /*//創建另一個表,用於存放來電信息 db.execSQL("create table if not exists callInfo(_id integer primary key autoincrement," + "name varchar(50)," + "number varchar(15),"+ "callTimes varchar(20));");*/ } } //插入 public void insert_callInfo(String name,String number,String time){ Cursor cursor = db.rawQuery("select * from callInfo where callTimes = '"+time+"';",null); if(cursor.getCount() == 0){ db.execSQL("insert into callInfo(name,number,callTimes) values('"+ name+ "','" + number +"','" + time + "');"); } cursor.close(); } public class CustomPhoneCallListener extends PhoneStateListener{ @Override public void onCallStateChanged(int state, String incomingNumber) { super.onCallStateChanged(state, incomingNumber); if(spf.getBoolean("isStartListen", false)){ //判斷該電話是否在黑名單中 create_db(); boolean callEnd_flag = false; String incomingName = null; SimpleDateFormat formatter = new SimpleDateFormat ("MM-dd HH:mm"); Date curDate = new Date(System.currentTimeMillis());//獲取當前時間 String strTime = formatter.format(curDate); //如果啟用白名單模式 if(spf.getBoolean("isWhiteList",false)){ System.out.println("whiteList"); callEnd_flag = !isInWhiteList(incomingNumber); //根據號碼找到聯系人姓名 incomingName = getContactsNameByNumber(incomingNumber); } //如果是黑名單模式 else{ incomingName = isInBalckList(incomingNumber); if(incomingName == null) callEnd_flag = false; else callEnd_flag = true; } //如果啟用時間段,則判斷當前撥打電話時間是否在設定時間段中 if(spf.getBoolean("isTime", false)){ System.out.println("inTime"); callEnd_flag = callEnd_flag && isInterceptTime(strTime); } switch(state){ case TelephonyManager.CALL_STATE_IDLE: break; case TelephonyManager.CALL_STATE_OFFHOOK : break; //當電話呼入時 case TelephonyManager.CALL_STATE_RINGING : toggleRingerMute(getApplicationContext()); if(callEnd_flag){ try { Method method = Class.forName("android.os.ServiceManager").getMethod("getService", String.class); //獲取遠程telephony_service的IBindler對象的代理 IBinder binder = (IBinder)method.invoke(null, new Object[]{TELEPHONY_SERVICE}); //將IBinder對象的代理轉換為ITelephony對象 ITelephony telephony = ITelephony.Stub.asInterface(binder); //掛斷電話 telephony.endCall(); } catch (NoSuchMethodException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (ClassNotFoundException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalAccessException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (IllegalArgumentException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (InvocationTargetException e) { // TODO Auto-generated catch block e.printStackTrace(); } catch (RemoteException e) { // TODO Auto-generated catch block e.printStackTrace(); } //將該號碼插入來電信息數據庫中 //獲得當前的時間 if(incomingName == null){ incomingName = "陌生號碼"; } insert_callInfo(incomingName, incomingNumber, strTime); } System.out.println("bindListen"); break; } } db.close(); } } //通過電話號碼查找聯系人的姓名,如果查找到,則返回聯系人的姓名,否則,返回null public String getContactsNameByNumber(String number){ Cursor c = getContentResolver().query(Uri.withAppendedPath( PhoneLookup.CONTENT_FILTER_URI, number), new String[] { PhoneLookup._ID, PhoneLookup.NUMBER, PhoneLookup.DISPLAY_NAME, PhoneLookup.TYPE, PhoneLookup.LABEL }, null, null, null ); if(c.getCount() == 0){ return null; } else { c.moveToFirst(); return c.getString(2); //獲取姓名 } } private static int previousMuteMode = -1; /** * 來電靜音 * * @param context */ private void toggleRingerMute(Context context) { AudioManager am = (AudioManager) context.getSystemService(Context.AUDIO_SERVICE); if (previousMuteMode == -1) { previousMuteMode = am.getRingerMode(); am.setRingerMode(0); } am.setRingerMode(previousMuteMode); previousMuteMode = -1; } //判斷當前撥打時間 是否在攔截時間段裡 public boolean isInterceptTime(String time){ //如果啟用時間段 if(spf.getBoolean("isTime", false)){ String startTime = spf.getString("startTime", ""); String endTime = spf.getString("endTime", ""); //比較當前時間是否在攔截時間段內 if(time.compareTo(startTime) >= 0 && time.compareTo(endTime) <= 0){ return true; } } return false; } //判斷給定號碼是否在白名單中 public boolean isInWhiteList(String phone){ Cursor cursor = db.rawQuery("select * from whiteList where number='"+phone+"';", null); cursor.moveToFirst(); //如果該號碼在白名單中,則返回true if(cursor.getCount() > 0){ cursor.close(); return true; } return false; } //判斷給定號碼是否在黑名單中 public String isInBalckList(String phone){ Cursor cursor = db.rawQuery("select * from blackList where number='"+phone+"';", null); String name = null; cursor.moveToFirst(); if(cursor.getCount()>0) name = cursor.getString(cursor.getColumnIndex("name")); cursor.close(); return name; } @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return null; } }
代碼很長,但核心的就是CustomPhoneCallListener這一部分,裡面的主要思路就是通過讀取用戶的設置信息,判斷是否攔截。
這裡同時也實現了,將攔截信息寫入數據庫,所以也就有了上述代碼中的數據庫的相關代碼了。
最後,重要的一點,就是,和Activity一樣,service同樣也需要進行注冊,在AndroidManifest.xml裡添加:
當然,因為要監聽來電狀態,少不了讀取通話記錄和讀取電話狀態的權限,在AndroidManifest.xml裡添加:
這樣,在該需要啟用該監聽服務時,就可以通過Intent來啟動該服務,當啟用該服務後,即使退出了Activity,也可以實現監聽,因為service依然在後台運行,這就是service最基本的功能。
最近開發App,美工設計了一個有鋸齒邊沿效果的背景圖,只給了我一個鋸齒,然後需要平鋪展示鋸齒效果: android中實現平鋪圖片有兩種方式:(1)在drawable中的d
本次分兩個大方向去講解Web Api,1、如何實現Web Api?2、如何Android端如何調用Web Api?對於Web Api是什麼?有什麼優缺點?為什麼用WebA
手機qq厘米秀是手機qq最新版本全新推出的一個全新的功能,您可以下載qq厘米秀內測版獲得更多qq獨特的表情和個人形象,手機qq厘米秀是PC版QQ秀在移動端的
小米手環是小米公司自主研發的電子智能輔助器,最近小米手環APP迎來了一次更新,多了幾個新功能,同時在微信接入位置也發生了改變,今天當下小編就小米手環如何接入