【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android源碼個(gè)個(gè)擊破之撥號(hào)源碼_第1頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android源碼個(gè)個(gè)擊破之撥號(hào)源碼_第2頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android源碼個(gè)個(gè)擊破之撥號(hào)源碼_第3頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android源碼個(gè)個(gè)擊破之撥號(hào)源碼_第4頁(yè)
【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android源碼個(gè)個(gè)擊破之撥號(hào)源碼_第5頁(yè)
已閱讀5頁(yè),還剩8頁(yè)未讀, 繼續(xù)免費(fèi)閱讀

下載本文檔

版權(quán)說(shuō)明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請(qǐng)進(jìn)行舉報(bào)或認(rèn)領(lǐng)

文檔簡(jiǎn)介

【移動(dòng)應(yīng)用開(kāi)發(fā)技術(shù)】Android源碼個(gè)個(gè)擊破之撥號(hào)源碼

#############需求#############最近我的一位同事大概是利用下面的方法監(jiān)聽(tīng)電話的狀態(tài)

/20110725/417.html

/lyen2010/article/details/42590099

相關(guān)demo下載鏈接:/download/weiyirong/6872889本來(lái)我是將系統(tǒng)的ITelephony.aidl復(fù)制進(jìn)去,但是編譯會(huì)報(bào)notfounttheimportclassxx錯(cuò)誤,于是看了一下上面的demo,對(duì)aidl作了簡(jiǎn)化:interface

ITelephony

{

boolean

endCall();

void

answerRingingCall();

boolean

enableDataConnectivity();

boolean

disableDataConnectivity();

boolean

isDataConnectivityPossible();

}

aidl文件及目錄建好,重新rebuild工程,就會(huì)在對(duì)應(yīng)的build目錄下生成對(duì)應(yīng)的java文件

然后我同事說(shuō)遇到兩個(gè)問(wèn)題

1.電話接通之后,無(wú)法掛斷

2.通話狀態(tài)無(wú)法正常顯示(準(zhǔn)確的說(shuō)是:通話中的狀態(tài)不顯示)

我寫(xiě)了個(gè)測(cè)試demo

掛斷方法:

public

void

hangup_call(View

view)

{

Log.e(TAG,"hangup_call

START");

...

}

接通電話之后,點(diǎn)擊掛斷按鈕:無(wú)響應(yīng),日志也沒(méi)有打。

我隱隱約約感覺(jué)線程阻塞了,果然接聽(tīng)加上線程就解決了問(wèn)題。上面的問(wèn)題就是接聽(tīng)電話阻塞了主線程,所以掛斷按鈕點(diǎn)擊不了,廣播也阻塞了。

#############源碼研究#############以下源碼基于android6.0.1撥號(hào)源碼詳解:

/so/search/s.do?q=Android6.0%E7%9A%84phone%E5%BA%94%E7%94%A8%E6%BA%90%E7%A0%81%E5%88%86%E6%9E%90&t=blog&u=u014386544撥號(hào)源碼架構(gòu):

/p/ca4ab4e9817f/

(一個(gè)電話應(yīng)用,實(shí)際由多個(gè)代碼模塊組成。由dialer下的Android.mk可以看出)

/wds1181977/article/details/61920067

(介紹各個(gè)模塊的作用)一、撥號(hào)

假如我不想調(diào)用系統(tǒng)的INTENT來(lái)打電話(最直接的方法就是調(diào)用ITelephony,文章開(kāi)頭已經(jīng)介紹過(guò)),那么就得對(duì)系統(tǒng)打電話的INTENT做一番探索了。

通過(guò)調(diào)用Intent.ACTION_CALL,會(huì)打開(kāi)系統(tǒng)的撥號(hào)引用。

向外撥號(hào),發(fā)現(xiàn)當(dāng)前顯示的activity是(通過(guò)sdk工具):

InCallActivity.java

現(xiàn)在,我們需求是想自己實(shí)現(xiàn)撥號(hào)級(jí)來(lái)電接聽(tīng),不走系統(tǒng)UI。

所以,我的思路是先確定Intent.ACTION_CALL是被誰(shuí)處理了,怎么處理的,如何調(diào)起InCallActivity,InCallActivity又干了啥。

InCallActivity被誰(shuí)打開(kāi)的

在xref全局搜索,發(fā)現(xiàn)InCallPresenter.java這個(gè)類(lèi)

通過(guò)官方的解釋,可以知道此類(lèi)正是管理通話狀態(tài),開(kāi)啟InCallActivity。搜索InCallPresenter又會(huì)被很多類(lèi)調(diào)用,可見(jiàn)此類(lèi)是集中處理通話狀態(tài)的核心類(lèi)。其中有

InCallServiceImpl,InCallServiceImpl注冊(cè)在dialer的清單文件里:

二、屏蔽原始UI

1./zuiaikg703/article/details/8178028

電話的UI都是通過(guò)InCallActivity添加Fragment實(shí)現(xiàn)的,所以,只要把其UI屏蔽掉就可以了。(修改源碼要一針見(jiàn)血,找到最佳修改位置。這樣既能減少工作量又能避免修改錯(cuò)誤)

2.但是來(lái)電時(shí)顯示的那個(gè)懸浮窗是如何出現(xiàn)的呢?如何屏蔽掉?

/u012439416/article/details/78946337

首先,得從“來(lái)電”來(lái)出發(fā)尋找,其實(shí)這個(gè)UI就叫做StatusBarNotifier

在InCallPresenter里找到一些蛛絲馬跡:

看看官方對(duì)此類(lèi)的解釋:

準(zhǔn)備把下面的方法注釋掉,應(yīng)該就不會(huì)顯示通知欄

經(jīng)測(cè)試,注釋上面的方法,確實(shí)可以屏蔽來(lái)電時(shí)顯示的通知欄。

三、主動(dòng)撥號(hào)之后無(wú)法掛斷的問(wèn)題

在(二.1),屏蔽IncallUI之后,發(fā)現(xiàn)主動(dòng)往外打電話之后,其他的按鈕沒(méi)法點(diǎn)擊。

public

void

call(View

view)

{

Log.d(TAG,

"call:

");

/*

//取得一個(gè)Callintent

final

Intent

intent

=

CallUtil.getCallIntent();

//交給DialerUtils去處理

DialerUtils.startActivityWithErrorToast(this,

intent);*/

callThread

=

new

Thread(){

@Override

public

void

run()

{

try

{

ITelephony

iTelephony

=

PhoneUtils.getITelephony((TelephonyManager)MainActivity.this.getSystemService(

Context.TELEPHONY_SERVICE));

iTelephony.call(getPackageName(),);

}

catch

(Exception

e)

{

Log.e(TAG,

"[Broadcast]Exception111="+e.getMessage(),

e);

}

}

};

callThread.start();

}

所以我猜想有2種原因:

1)打電話時(shí)InCallActivity彈出來(lái)了(眼睛看不見(jiàn)),擋住了我的Activity

2)系統(tǒng)電話的call方法阻塞了UI線程

是否是系統(tǒng)的UI擋住了我的Activity:

將上面的InCallActivity的布局顯示出來(lái),果然,是有個(gè)系統(tǒng)的撥打電話的界面。

那么如何隱藏并這個(gè)activity界面并屏蔽它的所有時(shí)間

1)將InCallActivity的theme變成透明

↓↓↓

2)屏蔽InCallActivity的點(diǎn)擊事件

在InCallActivity的onCreate方法里加上下面代碼

this.getWindow().setFlags(WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE,WindowManager.LayoutParams.FLAG_NOT_TOUCHABLE);

3)屏蔽InCallActivity對(duì)狀態(tài)欄的改變

對(duì)系統(tǒng)電話的call方法發(fā)起追蹤研究:

1.找service

↓↓↓

↓↓↓

注意Context.TELEPHONY_SERVICE的值是“phone”

通過(guò)搜索“extendsITelephony.Stub

”或者“phone”可以找到ITelephony的Service類(lèi)/packages/services/Telephony/src/com/android/phone/PhoneInterfaceManager.java:

可以看到這個(gè)service

上面的init方法在PhoneGlobals的onCreate方法里被調(diào)用

2.分析service的相應(yīng)call方法

↓↓↓

可以看到最終也是通過(guò)Intent去打開(kāi)撥號(hào)頁(yè)面的。

三、主動(dòng)撥號(hào)之后對(duì)方?jīng)]有接聽(tīng)直接掛斷,ITelephony沒(méi)有回調(diào)的問(wèn)題。

此種情況雖然ITelephony沒(méi)有回調(diào),但是系統(tǒng)會(huì)有個(gè)無(wú)人接聽(tīng)的提示語(yǔ)音,可以在此處修改系統(tǒng)源碼,人工發(fā)一個(gè)空閑狀態(tài)廣播。

四、去電,PhoneListener的狀態(tài)瞎回調(diào)的問(wèn)題。

去電時(shí):android6.0系統(tǒng)會(huì)立馬發(fā)一個(gè)通話中和空閑的狀態(tài),這些其實(shí)都是錯(cuò)誤的回調(diào)。需要人為的去處理,可以根據(jù)時(shí)間來(lái)過(guò)濾判斷,但是具有不可靠性。

一般對(duì)方接通電話之后,會(huì)再回調(diào)一個(gè)正確的通話中狀態(tài)。但有時(shí)候不會(huì)回調(diào)。

第一個(gè)錯(cuò)誤的空閑的狀態(tài)很好解決:

點(diǎn)擊撥打電話的按鈕時(shí),將Constants.isPhoneOut設(shè)置為true。 case

TelephonyManager.CALL_STATE_IDLE:

//

空閑

0

Log.d(tag,

"CALL_STATE_IDLE00isPhoneOut

=

"

+

Constants.isPhoneOut);

if(Constants.isPhoneOut

==

true){

//撥打電話時(shí),系統(tǒng)會(huì)誤發(fā)一個(gè)掛斷的廣播,需要自己區(qū)分處理

Constants.isPhoneOut

=

false;

return;

}

但是如果主動(dòng)往外撥打,對(duì)方?jīng)]有接通或者掛斷,是不會(huì)收到空閑回調(diào)的。上面這種判斷就會(huì)有缺陷,所以準(zhǔn)備找到撥打電話的源碼,去掉撥打電話前誤發(fā)的空閑狀態(tài)。

發(fā)現(xiàn)底層的回調(diào)是這樣的:07-15

17:16:28.591

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

NO_CALLS

->

NO_CALLS

07-15

17:16:28.666

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:16:28.725

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

PENDING_OUTGOING

07-15

17:16:28.774

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

PENDING_OUTGOING

->

INCALL

07-15

17:16:28.791

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

INCALL

07-15

17:16:28.819

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

INCALL

07-15

17:16:28.828

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

INCALL

07-15

17:16:28.830

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

INCALL

07-15

17:16:29.111

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

OUTGOING

07-15

17:16:30.776

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:16:30.833

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:16:30.849

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:16:30.863

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:16:30.878

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:16:30.892

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

OUTGOING

07-15

17:18:13.357

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

OUTGOING

->

INCALL

07-15

17:18:13.416

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

INCALL

07-15

17:18:15.404

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

INCALL

->

NO_CALLS

07-15

17:18:15.448

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

NO_CALLS

->

NO_CALLS

07-15

17:18:15.499

5456-5456/com.android.dialer

I/InCall:

InCallPresenter

-

Phone

switching

state22222:

NO_CALLS

->

NO_CALLS

撥打電話,系統(tǒng)立馬會(huì)發(fā)NO_CALLS->NO_CALLS狀態(tài),也就是app會(huì)無(wú)緣無(wú)故收到空閑狀態(tài)的原因。但是這個(gè)狀態(tài)不好限制。

等了很久,系統(tǒng)會(huì)發(fā)送OUTGOING->INCALL,也就是通話中狀態(tài),這也是個(gè)誤發(fā)。app不應(yīng)做處理。

最后會(huì)發(fā)個(gè)INCALL->NO_CALLS狀態(tài),也就是對(duì)方未接聽(tīng)或者拒接后系統(tǒng)的一個(gè)超時(shí)回調(diào),這里可以發(fā)一個(gè)空閑廣播。app處理這個(gè)空閑廣播,屏蔽api的空閑回調(diào)即可解決空閑問(wèn)題。

但是此時(shí)mInCallActivity為null,所以無(wú)法通過(guò)mInCallActivity發(fā)空閑廣播,改由mContext發(fā)送廣播。經(jīng)驗(yàn)證,mContext果然不為空。

**Log.d在logcat上不輸出日志,但是Log.i可以輸出日志。**

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

但是通話中狀態(tài)回調(diào)不準(zhǔn)確的問(wèn)題則不好解決,但是經(jīng)測(cè)試,發(fā)現(xiàn)系統(tǒng)電話應(yīng)用關(guān)于電話狀態(tài)的判斷則十分準(zhǔn)確,只有從源碼入手了。

網(wǎng)絡(luò)上搜到的關(guān)于通話中狀態(tài)判斷的解決方案:/qwe749082787/article/details/78364112

/qwe749082787/article/details/78364112

(可以修改源碼,此處發(fā)一個(gè)廣播),事實(shí)證明此方法行不通,撥打電話還沒(méi)有通話就回調(diào)了。

XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX

突然我腦洞大開(kāi),查看了一下電話應(yīng)用com.android.dialer的日志,發(fā)現(xiàn),在InCallPresenter類(lèi)里,在來(lái)電接聽(tīng)會(huì)有系統(tǒng)日志:

Phoneswitchingstate:INCOMING->INCALL

去電時(shí)會(huì)有系統(tǒng)日志:

Phoneswitchingstate:OUTGOING->INCALL

而且這個(gè)日志不會(huì)重復(fù),可以在上面發(fā)送兩個(gè)自定義廣播,就能準(zhǔn)確監(jiān)聽(tīng)到通話中狀態(tài)了。

在測(cè)試中發(fā)現(xiàn)

OUTGOING->INCALL,這個(gè)不一定只有去電通話中才會(huì)回調(diào),需要結(jié)合前一個(gè)狀態(tài)變化聯(lián)合判斷:

所以修改InCallPresenter類(lèi),緩存上一次的通話狀態(tài)變化,然后對(duì)比方能準(zhǔn)確判斷通話中的狀態(tài)

InCallState

newState

=

getPotentialStateFromCallList(callList);

InCallState

oldState

=

mInCallState;

Log.d(this,

"onCallListChange

oldState=

"

+

oldState

+

"

newState="

+

newState);

newState

=

startOrFinishUi(newState);

Log.d(this,

"onCallListChange

newState

changed

to

"

+

newState);

String

oldStateLast

=

phone_state_cacheSp.getString("oldState",

"");

溫馨提示

  • 1. 本站所有資源如無(wú)特殊說(shuō)明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請(qǐng)下載最新的WinRAR軟件解壓。
  • 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請(qǐng)聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
  • 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁(yè)內(nèi)容里面會(huì)有圖紙預(yù)覽,若沒(méi)有圖紙預(yù)覽就沒(méi)有圖紙。
  • 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
  • 5. 人人文庫(kù)網(wǎng)僅提供信息存儲(chǔ)空間,僅對(duì)用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對(duì)用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對(duì)任何下載內(nèi)容負(fù)責(zé)。
  • 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請(qǐng)與我們聯(lián)系,我們立即糾正。
  • 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時(shí)也不承擔(dān)用戶因使用這些下載資源對(duì)自己和他人造成任何形式的傷害或損失。

最新文檔

評(píng)論

0/150

提交評(píng)論