Подтвердить что ты не робот

Возможность вызова телефона Android

Как я могу узнать, имеет ли данное устройство возможность совершать телефонные звонки?

Например, моя Galaxy Tablet не может, это не телефон. Я хочу обнаружить это, прежде чем делать вызов isIntentAvailable(context, Intent.ACTION_DIAL). Я попытался проверить isIntentAvailable для этого, но это, похоже, не так.

4b9b3361

Ответ 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.
}

Ответ 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;
}