【问题标题】:Listen to calls Broadcast receiver in Android pie在 Android pie 中收听呼叫广播接收器
【发布时间】:2019-04-22 11:55:25
【问题描述】:

我正在尝试让应用程序监听呼叫(传入和传出),我现在所做的只是在清单中注册接收器,这在 9.0 以下的 Android 中完美运行。 但是,当我在 Android oreo 上测试该应用程序时出现了问题,我知道某些广播已被禁用。 我尝试制作一个前台服务来注册接收器并收听此广播,但它再次适用于 oreo 以下版本。

我不知道还能做什么,我必须让它工作,我不在乎它是否会以一种不优雅的方式,我不发布这个应用程序我只需要它供私人使用。

总结:即使应用当前未激活,我也需要在 Android pie 中收听电话

清单

<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>

我的接收者

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);
    }
}

其余的没关系,它只是在通话结束时启动一个活动来测试它是否工作

我添加了一个注册接收者的fourground服务,这适用于android oreo,但在android pie上仍然存在问题。

编辑:解决方案是混合一堆答案,直到它适用于每台设备。 我这样写了声明清单:

<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 行,它检查数字是否为空,如果是,它启动一个处理程序以运行 2 秒后,当处理程序启动时,我从调用日志中读取最后一个数字。 2 秒的延迟是为了让号码进入通话记录,如果您尝试立即读取它,它不起作用。

【问题讨论】:

  • 请发布您的代码尝试,否则有人会标记为“太板问题”。
  • 我会发布我的尝试,但是它在 android oero 中不起作用,所以它并不重要
  • 不计其数,其他人只有看到长相才能提供帮助!这个社区也没有按照某人的意愿工作。错误代码示例是这里的主要人员。从别人的错误中学习。
  • 我会发布,我再次告诉你广播接收器在 android oreo 上不起作用,所以我要求解决它。几分钟后我会回家并发布代码
  • @erantsalach 尝试注册动态接收器,而不是在清单文件中进行静态注册,即在运行时在 java 文件中注册此接收器。

标签: android broadcastreceiver


【解决方案1】:

我还创建了一个 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>

【讨论】:

  • 您好,感谢您的回答,但我已经有过这样的课程,问题是它甚至没有在 android oreo + 上调用
  • 你是如何注册接收方的?
  • 看看我编辑的问题,我做了你所做的,但它甚至没有被调用
  • 它适用于android oreo,我刚刚测试了这个,我也做了一个注册到广播的服务,但是我让我的朋友在android pie上测试,他说它不起作用他
  • 在哪个设备上?
【解决方案2】:

如下更改 Manifest 文件中的代码并将优先级设置为高。 我认为当应用程序处于后台时需要这个清单代码。

 <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>

此程序代码需要在应用程序处于前台时唤醒接收器,即。当用户从 Activity 处理 BroadcasteReciever 的操作时。 (接收者需要registerReceiver() in onResume() && unregisterReceiver() in 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);

【讨论】:

  • 好的,它几乎可以在任何设备上运行,问题出现在 Galaxy s8 上,我真的不知道为什么
  • 哎呀,但是这个代码在每台设备上运行,不管是什么制造商,它有什么版本......对不起,我不能帮助你更多......祝你好运......
  • @erantsalach 你发现哪里出了问题吗?如果你找到了,请回答问题stackoverflow.com/q/63027622/5359340
【解决方案3】:

您使用的是哪种安卓设备? 我也遇到过这样的错误,只有在应用程序运行时才会收到广播。然后我发现我的设备处于限制广播的省电模式,我们可以在设置>电池管理中为特定应用自定义这些设置。 我的设备是安卓版 Pie 的 Honor 9 lite。 如果问题仍然存在,请尝试将 toast 作为广播接收器中 onReceive() 方法的第一行。如果您收到 toast,则说明您的应用正在接收广播,但问题出在您的代码中。

尝试在不同的设备上运行相同的代码。可能问题出在您的设备设置上。

【讨论】:

  • 它在galaxy s9上,我最后解决了,不确定是什么问题,但可能是设备设置和一些代码错误的混合。
  • @erantsalach 您是否检查设备是否处于省电模式?如果它处于省电模式,您可以更改应用程序的设置。将特定应用的启动设置从自动更改为手动。
  • 我查了一下,这次不是这样
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2023-03-27
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多