Android设备的电话通话能力

我如何判断给定的设备是否可以拨打电话?

例如,我的银河平板电脑不能,它不是一个电话。 我想要在调用isIntentAvailable(context, Intent.ACTION_DIAL)之前检测。 我已经尝试检查isIntentAvailable这个,但是这似乎不是要走的路。

Solutions Collecting From Web of "Android设备的电话通话能力"

 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会发生什么:

  • 在本地拨号器/电话应用程序上input电话号码,然后按“呼叫”。
  • 会popup一个标题为“完成操作使用”并提供“拨号程序”或“Skype”应用程序(也可以列出其他应用程序)。

所以,我相信Skype可以在没有手机function的wifi设备上工作(根据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)安装了Skype的wifi-only Xoom。 它需要一个有效的WiFi连接,用户必须configurationSkype使用他们的帐户,否则呼叫将不会成功。

2)没有SIM卡的电话使能设备,或SIM卡被locking或用完。 该设备认为它可以处理电话,但通话导致“未注册networking”错误。

3)没有WiFi或移动连接的电话使能设备(或者因为处于飞行/飞行模式)。 该设备认为它可以处理电话,但通话将失败。

有一些方法可以检测到这些情况(例如,检查getSystemService(Context.TELEPHONY_SERVICE).getSimState() ),但是我认为这可能会导致脆弱的代码在将来发生变化时可能会中断。 例如,你可以总是可靠地检测列表中的哪个应用程序是默认的拨号器/电话应用程序? 如果Android在后续版本中更改了包名,该怎么办?

希望这给了你一些有用的信息 – 我想表明这是更棘手的,它可能会出现在第一眼!

我认为更好的方法是查询PackageManager来检测设备上的电话function是否可用。 如果设备具有电话,则设备应该只具有电话function。 我在没有电话的Nexus 7上testing了它,它工作正常。 我没有电话设备来testing相反的情况。

 PackageManager pm = getPackageManager(); if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)){ //has Telephony features. } 

史蒂夫,

检查TelephonyManager 。 它有getPhoneType()函数,在你的情况下将返回PHONE_TYPE_NONE

这些解决scheme中的大部分/全部在某些情况下有效,但不是全部。

正如@DanJ表示的那样。 有没有简单的方法来实现这一点。

我有问题检查PackageManager.FEATURE_TELEPHONYgetPhoneType ,因为两者似乎检查设备是否有理论上的能力,并假设它可以打电话,如果是这样的话。 如果您的手机没有SIM卡,并且可能没有覆盖/超出范围,则会中断。 检查哪些应用程序可以处理呼叫的方法也是一样,因为手机应用程序仍然安装,但是当没有SIM卡时,它将会中断(至less在我的Galaxy S3上)。

但是,有一次你可以做的检查,在我看来,大多数情况下工作,那就是检查你的电话的subscriberId ,基本上是“什么是你的networking提供商的名称/ ID”。

你可以这样做:

 if(((TelephonyManager)getContext() .getSystemService(Context.TELEPHONY_SERVICE)) .getSubscriberId() == null) { //No network id ~= can't make calls } 

在这里,我们检查是否没有networking,从而可以“安全地”假定设备不能拨打电话。 这种方法在有VoIP电话的情况下或在安装Skype之类的情况下给出了一个错误的结论。

这种方法需要你添加一个权限:

 <uses-permission android:name="android.permission.READ_PHONE_STATE" /> 

@TedHopp的解决scheme需要READ_SMS权限,这对我来说似乎更具侵略性。


哦,我希望phone.canMakeCallsWithoutCrashing()是一个在Android API中的东西。

您可以单独检查TELEPHONYfunction或GSMCDMA

 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; } 

效果很好!

我还没有检查过,但这是一个解决scheme,我想出来,似乎应该工作正常。 我不认为这需要任何特殊的权限,因为它只是寻找由制造商设置的布尔。

 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; }