我不介意生根设备,因为应用程序只能私下使用,我正在处理一个需要监控设备呼叫状态的项目,已经阅读了文档
https://developer.android.com/reference/android/telecom/Call.html
并且我一直在使用它,但我知道何时选择了一个电话,检查了文档和堆栈溢出,已经意识到谷歌本身已知问题。
Detecting outgoing call answered on Android
In rooted device detect if an outgoing call has been answered
和我尝试过的许多其他人。 我知道没有记录的方法来实现这一目标,我确信这是可能的,因为android本身会计算在通话上花费的时间,而且一些应用程序也像TRUE CALLER和其他一些私人应用程序监视花费的时间。基于何时接听电话以及何时挂断电话。 在决定发布之前我自己尝试了很多, 关于如何在ROOTED设备上实现此目的的任何建议。
答案 0 :(得分:1)
这是收听语音电话的电话广播接收器的一个例子。
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>
答案 1 :(得分:0)
在通话期间查看系统日志并查看源代码this和this后,我发现 PRECISE CALL STATE 可用于精确收听通话期间的变化。
但正如您所看到的,大多数内容都是使用@hide
注释隐藏在文档中的。
当应用于包,类,方法或字段时,@ hide会从文档中删除该节点及其所有子节点。
虽然隐藏了方法和类,但可以使用Java Reflection API访问它们,所以我想尝试一下。但开发人员社区规模如此之大,以至于大多数事情都可以在Google上找到。
因此,经过一些Google搜索,我找到了this blog,它解释了如何使用Java Reflection API监听精确的调用状态。 所以我把这段代码的原始格式source。
在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>
所需权限:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.PROCESS_OUTGOING_CALLS" />
<uses-permission android:name="android.permission.READ_PRECISE_PHONE_STATE" />
同时将此行添加到清单以使用功能android.hardware.telephony
<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);
}
将出现一个Toast,告诉您有关通话状态的信息。
由于您已经指出您不介意生根您的设备,您必须将生成的apk安装为系统应用。只需将生成的apk复制到/ system / app目录并重启设备即可。
免责声明:我尚未对上述代码进行测试,因为目前我还没有设备。