Android Phone возможность звонить
Как я могу узнать, имеет ли данное устройство возможность совершать телефонные звонки?
Например, мой планшет Galaxy не может, это не телефон. Я хочу обнаружить это, прежде чем сделать звонок isIntentAvailable(context, Intent.ACTION_DIAL)
, Я пытался проверить isIntentAvailable
для этого, но это не похоже на путь.
7 ответов
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getPhoneType()
== TelephonyManager.PHONE_TYPE_NONE)
{
// no phone
}
РЕДАКТИРОВАТЬ Я удивлен, что он возвращается PHONE_TYPE_CDMA
, Вот еще одна возможность:
if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
== null)
{
// no phone
}
Это потребует READ_PHONE_STATE
разрешение.
Устройства не обязательно нужны Context.TELEPHONY_SERVICE
совершать телефонные звонки. Посмотрим, что произойдет, если вы установите Skype:
- Введите номер телефона в родном приложении "Звонилка / Телефон" и нажмите "Позвонить".
- Появится всплывающее окно с заголовком "Выполнить действие с помощью", предлагающее приложения "Звонилка" или "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. Требуется действующее соединение Wi-Fi, и пользователь должен настроить Skype для использования своей учетной записи, в противном случае вызов не будет успешным.
2) Устройство с поддержкой телефонии без SIM-карты или SIM-карта, которая заблокирована или закончилась. Устройство считает, что оно может обрабатывать телефонию, но в результате вызова возникает ошибка "Не зарегистрирован в сети".
3) Устройство с поддержкой телефонии без Wi-Fi или мобильной связи (или потому, что оно находится в режиме полета / полета). Устройство считает, что оно может обрабатывать телефонию, но вызов не удастся.
Есть способы, которыми вы можете обнаружить некоторые из этих сценариев (например, проверка getSystemService(Context.TELEPHONY_SERVICE).getSimState()
), но я думаю, что это может привести к хрупкому коду, который может сломаться, когда что-то изменится в будущем. Например, можете ли вы всегда надежно определить, какое приложение в списке является приложением для набора номера / телефона по умолчанию? Что делать, если Android изменил имя пакета для него в следующем выпуске.
Надеюсь, это дало вам некоторую полезную информацию - я хотел показать, что это сложнее, чем может показаться на первый взгляд!
Я думаю, что лучшим подходом было бы запросить PackageManager, чтобы определить, доступны ли функции телефонии на устройстве. Устройство должно иметь функции телефонии, только если у него есть телефон. Я проверил это на Nexus 7, у которого нет телефона, и он работает. У меня нет устройства с телефоном для проверки противоположного случая.
PackageManager pm = getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)){
//has Telephony features.
}
Стив,
Проверять, выписываться TelephonyManager
, Имеет getPhoneType()
функция, которая будет возвращать PHONE_TYPE_NONE
в твоем случае.
Вы можете проверить только функцию ТЕЛЕФОНИЯ или 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;
}
работает хорошо!
Большинство / все эти решения здесь работают в некоторых случаях, но не во всех.
Как указывает @DanJ. Нет простого способа достичь этого.
У меня были проблемы с проверкой PackageManager.FEATURE_TELEPHONY
и getPhoneType
потому что оба, кажется, проверяют, способно ли устройство теоретически, и предполагают, что оно может делать вызовы, если это так. Это ломается, если у вас телефон без SIM-карты, и, возможно, если у вас нет покрытия / вне зоны действия. То же самое касается подхода проверки того, какие приложения могут обрабатывать вызов, потому что приложение телефона все еще установлено, но оно сломается (по крайней мере, на моей galaxy s3), когда SIM-карта отсутствует.
Тем не менее, есть одна проверка, которую вы можете сделать, которая, как мне кажется, работает в большинстве случаев, и это проверка вашего телефона subscriberId
, в основном "как называется /id вашего сетевого провайдера".
Вы можете сделать это:
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()
была вещь в Android API.
Я еще не проверил это, но вот решение, которое я придумал, похоже, что оно должно работать нормально. Я не думаю, что для этого требуются какие-то особые разрешения, поскольку он просто ищет 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;
}