Device showing signal Strength if no Sim is present - android

I have used the following code to get the signal strength,
SignalStrengthListener signalStrengthListener;
signalStrengthListener = new SignalStrengthListener();
((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).listen(
signalStrengthListener,
SignalStrengthListener.LISTEN_SIGNAL_STRENGTHS);
and then it is listening for the Signal strength,
private class SignalStrengthListener extends PhoneStateListener {
#Override
public void onSignalStrengthsChanged(
android.telephony.SignalStrength signalStrength) {
// get the signal strength (a value between 0 and 31)
int strengthAmplitude = signalStrength.getGsmSignalStrength();
// do something with it (in this case we update a text view)
// signalStrengthText.setText(String.valueOf(strengthAmplitude));
if (strengthAmplitude > 30) {
signalStrengthText.setText("Good");
// signalStrengthText.setTextColor(getResources().getColor(R.color.good));
} else if (strengthAmplitude > 20 && strengthAmplitude < 30) {
signalStrengthText.setText("Average");
// signalStrengthText.setTextColor(getResources().getColor(R.color.average));
} else if (strengthAmplitude < 20) {
signalStrengthText.setText("Weak");
// signalStrengthText.setTextColor(getResources().getColor(R.color.weak));
}
super.onSignalStrengthsChanged(signalStrength);
}
}
It works good if the sim is present in the device. But when I remove the sim from the device and then check for the signal strength, it still provides some value for the signal strength.
One possible solution, I can think of is to first check, if the sim is present in the device or not and then show the signal strength. But I would like to know an explanation for this weird behaviour and a possible solution for it.

no USIM is required for cell service - only for authentication. else emergency calls would fail.
it's not weird at all... that is common sense, since you do not remove the radio nor disable it.
a simple test: remove the USIM, call emergency services, pretend you were pocket dialing.

Before you're checking the Signal Strength, you could possibly check is the device having SIM card or not (if you're concerned about WIFI network then you need to handle that separately) then check for Signal Strength. you could try something like
public boolean isSimAvailable() {
boolean isAvailable = false;
TelephonyManager telMgr = (TelephonyManager) mContext.getSystemService(Context.TELEPHONY_SERVICE);
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT: //SimState = “No Sim Found!”;
break;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED: //SimState = “Network Locked!”;
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED: //SimState = “PIN Required to access SIM!”;
break;
case TelephonyManager.SIM_STATE_PUK_REQUIRED: //SimState = “PUK Required to access SIM!”; // Personal Unblocking Code
break;
case TelephonyManager.SIM_STATE_READY:
isAvailable = true;
break;
case TelephonyManager.SIM_STATE_UNKNOWN: //SimState = “Unknown SIM State!”;
break;
}
return isAvailable;
}
///When you get the signal strength, Check like
SignalStrengthListener signalStrengthListener;
if(isSimAvailable()){
signalStrengthListener = new SignalStrengthListener();
((TelephonyManager) getSystemService(TELEPHONY_SERVICE)).listen(
signalStrengthListener,
SignalStrengthListener.LISTEN_SIGNAL_STRENGTHS);
} else {
//alert the user or do other stuff.
}

Related

On the error during telephony manager null-checking on a specific device

I trying to save their phone numbers after checking permissions and USIM state.
In onCreate() methods, Initialized global variable TelephonyManager.
mTelephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
TelephonyManager initialized, but checked Null on a specific device(Galaxy S3).
// Null value confirmed here even though initialized
if(mTelephonyManager != null) {
if (mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_ABSENT
|| mTelephonyManager.getSimState() == TelephonyManager.SIM_STATE_UNKNOWN) {
// not USIM
numFlag = false;
finish();
} else if (ActivityCompat.checkSelfPermission(this, Manifest.permission.READ_PHONE_STATE)
!= PackageManager.PERMISSION_GRANTED) {
//Permission Check
numFlag = false;
finish();
} else {
// For security reasons, test in the following ways
if (TextUtils.isEmpty(SharedUtil.getInstance().getString(this, "phoneNumber"))) {
// PhoneNumber Init...
} else {
// Data Saved...
}
}
}else{
Toast.makeText(SmartIdActivity.this, "Unable to save phone number.", Toast.LENGTH_LONG).show();
finish();
}
Am I wrong or is this a special issue?
Some devices will return null when the sim card is not installed on the devices. Some devices will raise an exception when you're trying to call the following code:
TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
So, you need to handle both of them. Something like this:
private boolean isSimCardAvailable() {
try {
TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
if (telMgr == null) return false;
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
case TelephonyManager.SIM_STATE_READY:
case TelephonyManager.SIM_STATE_NOT_READY:
return true;
case TelephonyManager.SIM_STATE_UNKNOWN:
case TelephonyManager.SIM_STATE_ABSENT:
//SIM card state: SIM Card Error, permanently disabled
case TelephonyManager.SIM_STATE_PERM_DISABLED:
// SIM card state: SIM Card Error, present but faulty
case TelephonyManager.SIM_STATE_CARD_IO_ERROR:
// SIM card state: SIM Card restricted, present but not usable due to
//carrier restrictions.
case TelephonyManager.SIM_STATE_CARD_RESTRICTED:
return false;
default:
return false;
}
} catch (Exception e) {
Log.e("TAG", "Exception e = " + e.toString());
return false;
}
}

Reliable method to check if device can send SMS with current connectivity

I have an application that send SMS automatically to a remote server. I want to check if the phone is connected to a network capable to send SMS before calling the SMSManager.send() method.
I tried the following method :
TelephonyManager tlm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
boolean hasNetwork = tlm.getNetworkType() != android.telephony.TelephonyManager.NETWORK_TYPE_UNKNOWN;
Unfortunately, this method works on some phones like Acer or Nexus but not on others like some Sony Xperia.
I then tried an other approach :check if the phone is connected to antennas (and I assume that there is network when connected to an antenna)
private static boolean isSmsNetworkAvailable(Context context) {
TelephonyManager tlm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
boolean hasNetwork = false;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.JELLY_BEAN_MR1) {
// new API
List<CellInfo> listCellInfo = tlm.getAllCellInfo();
if (listCellInfo != null && !listCellInfo.isEmpty()) {
for (CellInfo cellInfo : listCellInfo) {
if (cellInfo.isRegistered()) {
hasNetwork = true;
break;
}
}
}
} else {
// old API
List<NeighboringCellInfo> listNeighboringCellInfo = tlm.getNeighboringCellInfo();
if (listNeighboringCellInfo != null && !listNeighboringCellInfo.isEmpty()) {
hasNetwork = true;
}
}
return hasNetwork;
}
This method is also unreliable , it works on Nexus, Xperia, but not on Acer phones (for example)...
So the question is : Is there a reliable method to check if a phone is really capable to send SMS with the current connectivity?

Unexpected telephonyManager.getSimCountryIso() behaviour

I am creating an app that depending on which country your mobile network provider is from, displays a list of all alternative mobile network providers from that same country. To achieve this, I was retrieving the country code using telephonyManager.getSimCountryIso().
Official android developer docs say : "Returns the ISO country code equivalent for the SIM provider's country code", so from this I was expecting country code will always be always the same independently from device location. But thats not how it actually works!
For example I recently experienced this case:
I have an android device with SIM card from Spain belonging to a spanish network provider. So if I am in Spain telephonyManager.getSimCountryIso() returns "es". Everything working fine to that point. The problem is when I travel to France for example I debug the app and find out the telephonyManager.getSimCountryIso() is returning country code: "nl" (from Netherlands!? and I am in France in roaming but with the same spanish SIM card!). I am using the same device and the same SIM card than in Spain so country code ISO should still be "es".
My question is How does this method actually work? why am I getting country code "nl" ( Netherlands) if I am using a spanish SIM card?
Thanks in advance for any help
You can use MCC MNC to get SIM country, it is SIM configured and has nothing to do with the network you are on.
Configuration config = getResources().getConfiguration();
int countryCode = config.mcc;
You can find MCC list here MccTable.java
For example Spain is 214 and France is 208
MCC should work on all GSM devices with SIM card but it is unreliable on CDMA networks
For CDMA devices I found the following solution
if (telephonyManager.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
Class<?> c = Class.forName("android.os.SystemProperties");
Method get = c.getMethod("get", String.class);
// Gives MCC + MNC
String homeOperator = ((String) get.invoke(c, "ro.cdma.home.operator.numeric"));
String country = homeOperator.substring(0, 3); // the last three digits is MNC
} else {
Configuration config = getResources().getConfiguration();
int countryCode = config.mcc;
}
You can try to get country code from TelephonyManager (from SIM or CDMA devices), and if not available try to get it from local configuration. Here is a complete example.
private static String getDeviceCountryCode(Context context) {
String countryCode;
// try to get country code from TelephonyManager service
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE);
if(tm != null) {
// query first getSimCountryIso()
countryCode = tm.getSimCountryIso();
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
if (tm.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA) {
// special case for CDMA Devices
countryCode = getCDMACountryIso();
} else {
// for 3G devices (with SIM) query getNetworkCountryIso()
countryCode = tm.getNetworkCountryIso();
}
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
}
// if network country not available (tablets maybe), get country code from Locale class
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
countryCode = context.getResources().getConfiguration().getLocales().get(0).getCountry();
} else {
countryCode = context.getResources().getConfiguration().locale.getCountry();
}
if (countryCode != null && countryCode.length() == 2)
return countryCode.toLowerCase();
// general fallback to "us"
return "us";
}
#SuppressLint("PrivateApi")
private static String getCDMACountryIso() {
try {
// try to get country code from SystemProperties private class
Class<?> systemProperties = Class.forName("android.os.SystemProperties");
Method get = systemProperties.getMethod("get", String.class);
// get homeOperator that contain MCC + MNC
String homeOperator = ((String) get.invoke(systemProperties,
"ro.cdma.home.operator.numeric"));
// first 3 chars (MCC) from homeOperator represents the country code
int mcc = Integer.parseInt(homeOperator.substring(0, 3));
// mapping just countries that actually use CDMA networks
switch (mcc) {
case 330: return "PR";
case 310: return "US";
case 311: return "US";
case 312: return "US";
case 316: return "US";
case 283: return "AM";
case 460: return "CN";
case 455: return "MO";
case 414: return "MM";
case 619: return "SL";
case 450: return "KR";
case 634: return "SD";
case 434: return "UZ";
case 232: return "AT";
case 204: return "NL";
case 262: return "DE";
case 247: return "LV";
case 255: return "UA";
}
} catch (ClassNotFoundException ignored) {
} catch (NoSuchMethodException ignored) {
} catch (IllegalAccessException ignored) {
} catch (InvocationTargetException ignored) {
} catch (NullPointerException ignored) {
}
return null;
}
Also another idea is to try an API request like in this answer, or to use fine location.
References here and here

Mobile Network Presence detection

My Application send SMS only if Mobile Network is available.
Currently i have set ON WIFI as well MOBILE NETWORK is present.
The following code snippet when executed gives me:
public boolean isNetworkAvailable(Context context) {
final ConnectivityManager connMgr = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
// WIFI is ON and MOBILE Network is present.
final NetworkInfo mobileNetwork = connMgr
.getNetworkInfo(ConnectivityManager.TYPE_MOBILE);
final State mobileState = mobileNetwork.getState();
if(mobileNetwork!=null)
{
// RETURNS FALSE
Log.d("Contacts","mobileNetwork.isConnected() "+mobileNetwork.isConnected());
// RETURNS FALSE
Log.d("Contacts","isConnectedOrConnecting() "+mobileNetwork.isConnectedOrConnecting());
// RETURNS TRUE
Log.d("Contacts","mobileNetwork.isAvailable()() "+mobileNetwork.isAvailable());
return mobileNetwork.isAvailable();
}
return false;
}
The question is how to detect now whether i can send SMS or not based on the value returned by the above three lines?
Since isAvailable() returns true and the other 2 lines returns false;
SOLUTION
i have came up with this code:
TelephonyManager telMgr = (TelephonyManager)getSystemService(Context.TELEPHONY_SERVICE);
int simCardState = telMgr.getSimState();
int simNetworkType = telMgr.getNetworkType();
int simDataState = telMgr.getDataState();
if(simCardState == TelephonyManager.SIM_STATE_READY && simDataState == TelephonyManager.DATA_CONNECTED)
{
//NETWORK IS AVAILABLE FOR SENDING SMS
}
this code should help you to detect different states
TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
int simCardState = telMgr.getSimState();
switch (simCardState) {
case TelephonyManager.SIM_STATE_ABSENT:
// do something
break;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
// do something
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
// do something
break;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
// do something
break;
case TelephonyManager.SIM_STATE_READY:
// here you may set a flag that the phone is ready to send SMS
break;
case TelephonyManager.SIM_STATE_UNKNOWN:
// do something
break;
}

How can I check whether the Sim Card is available in an android device?

I need help checking whether a device has a sim card programatically. Please provide sample code.
Use TelephonyManager.
http://developer.android.com/reference/android/telephony/TelephonyManager.html
As Falmarri notes, you will want to use getPhoneType FIRST of all, to see if you are even dealing with a GSM phone. If you are, then you can also get the SIM state.
TelephonyManager telMgr = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE);
int simState = telMgr.getSimState();
switch (simState) {
case TelephonyManager.SIM_STATE_ABSENT:
// do something
break;
case TelephonyManager.SIM_STATE_NETWORK_LOCKED:
// do something
break;
case TelephonyManager.SIM_STATE_PIN_REQUIRED:
// do something
break;
case TelephonyManager.SIM_STATE_PUK_REQUIRED:
// do something
break;
case TelephonyManager.SIM_STATE_READY:
// do something
break;
case TelephonyManager.SIM_STATE_UNKNOWN:
// do something
break;
}
EDIT:
Starting at API 26 (Android O Preview) you can query the SimState for individual sim slots by using getSimState(int slotIndex) ie:
int simStateMain = telMgr.getSimState(0);
int simStateSecond = telMgr.getSimState(1);
official documentation
If you're developing with and older api, you can use TelephonyManager's
String getDeviceId (int slotIndex)
//returns null if device ID is not available. ie. query slotIndex 1 in a single sim device
int devIdSecond = telMgr.getDeviceId(1);
//if(devIdSecond == null)
// no second sim slot available
which was added in API 23 - docs here
You can check with the below code :
public static boolean isSimSupport(Context context)
{
TelephonyManager tm = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); //gets the current TelephonyManager
return !(tm.getSimState() == TelephonyManager.SIM_STATE_ABSENT);
}
Found another way to do this.
public static boolean isSimStateReadyorNotReady() {
int simSlotCount = sSlotCount;
String simStates = SystemProperties.get("gsm.sim.state", "");
if (simStates != null) {
String[] slotState = simStates.split(",");
int simSlot = 0;
while (simSlot < simSlotCount && slotState.length > simSlot) {
String simSlotState = slotState[simSlot];
Log.d("MultiSimUtils", "isSimStateReadyorNotReady() : simSlot = " + simSlot + ", simState = " + simSlotState);
if (simSlotState.equalsIgnoreCase("READY") || simSlotState.equalsIgnoreCase("NOT_READY")) {
return true;
}
simSlot++;
}
}
return false;
}
Thanks #Arun kumar answer, kotlin version as below
fun isSIMInserted(context: Context): Boolean {
return TelephonyManager.SIM_STATE_ABSENT != (context.getSystemService(Context.TELEPHONY_SERVICE) as TelephonyManager).simState
}

Categories

Resources