Возможность вызова телефона Android
Как я могу узнать, имеет ли данное устройство возможность совершать телефонные звонки?
Например, моя Galaxy Tablet не может, это не телефон. Я хочу обнаружить это, прежде чем делать вызов isIntentAvailable(context, Intent.ACTION_DIAL)
. Я попытался проверить isIntentAvailable
для этого, но это, похоже, не так.
Ответы
Ответ 1
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getPhoneType()
== TelephonyManager.PHONE_TYPE_NONE)
{
// no phone
}
EDIT Я удивлен, что он вернулся PHONE_TYPE_CDMA
. Здесь еще одна возможность:
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
== null)
{
// no phone
}
Для этого потребуется разрешение READ_PHONE_STATE
.
Ответ 2
Устройства не обязательно должны Context.TELEPHONY_SERVICE
совершать телефонные звонки. Посмотрите, что произойдет, если вы установите Skype:
- Введите номер телефона в приложении Dialer/Phone и нажмите "Вызов".
- Появится всплывающее окно под названием "Полное действие с использованием" и предлагает приложения "Dialer" или "Skype" (он также может отображать другие приложения).
Итак, я уверен, что Skype будет работать на устройстве с Wi-Fi, не имеющем телефонных возможностей (согласно Context.TELEPHONY_SERVICE
).
Я думаю, что вы были верны своей оригинальной идее, но вам нужно проверить, какие приложения зарегистрированы для обработки Intent.ACTION_CALL
вместо Intent.ACTION_DIAL
, например.
Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:5551231234"));
List<ResolveInfo> callAppsList =
context.getPackageManager().queryIntentActivities(callIntent, 0);
Однако я не знаю никаких надежных и надежных способов выяснить, смогут ли эти приложения обрабатывать телефонный звонок. Рассмотрим следующие случаи:
1) Установлен только Wi-Fi Xoom с установленной Skype. Он должен иметь действительное соединение wifi, и пользователь должен настроить Skype для использования своей учетной записи, иначе вызов не будет выполнен.
2) Устройство с поддержкой телефонии без SIM-карты или SIM-карта, которая заблокирована или закончилась. Устройство считает, что оно может обрабатывать телефонию, но вызов приводит к ошибке "Not registered on network".
3) Устройство с поддержкой телефонии без Wi-Fi или мобильного соединения (или потому, что оно находится в режиме полета/полета). Устройство считает, что оно может обрабатывать телефонию, но вызов не удастся.
Есть способы обнаружения некоторых из этих сценариев (например, проверка getSystemService(Context.TELEPHONY_SERVICE).getSimState()
), но я думаю, что это, вероятно, приведет к хрупкому коду, который может сломаться, когда что-то изменится в будущем. Например, можете ли вы всегда надежно определить, какое приложение в списке является приложением Dialer/Phone по умолчанию? Что делать, если Android изменил название пакета для него в следующей версии.
Надеюсь, это дало вам полезную информацию - я хотел показать, что это более сложно, чем может показаться на первый взгляд!
Ответ 3
Я думаю, что лучший подход заключался бы в том, чтобы запросить PackageManager, чтобы определить, доступны ли функции телефонии на устройстве. Устройство должно иметь только функции телефонии, если у него есть телефон. Я тестировал это на Nexus 7, у которого нет телефона, и он работает. У меня нет устройства с телефоном для проверки обратного случая.
PackageManager pm = getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)){
//has Telephony features.
}
Ответ 4
Стив,
Отъезд TelephonyManager
. Он имеет функцию getPhoneType()
, которая вернет PHONE_TYPE_NONE
в вашем случае.
Ответ 5
В большинстве случаев все эти решения работают, но не все.
Как указывает @DanJ. Нет простого способа добиться этого.
У меня были проблемы с проверкой PackageManager.FEATURE_TELEPHONY
и getPhoneType
, потому что оба, похоже, проверяют, способно ли устройство в теории, и предположим, что он может совершать вызовы, если это так. Это прерывается, если у вас есть телефон без SIM-карты, и, возможно, если у вас нет покрытия/вне диапазона. То же самое происходит с подходом к проверке того, какие приложения могут обрабатывать вызов, потому что телефонное приложение все еще установлено, но оно сломается (по крайней мере, на моей галактике s3), когда нет SIM-карты.
Однако однажды вы можете проверить, что мне кажется, что я работаю в большинстве случаев, и это проверить ваш телефон subscriberId
, в основном "что такое имя/идентификатор вашего сетевого провайдера".
Вы можете сделать это:
if(((TelephonyManager)getContext()
.getSystemService(Context.TELEPHONY_SERVICE))
.getSubscriberId() == null) {
//No network id ~= can't make calls
}
Здесь мы проверяем, нет ли у нас сети, поэтому можем "безопасно" предположить, что устройство не может позвонить. Этот подход дает ложные негативы в случае, когда у вас есть VoIP-телефон или что-то вроде Skype установлено.
Этот подход требует, чтобы вы добавили разрешение:
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
Решение @TedHopp требует разрешения READ_SMS
, которое кажется мне более навязчивым.
Ох, как бы я хотел, phone.canMakeCallsWithoutCrashing()
было в андроиде api.
Ответ 6
Вы можете проверить только ТЕЛЕФОНИЯ или GSM и CDMA отдельно:
private boolean hasTelephony() {
return getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}
или
private boolean hasGsmOrCdma() {
PackageManager pm = getPackageManager();
boolean gsmSupported = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_GSM);
boolean cdmaSupported = pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
//if necessary write somehow what exactly the devise supports
return gsmSupported || cdmaSupported;
}
работает хорошо!
Ответ 7
Я еще не проверил это, но вот решение, которое я придумал, похоже, должно работать нормально. Я не думаю, что это требует каких-либо специальных разрешений, так как это просто поиск bools, установленных при изготовлении.
static boolean isRunningOnPhone(Context context){
UiModeManager uiModeManager = (UiModeManager) context.getSystemService(UI_MODE_SERVICE);
PackageManager packageManager = context.getPackageManager();
boolean a = packageManager.hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
boolean b = packageManager.hasSystemFeature(PackageManager.FEATURE_SIP_VOIP) || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA) || context.getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY_CDMA);
boolean c = packageManager.hasSystemFeature(PackageManager.FEATURE_TOUCHSCREEN);
boolean d;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
d = packageManager.hasSystemFeature(PackageManager.FEATURE_AUTOMOTIVE);
}else {
d = !(uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_CAR);
}
boolean e = !(uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_TELEVISION);
boolean f = uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_APPLIANCE;
boolean g = true;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT_WATCH) {
g = !(uiModeManager.getCurrentModeType() == Configuration.UI_MODE_TYPE_WATCH);
}
return a && b && c && d && e && f && g;
}