[英]Listen to calls Broadcast receiver in Android pie
我正在尝试让应用程序听取呼叫(传入和传出),我现在所做的只是在清单中注册接收器,这在Android 9.0以下完美运行。 然而,当我在Android oreo上测试应用程序时出现问题,我知道有些广播被禁用了。 我尝试制作一个前台服务,注册一个接收器并收听这个广播,但它再次在oreo下面的版本上工作。
我不知道还能做什么,我必须让它工作,我不在乎它是否会以一种不雅的方式,我不发布这个应用程序我只是需要私人使用。
简介:即使应用程序当前未处于活动状态,我也需要在Android饼中收听电话
表现
<receiver android:name=".MyReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
MyReceiver
public class MyReceiver extends BroadcastReceiver {
private static Date callStartTime;
private static boolean isIncoming;
private static int lastState;
private static String savedNumber;
private static String savedOutgoingNumber;
private TelephonyManager tm;
@Override
public void onReceive(Context context, Intent intent) {
//We listen to two intents. The new outgoing call only tells us of an outgoing call. We use it to get the number.
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
}
else{
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
state = TelephonyManager.CALL_STATE_RINGING;
}
onCallStateChanged(context, state, number);
}
}
“
问题是它甚至没有在android oreo上调用编辑:我让它在android oreo上工作但它在android pie中有问题
另一个编辑:
@Override
public void onCreate() {
super.onCreate();
createNotificationChannel();
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.PHONE_STATE");
filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
CallListenerService.this.onReceive(intent);
}
};
registerReceiver(receiver, filter);
}
public void onReceive(Intent i){
if (i.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = i.getExtras().getString("android.intent.extra.PHONE_NUMBER");
}
else{
String stateStr = i.getExtras().getString(TelephonyManager.EXTRA_STATE);
String number = i.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if(stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)){
state = TelephonyManager.CALL_STATE_IDLE;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)){
state = TelephonyManager.CALL_STATE_OFFHOOK;
}
else if(stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)){
state = TelephonyManager.CALL_STATE_RINGING;
}
onCallStateChanged(this, state, number);
}
}
其余的并不重要,只需在呼叫结束时启动一个活动,以测试它是否吵闹
我已经添加了一个注册接收器的四地服务,这适用于android oreo但仍然在android pie上有问题。
编辑:解决方案是混合一堆答案,直到它在每个设备上工作。 我写了这样的decleration清单:
<receiver
android:name=".MyReceiver"
android:enabled="true">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
<intent-filter android:priority="1000">
<action android:name="android.intent.action.NEW_OUTGOING_CALL"
/>
</intent-filter>
</receiver>
真的不知道那是做了什么的。 我使用普通的广播接收器而不是服务,我不知道发生了什么,但突然它在某些设备上工作。
现在有最后的触摸,我发现我可以通过阅读通话记录获取电话号码,所以我做的是添加此代码:
protected void onMissedCall(final Context ctx, String number, Date start) {
if (PreferenceManager.getDefaultSharedPreferences(ctx).getBoolean("missed_calls", false)) {
if (number == null) {
new Handler().postDelayed(new Runnable() {
@Override
public void run() {
final String phoneNumber = getLastCallNumber(ctx);
if (phoneNumber != null) {
Intent intent = new Intent(ctx, Dialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("number", phoneNumber);
intent.putExtra("missed_call", true);
ctx.startActivity(intent);
} else {
Toast.makeText(ctx, "cannot get phone number", Toast.LENGTH_SHORT).show();
}
}
}, 2000);
} else {
Intent intent = new Intent(ctx, Dialog.class);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.putExtra("number", number);
intent.putExtra("missed_call", true);
ctx.startActivity(intent);
}
}
}
private String getLastCallNumber(Context context) {
Uri contacts = CallLog.Calls.CONTENT_URI;
if (ActivityCompat.checkSelfPermission(context, android.Manifest.permission.READ_CALL_LOG) != PackageManager.PERMISSION_GRANTED) {
Toast.makeText(context, "Permission denied can not get phone number", Toast.LENGTH_SHORT).show();
}
Cursor managedCursor = context.getContentResolver().query(
contacts, null, null, null, null);
int number = managedCursor.getColumnIndex( CallLog.Calls.NUMBER );
String phoneNumber = null;
if( managedCursor.moveToLast() == true ) {
phoneNumber = managedCursor.getString( number );
}
managedCursor.close();
return phoneNumber;
}
我添加了if行来检查数字是否为null,如果是,则启动处理程序运行2秒,当处理程序启动时,我从调用日志中读取最后一个数字。 2秒延迟是进入通话记录的数字,如果你试图立即读取它不起作用。
我还创建了一个CallReceiver: -
public class CallReceiver extends BroadcastReceiver {
private static int lastState = TelephonyManager.CALL_STATE_IDLE;
private static Date callStartTime;
private static boolean isIncoming;
private static String savedNumber;
public static MyCallsAppDatabase myCallsAppDatabase;
@Override
public void onReceive(Context context, Intent intent) {
if (intent.getAction().equals("android.intent.action.NEW_OUTGOING_CALL")) {
savedNumber = intent.getExtras().getString("android.intent.extra.PHONE_NUMBER");
} else {
String stateStr = intent.getExtras().getString(TelephonyManager.EXTRA_STATE);
String number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
int state = 0;
if (stateStr.equals(TelephonyManager.EXTRA_STATE_IDLE)) {
state = TelephonyManager.CALL_STATE_IDLE;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_OFFHOOK)) {
state = TelephonyManager.CALL_STATE_OFFHOOK;
} else if (stateStr.equals(TelephonyManager.EXTRA_STATE_RINGING)) {
state = TelephonyManager.CALL_STATE_RINGING;
}
onCallStateChanged(context, state, number, intent);
}
}
public void onCallStateChanged(Context context, int state, String number, Intent intent) {
if (lastState == state) {
//No change, debounce extras
return;
}
switch (state) {
case TelephonyManager.CALL_STATE_RINGING:
isIncoming = true;
callStartTime = new Date();
onIncomingCallStarted(context, number, callStartTime, intent);
break;
case TelephonyManager.CALL_STATE_OFFHOOK:
//Transition of ringing->offhook are pickups of incoming calls. Nothing done on them
if (lastState != TelephonyManager.CALL_STATE_RINGING) {
isIncoming = false;
callStartTime = new Date();
onOutgoingCallStarted(context, number, callStartTime, intent);
}
break;
case TelephonyManager.CALL_STATE_IDLE:
//Went to idle- this is the end of a call. What type depends on previous state(s)
if (lastState == TelephonyManager.CALL_STATE_RINGING) {
//Ring but no pickup- a miss
onMissedCall(context, number, callStartTime, intent);
} else if (isIncoming) {
onIncomingCallEnded(context, number, callStartTime, new Date(), intent);
} else {
onOutgoingCallEnded(context, number, callStartTime, new Date(), intent);
}
break;
}
lastState = state;
Intent intent1 = new Intent("CallApp");
context.sendBroadcast(intent1);
}
protected void onIncomingCallStarted(Context ctx, String number, Date start, Intent intent) {
// Toast.makeText(ctx, "calling from " + number, Toast.LENGTH_SHORT).show();
}
protected void onOutgoingCallStarted(Context ctx, String number, Date start, Intent intent) {
// Toast.makeText(ctx, "calling to " + number, Toast.LENGTH_SHORT).show();
}
protected void onIncomingCallEnded(Context ctx, String number, Date start, Date end, Intent intent) {
// Toast.makeText(ctx, "calling from " + number + " ended ", Toast.LENGTH_SHORT).show();
saveData(ctx, number, intent, "Incoming Call");
}
protected void onOutgoingCallEnded(Context ctx, String number, Date start, Date end, Intent intent) {
// Toast.makeText(ctx, "calling to " + number + " ended ", Toast.LENGTH_SHORT).show();
saveData(ctx, number, intent, "Outgoing Call");
}
protected void onMissedCall(Context ctx, String number, Date start, Intent intent) {
// Toast.makeText(ctx, "missed call from " + number + " sim ", Toast.LENGTH_SHORT).show();
saveData(ctx, number, intent, "Missed Call");
}
@SuppressLint("ServiceCast")
protected void saveData(Context ctx, String number, Intent intent, String callType) {
myCallsAppDatabase = Room.databaseBuilder(ctx, MyCallsAppDatabase.class, "calldb")
.allowMainThreadQueries()
.build();
number = intent.getExtras().getString(TelephonyManager.EXTRA_INCOMING_NUMBER);
number = filterNumber(number);
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss aaa");
String dateString = dateFormat.format(new Date(System.currentTimeMillis()));
CallLog callLog = new CallLog();
callLog.setMobile(number);
callLog.setCallType(callType);
callLog.setTime(dateString);
myCallsAppDatabase.myCallDao().addCallDetails(callLog);
}
}
在Manifest.xml文件中: -
<receiver android:name=".broadcaestReceiver.CallReceiver">
<intent-filter>
<action android:name="android.intent.action.PHONE_STATE" />
</intent-filter>
</receiver>
更改Manifest文件中的代码如下,setPriority更高。 当应用程序处于后台时,我认为这个清单代码需要。
<receiver android:name=".MyReceiver">
<intent-filter android:priority="1000">
<action android:name="android.intent.action.PHONE_STATE" />
<action android:name="android.intent.action.NEW_OUTGOING_CALL" />
</intent-filter>
</receiver>
当app是前景时,这个程序代码需要唤醒Reciever。 当用户正在处理来自Activity的BroadcasteReciever的操作时。 (接收者需要在onDestroy()
中的onResume()
&& unregisterReceiver()
中registerReceiver()
onDestroy()
)
IntentFilter filter = new IntentFilter();
filter.addAction("android.intent.action.PHONE_STATE");
filter.addAction("android.intent.action.NEW_OUTGOING_CALL");
filter.setPriority(1000);
BroadcastReceiver receiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
CallListenerService.this.onReceive(intent);
}
};
registerReceiver(receiver, filter);
你使用的是哪个Android设备? 我也遇到过这样的错误,只有在应用程序运行时才会收到广播。 然后我发现我的设备处于省电模式,限制了广播,我们可以在设置>电池管理中为特定应用自定义这些设置。 我的设备是荣耀9升与Android版Pie。 如果问题仍然存在,请尝试在广播接收器中将onast作为onReceive()方法的第一行。 如果您收到吐司,您的应用程序正在接收广播,但问题将出现在您的代码中。
尝试在不同的设备中运行相同的代码。 可能是你的设备设置问题。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.