Завершить звонок в 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();