[英]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.