Android 實現手機接通電話後震動提示的功能_Android

來源:互聯網
上載者:User

有些手機在電話接通後會有震動提示,這有個好處就是可以等到接通後再放到耳邊接聽,減少輻射。本文就講講如何在Android手機中實現這種接通電話後的震動提示功能,這裡主要針對撥出的電話。

       Android SDK提供的通話狀態

       很明顯,要在電話接通的時候產生震動提示,首先需要知道電話在何時被接通。而Android SDK並沒有給出直接讀取這種狀態的方法。下面是Android SDK的電話語音類TelephonyManager提供的三種電話狀態:

       CALL_STATE_IDLE         空閑狀態

       CALL_STATE_OFFHOOK 摘機狀態

       CALL_STATE_RINGING   響鈴狀態

       這幾個狀態很容易理解:摘機狀態即拿起話筒(對於有線電話電話而言的動作),但這個狀態可能發生在撥入電話接通時,也可能是已撥電話時,但是卻不能說明已撥電話接通時。通過以上3種狀態我們僅能組合出掛機和來電接通這兩個狀態。而今天我們要實現的功能卻無法做到。

       看來我們需要尋找其他方法來實現了,SDK靠不住啊……

       Android運行log分析

       還好Android在運行時會有大量的log產生,看看我們能不能從這上面找到突波口呢?我們選擇Android的Radio模組的日誌來分析。首先我們需要寫一段代碼來讀取Radio相關的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) {       } 

另外,要讓程式能夠讀取系統log需要指定許可權,在AndroidManifest.xml檔案中加入一下內容。

XML/HTML代碼

<uses-permission android:name="android.permission.READ_LOGS"></uses-permission>  

       通過上面這段代碼我們就可以將Radio的log輸出到了,這樣我們就可以通過在DDMS中查看這些log,分析其中的通話過程。具體抓到的log就不貼出來了,大家可以自己編寫程式通過上面的代碼來抓取和分析。我只說一下我的分析結果。

       通過分析log發現了一些蛛絲馬跡。其中有幾條日誌很有用:

       GET_CURRENT_CALLS  id=1,DIALING

       GET_CURRENT_CALLS  id=1,ALERTING

       GET_CURRENT_CALLS  id=1,ACTIVE

       由於log較長我只拿了每條log的開頭部分,真實的會多很多內容。當我們已撥電話的時候,會輸入這麼幾條log。

       撥號->提醒->活動

       大致是這麼個過程。經過幾次測試發現,電話接通時會進入活動狀態,並會輸出:GET_CURRENT_CALLS  id=1,ACTIVE  這條log,至此我們已經接近成功了。

       不過之後我又發現在撥號開始到電話接通這段時間內會經過多次的“撥號->提醒->活動”這樣的狀態變化,僅當話筒中嘟聲響起後GET_CURRENT_CALLS這條日誌會鎖定在ALERTING。在電話接通前便不再出現GET_CURRENT_CALLS日誌了。

       可能上面的這段表述大家不是很清楚,換句話說在通話接通之前會出現多次的GET_CURRENT_CALLS ACTIVE 這樣的日誌,而僅有一次是電話接通產生的。這就給我們造成了麻煩。不能只是單純的抓取GET_CURRENT_CALLS ACTIVE 這樣的資訊來判斷了。

       我們只能通過一些邏輯上的判斷來實現了。

       執行個體代碼講解

       下面看My Code:

class TestThread implements Runnable {  //震動器  Vibrator mVibrator;  //電話語音  TelephonyManager telManager;  public TestThread(Vibrator mVibrator, TelephonyManager telManager) {   this.mVibrator = mVibrator;   this.telManager = telManager;  }  @Override  public void run() {   //擷取當前話機狀態   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) {     //如果話機狀態從摘機變為空白閑,銷毀線程     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狀態DIALING     if (str.contains("GET_CURRENT_CALLS")       && str.contains("DIALING")) {      // 當DIALING開始並且已經經過ALERTING或者首次DIALING      if (!isAlert || dialingStart == 0) {       //記錄DIALING狀態產生時間       dialingStart = System.currentTimeMillis();       isAlert = false;      }      continue;     }     if (str.contains("GET_CURRENT_CALLS")       && str.contains("ALERTING")&&!enableVibrator) {            long temp = System.currentTimeMillis() - dialingStart;      isAlert = true;      //這個是關鍵,當第一次DIALING狀態的時間,與當前的ALERTING間隔時間在1.5秒以上並且在20秒以內的話      //那麼認為下次的ACTIVE狀態為通話接通.      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", "結束.........."      + Thread.currentThread().getName());   } catch (Exception e) {    // TODO: handle exception   }  } } 

      我的這個方法比較牽強,是通過判斷第一次DIALING與每一次ALERTING之間的間隔,如果間隔大於1.5秒,那麼認為已經進入了“嘟”聲提示的時候了,那麼下一個ACTIVE將是電話接通。這個1.5秒是通過分析日誌得出的。但是這種方法我始終覺得不太靠譜。如果大家有好的方法可以交流交流。

       剩下的就是讓這個線程在電話撥出時觸發,並且常駐在電話中時候準備這就可以了。可以採用Service配合Receiver來實現。Service來實現常駐,Receiver來實現監聽已撥電話。基本就可以完成我們想要的功能了。

        以上代碼我都測試過,99%有效,哈哈。這裡面提到了一些Android的基礎內容,像logcat、Service、Receiver,這些如果大家不瞭解的話可以找相關文章資料學習下。

        通過此文希望能協助Android 開發的朋友,謝謝大家對本站的支援!

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.