Завершить звонок в Android программно

Я вижу много вопросов, которые невозможно программно завершить в Android. В то же время, я вижу много приложений для набора номера на рынке GooglePlay, где вы можете активировать вызов и сбросить его. Как они работают?

Изменить: я где-то читал, что мое приложение должно быть системным приложением. Тогда как сделать его системным, и в чем разница между системными и пользовательскими приложениями?

9 ответов

Решение

Вам не нужно быть системным приложением. Сначала создайте пакет com.android.internal.telephony в вашем проекте, и поместите это в файл с именем " ITelephony.aidl ":

package com.android.internal.telephony; 

interface ITelephony {      

boolean endCall();     

void answerRingingCall();      

void silenceRinger(); 

}

Как только у вас есть это, вы можете использовать этот код для завершения вызова:

TelephonyManager telephonyManager = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
Class clazz = Class.forName(telephonyManager.getClass().getName());
Method method = clazz.getDeclaredMethod("getITelephony");
method.setAccessible(true);
ITelephony telephonyService = (ITelephony) method.invoke(telephonyManager);
telephonyService.endCall();

Вы можете использовать это внутри PhoneStateListener, например. Чтобы это работало, вам необходимы разрешения в манифесте:

<uses-permission android:name="android.permission.MODIFY_PHONE_STATE" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />

Редактировать: извинения за ужасное форматирование, я до сих пор не могу понять, как правильно делать блоки кода здесь:/

Для Android P (начиная с бета-версии 2) и выше, наконец, существует формальный API для endCall:

https://developer.android.com/reference/android/telecom/TelecomManager

ANSWER_PHONE_CALLS разрешение требуется в манифесте:

<uses-permission android:name="android.permission.ANSWER_PHONE_CALLS" />

С разрешения, для уровня API 28 или выше:

TelecomManager tm = (TelecomManager) mContext.getSystemService(Context.TELECOM_SERVICE);

if (tm != null) {
    boolean success = tm.endCall();
    // success == true if call was terminated.
}

В то же время оригинал endCall() метод под TelephonyManager теперь защищен MODIFY_PHONE_STATE разрешения и больше не могут вызываться несистемными приложениями путем отражения без разрешения (в противном случае будет сгенерировано исключение безопасности).

Для информации.

Может быть полезным в некоторых ситуациях. Существует потенциальный обходной путь с использованием InCallService учебный класс. Большая часть необходимой информации здесь. https://developer.android.com/reference/android/telecom/InCallService.html

Это требует настройки вашего приложения в качестве телефонного приложения по умолчанию и обеспечения следующего.

<uses-permission android:name="android.permission.CALL_PHONE" />

Если вы реализуете свой собственный класс расширения InCallService затем, когда звонок начинается, он привязывается к вашему приложению, и вы получаете информацию о звонке через onCallAdded() функция. Вы можете тогда просто call.disconnect() и звонок закончится.

Вырезать вызов для Api 28+

private void cutCall(){
    ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.READ_PHONE_STATE }, PHONE_STATE);
}

}

@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
    if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED) {
        if (requestCode == PHONE_STATE) {
            ActivityCompat.requestPermissions(this, new String[] { Manifest.permission.ANSWER_PHONE_CALLS }, ANSWER_CALLS);
        } else if (requestCode == ANSWER_CALLS) {
            cutTheCall;
        }
    }
}

// Этот код будет работать на Android N (Api 28 и выше)

private boolean cutTheCall() {
    TelecomManager telecomManager = (TelecomManager) getApplicationContext().getSystemService(TELECOM_SERVICE);
    if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE) != PackageManager.PERMISSION_GRANTED || telecomManager == null) {
        return false;
    }

    if (telecomManager.isInCall()) {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.P) {
            callDisconnected = telecomManager.endCall();
        }
    }
    return true;
}

Наряду с добавлением интерфейса android-телефонии и приемника вещания, вам также необходимо добавить запись приемника android манифеста с действием android.intent.action.PHONE_STATE для получателя вы хотите справиться с намерением.

Вы получите ошибку времени компиляции, если добавите

uses-permission android:name="android.permission.MODIFY_PHONE_STATE`

в вашем файле манифеста. Но даже если мы удалим это, он автоматически отклонит входящие звонки.

SilenceRinger() не работает для версий Android 2.3+. Просто прокомментируйте, другой код будет работать нормально. Надеюсь, что это работает для вас!

Просто чтобы добавить к ответу @headuck. Для API 28 вам также необходимо добавить:

<uses-permission android:name="android.permission.READ_CALL_LOG"/>

затем запросите разрешение на свою деятельность. Всего я запросил эти разрешения, чтобы он работал (READ_PHONE_STATE, CALL_PHONE, ANSWER_PHONE_CALLS, READ_CONTACTS, READ_CALL_LOG)

public static boolean isCallActive(Context context){
    AudioManager manager = (AudioManager)context.getSystemService(Context.AUDIO_SERVICE);
    if(manager.getMode()==AudioManager.MODE_IN_CALL || manager.getMode()==AudioManager.MODE_IN_COMMUNICATION){
        return true;
    }

    return false;
}

Вы можете завершать вызовы с помощью Telecom manager. Я проверил это, и это сработало. Для этого вам необходимо разрешение ANSWER_PHONE_CALLS. Несмотря на то, что это намекает на отвеченные звонки, у меня было завершение звонка с этого телефона. И это работает для современных Android.

         TelecomManager telecomManager = (TelecomManager) getSystemService(Context.TELECOM_SERVICE);

telecomManager.endCall();

Другие вопросы по тегам