繁体   English   中英

听取调用Android手机中的广播接收器

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM