如何判断给定的设备是否具有打电话的功能?
例如,我的Galaxy平板电脑不能发起呼叫,它不是一部电话。在调用isIntentAvailable(context, Intent.ACTION_DIAL)
之前,我想检测到这一点。我尝试检查isIntentAvailable
,但似乎不是正确的方法。
如何判断给定的设备是否具有打电话的功能?
例如,我的Galaxy平板电脑不能发起呼叫,它不是一部电话。在调用isIntentAvailable(context, Intent.ACTION_DIAL)
之前,我想检测到这一点。我尝试检查isIntentAvailable
,但似乎不是正确的方法。
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会发生什么:
因此,我相信即使没有手机功能(根据Context.TELEPHONY_SERVICE
),Skype也可以在仅限WiFi的设备上工作。
我认为您最初的想法是正确的,但您需要检查哪些应用程序已注册处理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);
然而,我不知道有任何可靠的、具备前瞻性的方法来确定那些应用程序是否能够处理电话呼叫。考虑以下情况:getSystemService(Context.TELEPHONY_SERVICE).getSimState()
),但我认为这可能会导致脆弱的代码,在未来发生变化时可能会出现问题。例如,您能始终可靠地检测到列表中哪个应用程序是默认的拨号器/电话应用程序吗?如果Android在随后的发布中更改了其软件包名称,该怎么办?ACTION_CALL
并不是百分之百可靠的。我尝试在一款市场上最受欢迎的 Android 平板电脑 ASUS Eee Pad Transformer TF101 16GB 上运行 Android 3.2.1,该设备没有电话功能。出乎意料的是,它返回了一个由类 com.android.phone.PhoneApp
标识的单个意图。我本以为会返回0个意图。 我推测,PhoneApp 是通过显示“电话号码:[XXX]XXX-XXXX” [添加到联系人] [关闭] 对话框来处理拨号尝试的设备(类似于 iOS 触摸设备)。 - Goffredo我认为更好的方法是查询PackageManager以检测设备上是否有可用的电话功能。只有具备电话功能的设备才应该拥有电话功能。我在Nexus 7上进行了测试,它没有电话功能,而且它可以正常工作。我没有带有电话的设备来测试相反的情况。
PackageManager pm = getPackageManager();
if (pm.hasSystemFeature(PackageManager.FEATURE_TELEPHONY)){
//has Telephony features.
}
您可以仅检查电话功能或单独检查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卡,可能会出现错误,如果没有覆盖范围/超出范围也可能会出现错误。检查哪些应用程序可以处理呼叫的方法也是如此,因为电话应用程序仍然安装在手机上,但如果没有SIM卡,则会出现错误(至少在我的Galaxy S3上)。
然而,有一种检查方法对于大多数情况来说似乎可行,那就是检查您的电话的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
权限,这对我来说似乎更具侵入性。
哦,我多么希望在Android API中有phone.canMakeCallsWithoutCrashing()
这样的东西。
我还没有检查过这个,但是这里有一个解决方案,看起来应该可以很好地工作。我认为这不需要任何特殊权限,因为它只是在查找制造商设置的布尔值。
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;
}
getLine1Number()
方法返回一个非空字符串吗?这个字符串里面是什么?(同样的,当你在 Nexus 10 模拟器上尝试时,这个字符串里面又是什么?) - Ted Hopp