Java 在根设备上检测何时接听传出呼叫

Java 在根设备上检测何时接听传出呼叫,java,android,android-studio,reflection,phone-call,Java,Android,Android Studio,Reflection,Phone Call,我不介意在设备上生根,因为该应用程序只能在私人场合使用,我正在从事一个需要监控设备调用状态的项目,我已经阅读了该项目的文档 我一直在使用它,但我有一个问题,知道什么时候接电话,检查了文档和stackoverflow,意识到这是谷歌本身的一个已知问题 还有很多我试过的。 我知道没有记录在案的方法来实现这一点,我相信这是可能的,因为android本身计算通话时间,也有一些应用程序(如TRUE CALLER)和其他一些私人应用程序监控通话时间,这是基于接听电话的时间和挂断电话的时间。 在决定发布

我不介意在设备上生根,因为该应用程序只能在私人场合使用,我正在从事一个需要监控设备调用状态的项目,我已经阅读了该项目的文档

我一直在使用它,但我有一个问题,知道什么时候接电话,检查了文档和stackoverflow,意识到这是谷歌本身的一个已知问题

还有很多我试过的。 我知道没有记录在案的方法来实现这一点,我相信这是可能的,因为android本身计算通话时间,也有一些应用程序(如TRUE CALLER)和其他一些私人应用程序监控通话时间,这是基于接听电话的时间和挂断电话的时间。 在决定发布这篇文章之前,我已经尝试了很多,
关于如何在根设备上实现这一点的任何建议。

这是一个监听语音呼叫的电话广播接收器示例

import android.app.Notification;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Environment;
import android.support.v4.app.NotificationCompat;
import android.telephony.TelephonyManager;
import android.util.Log;

import com.nitesh.brill.saleslines.Common_Files.SaveData;
import com.nitesh.brill.saleslines.R;

public class MyPhoneReceiver extends BroadcastReceiver {

    private String phoneNumber;
    Context context;

    @Override
    public void onReceive(final Context context, Intent intent) {
        this.context = context;

        phoneNumber = intent.getStringExtra(Intent.EXTRA_PHONE_NUMBER);
        String extraState = intent.getStringExtra(TelephonyManager.EXTRA_STATE);


            try {

                if (extraState != null) {
                    if (extraState.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {

                        Log.e("State","Offhook");

                    } else if (extraState
                            .equals(TelephonyManager.EXTRA_STATE_IDLE)) {

                        Log.e("State","Idle");


                    } else if (extraState
                            .equals(TelephonyManager.EXTRA_STATE_RINGING)) {
                        if (phoneNumber == null)
                            phoneNumber = intent
                                    .getStringExtra(TelephonyManager.EXTRA_INCOMING_NUMBER);

                        Log.e("State","Ringing");

                    }
                } else if (phoneNumber != null) {
                    Log.e("Outgoing call",""+phoneNumber);



                }
            } catch (Exception e) {
                Log.e(Constants.TAG, "Exception");
                e.printStackTrace();
            }
    }


}
将此代码添加到清单文件中

<receiver android:name=".MyPhoneReceiver">
            <intent-filter>

                <!-- Intent filters for broadcast receiver -->
                <action android:name="android.intent.action.PHONE_STATE" />
                <action android:name="android.intent.action.NEW_OUTGOING_CALL" />


            </intent-filter>
        </receiver>

在查看调用期间的系统日志并查看源代码和中的后,我发现精确调用状态可以用来监听调用期间的精确更改

但正如您所看到的,大多数内容都是使用注释从文档中隐藏的

当应用于包、类、方法或字段时,@hide将从文档中删除该节点及其所有子节点

虽然方法和类是隐藏的,但它们可以使用访问,所以我想尝试一下。但是开发者社区是如此之大,以至于你想到的大部分东西都可以在谷歌上找到

所以在谷歌搜索之后,我发现,这解释了如何使用Java反射API监听精确的调用状态。 所以我把这段代码原封不动

将此添加到
AndroidManifest.xml
文件中以声明广播接收器

<receiver
    android:name=".OutCallLogger"
    android:enabled="true"
    android:exported="true" >
        <intent-filter>
            <action android:name="android.intent.action.PRECISE_CALL_STATE" />
            <action android:name="android.intent.action.NEW_OUTGOING_CALL" />
        </intent-filter>
</receiver>
这是您的广播接收器类,用于获取传出呼叫的精确呼叫状态

public class OutCallLogger extends BroadcastReceiver {

public OutCallLogger() {

}

TelephonyManager Tm;
ITelephony telephonyService;
Class c = null;
Method methodGetInstance = null;
Method methodGetActiveFgCallState=null;
String TAG="Tag";
Object objectCallManager=null;
Context context1;
Class<?> classCallManager;

Class telephonyClass;
Class telephonyStubClass;
Class serviceManagerClass;
Class serviceManagerStubClass;
Class serviceManagerNativeClass;
Class serviceManagerNativeStubClass;

Method telephonyCall;
Method telephonyEndCall;
Method telephonyAnswerCall;
Method getDefault;

Method[] temps;
Constructor[] serviceManagerConstructor;

// Method getService;
Object telephonyObject;
Object serviceManagerObject;
private Timer timer= null;

@Override
public void onReceive(Context context, Intent intent) {
    // TODO: This method is called when the BroadcastReceiver is receiving
    // an Intent broadcast.



    this.context1= context;
    Tm=(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);

    final ClassLoader classLoader = this.getClass().getClassLoader();
    try {
        classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
        Log.e(TAG, "CallManager: Class loaded " + classCallManager.toString());
        methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
        methodGetInstance.setAccessible(true);
        Log.e(TAG, "CallManager: Method loaded " + methodGetInstance.getName());
        objectCallManager = methodGetInstance.invoke(null);
        Log.e(TAG, "CallManager: Object loaded " + objectCallManager.getClass().getName());
        Method[] aClassMethods = classCallManager.getDeclaredMethods();
        for(Method m : aClassMethods)
        {
            Log.e("MEthods", m.getName());
        }
        methodGetActiveFgCallState = classCallManager.getDeclaredMethod("getActiveFgCallState");
        Log.e(TAG, "CallManager: Method loaded " + methodGetActiveFgCallState.getName());

        Log.e(TAG, "CallManager: What is the Call state = " + methodGetActiveFgCallState.invoke(objectCallManager));
    }
    catch (ClassNotFoundException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    catch (NoSuchMethodException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    catch (InvocationTargetException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    catch (IllegalAccessException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    Tm.listen(new PhoneStateListener(){
        public void  onCallStateChanged(int state,String number) {
            super.onCallStateChanged(state, number);

            try {
                if (methodGetActiveFgCallState.invoke(objectCallManager).toString().toLowerCase() .equals("idle"))
                {
                    //Toast.makeText(context1, "I am in idle state", Toast.LENGTH_LONG).show();            }
                    if (methodGetActiveFgCallState.invoke(objectCallManager).toString().toLowerCase() .equals("active"))
                    {
                        //Toast.makeText(context1, "I am in active state", Toast.LENGTH_LONG).show();            }

                        Toast.makeText(context1, " "+methodGetActiveFgCallState.invoke(objectCallManager).toString(), Toast.LENGTH_LONG).show();


                    } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block            e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block            e.printStackTrace();
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block            e.printStackTrace();
                }

                }

            }, PhoneStateListener.LISTEN_CALL_STATE);

        }
公共类OutCallLogger扩展了BroadcastReceiver{
公共OutCallLogger(){
}
TelephonyManager Tm;
ITelephony电话服务;
c类=空;
方法methodGetInstance=null;
方法methodGetActiveFgCallState=null;
String TAG=“TAG”;
objectCallManager=null;
语境1;
班级经理;
类电话类;
类电话子类;
类serviceManagerClass;
类serviceManagerStubClass;
类serviceManagerNativeClass;
类服务管理器活动子类;
方法电话呼叫;
方法电话呼叫;
方法电话呼叫;
方法getDefault;
方法[]temps;
构造函数[]服务管理器构造函数;
//方法获取服务;
对象电话对象;
对象服务管理对象;
专用定时器=空;
@凌驾
公共void onReceive(上下文、意图){
//TODO:当BroadcastReceiver正在接收时调用此方法
//有意图的广播。
this.context1=上下文;
Tm=(TelephonyManager)context.getSystemService(context.TELEPHONY_服务);
final ClassLoader ClassLoader=this.getClass().getClassLoader();
试一试{
classCallManager=classLoader.loadClass(“com.android.internal.telephony.CallManager”);
Log.e(标记“CallManager:Class loaded”+classCallManager.toString());
methodGetInstance=classCallManager.getDeclaredMethod(“getInstance”);
methodGetInstance.setAccessible(true);
e(标记“CallManager:MethodLoaded”+methodGetInstance.getName());
objectCallManager=methodGetInstance.invoke(null);
Log.e(标记“CallManager:Object loaded”+objectCallManager.getClass().getName());
方法[]aClassMethods=classCallManager.getDeclaredMethods();
对于(方法m:aClassMethods)
{
Log.e(“方法”,m.getName());
}
methodGetActiveFgCallState=classCallManager.getDeclaredMethod(“getActiveFgCallState”);
Log.e(标记“CallManager:MethodLoaded”+methodGetActiveFgCallState.getName());
Log.e(标记,“CallManager:调用状态是什么=“+methodGetActiveFgCallState.invoke(objectCallManager));
}
catch(classnotfounde异常){
Log.e(标记,e.getClass().getName()+e.toString());
}
捕获(无此方法例外){
Log.e(标记,e.getClass().getName()+e.toString());
}
捕获(调用TargetException e){
Log.e(标记,e.getClass().getName()+e.toString());
}
捕获(非法访问例外e){
Log.e(标记,e.getClass().getName()+e.toString());
}
Tm.listen(新的PhoneStateListener(){
public void onCallStateChanged(int状态,字符串编号){
super.onCallStateChanged(状态、编号);
试一试{
if(methodGetActiveFgCallState.invoke(objectCallManager.toString().toLowerCase().equals(“idle”))
{
//Toast.makeText(context1,“我处于空闲状态”,Toast.LENGTH_LONG.show();}
if(methodGetActiveFgCallState.invoke(objectCallManager.toString().toLowerCase().equals(“active”))
{
//Toast.makeText(context1,“我处于活动状态”,Toast.LENGTH_LONG.show();}
Toast.makeText(context1,“+methodGetActiveFgCallState.invoke(objectCallManager).toString(),Toast.LENGTH_LONG.show();
}捕获(IllegalArgumentException e){
//TODO自动生成的捕捉块e.printStackTrace();
}捕获(非法访问例外e){
//TODO自动生成的捕捉块e.printStackTrace();
}捕获(调用TargetException e){
//TODO自动生成的捕捉块e.printStac
 <uses-feature android:name="android.hardware.telephony"></uses-feature>
public class OutCallLogger extends BroadcastReceiver {

public OutCallLogger() {

}

TelephonyManager Tm;
ITelephony telephonyService;
Class c = null;
Method methodGetInstance = null;
Method methodGetActiveFgCallState=null;
String TAG="Tag";
Object objectCallManager=null;
Context context1;
Class<?> classCallManager;

Class telephonyClass;
Class telephonyStubClass;
Class serviceManagerClass;
Class serviceManagerStubClass;
Class serviceManagerNativeClass;
Class serviceManagerNativeStubClass;

Method telephonyCall;
Method telephonyEndCall;
Method telephonyAnswerCall;
Method getDefault;

Method[] temps;
Constructor[] serviceManagerConstructor;

// Method getService;
Object telephonyObject;
Object serviceManagerObject;
private Timer timer= null;

@Override
public void onReceive(Context context, Intent intent) {
    // TODO: This method is called when the BroadcastReceiver is receiving
    // an Intent broadcast.



    this.context1= context;
    Tm=(TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);

    final ClassLoader classLoader = this.getClass().getClassLoader();
    try {
        classCallManager = classLoader.loadClass("com.android.internal.telephony.CallManager");
        Log.e(TAG, "CallManager: Class loaded " + classCallManager.toString());
        methodGetInstance = classCallManager.getDeclaredMethod("getInstance");
        methodGetInstance.setAccessible(true);
        Log.e(TAG, "CallManager: Method loaded " + methodGetInstance.getName());
        objectCallManager = methodGetInstance.invoke(null);
        Log.e(TAG, "CallManager: Object loaded " + objectCallManager.getClass().getName());
        Method[] aClassMethods = classCallManager.getDeclaredMethods();
        for(Method m : aClassMethods)
        {
            Log.e("MEthods", m.getName());
        }
        methodGetActiveFgCallState = classCallManager.getDeclaredMethod("getActiveFgCallState");
        Log.e(TAG, "CallManager: Method loaded " + methodGetActiveFgCallState.getName());

        Log.e(TAG, "CallManager: What is the Call state = " + methodGetActiveFgCallState.invoke(objectCallManager));
    }
    catch (ClassNotFoundException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    catch (NoSuchMethodException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    catch (InvocationTargetException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    catch (IllegalAccessException e) {
        Log.e(TAG, e.getClass().getName() + e.toString());
    }
    Tm.listen(new PhoneStateListener(){
        public void  onCallStateChanged(int state,String number) {
            super.onCallStateChanged(state, number);

            try {
                if (methodGetActiveFgCallState.invoke(objectCallManager).toString().toLowerCase() .equals("idle"))
                {
                    //Toast.makeText(context1, "I am in idle state", Toast.LENGTH_LONG).show();            }
                    if (methodGetActiveFgCallState.invoke(objectCallManager).toString().toLowerCase() .equals("active"))
                    {
                        //Toast.makeText(context1, "I am in active state", Toast.LENGTH_LONG).show();            }

                        Toast.makeText(context1, " "+methodGetActiveFgCallState.invoke(objectCallManager).toString(), Toast.LENGTH_LONG).show();


                    } catch (IllegalArgumentException e) {
                    // TODO Auto-generated catch block            e.printStackTrace();
                } catch (IllegalAccessException e) {
                    // TODO Auto-generated catch block            e.printStackTrace();
                } catch (InvocationTargetException e) {
                    // TODO Auto-generated catch block            e.printStackTrace();
                }

                }

            }, PhoneStateListener.LISTEN_CALL_STATE);

        }