Android 實現(xiàn)手機接通電話后振動提示的功能
有些手機在電話接通后會有振動提示,這有個好處就是可以等到接通后再放到耳邊接聽,減少輻射。本文就講講如何在Android手機中實現(xiàn)這種接通電話后的振動提示功能,這里主要針對撥出的電話。
Android SDK提供的通話狀態(tài)
很明顯,要在電話接通的時候產(chǎn)生振動提示,首先需要知道電話在何時被接通。而Android SDK并沒有給出直接讀取這種狀態(tài)的方法。下面是Android SDK的電話服務(wù)類TelephonyManager提供的三種電話狀態(tài):
CALL_STATE_IDLE 空閑狀態(tài)
CALL_STATE_OFFHOOK 摘機狀態(tài)
CALL_STATE_RINGING 響鈴狀態(tài)
這幾個狀態(tài)很容易理解:摘機狀態(tài)即拿起話筒(對于座機電話而言的動作),但這個狀態(tài)可能發(fā)生在撥入電話接通時,也可能是撥出電話時,但是卻不能說明撥出電話接通時。通過以上3種狀態(tài)我們僅能組合出掛機和來電接通這兩個狀態(tài)。而今天我們要實現(xiàn)的功能卻無法做到。
看來我們需要尋找其他方法來實現(xiàn)了,SDK靠不住啊……
Android運行l(wèi)og分析
還好Android在運行時會有大量的log產(chǎn)生,看看我們能不能從這上面找到突波口呢?我們選擇Android的Radio模塊的日志來分析。首先我們需要寫一段代碼來讀取Radio相關(guān)的log,讀取log就不得不用到logcat了。
Process process;
InputStream inputstream;
BufferedReader bufferedreader;
try {
process = Runtime.getRuntime().exec("logcat -v time -b radio");
inputstream = process.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(
inputstream);
bufferedreader = new BufferedReader(inputstreamreader);
String str = "";
while ((str = bufferedreader.readLine()) != null) {
log.i("mLogcat",str);
}
} catch (Exception e) {
}
另外,要讓程序能夠讀取系統(tǒng)log需要指定權(quán)限,在AndroidManifest.xml文件中加入一下內(nèi)容。
XML/HTML代碼
<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>
通過上面這段代碼我們就可以將Radio的log輸出到了,這樣我們就可以通過在DDMS中查看這些log,分析其中的通話過程。具體抓到的log就不貼出來了,大家可以自己編寫程序通過上面的代碼來抓取和分析。我只說一下我的分析結(jié)果。
通過分析log發(fā)現(xiàn)了一些蛛絲馬跡。其中有幾條日志很有用:
GET_CURRENT_CALLS id=1,DIALING
GET_CURRENT_CALLS id=1,ALERTING
GET_CURRENT_CALLS id=1,ACTIVE
由于log較長我只拿了每條log的開頭部分,真實的會多很多內(nèi)容。當我們撥出電話的時候,會輸入這么幾條log。
撥號->提醒->活動
大致是這么個過程。經(jīng)過幾次測試發(fā)現(xiàn),電話接通時會進入活動狀態(tài),并會輸出:GET_CURRENT_CALLS id=1,ACTIVE 這條log,至此我們已經(jīng)接近成功了。
不過之后我又發(fā)現(xiàn)在撥號開始到電話接通這段時間內(nèi)會經(jīng)過多次的“撥號->提醒->活動”這樣的狀態(tài)變化,僅當話筒中嘟聲響起后GET_CURRENT_CALLS這條日志會鎖定在ALERTING。在電話接通前便不再出現(xiàn)GET_CURRENT_CALLS日志了。
可能上面的這段表述大家不是很清楚,換句話說在通話接通之前會出現(xiàn)多次的GET_CURRENT_CALLS ACTIVE 這樣的日志,而僅有一次是電話接通產(chǎn)生的。這就給我們造成了麻煩。不能只是單純的抓取GET_CURRENT_CALLS ACTIVE 這樣的信息來判斷了。
我們只能通過一些邏輯上的判斷來實現(xiàn)了。
實例代碼講解
下面看我的代碼:
class TestThread implements Runnable {
//振動器
Vibrator mVibrator;
//電話服務(wù)
TelephonyManager telManager;
public TestThread(Vibrator mVibrator, TelephonyManager telManager) {
this.mVibrator = mVibrator;
this.telManager = telManager;
}
@Override
public void run() {
//獲取當前話機狀態(tài)
int callState = telManager.getCallState();
Log.i("TestService", "開始.........." + Thread.currentThread().getName());
//記錄撥號開始時間
long threadStart = System.currentTimeMillis();
Process process;
InputStream inputstream;
BufferedReader bufferedreader;
try {
process = Runtime.getRuntime().exec("logcat -v time -b radio");
inputstream = process.getInputStream();
InputStreamReader inputstreamreader = new InputStreamReader(
inputstream);
bufferedreader = new BufferedReader(inputstreamreader);
String str = "";
long dialingStart = 0;
boolean enableVibrator = false;
boolean isAlert = false;
while ((str = bufferedreader.readLine()) != null) {
//如果話機狀態(tài)從摘機變?yōu)榭臻e,銷毀線程
if (callState == TelephonyManager.CALL_STATE_OFFHOOK
&& telManager.getCallState() == TelephonyManager.CALL_STATE_IDLE) {
break;
}
// 線程運行5分鐘自動銷毀
if (System.currentTimeMillis() - threadStart > 300000) {
break;
}
Log.i("TestService", Thread.currentThread().getName() + ":"
+ str);
// 記錄GSM狀態(tài)DIALING
if (str.contains("GET_CURRENT_CALLS")
&& str.contains("DIALING")) {
// 當DIALING開始并且已經(jīng)經(jīng)過ALERTING或者首次DIALING
if (!isAlert || dialingStart == 0) {
//記錄DIALING狀態(tài)產(chǎn)生時間
dialingStart = System.currentTimeMillis();
isAlert = false;
}
continue;
}
if (str.contains("GET_CURRENT_CALLS")
&& str.contains("ALERTING")&&!enableVibrator) {
long temp = System.currentTimeMillis() - dialingStart;
isAlert = true;
//這個是關(guān)鍵,當?shù)谝淮蜠IALING狀態(tài)的時間,與當前的ALERTING間隔時間在1.5秒以上并且在20秒以內(nèi)的話
//那么認為下次的ACTIVE狀態(tài)為通話接通.
if (temp > 1500 && temp < 20000) {
enableVibrator = true;
Log.i("TestService", "間隔時間....." + temp + "....."
+ Thread.currentThread().getName());
}
continue;
}
if (str.contains("GET_CURRENT_CALLS") && str.contains("ACTIVE")
&& enableVibrator) {
mVibrator.vibrate(100);
enableVibrator = false;
break;
}
}
Log.i("TestService", "結(jié)束.........."
+ Thread.currentThread().getName());
} catch (Exception e) {
// TODO: handle exception
}
}
}
我的這個方法比較牽強,是通過判斷第一次DIALING與每一次ALERTING之間的間隔,如果間隔大于1.5秒,那么認為已經(jīng)進入了“嘟”聲提示的時候了,那么下一個ACTIVE將是電話接通。這個1.5秒是通過分析日志得出的。但是這種方法我始終覺得不太靠譜。如果大家有好的方法可以交流交流。
剩下的就是讓這個線程在電話撥出時觸發(fā),并且常駐在電話中時候準備這就可以了??梢圆捎肧ervice配合Receiver來實現(xiàn)。Service來實現(xiàn)常駐,Receiver來實現(xiàn)監(jiān)聽撥出電話?;揪涂梢酝瓿晌覀兿胍墓δ芰恕?/p>
以上代碼我都測試過,99%有效,哈哈。這里面提到了一些Android的基礎(chǔ)內(nèi)容,像logcat、Service、Receiver,這些如果大家不了解的話可以找相關(guān)文章資料學(xué)習(xí)下。
通過此文希望能幫助Android 開發(fā)的朋友,謝謝大家對本站的支持!
相關(guān)文章
使用android studio開發(fā)工具編譯GBK轉(zhuǎn)換三方庫iconv的方法
這篇文章主要介紹了使用android studio開發(fā)工具編譯GBK轉(zhuǎn)換三方庫iconv的教程,本文通過圖文并茂的形式給大家介紹的非常詳細,對大家的學(xué)習(xí)或工作具有一定的參考借鑒價值,需要的朋友可以參考下2020-06-06
在Android Studio中Parcelable插件的簡單使用教程
下面小編就為大家分享一篇在Android Studio中Parcelable插件的簡單使用教程,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2017-11-11
Android常用命令集錦(圖文并茂適應(yīng)于初學(xué)者)
大家好,今天我們要講的是android開發(fā)中,比較常用的名令集錦, 在我們開發(fā)中難免用到Android命令,有些確實命令確實很有用處,這也是我為什么總結(jié)這篇文章的原因了,希望對大家有所幫助2013-01-01
Android自定義RadioGroupX實現(xiàn)多行多列布局
這篇文章主要為大家詳細介紹了Android自定義RadioGroupX實現(xiàn)多行多列布局,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-09-09
Android開發(fā)自定義控件之折線圖實現(xiàn)方法詳解
這篇文章主要介紹了Android開發(fā)自定義控件之折線圖實現(xiàn)方法,結(jié)合實例形式詳細分析了Android自定義控件中折線圖原理、實現(xiàn)方法與操作注意事項,需要的朋友可以參考下2020-05-05

