Skip to content
This repository has been archived by the owner on May 23, 2023. It is now read-only.

Commit

Permalink
Handle multiple SIM cards on Android
Browse files Browse the repository at this point in the history
  • Loading branch information
pbakondy committed Sep 22, 2016
1 parent 1cf48d4 commit 529ae12
Show file tree
Hide file tree
Showing 6 changed files with 180 additions and 22 deletions.
1 change: 1 addition & 0 deletions .gitignore
@@ -1,3 +1,4 @@
node_modules/
.DS_Store
npm-debug.log
notes
25 changes: 25 additions & 0 deletions CHANGELOG.md
@@ -0,0 +1,25 @@
# Changelog

## v1.3.0

- add multiple SIM support on Android

## v1.2.1

- separate Android-related javascript methods

## v1.2.0

- handle Android API 23 Permissions

## v1.1.0

- add new properties on Android

## v1.0.1

- rename plugin to follow new cordova plugin naming conventions

## v1.0.0

- initial release
64 changes: 50 additions & 14 deletions README.md
Expand Up @@ -59,19 +59,53 @@ You can find the name of mobile provider using [mcc-mnc-list](https://www.npmjs.

Install `Extras` / `Android Support Library` from Android SDK.

### Additional return values

* `phoneNumber`: String - phone number string for line 1, for example, the [MSISDN](http://en.wikipedia.org/wiki/MSISDN) for a GSM phone <sup>1</sup>
* `deviceId`: String - the unique device ID, for example, the IMEI for GSM and the MEID or ESN for CDMA phones
* `deviceSoftwareVersion`: String - the software version number for the device, for example, the IMEI/SV for GSM phones
* `simSerialNumber`: String - the serial number of the SIM, if applicable
* `subscriberId`: String - the unique subscriber ID, for example, the IMSI for a GSM phone
* `callState`: Number - the call state (cellular) on the device
* `dataActivity`: Number - the type of activity on a data connection (cellular)
* `networkType`: Number - the NETWORK_TYPE_xxxx for current data connection
* `phoneType`: Number - the device phone type. This indicates the type of radio used to transmit voice calls
* `simState`: Number - the state of the device SIM card
* `isNetworkRoaming`: Boolean - true if the device is considered roaming on the current network, for GSM purposes
### Under the hood

This plugin uses two different Android APIs to receive SIM data:
- `TelephonyManager` (since API level 1)
- `SubscriptionManager` (since API level 22)

Since Android 6 (API level 23) a few methods of `TelephonyManager` require permission `READ_PHONE_STATE`.

All methods of `SubscriptionManager` require permission `READ_PHONE_STATE`.

`SubscriptionManager` is able to access multiple SIM data. The return object of this cordova plugin provides the details of the available sim cards in an array (`cards`).

### Return object


- `carrierName`: {String} Service Provider Name (SPN)
- `countryCode`: {String} ISO country code equivalent for the SIM provider's country code
- `mcc`: {String} MCC (mobile country code) of the provider of the SIM
- `mnc`: {String} MNC (mobile network code) of the provider of the SIM
- `callState`: {Number} call state (cellular) on the device
- `dataActivity`: {Number} type of activity on a data connection (cellular)
- `networkType`: {Number} the NETWORK_TYPE_xxxx for current data connection
- `phoneType`: {Number} device phone type. This indicates the type of radio used to transmit voice calls
- `simState`: {Number} the state of the device SIM card
- `isNetworkRoaming`: {Boolean} true if the device is considered roaming on the current network, for GSM purposes
- `phoneCount`: {Number} the number of phones available. Returns 0 if none of voice, sms, data is not supported. Returns 1 for Single standby mode (Single SIM functionality). Returns 2 for Dual standby mode (Dual SIM functionality)
- `activeSubscriptionInfoCount`: {Number} [`READ_PHONE_STATE`] the current number of active subscriptions
- `activeSubscriptionInfoCountMax`: {Number} [`READ_PHONE_STATE`] the maximum number of active subscriptions
- `phoneNumber`: {String} [`READ_PHONE_STATE`] - phone number string for line 1, for example, the [MSISDN](http://en.wikipedia.org/wiki/MSISDN) for a GSM phone <sup>1</sup>
- `deviceId`: {String} [`READ_PHONE_STATE`] the unique device ID, for example, the IMEI for GSM and the MEID or ESN for CDMA phones
- `deviceSoftwareVersion`: {String} [`READ_PHONE_STATE`] the software version number for the device, for example, the IMEI/SV for GSM phones
- `simSerialNumber`: {String} [`READ_PHONE_STATE`] the serial number of the SIM, if applicable
- `subscriberId`: {String} [`READ_PHONE_STATE`] the unique subscriber ID, for example, the IMSI for a GSM phone
- `cards`: {Array} [`READ_PHONE_STATE`] List of SIM cards
- `carrierName`: {String} the name displayed to the user that identifies Subscription provider name
- `displayName`: {String} the name displayed to the user that identifies this subscription
- `countryCode`: {String} the ISO country code
- `mcc`: {String} MCC (mobile country code) of the provider of the SIM
- `mnc`: {String} MNC (mobile network code) of the provider of the SIM
- `isNetworkRoaming`: {Boolean} Returns true if the device is considered roaming on the current network for a subscription
- `isDataRoaming`: {Boolean} the data roaming state for this subscription
- `simSlotIndex`: {Number} the slot index of this Subscription's SIM card
- `phoneNumber`: {String} the number of this subscription
- `deviceId`: {String} the unique device ID of a subscription, for example, the IMEI for GSM and the MEID for CDMA phones
- `simSerialNumber`: {String} ICC ID
- `subscriptionId`: {String} Subscription Identifier, this is a device unique number


<sup>1)</sup> Notice: the content of phoneNumber is unreliable (see [this](http://stackoverflow.com/questions/7922734/getting-reliable-msisdn-from-android-phone-voicemailnumber-line1number) and [this](http://stackoverflow.com/questions/25861064/retrieving-line1-number-from-telephonymanager-in-android) article).
Sometimes phoneNumber is only an empty string.
Expand Down Expand Up @@ -188,7 +222,9 @@ This plugin needs `READ_PHONE_STATE` permission for getting the following values
* `deviceSoftwareVersion`
* `simSerialNumber`
* `subscriberId`

* `activeSubscriptionInfoCount`
* `activeSubscriptionInfoCountMax`
* multiple SIM card data

Wiki: [How to test permissions](https://github.com/pbakondy/cordova-plugin-sim/wiki/Testing-Android-API-23-Permissions)

Expand Down
2 changes: 1 addition & 1 deletion package.json
@@ -1,6 +1,6 @@
{
"name": "cordova-plugin-sim",
"version": "1.2.1",
"version": "1.3.0",
"description": "A plugin to get the device's SIM data (carrier name, mcc mnc, country code, telephonenumber, imei, etc)",
"cordova": {
"id": "cordova-plugin-sim",
Expand Down
2 changes: 1 addition & 1 deletion plugin.xml
Expand Up @@ -2,7 +2,7 @@
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
xmlns:android="http://schemas.android.com/apk/res/android"
id="cordova-plugin-sim"
version="1.2.1">
version="1.3.0">
<name>SIM</name>
<description>A plugin to get the device's SIM data (carrier name, mcc mnc, country code, telephonenumber, imei, etc)</description>
<license>MIT</license>
Expand Down
108 changes: 102 additions & 6 deletions src/android/com/pbakondy/Sim.java
Expand Up @@ -6,10 +6,23 @@

// class TelephonyManager
// http://developer.android.com/reference/android/telephony/TelephonyManager.html
// https://github.com/android/platform_frameworks_base/blob/master/telephony/java/android/telephony/TelephonyManager.java

// permissions
// http://developer.android.com/training/permissions/requesting.html

// Multiple SIM Card Support
// https://developer.android.com/about/versions/android-5.1.html

// class SubscriptionManager
// https://developer.android.com/reference/android/telephony/SubscriptionManager.html
// https://github.com/android/platform_frameworks_base/blob/master/telephony/java/android/telephony/SubscriptionManager.java

// class SubscriptionInfo
// https://developer.android.com/reference/android/telephony/SubscriptionInfo.html
// https://github.com/android/platform_frameworks_base/blob/master/telephony/java/android/telephony/SubscriptionInfo.java


package com.pbakondy;

import org.apache.cordova.CallbackContext;
Expand All @@ -20,15 +33,19 @@
import org.json.JSONArray;
import org.json.JSONException;

import android.app.Activity;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.pm.PackageManager;
import android.os.Build;
import android.Manifest;
import android.support.v4.app.ActivityCompat;
import android.support.v4.content.ContextCompat;
import android.telephony.SubscriptionInfo;
import android.telephony.SubscriptionManager;
import android.telephony.TelephonyManager;

import java.util.List;

public class Sim extends CordovaPlugin {

private static final String GET_SIM_INFO = "getSimInfo";
Expand All @@ -37,6 +54,7 @@ public class Sim extends CordovaPlugin {

private CallbackContext callback;

@SuppressLint("HardwareIds")
@Override
public boolean execute(String action, JSONArray args, CallbackContext callbackContext) throws JSONException {
callback = callbackContext;
Expand All @@ -46,15 +64,79 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo

TelephonyManager manager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);

String phoneNumber = "";
// dual SIM detection with SubscriptionManager API
// requires API 22
// requires permission READ_PHONE_STATE
JSONArray sims = null;
Integer phoneCount = null;
Integer activeSubscriptionInfoCount = null;
Integer activeSubscriptionInfoCountMax = null;

try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {

phoneCount = manager.getPhoneCount();

if (simPermissionGranted(Manifest.permission.READ_PHONE_STATE)) {

SubscriptionManager subscriptionManager = (SubscriptionManager) context.getSystemService(Context.TELEPHONY_SUBSCRIPTION_SERVICE);
activeSubscriptionInfoCount = subscriptionManager.getActiveSubscriptionInfoCount();
activeSubscriptionInfoCountMax = subscriptionManager.getActiveSubscriptionInfoCountMax();

sims = new JSONArray();

List<SubscriptionInfo> subscriptionInfos = subscriptionManager.getActiveSubscriptionInfoList();
for (SubscriptionInfo subscriptionInfo : subscriptionInfos) {

CharSequence carrierName = subscriptionInfo.getCarrierName();
String countryIso = subscriptionInfo.getCountryIso();
int dataRoaming = subscriptionInfo.getDataRoaming(); // 1 is enabled ; 0 is disabled
CharSequence displayName = subscriptionInfo.getDisplayName();
String iccId = subscriptionInfo.getIccId();
int mcc = subscriptionInfo.getMcc();
int mnc = subscriptionInfo.getMnc();
String number = subscriptionInfo.getNumber();
int simSlotIndex = subscriptionInfo.getSimSlotIndex();
int subscriptionId = subscriptionInfo.getSubscriptionId();

boolean networkRoaming = subscriptionManager.isNetworkRoaming(simSlotIndex);
String deviceId = manager.getDeviceId(simSlotIndex);

JSONObject simData = new JSONObject();

simData.put("carrierName", carrierName.toString());
simData.put("displayName", displayName.toString());
simData.put("countryCode", countryIso);
simData.put("mcc", mcc);
simData.put("mnc", mnc);
simData.put("isNetworkRoaming", networkRoaming);
simData.put("isDataRoaming", (dataRoaming == 1));
simData.put("simSlotIndex", simSlotIndex);
simData.put("phoneNumber", number);
simData.put("deviceId", deviceId);
simData.put("simSerialNumber", iccId);
simData.put("subscriptionId", subscriptionId);

sims.put(simData);

}
}
}
} catch (JSONException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}

String phoneNumber = null;
String countryCode = manager.getSimCountryIso();
String simOperator = manager.getSimOperator();
String carrierName = manager.getSimOperatorName();

String deviceId = "";
String deviceSoftwareVersion = "";
String simSerialNumber = "";
String subscriberId = "";
String deviceId = null;
String deviceSoftwareVersion = null;
String simSerialNumber = null;
String subscriberId = null;

int callState = manager.getCallState();
int dataActivity = manager.getDataActivity();
Expand Down Expand Up @@ -95,6 +177,16 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo

result.put("isNetworkRoaming", isNetworkRoaming);

if (phoneCount != null) {
result.put("phoneCount", (int)phoneCount);
}
if (activeSubscriptionInfoCount != null) {
result.put("activeSubscriptionInfoCount", (int)activeSubscriptionInfoCount);
}
if (activeSubscriptionInfoCountMax != null) {
result.put("activeSubscriptionInfoCountMax", (int)activeSubscriptionInfoCountMax);
}

if (simPermissionGranted(Manifest.permission.READ_PHONE_STATE)) {
result.put("phoneNumber", phoneNumber);
result.put("deviceId", deviceId);
Expand All @@ -103,6 +195,10 @@ public boolean execute(String action, JSONArray args, CallbackContext callbackCo
result.put("subscriberId", subscriberId);
}

if (sims != null && sims.length() != 0) {
result.put("cards", sims);
}

callbackContext.success(result);

return true;
Expand Down

0 comments on commit 529ae12

Please sign in to comment.