aidl源碼
『壹』 android怎麼寫aidl文件
建立AIDL服務要比建立普通的服務復雜一些,具體步驟如下:
(1)在Eclipse Android工程的java包目錄中建立一個擴展名為aidl的文件。該文件的語法類似於Java代碼,但會稍有不同。詳細介紹見實例52的內容。
(2)如果aidl文件的內容是正確的,ADT會自動生成一個Java介面文件(*.java)。
(3)建立一個服務類(Service的子類)。
(4)實現由aidl文件生成的Java介面。
(5)在AndroidManifest.xml文件中配置AIDL服務,尤其要注意的是,<action>標簽中android:name的屬性值就是客戶端要引用該服務的ID,也就是Intent類的參數值。
建立AIDL服務
本例中將建立一個簡單的AIDL服務。這個AIDL服務只有一個getValue方法,該方法返回一個String類型的值。在安裝完服務後,會在客戶端調用這個getValue方法,並將返回值在TextView組件中輸出。建立這個AIDL服務的步驟如下:
(1)建立一個aidl文件。在Java包目錄中建立一個IMyService.aidl文件。IMyService.aidl文件的位置如圖
IMyService.aidl文件的內容如下:
Java代碼:
package eoe.demo;
interface IMyService {
String getValue();
}
IMyService.aidl文件的內容與Java代碼非常相似,但要注意,不能加修飾符(例如,public、private)、AIDL服務不支持的數據類型(例如,InputStream、OutputStream)等內容。
(2)如果IMyService.aidl文件中的內容輸入正確,ADT會自動生成一個IMyService.java文件。讀者一般並不需要關心這個文件的具體內容,也不需要維護這個文件。關於該文件的具體內容,讀者可以查看本節提供的源代碼。
(3)編寫一個MyService類。MyService是Service的子類,在MyService類中定義了一個內嵌類(MyServiceImpl),該類是IMyService.Stub的子類。MyService類的代碼如下:
Java代碼:
package eoe.demo;
import android.app.Service;
import android.content.Intent;
import android.os.IBinder;
import android.os.RemoteException;
public class MyService extends Service {
public class MyServiceImpl extends IMyService.Stub {
@Override
public String getValue() throws RemoteException {
return "Android/OPhone開發講義";
}
}
@Override
public IBinder onBind(Intent intent) {
return new MyServiceImpl();
}
}
在編寫上面代碼時要注意如下兩點:
IMyService.Stub是根據IMyService.aidl文件自動生成的,一般並不需要管這個類的內容,只需要編寫一個繼承於IMyService.Stub類的子類(MyServiceImpl類)即可。
onBind方法必須返回MyServiceImpl類的對象實例,否則客戶端無法獲得服務對象。
(4)在AndroidManifest.xml文件中配置MyService類,代碼如下:
Java代碼:
<service android:name=".MyService" >
<intent-filter>
<action android:name="net.blogjava.mobile.aidl.IMyService" />
</intent-filter>
</service>
下面來編寫客戶端的調用代碼。首先新建一個Eclipse Android工程(ch08_aidlclient),並將自動生成的IMyService.java文件連同包目錄一起復制到ch08_aidlclient工程的src目錄中,如圖所示。
調用AIDL服務首先要綁定服務,然後才能獲得服務對象,代碼如下:
Java代碼:
package net.blogjava.mobile;
import net.blogjava.mobile.aidl.IMyService;
import android.app.Activity;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.os.Bundle; import android.os.IBinder;
import android.view.View; import android.view.View.OnClickListener;
import android.widget.Button; import android.widget.TextView;
public class Main extends Activity implements OnClickListener {
private IMyService myService = null;
private Button btnInvokeAIDLService;
private Button btnBindAIDLService;
private TextView textView;
private ServiceConnection serviceConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
// 獲得服務對象
myService = IMyService.Stub.asInterface(service);
btnInvokeAIDLService.setEnabled(true);
}
@Override
public void onServiceDisconnected(ComponentName name) {
}
};
@Override
public void onClick(View view) {
switch (view.getId()) {
case R.id.btnBindAIDLService:
// 綁定AIDL服務
bindService(new Intent("net.blogjava.mobile.aidl.IMyService"), serviceConnection, Context.BIND_AUTO_CREATE);
break;
case R.id.btnInvokeAIDLService:
try {
textView.setText(myService.getValue());
// 調用服務端的getValue方法
} catch (Exception e) {
}
break;
}
}
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.main);
btnInvokeAIDLService = (Button) findViewById(R.id.btnInvokeAIDLService);
btnBindAIDLService = (Button) findViewById(R.id.btnBindAIDLService); btnInvokeAIDLService.setEnabled(false);
textView = (TextView) findViewById(R.id.textview);
btnInvokeAIDLService.setOnClickListener(this);
btnBindAIDLService.setOnClickListener(this);
}。
『貳』 如何在android中使用閃光燈
下圖是android學習手冊中的介紹截圖,例子、文檔、源碼隨便看。

用IHardwareService直接控制Android1.5以前是直接提供這個介面的,之後呢,需要我們自己來做一下。在你的項目中新建一個包Android.os,新建一個IHardwareService.aidl文件,內容如下:package Android.os;
/** {@hide} */
interface IHardwareService{// obsolete flashlight support
boolean getFlashlightEnabled();
void setFlashlightEnabled(boolean on);}然後在你的程序中引入import Android.os.IHardwareService;/*** 設置閃光燈的開啟和關閉
* @param isEnable
* @author linc
IBinder binder = (IBinder) method.invoke(null, new Object[] { "hardware" });
IHardwareService localhardwareservice = IHardwareService.Stub.asInterface(binder);
localhardwareservice.setFlashlightEnabled(isEnable);}catch (Exception e){
e.printStackTrace();}}這樣就可以開啟閃光燈了。要使用的許可權:<uses-permission Android:name="android.permission.FLASHLIGHT" />
<uses-permission Android:name="android.permission.HARDWARE_TEST" />
三、用照相機來控制閃光燈這是思維的另一個方向。Camera自帶豐富的介面與Parameters,我們只管拿來使用就好了。private Camera camera = null;
private Parameters parameters = null;//直接開啟camera = Camera.open();
parameters = camera.getParameters();
parameters.setFlashMode(Parameters.FLASH_MODE_TORCH);//開啟
camera.setParameters(parameters);//直接關閉parameters.setFlashMode(Parameters.FLASH_MODE_OFF);//關閉
camera.setParameters(parameters);
camera.release();
如果這樣遇到問題的話,可以嘗試用camera的preview方法:private void OpenLightOn() {
if ( null == m_Camera ){m_Camera = Camera.open();}
Camera.Parameters parameters = m_Camera.getParameters();
parameters.setFlashMode(Camera.Parameters.FLASH_MODE_TORCH);
m_Camera.setParameters( parameters );
m_Camera.autoFocus( new Camera.AutoFocusCallback (){
public void onAutoFocus(boolean success, Camera camera) {}});m_Camera.startPreview();}
private void CloseLightOff() {
if ( m_Camera != null ){m_Camera.stopPreview();
『叄』 compileDebugKotlin FAILED和aidl
自從入職CS,項目編譯一直有個神坑報錯,每次都需要clean rebuild若干次, 非常耽誤時間
簡單的說, 如果在使用AIDL時需要一個自定義的數據類型, 我們一般會這么寫:
當我們寫一個子類SubClass繼承該類.然敏毀後槐返在Kotlin文件中直接或者間接引用到SubClass時, 就會出現一個以下的報錯
報錯發生在 app:compileDebugKotlin , 也就是kotlinc. 但是我們明明已經定義了該類. 全局搜索發現有兩個 CustomParcel.java , 推測是兩個同名鉛拿飢的文件引起.
除了我們自己寫的Java文件, 另外一個肯定是aidl生成的. 引用一張圖:
在編譯開始時會把aidl轉化為Java文件, 接下來才會經過javac, kotlinc把JVM語言文件轉化為位元組碼 .class 文件.
查看aidl生成的文件, 發現是空的, 並且有一行注釋: 說明這是一個 PlaceHolder , 也就是佔位文件.
網上搜到有人遇到了 相同的問題 ,問題確實發生在kotlinC編譯器以aidl生成的空java文件為編譯目標, 而不是真正的java類文件. 並且也給出了解決辦法,升級buildTools版本.
查看 buildTools提交記錄
提交記錄: No java output for parcelable declaration . 也就是移除了以下的為自定義的aidl Parcelable類生成Java文件的設定(29.0.2之前的實現)
升級29.0.3, 再次編譯, 發現build/aidl目錄下不再生成同名的 PlaceHolder 文件了, 只剩下唯一的我們自己的文件, kotlinC這次只能用唯一的文件來編譯,報錯解決.
至於為什麼有時候clean rebuild能編譯成功,需要探究下kotlinC的源碼.
最坑的是, 29.0.2就是 gradle plugin4.1默認支持的版本 , 所以你不手動指定buildTools版本為29.0.3以上就會掉進坑裡.
『肆』 新人求教,編譯一個最簡單的Android程序,提示下面的錯誤咋解決
1、32位系統下的編譯
如果需要在32位系統中編譯android系統,在編譯前需要對部分makefile進行修改
首先修改build/core/main.mk,修改的內容如下所示:
-ifneq (64,$(findstring 64,$(build_arch)))
+ifneq
(i686,$(findstring i686,$(build_arch)))
$(warning
************************************************************) $(warning You are attempting to build on a 32-bit system.)
$(warning Only 64-bit build environments are supported beyond froyo/2.2.)
其次修改如下四個文件:
external/clearsilver/cgi/Android.mk
external/clearsilver/java-jni/Android.mk
external/clearsilver/util/Android.mk
external/clearsilver/cs/Android.mk # This forces a 64-bit build for Java6
-LOCAL_CFLAGS += -m64
-LOCAL_LDFLAGS += -m64
+LOCAL_CFLAGS += -m32
+LOCAL_LDFLAGS += -m32即將LOCAL_CFLAGS和LOCAL_LDFLAGS由-m64改為-m32,從而指定使用32位系統進行編譯如果使用 64bit 的操作系統編譯,這些就都不用修改,但記得需要安裝:For 64-bit servers the following extra packages may be needed:
"sudo apt-get install libc6-dev-i386" (libc6-dev-amd64 if AMD CPU)
"sudo apt-get install g++-multilib lib32ncurses5-dev lib32z1-dev"
還有 jdk64bit 的版本編譯2 、build/core/base_rules.mk:128:*** frameworks/opt/emoji/jni:
.... libgl2jni already defined by framwworks/base/opengl/tests/gl2_jni/jni 停止
從編譯規則上看:
# Make sure that this IS_HOST/CLASS/MODULE combination is unique.
mole_id := MODULE.$(if \
$(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE)
ifdef $(mole_id)
$(error $(LOCAL_PATH): $(mole_id) already defined by $($(mole_id)))
endif
在framwworks/base/opengl/tests/gl2_jni/下面定義的android.mk定義了:
LOCAL_MODULE := libgl2jni
include $(BUILD_SHARED_LIBRARY)
導致生成的動態庫重復,這是不對的,修改tests這個目錄不參與編譯即可,最直接的辦法刪除掉framwworks/base/opengl/tests/gl2_jni這個文件夾
3、AIDL 編譯報couldn't find import for class原因
「AIDL服務只支持有限的數據類型,因此,如果用AIDL服 務傳遞一些復雜的數據就需要做更一步處理。AIDL服務支持的數據類型如下:
Java的簡單類 型(int、char、boolean等)。不需要導入(import)。String和 CharSequence。不需要導入(import)。
List和 Map。但要注意,List和Map對象的元素類型必須是AIDL服務支持的數據類型。不需要導入(import)。AIDL自動生成 的介面。需要導入(import)。
實現 android.os.Parcelable介面的類。需要導入(import)。
其中後兩種數據類 型需要使用import進行導入,傳遞不需要 import的數據類型的值的方式相同。傳遞一個需要import的數據類型的值(例如,實現android.os.Parcelable 介面的類)的步 驟略顯復雜。除了要建立一個實現android.os.Parcelable介面的類外,還需要為這個類單獨建立一個aidl文件,並使用parcelable關鍵字進行定義。」
沒有加LOCAL_AIDL_INCLUDES += xxx ,所以找不到我的parcelable aidl文件。
修改android源碼根目錄下的build/core/pathmap.mk把你的目錄加進去,此時再make update-api
4、老是提示 @Override錯誤 方法未覆蓋其父類的方法
使 用JDK1.6編譯沒有問題,使用JDK1.5編譯,會報@Override方法未覆蓋其父類的方法。實際上這個方法是類實現的介面中方法,
但是,這個語 法的jdk1.6的下面是可以通過的,也就是說jdk1.6認為類覆蓋父類方法與實現介面方法都叫override,而jdk1.5不
是這樣認為的,不知 道這是當初jdk1.5的bug,還是當初就是認為覆蓋父類方法與實現介面方法是不一樣的,不得而知。但是從
OO角度來看,覆蓋父類方法與實現介面方法都 可以認為override,因為他們目的都是一樣的,都是為了重用,都是多態的一種
表現方式。
更改jdk版本為1.6即可
5、編譯alsa-lib庫錯誤
android系統開發移植alsa-lib庫的過程中編譯的時候出現了如下的錯誤
/tmp/cckyaR40.s: Assembler messages:
/tmp/cckyaR40.s:2763: Error: selected processor does not support `mrs ip,cpsr'
/tmp/cckyaR40.s:2764: Error: unshifted register required -- `orr r2,ip,#128'
/tmp/cckyaR40.s:2765: Error: selected processor does not support `msr cpsr_c,r2
字面的意思報的是匯編錯誤,選擇的處理器不支持mrs和msr指令。
原來的ARM指令有32位和16位兩種指令模式,16位為thumb指令集,thumb指令集編譯出的代碼佔用空間小,
而且效率也高,所以android的arm編譯器默認用的是thumb模式編譯,問題在於alsa的代碼中有部分的內容
用到了32位的指令,所以才會報如下的錯誤,修改的方法也很簡單,在Android.mk中加入如下內容即可:
LOCAL_ARM_MODE := arm
android的編譯系統中LOCAL_ARM_MODE變數的取值為arm或者thumb,代表32位和16位兩種arm指令集,默認為thumb
prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: failed to set dynamic section sizes: Bad value
collect2: ld returned 1 exit status
make: *** [out/target/proct/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so] 錯誤 1
解決此問題將alsa-lib/include/config.h文件中的如下宏定義去掉即可:
#define VERSIONED_SYMBOLS
開發過程中碰到過很多錯誤,後續再一一總結記錄下來,有些忘記了。。
在android.mk中編譯:
include $(CLEAR_VARS)
$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
出現提示需要定義:LOCAL_MODULE_TAGS := optional 一般修改方法是:
build\core\definitions.mk 中的宏定義變數:
define include-prebuilt
include $$(CLEAR_VARS)
LOCAL_SRC_FILES := $(1)
LOCAL_BUILT_MODULE_STEM := $(1)
LOCAL_MODULE_SUFFIX := $$(suffix $(1))
LOCAL_MODULE := $$(basename $(1))
LOCAL_MODULE_CLASS := $(2)
include $$(BUILD_PREBUILT)
endef
在這里增加一個LOCAL_MODULE_TAGS := optional
但是這需要修改android源碼,如果不是自已的android系統,這么做就麻煩了,所以必須想其它辦法解決:
#include $(CLEAR_VARS)
#$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libyfcdca.a
LOCAL_BUILT_MODULE_STEM := libyfcdca.a
LOCAL_MODULE_SUFFIX := lib
LOCAL_MODULE := yfcdca
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
如此即可了。供你參考
1、32位系統下的編譯
如果需要在32位系統中編譯android系統,在編譯前需要對部分makefile進行修改
首先修改build/core/main.mk,修改的內容如下所示:
-ifneq (64,$(findstring 64,$(build_arch)))
+ifneq
(i686,$(findstring i686,$(build_arch)))
$(warning
************************************************************) $(warning You are attempting to build on a 32-bit system.)
$(warning Only 64-bit build environments are supported beyond froyo/2.2.)
其次修改如下四個文件:
external/clearsilver/cgi/Android.mk
external/clearsilver/java-jni/Android.mk
external/clearsilver/util/Android.mk
external/clearsilver/cs/Android.mk # This forces a 64-bit build for Java6
-LOCAL_CFLAGS += -m64
-LOCAL_LDFLAGS += -m64
+LOCAL_CFLAGS += -m32
+LOCAL_LDFLAGS += -m32即將LOCAL_CFLAGS和LOCAL_LDFLAGS由-m64改為-m32,從而指定使用32位系統進行編譯如果使用 64bit 的操作系統編譯,這些就都不用修改,但記得需要安裝:For 64-bit servers the following extra packages may be needed:
"sudo apt-get install libc6-dev-i386" (libc6-dev-amd64 if AMD CPU)
"sudo apt-get install g++-multilib lib32ncurses5-dev lib32z1-dev"
還有 jdk64bit 的版本編譯2 、build/core/base_rules.mk:128:*** frameworks/opt/emoji/jni:
.... libgl2jni already defined by framwworks/base/opengl/tests/gl2_jni/jni 停止
從編譯規則上看:
# Make sure that this IS_HOST/CLASS/MODULE combination is unique.
mole_id := MODULE.$(if \
$(LOCAL_IS_HOST_MODULE),HOST,TARGET).$(LOCAL_MODULE_CLASS).$(LOCAL_MODULE)
ifdef $(mole_id)
$(error $(LOCAL_PATH): $(mole_id) already defined by $($(mole_id)))
endif
在framwworks/base/opengl/tests/gl2_jni/下面定義的android.mk定義了:
LOCAL_MODULE := libgl2jni
include $(BUILD_SHARED_LIBRARY)
導致生成的動態庫重復,這是不對的,修改tests這個目錄不參與編譯即可,最直接的辦法刪除掉framwworks/base/opengl/tests/gl2_jni這個文件夾
3、AIDL 編譯報couldn't find import for class原因
「AIDL服務只支持有限的數據類型,因此,如果用AIDL服 務傳遞一些復雜的數據就需要做更一步處理。AIDL服務支持的數據類型如下:
Java的簡單類 型(int、char、boolean等)。不需要導入(import)。String和 CharSequence。不需要導入(import)。
List和 Map。但要注意,List和Map對象的元素類型必須是AIDL服務支持的數據類型。不需要導入(import)。AIDL自動生成 的介面。需要導入(import)。
實現 android.os.Parcelable介面的類。需要導入(import)。
其中後兩種數據類 型需要使用import進行導入,傳遞不需要 import的數據類型的值的方式相同。傳遞一個需要import的數據類型的值(例如,實現android.os.Parcelable 介面的類)的步 驟略顯復雜。除了要建立一個實現android.os.Parcelable介面的類外,還需要為這個類單獨建立一個aidl文件,並使用parcelable關鍵字進行定義。」
沒有加LOCAL_AIDL_INCLUDES += xxx ,所以找不到我的parcelable aidl文件。
修改android源碼根目錄下的build/core/pathmap.mk把你的目錄加進去,此時再make update-api
4、老是提示 @Override錯誤 方法未覆蓋其父類的方法
使 用JDK1.6編譯沒有問題,使用JDK1.5編譯,會報@Override方法未覆蓋其父類的方法。實際上這個方法是類實現的介面中方法,
但是,這個語 法的jdk1.6的下面是可以通過的,也就是說jdk1.6認為類覆蓋父類方法與實現介面方法都叫override,而jdk1.5不
是這樣認為的,不知 道這是當初jdk1.5的bug,還是當初就是認為覆蓋父類方法與實現介面方法是不一樣的,不得而知。但是從
OO角度來看,覆蓋父類方法與實現介面方法都 可以認為override,因為他們目的都是一樣的,都是為了重用,都是多態的一種
表現方式。
更改jdk版本為1.6即可
5、編譯alsa-lib庫錯誤
android系統開發移植alsa-lib庫的過程中編譯的時候出現了如下的錯誤
/tmp/cckyaR40.s: Assembler messages:
/tmp/cckyaR40.s:2763: Error: selected processor does not support `mrs ip,cpsr'
/tmp/cckyaR40.s:2764: Error: unshifted register required -- `orr r2,ip,#128'
/tmp/cckyaR40.s:2765: Error: selected processor does not support `msr cpsr_c,r2
字面的意思報的是匯編錯誤,選擇的處理器不支持mrs和msr指令。
原來的ARM指令有32位和16位兩種指令模式,16位為thumb指令集,thumb指令集編譯出的代碼佔用空間小,
而且效率也高,所以android的arm編譯器默認用的是thumb模式編譯,問題在於alsa的代碼中有部分的內容
用到了32位的指令,所以才會報如下的錯誤,修改的方法也很簡單,在Android.mk中加入如下內容即可:
LOCAL_ARM_MODE := arm
android的編譯系統中LOCAL_ARM_MODE變數的取值為arm或者thumb,代表32位和16位兩種arm指令集,默認為thumb
prebuilt/linux-x86/toolchain/arm-eabi-4.4.0/bin/../lib/gcc/arm-eabi/4.4.0/../../../../arm-eabi/bin/ld: failed to set dynamic section sizes: Bad value
collect2: ld returned 1 exit status
make: *** [out/target/proct/merlin/obj/SHARED_LIBRARIES/libasound_intermediates/LINKED/libasound.so] 錯誤 1
解決此問題將alsa-lib/include/config.h文件中的如下宏定義去掉即可:
#define VERSIONED_SYMBOLS
開發過程中碰到過很多錯誤,後續再一一總結記錄下來,有些忘記了。。
在android.mk中編譯:
include $(CLEAR_VARS)
$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
出現提示需要定義:LOCAL_MODULE_TAGS := optional 一般修改方法是:
build\core\definitions.mk 中的宏定義變數:
define include-prebuilt
include $$(CLEAR_VARS)
LOCAL_SRC_FILES := $(1)
LOCAL_BUILT_MODULE_STEM := $(1)
LOCAL_MODULE_SUFFIX := $$(suffix $(1))
LOCAL_MODULE := $$(basename $(1))
LOCAL_MODULE_CLASS := $(2)
include $$(BUILD_PREBUILT)
endef
在這里增加一個LOCAL_MODULE_TAGS := optional
但是這需要修改android源碼,如果不是自已的android系統,這么做就麻煩了,所以必須想其它辦法解決:
#include $(CLEAR_VARS)
#$(call add-prebuilt-files, STATIC_LIBRARIES, libyfcdca.a)
include $(CLEAR_VARS)
LOCAL_SRC_FILES := libyfcdca.a
LOCAL_BUILT_MODULE_STEM := libyfcdca.a
LOCAL_MODULE_SUFFIX := lib
LOCAL_MODULE := yfcdca
LOCAL_MODULE_CLASS := STATIC_LIBRARIES
LOCAL_MODULE_TAGS := optional
include $(BUILD_PREBUILT)
如此即可了。
『伍』 android怎麼實現自動接聽和掛斷電話功能
android 實現來電自動接聽和自動掛斷的方法:
第一步:准備應用環境需要的系統包和aidl文件。
(1)在應用中創建包:android.telephony
將android系統框架下的\framework\telephony\java\android\telephony目錄中的NeighboringCellInfo.aidl文件復制到上面創建的包(android.telephony )中;
(2)在應用中創建包:com.android.internal.telephony
將android系統框架下的\framework\telephony\java\com\android\internal\telephony目錄中的ITelephony.aidl文件復制到上面創建的包(com.android.internal.telephony )中。
第二步:創建一個獲取ITelephony的方法
PhoneUtils.java
package com.zhouzijing.android.demo;
import java.lang.reflect.Method;
import com.android.internal.telephony.ITelephony;
import android.telephony.TelephonyManager;
public class PhoneUtils {
/**
* 根據傳入的TelephonyManager來取得系統的ITelephony實例.
* @param telephony
* @return 系統的ITelephony實例
* @throws Exception
*/
public static ITelephony getITelephony(TelephonyManager telephony) throws Exception {
Method getITelephonyMethod = telephony.getClass().getDeclaredMethod("getITelephony");
getITelephonyMethod.setAccessible(true);//私有化函數也能使用
return (ITelephony)getITelephonyMethod.invoke(telephony);
}
}
第三步:創建電話廣播攔截器
MyPhoneBroadcastReceiver.java
package com.zhouzijing.android.demo;
import com.android.internal.telephony.ITelephony;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.telephony.TelephonyManager;
import android.util.Log;
public class MyPhoneBroadcastReceiver extends BroadcastReceiver {
private final static String TAG = MyPhone.TAG;
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction();
Log.i(TAG, "[Broadcast]"+action);
//呼入電話
if(action.equals(MyPhone.B_PHONE_STATE)){
Log.i(TAG, "[Broadcast]PHONE_STATE");
doReceivePhone(context,intent);
}
}
/**
* 處理電話廣播.
* @param context
* @param intent
*/
public void doReceivePhone(Context context, Intent intent) {
String phoneNumber = intent.getStringExtra(
TelephonyManager.EXTRA_INCOMING_NUMBER);
TelephonyManager telephony = (TelephonyManager)context.getSystemService(
Context.TELEPHONY_SERVICE);
int state = telephony.getCallState();
switch(state){
case TelephonyManager.CALL_STATE_RINGING:
Log.i(TAG, "[Broadcast]等待接電話="+phoneNumber);
try {
ITelephony iTelephony = PhoneUtils.getITelephony(telephony);
iTelephony.answerRingingCall();//自動接通電話
//iTelephony.endCall();//自動掛斷電話
} catch (Exception e) {
Log.e(TAG, "[Broadcast]Exception="+e.getMessage(), e);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
Log.i(TAG, "[Broadcast]電話掛斷="+phoneNumber);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
Log.i(TAG, "[Broadcast]通話中="+phoneNumber);
break;
}
}
}
第四部:注冊電話廣播攔截器
MyPhone.java
package com.zhouzijing.android.demo;
import android.app.Activity;
import android.content.IntentFilter;
import android.os.Bundle;
import android.telephony.TelephonyManager;
import android.util.Log;
import android.view.View;
public class MyPhone extends Activity {
public final static String TAG = "MyPhone";
public final static String B_PHONE_STATE = TelephonyManager.ACTION_PHONE_STATE_CHANGED;
private MyPhoneBroadcastReceiver mBroadcastReceiver;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.my_phone);
}
//按鈕1-注冊廣播
public void registerThis(View v) {
Log.i(TAG, "registerThis");
mBroadcastReceiver = new MyPhoneBroadcastReceiver();
IntentFilter intentFilter = new IntentFilter();
intentFilter.addAction(B_PHONE_STATE);
intentFilter.setPriority(Integer.MAX_VALUE);
registerReceiver(mBroadcastReceiver, intentFilter);
}
//按鈕2-撤銷廣播
public void unregisterThis(View v) {
Log.i(TAG, "unregisterThis");
unregisterReceiver(mBroadcastReceiver);
}
}
第5步:在AndroidManifest.xml配置許可權
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE"/>
其中:
iTelephony.answerRingingCall();//自動接通電話
必須有許可權 android.permission.MODIFY_PHONE_STATE
iTelephony.endCall();//自動掛斷電話
必須有許可權 android.permission.CALL_PHONE。
