Android 电话的反射调用机制实现自动接听电话


最近在看一些有关反射和aidl远程服务控制的类,自己也小写了这么一个Android 电话的反射调用机制实现静默接听电话demo 自己总结出来,以供查阅,若是还有其他问题,希望大家指出。

首先要调用系统的接听电话功能,就要用到TelephonyManager和ITelephony类,其中TelephonyManager是可访问的,ITelephony不可访问,但是我们要用的功能:接听电话和拒绝电话被封装在ITelephony里面了。对此我们便要用到反射和aidl远程服务控制的知识。详细知识,不在阐释。

第一步:

  在建好的工程中添加包com.android.internal.telephony,复制一下内容到新创建的ITelephony.aidl文件中

/* 
 * Copyright (C) 2007 The Android Open Source Project 
 * 
 * Licensed under the Apache License, Version 2.0 (the "License"); 
 * you may not use this file except in compliance with the License. 
 * You may obtain a copy of the License at 
 * 
 *      http://www.apache.org/licenses/LICENSE-2.0 
 * 
 * Unless required by applicable law or agreed to in writing, software 
 * distributed under the License is distributed on an "AS IS" BASIS, 
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 
 * See the License for the specific language governing permissions and 
 * limitations under the License. 
 */  
package com.android.internal.telephony;  
import android.os.Bundle;  
import java.util.List;  
/** 
 * Interface used to interact with the phone.  Mostly this is used by the 
 * TelephonyManager class.  A few places are still using this directly. 
 * Please clean them up if possible and use TelephonyManager insteadl. 
 * 
 * {@hide} 
 */  
interface ITelephony {  
    /** 
     * Dial a number. This doesn't place the call. It displays 
     * the Dialer screen. 
     * @param number the number to be dialed. If null, this 
     * would display the Dialer screen with no number pre-filled. 
     */  
    void dial(String number);  
    /** 
     * Place a call to the specified number. 
     * @param number the number to be called. 
     */  
    void call(String number);  
    /** 
     * If there is currently a call in progress, show the call screen. 
     * The DTMF dialpad may or may not be visible initially, depending on 
     * whether it was up when the user last exited the InCallScreen. 
     * 
     * @return true if the call screen was shown. 
     */  
    boolean showCallScreen();  
    /** 
     * Variation of showCallScreen() that also specifies whether the 
     * DTMF dialpad should be initially visible when the InCallScreen 
     * comes up. 
     * 
     * @param showDialpad if true, make the dialpad visible initially, 
     *                    otherwise hide the dialpad initially. 
     * @return true if the call screen was shown. 
     * 
     * @see showCallScreen 
     */  
    boolean showCallScreenWithDialpad(boolean showDialpad);  
    /** 
     * End call or go to the Home screen 
     * 
     * @return whether it hung up 
     */  
    boolean endCall();  
    /** 
     * Answer the currently-ringing call. 
     * 
     * If there's already a current active call, that call will be 
     * automatically put on hold.  If both lines are currently in use, the 
     * current active call will be ended. 
     * 
     * TODO: provide a flag to let the caller specify what policy to use 
     * if both lines are in use.  (The current behavior is hardwired to 
     * "answer incoming, end ongoing", which is how the CALL button 
     * is specced to behave.) 
     * 
     * TODO: this should be a oneway call (especially since it's called 
     * directly from the key queue thread). 
     */  
    void answerRingingCall();  
    /** 
     * Silence the ringer if an incoming call is currently ringing. 
     * (If vibrating, stop the vibrator also.) 
     * 
     * It's safe to call this if the ringer has already been silenced, or 
     * even if there's no incoming call.  (If so, this method will do nothing.) 
     * 
     * TODO: this should be a oneway call too (see above). 
     *       (Actually *all* the methods here that return void can 
     *       probably be oneway.) 
     */  
    void silenceRinger();  
    /** 
     * Check if we are in either an active or holding call 
     * @return true if the phone state is OFFHOOK. 
     */  
    boolean isOffhook();  
    /** 
     * Check if an incoming phone call is ringing or call waiting. 
     * @return true if the phone state is RINGING. 
     */  
    boolean isRinging();  
    /** 
     * Check if the phone is idle. 
     * @return true if the phone state is IDLE. 
     */  
    boolean isIdle();  
    /** 
     * Check to see if the radio is on or not. 
     * @return returns true if the radio is on. 
     */  
    boolean isRadioOn();  
    /** 
     * Check if the SIM pin lock is enabled. 
     * @return true if the SIM pin lock is enabled. 
     */  
    boolean isSimPinEnabled();  
    /** 
     * Cancels the missed calls notification. 
     */  
    void cancelMissedCallsNotification();  
    /** 
     * Supply a pin to unlock the SIM.  Blocks until a result is determined. 
     * @param pin The pin to check. 
     * @return whether the operation was a success. 
     */  
    boolean supplyPin(String pin);  
    /** 
     * Handles PIN MMI commands (PIN/PIN2/PUK/PUK2), which are initiated 
     * without SEND (so <code>dial</code> is not appropriate). 
     * 
     * @param dialString the MMI command to be executed. 
     * @return true if MMI command is executed. 
     */  
    boolean handlePinMmi(String dialString);  
    /** 
     * Toggles the radio on or off. 
     */  
    void toggleRadioOnOff();  
    /** 
     * Set the radio to on or off 
     */  
    boolean setRadio(boolean turnOn);  
    /** 
     * Request to update location information in service state 
     */  
    void updateServiceLocation();  
    /** 
     * Enable location update notifications. 
     */  
    void enableLocationUpdates();  
    /** 
     * Disable location update notifications. 
     */  
    void disableLocationUpdates();  
    /** 
     * Enable a specific APN type. 
     */  
    int enableApnType(String type);  
    /** 
     * Disable a specific APN type. 
     */  
    int disableApnType(String type);  
    /** 
     * Allow mobile data connections. 
     */  
    boolean enableDataConnectivity();  
    /** 
     * Disallow mobile data connections. 
     */  
    boolean disableDataConnectivity();  
    /** 
     * Report whether data connectivity is possible. 
     */  
    boolean isDataConnectivityPossible();  
    Bundle getCellLocation();  
    /** 
     * Returns the neighboring cell information of the device. 
     */  
      
     int getCallState();  
     int getDataActivity();  
     int getDataState();  
    /** 
     * Returns the current active phone type as integer. 
     * Returns TelephonyManager.PHONE_TYPE_CDMA if RILConstants.CDMA_PHONE 
     * and TelephonyManager.PHONE_TYPE_GSM if RILConstants.GSM_PHONE 
     */  
    int getActivePhoneType();  
    /** 
     * Returns the CDMA ERI icon index to display 
     */  
    int getCdmaEriIconIndex();  
    /** 
     * Returns the CDMA ERI icon mode, 
     * 0 - ON 
     * 1 - FLASHING 
     */  
    int getCdmaEriIconMode();  
    /** 
     * Returns the CDMA ERI text, 
     */  
    String getCdmaEriText();  
    /** 
     * Returns true if CDMA provisioning needs to run. 
     */  
    boolean getCdmaNeedsProvisioning();  
    /** 
      * Returns the unread count of voicemails 
      */  
    int getVoiceMessageCount();  
    /** 
      * Returns the network type 
      */  
    int getNetworkType();  
      
    /** 
     * Return true if an ICC card is present 
     */  
    boolean hasIccCard();  
}  

保存后ADT会自动的在gen目录下生成相应的包和.java文件

第二步:

应用反射技术(请自行查阅)

新建类PhoneUtil

主要写两个方法

public class PhoneUtil {
	/**
	 * 运用反射技术获得ITelephony
	 * @param telMgr
	 * @return
	 * @throws Exception
	 */
	 public static ITelephony getITelephony(TelephonyManager telMgr) throws Exception{
   	     Method method = telMgr.getClass().getDeclaredMethod("getITelephony");
   	     method.setAccessible(true);
   	     return (ITelephony)method.invoke(telMgr);//发回ITelephony
     }
	 static public void printAllInform(Class clsShow) {      
		 
	        try {      
	            // 取得所有方法       
	            Method[] hideMethod = clsShow.getDeclaredMethods();      
	            int i = 0;      
	            for (; i < hideMethod.length; i++) {      
	                Log.e("method name", hideMethod[i].getName());      
	            }      
	            // 取得所有常量       
	            Field[] allFields = clsShow.getFields();      
	            for (i = 0; i < allFields.length; i++) {      
	                Log.e("Field name", allFields[i].getName());      
	            }      
	        } catch (SecurityException e) {      
	            // throw new RuntimeException(e.getMessage());       
	            e.printStackTrace();      
	        } catch (IllegalArgumentException e) {      
	            // throw new RuntimeException(e.getMessage());       
	            e.printStackTrace();      
	        } catch (Exception e) {      
	            // TODO Auto-generated catch block       
	            e.printStackTrace();      
	        }      
	    } 
}


 第三步:

创建一个服务用于监听电话状态和自动接听电话事件

/**
 * 自动接听来电类广播
 * @author Owner
 *
 */
public class TPhoneReceiver extends Service {

	private TelephonyManager tlmar ;
	@Override
	public void onCreate() {
		// TODO Auto-generated method stub
		super.onCreate();
	}
 
	@Override
	public int onStartCommand(Intent intent, int flags, int startId) {
		// TODO Auto-generated method stub
		tlmar = (TelephonyManager) getSystemService(TELEPHONY_SERVICE);
		tlmar.listen(new CallPhoneStateListener(), //注册手机电话监听
				CallPhoneStateListener.LISTEN_CALL_STATE);
		return super.onStartCommand(intent, flags, startId);
	}

	@Override
	public void onDestroy() {
		// TODO Auto-generated method stub
		super.onDestroy();
	}


	@Override
	public IBinder onBind(Intent intent) {
		// TODO Auto-generated method stub
		return null;
	}
	class CallPhoneStateListener extends PhoneStateListener{

		@Override
		public void onCallStateChanged(int state, String incomingNumber) {
			// TODO Auto-generated method stub
			switch (state) {
			case TelephonyManager.CALL_STATE_IDLE:// 空闲
				
				break;
			case TelephonyManager.CALL_STATE_OFFHOOK:// 接听
				
				break;
			case TelephonyManager.CALL_STATE_RINGING:// 来电
				try {
					Toast.makeText(getApplicationContext(), "dddd", 1).show();
					ITelephony it = PhoneUtil.getITelephony(tlmar);
					it.silenceRinger();
                                           //	it.endCall();//拒接
					it.answerRingingCall();//自动接听
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				break;

			default:
				break;
			}
		}
		
	}
}
并且在AndroidManifest.xml李进行注册
 
<service android:name=".TPhoneReceiver" 
             android:priority="10000" >
            <intent-filter>  
                <action android:name="com.example.baidumap.TPhoneReceiver" />  
            </intent-filter>  
        </service>


第四步:

创建主activity

用于启动服务

Intent tIntent = new Intent(this , TPhoneReceiverBordcast.class);
		tIntent.setAction("com.example.baidumap.TPhoneReceiver");
		startService(tIntent);
@Override
   protected void onDestroy() {
    // TODO Auto-generated method stub
    if (tIntent != null) {
   stopService(tIntent);
  }
    super.onDestroy();
   }

最后别忘记了在AndroidManifest.xml李进行权限声明(主要权限)

         <uses-permission android:name="android.permission.READ_PHONE_STATE"></uses-permission>
	<uses-permission android:name="android.permission.MODIFY_PHONE_STATE"></uses-permission>
	<uses-permission android:name="android.permission.CALL_PHONE"></uses-permission>

到这里已经OK了!

启动模拟器并看看结果吧!

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值