編輯:關於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最基本的功能。
Android實現平鋪圖片效果
最近開發App,美工設計了一個有鋸齒邊沿效果的背景圖,只給了我一個鋸齒,然後需要平鋪展示鋸齒效果: android中實現平鋪圖片有兩種方式:(1)在drawable中的d
android移動開發學習筆記(二)神奇的Web API
本次分兩個大方向去講解Web Api,1、如何實現Web Api?2、如何Android端如何調用Web Api?對於Web Api是什麼?有什麼優缺點?為什麼用WebA
qq厘米秀怎麼邀請?qq厘米秀使用常見問題及解決方法匯總
手機qq厘米秀是手機qq最新版本全新推出的一個全新的功能,您可以下載qq厘米秀內測版獲得更多qq獨特的表情和個人形象,手機qq厘米秀是PC版QQ秀在移動端的
小米手環怎麼接入微信 小米手環接入微信方法
小米手環是小米公司自主研發的電子智能輔助器,最近小米手環APP迎來了一次更新,多了幾個新功能,同時在微信接入位置也發生了改變,今天當下小編就小米手環如何接入