开发者

Android Device phone call ability

开发者 https://www.devze.com 2023-02-15 08:21 出处:网络
How can I tell whether a given device has the ability to make phone calls? For example, my Galaxy Tablet cannot initiate call, its not a phone.I want to detect that before doing a call to isI开发者_高

How can I tell whether a given device has the ability to make phone calls?

For example, my Galaxy Tablet cannot initiate call, its not a phone. I want to detect that before doing a call to isI开发者_高级运维ntentAvailable(context, Intent.ACTION_DIAL). I've tried checking the isIntentAvailable for this, but that doesn't seem to be the way to go.


if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getPhoneType()
    == TelephonyManager.PHONE_TYPE_NONE)
{
    // no phone
}

EDIT I'm surprised it comes back PHONE_TYPE_CDMA. Here's another possibility:

if (((TelephonyManager)getContext().getSystemService(Context.TELEPHONY_SERVICE)).getLine1Number()
    == null)
{
    // no phone
}

This will require the READ_PHONE_STATE permission.


Devices do not necessarily need Context.TELEPHONY_SERVICE to make phone calls. Consider what happens if you install Skype:

  • Enter a phone number on the native Dialer/Phone app and press "Call".
  • A popup appears titled "Complete action using" and offering "Dialer" or "Skype" applications (it could list other applications too).

So, I believe Skype would work on a wifi-only device with no phone capabilities (according to Context.TELEPHONY_SERVICE).

I think you were correct with your original idea, but you need to check what applications are registered to handle Intent.ACTION_CALL instead of Intent.ACTION_DIAL, e.g.

Intent callIntent = new Intent(Intent.ACTION_CALL);
callIntent.setData(Uri.parse("tel:5551231234"));
List<ResolveInfo> callAppsList = 
  context.getPackageManager().queryIntentActivities(callIntent, 0);

However, I am not aware of any reliable, forward-proof ways of figuring out if those applications will be able to handle the phone call. Consider these cases:

1) A wifi-only Xoom with Skype installed. It needs a valid wifi connection, and the user must have configured Skype to use their account, otherwise the call won't succeed.

2) A telephony enabled device with no SIM card in, or a SIM card that is locked or has run out. The device thinks it can handle telephony, but the call results in a "Not registered on network" error.

3) A telephony enabled device with no wifi or mobile connection (or because it is in Airplane/Flight mode). The device thinks it can handle telephony, but the call will fail.

There are ways you could detect some of these scenarios (e.g. inspecting getSystemService(Context.TELEPHONY_SERVICE).getSimState()), but I think this would probably lead to fragile code that may break when things change in future. For example, could you always reliably detect which application in the list is the default Dialer/Phone app? What if Android changed the package name for it in a subsequent release.

Hopefully that gave you some useful information - I wanted to show this is more tricky that it might appear at a first glance!


I think a better approach would be to query the PackageManager to detect if Telephony features are even available on the device. A device should only have Telephony features if it has a phone. I tested this on a Nexus 7, which does not have a phone, and it works. I do not have a device with a phone to test the opposite case.

PackageManager pm = getPackageManager();

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


Steve,

Check out TelephonyManager. It has the getPhoneType() function which will return PHONE_TYPE_NONE in your case.


You can check only TELEPHONY feature or GSM and CDMA separately:

private boolean hasTelephony() {
    return getPackageManager().hasSystemFeature(PackageManager.FEATURE_TELEPHONY);
}

or

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

works well!


Most/all of these solutions here work in some cases, but not all.

As @DanJ indicates. There are no easy way of achieving this.

I had issues checking the PackageManager.FEATURE_TELEPHONY and the getPhoneType, because both appear to check if the device is capable in theory, and assume it can make calls if this is the case. This breaks if you have a phone with no SIM card, and possibly if you have no coverage/out of range. The same goes with the approach of checking which applications can handle a call, because the phone app is still installed, but it will break (at least on my galaxy s3) when there is no SIM.

However, there is once check you can do which appears to me to work for most cases, and that is to check your telephone's subscriberId, basically "what is the name/id of your network provider".

You can do this:

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

Here we check if we have no network, thus can "safely" assume that the device can't make a call. This approach gives a false negatives in the case where you have a VoIP phone, or have something like Skype installed.

This approach requires you to add a permission:

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

@TedHopp's solution requires the READ_SMS permission which seems more intrusive to me.


Ohh how I wish phone.canMakeCallsWithoutCrashing() was a thing in the android api.


I have not checked this yet but here is a solution I came up with that seems like it should work fine. I don't think this requires any special permissions since it is just looking for bools set by the manufacture.

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

精彩评论

暂无评论...
验证码 换一张
取 消