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;
}
Другие вопросы по тегам