Слушайте звонки Broadcast приемник в Android пирог - PullRequest
0 голосов
/ 22 апреля 2019

Я пытаюсь заставить приложение прослушивать звонки (входящие и исходящие), на данный момент я просто зарегистрировал получателя в манифесте, который отлично работал в 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 пирог

Другое редактирование:

  @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 пирогом.

Редактировать: решение состояло в том, чтобы смешать кучу ответов, пока они не сработали на каждом устройстве. Я написал манифест декларации так:

<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 секунды для номера, чтобы войти в журнал звонков, если вы попытаетесь прочитать его сразу, он не будет работать.

Ответы [ 2 ]

0 голосов
/ 22 апреля 2019

Измените код в файле манифеста, как показано ниже, и установите значение Приоритет на высокое.Я думаю, что этот очевидный код нужен, когда приложение находится в фоновом режиме.

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

Этот программный код должен разбудить Приемник, когда приложение находится на переднем плане, т.е.когда Пользователь имеет дело с действиями BroadcasteReciever из Activity.(Приемник должен registerReceiver() в onResume() && unregisterReceiver() в 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);
0 голосов
/ 22 апреля 2019

Я также создал 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>
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...