How to get neighbor cell info from getAllCellInfo? - android

this is the phone state listener i'm using to detect the changes
public PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
Log.d("SIGNAL ", " " + signalStrength.toString());
TelephonyManager tm = (TelephonyManager) mContext.getSystemService(mContext.TELEPHONY_SERVICE);
List<CellInfo> cellInfos = tm.getAllCellInfo();
for (int i=0 ;i<cellInfos.size() ;i++)
{
Log.d("test ",cellInfos.get(0).toString() );
}
}
};
The problem is currently i'm getting all cell information as below:
result - > logs CellInfoLte:{mRegistered=YES mTimeStampType=oem_ril
mTimeStamp=192908703241551ns CellIdentityLte:{ mMcc=405 mMnc=869
mCi=2971664 mPci=123 mTac=56} CellSignalStrengthLte: ss=27 rsrp=-90
rsrq=-10 rssnr=2147483647 cqi=2147483647 ta=2147483647}
How can i parse this to get CellInfoLte, CellIdentityLte and CellSignalStrengthLte from the above result

if you're still struggling with the problem, this is the method I'm using:
//permission check
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions((Activity)this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
String list = ""; //I'm just adding everything to a string to display, but you can do whatever
//get cell info
TelephonyManager tel = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
List<CellInfo> infos = tel.getAllCellInfo();
for (int i = 0; i<infos.size(); ++i)
{
try {
CellInfo info = infos.get(i);
if (info instanceof CellInfoGsm) //if GSM connection
{
list += "Site_"+i + "\r\n";
list += "Registered: " + info.isRegistered() + "\r\n";
CellSignalStrengthGsm gsm = ((CellInfoGsm) info).getCellSignalStrength();
CellIdentityGsm identityGsm = ((CellInfoGsm) info).getCellIdentity();
list += "cellID: "+ identityGsm.getCid() + "\r\n";
list += "dBm: " + gsm.getDbm() + "\r\n\r\n";
//call whatever you want from gsm / identitydGsm
}
else if (info instanceof CellInfoLte) //if LTE connection
{
list += "Site_"+i + "\r\n";
list += "Registered: " + info.isRegistered() + "\r\n";
CellSignalStrengthLte lte = ((CellInfoLte) info).getCellSignalStrength();
CellIdentityLte identityLte = ((CellInfoLte) info).getCellIdentity();
//call whatever you want from lte / identityLte
}
else if (info instanceof CellInfoWcdma) //if wcdma connection
{
CellSignalStrengthWcdma wcdmaS = ((CellInfoWcdma) info).getCellSignalStrength();
CellIdentityWcdma wcdmaid = ((CellInfoWcdma)info).getCellIdentity();
list += "Site_"+i + "\r\n";
list += "Registered: " + info.isRegistered() + "\r\n";
//call whatever you want from wcdmaS / wcdmaid
}
} catch (Exception ex) {
Log.i("neighboring error 2: " ,ex.getMessage());
}
}
Log.i("Info display", list); //display everything.
And while we're busy, just a heads up, the LTE parsing is all screwy (you will see if you do getCi(), getTac() etc. ), so I wrote my own parsing class, and posted my answer here.
Hede of warning though, when you start to see that your neighboring cell info is totally wrong... (the problem that I'm currently at), this dilemma is also posted here. Good luck, and let me know if this part is not a issue for you

Try this (according to cocorico):
String ssignal = signalStrength.toString();
String[] parts = ssignal.split(" ");
Where signalStrength.toString() comes from signalStrength.
The parts[] array will then contain these elements:
part[0] = "Signalstrength:" _ignore this, it's just the title_
parts[1] = GsmSignalStrength
parts[2] = GsmBitErrorRate
parts[3] = CdmaDbm
parts[4] = CdmaEcio
parts[5] = EvdoDbm
parts[6] = EvdoEcio
parts[7] = EvdoSnr
parts[8] = LteSignalStrength
parts[9] = LteRsrp
parts[10] = LteRsrq
parts[11] = LteRssnr
parts[12] = LteCqi
parts[13] = gsm|lte|cdma
parts[14] = _not really sure what this number is_
So, LTEdBm is :
TelephonyManager tm = (TelephonyManager)context.getSystemService(Context.TELEPHONY_SERVICE);
int dbm = 0;
if ( tm.getNetworkType() == TelephonyManager.NETWORK_TYPE_LTE){
// For Lte SignalStrength: dbm = ASU - 140.
dbm = Integer.parseInt(parts[8])-140;
} else {
// For GSM Signal Strength: dbm = (2*ASU)-113.
if (signalStrength.getGsmSignalStrength() != 99) {
int intdbm = -113 + 2
* signalStrength.getGsmSignalStrength();
dbm = Integer.toString(intdbm);
}
}

Related

TelephonyManager.getAllCellInfo() return Null or displays Nothing

I'm facing an issue with getAllCellInfo().
App has permissions needed :
here is my code :
1- listener
private PhoneStateListener mPhoneStateListener = new PhoneStateListener() {
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onSignalStrengthsChanged(SignalStrength signalStrength) {
super.onSignalStrengthsChanged(signalStrength);
2- Info from SignalStrength
TextView comparisonText = (TextView) findViewById(R.id.textViewComparison);
Object ssFieldValueRsrp = null;
Object ssFieldValueRsrq = null;
Object ssFieldValueRssnr = null;
Object ssFieldValueCqi=null;
try {
Field privateStringSsFieldRSRQ = SignalStrength.class.getDeclaredField("mLteRsrq");
Field privateStringSsFieldRSRP = SignalStrength.class.getDeclaredField("mLteRsrp");
Field privateStringSsFieldRssnr = SignalStrength.class.getDeclaredField("mLteRssnr");
Field privateStringSsFieldCqi = SignalStrength.class.getDeclaredField("mLteCqi");
privateStringSsFieldRSRQ.setAccessible(true);
ssFieldValueRsrq = privateStringSsFieldRSRQ.get(signalStrength);
privateStringSsFieldRSRP.setAccessible(true);
ssFieldValueRsrp = privateStringSsFieldRSRP.get(signalStrength);
privateStringSsFieldRssnr.setAccessible(true);
ssFieldValueRssnr = privateStringSsFieldRssnr.get(signalStrength);
privateStringSsFieldCqi.setAccessible(true);
ssFieldValueCqi = privateStringSsFieldCqi.get(signalStrength);
} catch (NoSuchFieldException ex) {
} catch (IllegalAccessException x) {
}
String ssRsrp = Integer.toString((int) ssFieldValueRsrp);
String ssRsrq = Integer.toString((int) ssFieldValueRsrq);
String ssRssnr = Integer.toString((int) ssFieldValueRssnr);
String ssCqi = Integer.toString((int) ssFieldValueCqi);
String headerString = "Info from \"SignalStrength\":";
SpannableString spannableHeaderString = new SpannableString(headerString);
spannableHeaderString.setSpan(new UnderlineSpan(), 0, spannableHeaderString.length(), 0);
comparisonText.setText(spannableHeaderString);
comparisonText.append
(
"\nRSRP: " + ssRsrp
+ "\nRSRQ: " + ssRsrq
+"\nCQI: "+ ssCqi
+"\nRSSNR: "+ ssRssnr
);
3- Info from CellSignalStrengthLte
Location loc = lm.getLastKnownLocation(LocationManager.GPS_PROVIDER);
List<android.telephony.CellInfo> infor = tm.getAllCellInfo();
for (android.telephony.CellInfo info : infor)
{
if (info instanceof CellInfoLte)
{
CellSignalStrengthLte ss = ((CellInfoLte) info).getCellSignalStrength();
//theButton.setText( ss.toString());
Object fieldValueRSRP = null;
Object fieldValueRSRQ = null;
Object fieldValueRssnr = null;
Object fieldValueCqi=null;
try
{
Field privateStringFieldRSRQ = CellSignalStrengthLte.class.getDeclaredField("mRsrq");
Field privateStringFieldRSRP = CellSignalStrengthLte.class.getDeclaredField("mRsrp");
Field privateStringFieldCqi = CellSignalStrengthLte.class.getDeclaredField("mCqi");
Field privateStringFieldRSSNR = CellSignalStrengthLte.class.getDeclaredField("mRssnr");
privateStringFieldRSRQ.setAccessible(true);
fieldValueRSRQ = privateStringFieldRSRQ.get(ss);
privateStringFieldRSRP.setAccessible(true);
fieldValueRSRP = privateStringFieldRSRP.get(ss);
privateStringFieldRSSNR.setAccessible(true);
fieldValueRssnr = privateStringFieldRSSNR.get(ss);
privateStringFieldCqi.setAccessible(true);
fieldValueCqi = privateStringFieldCqi.get(ss);
}
catch (NoSuchFieldException ex) {}
catch (IllegalAccessException x) {}
String rsrp = Integer.toString((int) fieldValueRSRP);
String rsrq = Integer.toString((int) fieldValueRSRQ);
String rssnr = Integer.toString((int) fieldValueRssnr);
String cqi = Integer.toString((int) fieldValueCqi);
headerString = "Info from \"CellSignalStrengthLte\":";
spannableHeaderString = new SpannableString(headerString);
spannableHeaderString.setSpan( new UnderlineSpan(), 0, spannableHeaderString.length(), 0);
theText.setText
(
"\nAltitude: " + loc.getAltitude() + "\n\n"+loc.getLongitude()+"\n\n"+loc.getLatitude()+"\n\n"
);
theText.append(spannableHeaderString);
theText.append
(
"\nRSRP: " + rsrp
+ "\nRSRQ: " + rsrq
+ "\nCQI: " + cqi
+ "\nRSSNR: " + rssnr
);
}
}
Huawei Y6II : marshmallow (android 6) :
App run smoothly but function skipped
Huawei Nova3i (android 9)
app crashes with null pointer on List<android.telephony.CellInfo> infor = tm.getAllCellInfo();
Samsun S10 (android 9)
app running perfectly
Resolved :
This issue is related to some dual SIM phones

Parse getAllcellinfo values from telephony manager

i'm using the following function to get Allcellinfo of an device network and im getting the values as an string now i need to parse it in order to get the CellSignalStrengthLte data how can i achieve it
//code
TelephonyManager tm = (TelephonyManager) Context.getSystemService(mContext.TELEPHONY_SERVICE);
List<CellInfo> cellInfos = tm.getAllCellInfo();
String data = cellInfos.get(0).toString();
Log.d("Info ", " "+data);
Result is
CellInfoLte:{mRegistered=YES mTimeStampType=oem_ril mTimeStamp=207387894126206ns CellIdentityLte:{ mMcc=405 mMnc=869 mCi=2971664 mPci=123 mTac=56} CellSignalStrengthLte: ss=25 rsrp=-91 rsrq=-7 rssnr=2147483647 cqi=2147483647 ta=2147483647}
How can parse this string to get details regaridng CellinfoLte,CellIdentityLte
I also noticed that CellinfoLTE and CellIdentityLTE is not so great at the moment, so I just wrote my own parsing class. Only tested this a few times, and didn't have problems, but more testing should display if additional future tweaking will be necessary.
Here's the class:
public class LTEStruct
{
public static final int UNKNOWN = Integer.MAX_VALUE; //Default value for unknown fields
public boolean isRegistered;
public long timeStamp;
public int MCC;
public int MNC;
public int CID;
public int PCI;
public int TAC;
public int SS;
public int RSRP;
public int RSRQ;
public int RSSNR;
public int CQI;
public int tAdvance;
Context mContext;
//Public constructor
public LTEStruct(Context context)
{
mContext = context; //not used at the moment but possibly for future function
}
public void parse(String inTest)
{
//get isRegistered
int index = inTest.indexOf("mRegistered=") + ("mRegistered=").length();
if(inTest.substring(index,index + 3).contains("YES"))
isRegistered = true;
else
isRegistered = false;
//getTimestamp
timeStamp = getValue(inTest,"mTimeStamp=", "ns");
//get Cell Identity paramters
MCC = (int) getValue(inTest,"mMcc=", " "); //get Mcc
MNC = (int) getValue(inTest,"mMnc=", " "); //get MNC
CID = (int) getValue(inTest,"mCi=", " "); //get CID
PCI = (int) getValue(inTest,"mPci="," "); //get PCI
TAC = (int) getValue(inTest,"mTac=","}"); //get TAC
//get RF related parameters
SS = (int) getValue(inTest," ss="," "); //get SS
RSRP = (int)getValue(inTest,"rsrp=", " "); //get RSRP
RSRQ = (int)getValue(inTest,"rsrq=", " "); //get RSRQ
RSSNR = (int)getValue(inTest,"rssnr=", " "); //get RSSNR
CQI = (int)getValue(inTest," cqi=", " "); //get CQI
tAdvance = (int)getValue(inTest," ta=", "}"); //get timing advance
}
//internal function to help with parsing of raw LTE strings
private long getValue(String fullS, String startS, String stopS)
{
int index = fullS.indexOf(startS) + (startS).length();
int endIndex = fullS.indexOf(stopS,index);
return Long.parseLong(fullS.substring(index,endIndex).trim());
}
}
So if I implement this very basically with the input LTE string:
//permission check
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED)
ActivityCompat.requestPermissions((Activity)this,new String[]{Manifest.permission.ACCESS_COARSE_LOCATION},1);
//get cell info
TelephonyManager tel = (TelephonyManager) this.getSystemService(Context.TELEPHONY_SERVICE);
List<CellInfo> infos = tel.getAllCellInfo();
for (int i = 0; i<infos.size(); ++i)
{
try
{
CellInfo info = infos.get(i);
if (info instanceof CellInfoLte) {
LTEStruct lte = new LTEStruct(this);
lte.parse(info.toString());
//write out parsed results for what it's worth
Log.i("LTE parseOutput", "tAdvance: " + lte.tAdvance + "\r\nCQI: " + lte.CQI + "\r\nRSSNR: " + lte.RSSNR + "\r\nRSRP: " + lte.RSRP + "\r\nSS: " + lte.SS +
"\r\nCID: " + lte.CID + "\r\nTimestamp: " + lte.timeStamp + "\r\nTAC: " + lte.TAC + "\r\nPCI: " + lte.PCI + "\r\nMNC: " + lte.MNC + "\r\nMCC: " + lte.MCC + "\r\nRegistered: " + lte.isRegistered);
} else
Log.i("LTE testing", "not LTE cell info measured");
} catch (Exception ex) {
Log.i("neighboring error: ", ex.getMessage());
}
}
Hope it helps ;)

Android get Device Country Code

I want to get device country code with out using sim card.
e.g If Country : Sri lanka
Country code : LK
my final goal is get calling code (+94 for sri lanka)
i tried with this
TelephonyManager tm = (TelephonyManager)this.getSystemService(getApplicationContext().TELEPHONY_SERVICE);
String countryCodeValue = tm.getNetworkCountryIso();
but this return empty string
It's returning an empty string because the device doesn't have a sim card.
You might be able to use the device's current locale:
Locale current = getResources().getConfiguration().locale;
but that's not necessarily going to be the same as what you'd get by looking at the carrier iso and the user can update that in the settings whenever they want to whatever they want. As pointed out, you can also ask the location manager for the user's coordinates. But remember, users move around and their current location may not always correspond to their carrier's iso.
Here is a complete example. Try to get country code from TelephonyManager (from SIM or CDMA devices), and if not available try to get it from local configuration.
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.
And in order to get country prefix you can use LibPhoneNumber library from Google.
References here and here
You can use this http://maps.googleapis.com/maps/api/geocode/json?latlng=7.0000,81.0000&sensor=false for getting country code ..The short name will give you country code ..
public void getAddress(double lat,double lng) {
Address1 = "";
Address2 = "";
City = "";
State = "";
Country = "";
County = "";
PIN = "";
try {
JSONObject jsonObj = JsonParser.getJSONfromURL("http://maps.googleapis.com/maps/api/geocode/json?latlng=" + lat + ","
+lng + "&sensor=false");
String Status = jsonObj.getString("status");
if (Status.equalsIgnoreCase("OK")) {
JSONArray Results = jsonObj.getJSONArray("results");
JSONObject zero = Results.getJSONObject(0);
JSONArray address_components = zero.getJSONArray("address_components");
for (int i = 0; i < address_components.length(); i++) {
JSONObject zero2 = address_components.getJSONObject(i);
String long_name = zero2.getString("long_name");
String short_name = zero2.getString("short_name");
JSONArray mtypes = zero2.getJSONArray("types");
String Type = mtypes.getString(0);
if (TextUtils.isEmpty(long_name) == false || !long_name.equals(null) || long_name.length() > 0 || long_name != "") {
if (Type.equalsIgnoreCase("street_number")) {
Address1 = long_name + " ";
} else if (Type.equalsIgnoreCase("route")) {
Address1 = Address1 + long_name;
} else if (Type.equalsIgnoreCase("sublocality")) {
Address2 = long_name;
} else if (Type.equalsIgnoreCase("locality")) {
// Address2 = Address2 + long_name + ", ";
City = long_name;
} else if (Type.equalsIgnoreCase("administrative_area_level_2")) {
County = long_name;
} else if (Type.equalsIgnoreCase("administrative_area_level_1")) {
State = long_name;
} else if (Type.equalsIgnoreCase("country")) {
Country = short_name;
} else if (Type.equalsIgnoreCase("postal_code")) {
PIN = long_name;
}
}
// JSONArray mtypes = zero2.getJSONArray("types");
// String Type = mtypes.getString(0);
// Log.e(Type,long_name);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
But you need to get the current lat and long ..
Use this link for getting the current lat and lng
http://gabesechansoftware.com/location-tracking/
In my case telephonyManager.getNetworkCountryIso() is returning empty as i have two sim slots, you can pass slot as parameter if it returns "". Simply change your code to:
String iso=telephonyManager.getNetworkCountryIso();
if(TextUtils.isEmpty(iso))
iso=telephonyManager.getNetworkCountryIso(1);
if(TextUtils.isEmpty(iso))
iso=telephonyManager.getNetworkCountryIso(2);
// this code will give preference to Sim Slot 1
get iso country code => US
lookup this table => 1
https://countrycode.org/

Gsm network info in android

Does someone know how to get gsm information in android? Information like BCCH (Broadcast Control Channel) and BCIS (Base Station Identity Code). I already got the LAC (Location Area Code) and CID (Cell ID). I know that is a low level information but does someone know to get those information? I am having a hard time researching and i don't have an idea about cellular network. Please Help thanks :)
Here is function which gives you complete information of gsm network.
just Call with context from your activity
private void getNWInfo(Context context) {
/**
* <uses-permission android:name="android.permission.READ_PHONE_STATE"
* /> <uses-permission
* android:name="android.permission.ACCESS_NETWORK_STATE"/>
*/
TelephonyManager telephonyManager = (TelephonyManager) context
.getSystemService(Context.TELEPHONY_SERVICE);
String networkOperator = telephonyManager.getNetworkOperator();
int mcc = 0, mnc = 0;
if (networkOperator != null) {
mcc = Integer.parseInt(networkOperator.substring(0, 3));
mnc = Integer.parseInt(networkOperator.substring(3));
}
String SimNumber = telephonyManager.getLine1Number();
String SimSerialNumber = telephonyManager.getSimSerialNumber();
String countryISO = telephonyManager.getSimCountryIso();
String operatorName = telephonyManager.getSimOperatorName();
String operator = telephonyManager.getSimOperator();
int simState = telephonyManager.getSimState();
String voicemailNumer = telephonyManager.getVoiceMailNumber();
String voicemailAlphaTag = telephonyManager.getVoiceMailAlphaTag();
// Getting connected network iso country code
String networkCountry = telephonyManager.getNetworkCountryIso();
// Getting the connected network operator ID
String networkOperatorId = telephonyManager.getNetworkOperator();
// Getting the connected network operator name
String networkName = telephonyManager.getNetworkOperatorName();
int networkType = telephonyManager.getNetworkType();
String network = "";
ConnectivityManager cm = (ConnectivityManager) context
.getSystemService(Context.CONNECTIVITY_SERVICE);
try {
if (cm.getActiveNetworkInfo().getTypeName().equals("MOBILE"))
network = "Cell Network/3G";
else if (cm.getActiveNetworkInfo().getTypeName().equals("WIFI"))
network = "WiFi";
else
network = "N/A";
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
TextView textView = (TextView) findViewById(R.id.textView);
textView.setText("network :" + network +
"\n" + "countryISO : " + countryISO + "\n" + "operatorName : "
+ operatorName + "\n" + "operator : " + operator + "\n"
+ "simState :" + simState + "\n" + "Sim Serial Number : "
+ SimSerialNumber + "\n" + "Sim Number : " + SimNumber + "\n"
+ "Voice Mail Numer" + voicemailNumer + "\n"
+ "Voice Mail Alpha Tag" + voicemailAlphaTag + "\n"
+ "Sim State" + simState + "\n" + "Mobile Country Code MCC : "
+ mcc + "\n" + "Mobile Network Code MNC : " + mnc + "\n"
+ "Network Country : " + networkCountry + "\n"
+ "Network OperatorId : " + networkOperatorId + "\n"
+ "Network Name : " + networkName + "\n" + "Network Type : "
+ networkType);
}
you can find more details on this blog
http://khurramitdeveloper.blogspot.in/search?updated-max=2013-11-07T03:23:00-08:00&max-results=7
hope it will help you :)
Please visit here. It explains that no APIs are available to get the Radio Information.
You can try this:
public static JSONArray getCellInfo(Context ctx){
TelephonyManager tel = (TelephonyManager) ctx.getSystemService(Context.TELEPHONY_SERVICE);
JSONArray cellList = new JSONArray();
int phoneTypeInt = tel.getPhoneType();
String phoneType = "unknown";
if (phoneTypeInt == TelephonyManager.PHONE_TYPE_GSM)
phoneType = "gsm";
else if (phoneTypeInt == TelephonyManager.PHONE_TYPE_CDMA)
phoneType = "cdma";
//from Android M up must use getAllCellInfo
if (Build.VERSION.SDK_INT < Build.VERSION_CODES.JELLY_BEAN_MR1) {
List<NeighboringCellInfo> neighCells = tel.getNeighboringCellInfo();
for (int i = 0; i < neighCells.size(); i++) {
try {
JSONObject cellObj = new JSONObject();
NeighboringCellInfo thisCell = neighCells.get(i);
cellObj.put("cellId", thisCell.getCid());
cellObj.put("lac", thisCell.getLac());
cellObj.put("rssi", thisCell.getRssi());
cellList.put(cellObj);
} catch (Exception e) {
}
}
} else {
List<CellInfo> infos = tel.getAllCellInfo();
for (int i = 0; i < infos.size(); ++i) {
try {
JSONObject cellObj = new JSONObject();
CellInfo info = infos.get(i);
if (info instanceof CellInfoGsm) {
CellSignalStrengthGsm gsm = ((CellInfoGsm) info).getCellSignalStrength();
CellIdentityGsm identityGsm = ((CellInfoGsm) info).getCellIdentity();
cellObj.put("cellId", identityGsm.getCid());
cellObj.put("lac", identityGsm.getLac());
cellObj.put("dbm", gsm.getDbm());
cellList.put(cellObj);
} else if (info instanceof CellInfoLte) {
CellSignalStrengthLte lte = ((CellInfoLte) info).getCellSignalStrength();
CellIdentityLte identityLte = ((CellInfoLte) info).getCellIdentity();
cellObj.put("cellId", identityLte.getCi());
cellObj.put("tac", identityLte.getTac());
cellObj.put("dbm", lte.getDbm());
cellList.put(cellObj);
}
} catch (Exception ex) {
}
}
}
return cellList;
}

Android USB host read from device

I'm trying to get some data out of a USB device connected to my Android phone that is on host mode. I'm able to send data to it, but reading fails.
I've looked at several examples and tried all I could but I don't have any experience in USB communication, although by now I know a little, and I've been stuck on this longer that I care to admit.
I'm not very familiar with the endpoint configuration, but I know is that my device uses a CDC type communication method and both the output (from phone to device) and input are registered.
Here's the whole class that manages the USB connection with the only device that is connected to the phone, it's not finished by any means, but I'd like to get that reading part to work before I go any further.
public class UsbCommunicationManager
{
static final String ACTION_USB_PERMISSION = "com.android.example.USB_PERMISSION";
UsbManager usbManager;
UsbDevice usbDevice;
UsbInterface intf = null;
UsbEndpoint input, output;
UsbDeviceConnection connection;
PendingIntent permissionIntent;
Context context;
byte[] readBytes = new byte[64];
public UsbCommunicationManager(Context context)
{
this.context = context;
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
// ask permission from user to use the usb device
permissionIntent = PendingIntent.getBroadcast(context, 0, new Intent(ACTION_USB_PERMISSION), 0);
IntentFilter filter = new IntentFilter(ACTION_USB_PERMISSION);
context.registerReceiver(usbReceiver, filter);
}
public void connect()
{
// check if there's a connected usb device
if(usbManager.getDeviceList().isEmpty())
{
Log.d("trebla", "No connected devices");
return;
}
// get the first (only) connected device
usbDevice = usbManager.getDeviceList().values().iterator().next();
// user must approve of connection
usbManager.requestPermission(usbDevice, permissionIntent);
}
public void stop()
{
context.unregisterReceiver(usbReceiver);
}
public String send(String data)
{
if(usbDevice == null)
{
return "no usb device selected";
}
int sentBytes = 0;
if(!data.equals(""))
{
synchronized(this)
{
// send data to usb device
byte[] bytes = data.getBytes();
sentBytes = connection.bulkTransfer(output, bytes, bytes.length, 1000);
}
}
return Integer.toString(sentBytes);
}
public String read()
{
// reinitialize read value byte array
Arrays.fill(readBytes, (byte) 0);
// wait for some data from the mcu
int recvBytes = connection.bulkTransfer(input, readBytes, readBytes.length, 3000);
if(recvBytes > 0)
{
Log.d("trebla", "Got some data: " + new String(readBytes));
}
else
{
Log.d("trebla", "Did not get any data: " + recvBytes);
}
return Integer.toString(recvBytes);
}
public String listUsbDevices()
{
HashMap<String, UsbDevice> deviceList = usbManager.getDeviceList();
if(deviceList.size() == 0)
{
return "no usb devices found";
}
Iterator<UsbDevice> deviceIterator = deviceList.values().iterator();
String returnValue = "";
UsbInterface usbInterface;
while(deviceIterator.hasNext())
{
UsbDevice device = deviceIterator.next();
returnValue += "Name: " + device.getDeviceName();
returnValue += "\nID: " + device.getDeviceId();
returnValue += "\nProtocol: " + device.getDeviceProtocol();
returnValue += "\nClass: " + device.getDeviceClass();
returnValue += "\nSubclass: " + device.getDeviceSubclass();
returnValue += "\nProduct ID: " + device.getProductId();
returnValue += "\nVendor ID: " + device.getVendorId();
returnValue += "\nInterface count: " + device.getInterfaceCount();
for(int i = 0; i < device.getInterfaceCount(); i++)
{
usbInterface = device.getInterface(i);
returnValue += "\n Interface " + i;
returnValue += "\n\tInterface ID: " + usbInterface.getId();
returnValue += "\n\tClass: " + usbInterface.getInterfaceClass();
returnValue += "\n\tProtocol: " + usbInterface.getInterfaceProtocol();
returnValue += "\n\tSubclass: " + usbInterface.getInterfaceSubclass();
returnValue += "\n\tEndpoint count: " + usbInterface.getEndpointCount();
for(int j = 0; j < usbInterface.getEndpointCount(); j++)
{
returnValue += "\n\t Endpoint " + j;
returnValue += "\n\t\tAddress: " + usbInterface.getEndpoint(j).getAddress();
returnValue += "\n\t\tAttributes: " + usbInterface.getEndpoint(j).getAttributes();
returnValue += "\n\t\tDirection: " + usbInterface.getEndpoint(j).getDirection();
returnValue += "\n\t\tNumber: " + usbInterface.getEndpoint(j).getEndpointNumber();
returnValue += "\n\t\tInterval: " + usbInterface.getEndpoint(j).getInterval();
returnValue += "\n\t\tType: " + usbInterface.getEndpoint(j).getType();
returnValue += "\n\t\tMax packet size: " + usbInterface.getEndpoint(j).getMaxPacketSize();
}
}
}
return returnValue;
}
private void setupConnection()
{
// find the right interface
for(int i = 0; i < usbDevice.getInterfaceCount(); i++)
{
// communications device class (CDC) type device
if(usbDevice.getInterface(i).getInterfaceClass() == UsbConstants.USB_CLASS_CDC_DATA)
{
intf = usbDevice.getInterface(i);
// find the endpoints
for(int j = 0; j < intf.getEndpointCount(); j++)
{
if(intf.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_OUT && intf.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
{
// from android to device
output = intf.getEndpoint(j);
}
if(intf.getEndpoint(j).getDirection() == UsbConstants.USB_DIR_IN && intf.getEndpoint(j).getType() == UsbConstants.USB_ENDPOINT_XFER_BULK)
{
// from device to android
input = intf.getEndpoint(j);
}
}
}
}
}
private final BroadcastReceiver usbReceiver = new BroadcastReceiver()
{
public void onReceive(Context context, Intent intent)
{
String action = intent.getAction();
if(ACTION_USB_PERMISSION.equals(action))
{
// broadcast is like an interrupt and works asynchronously with the class, it must be synced just in case
synchronized(this)
{
if(intent.getBooleanExtra(UsbManager.EXTRA_PERMISSION_GRANTED, false))
{
setupConnection();
connection = usbManager.openDevice(usbDevice);
connection.claimInterface(intf, true);
// set flow control to 8N1 at 9600 baud
int baudRate = 9600;
byte stopBitsByte = 1;
byte parityBitesByte = 0;
byte dataBits = 8;
byte[] msg = {
(byte) (baudRate & 0xff),
(byte) ((baudRate >> 8) & 0xff),
(byte) ((baudRate >> 16) & 0xff),
(byte) ((baudRate >> 24) & 0xff),
stopBitsByte,
parityBitesByte,
(byte) dataBits
};
connection.controlTransfer(UsbConstants.USB_TYPE_CLASS | 0x01, 0x20, 0, 0, msg, msg.length, 5000);
}
else
{
Log.d("trebla", "Permission denied for USB device");
}
}
}
else if(UsbManager.ACTION_USB_DEVICE_DETACHED.equals(action))
{
Log.d("trebla", "USB device detached");
}
}
};
}
I keep getting -1 from the read() method which indicates some kind of error, it always times out. Maybe the problem comes from the connection configuration, I've tried several (read: trial and error) and none worked, surprisingly I don't need any configuration to send data to the device.
Edit
It must also be noted that the cable I'm using is micro-USB to micro-USB and it only works in one way, that is my device is powered by my phone only when the plug A connected to phone and plug B connected to device, not the other way around... it seems very strange. The fact that I'm able to send data and not receive when plugged the right way remains.
EDIT 2
I found that somebody else had the same problem but it seems he wasn't able to solve it.
EDIT 3
I finally found the solution on this page:
Another major oversight is that there is no mechanism for the host to notify the device that there is a data sink on the host side ready to accept data. This means that the device may try to send data while the host isn't listening, causing lengthy blocking timeouts in the transmission routines. It is thus highly recommended that the virtual serial line DTR (Data Terminal Ready) signal be used where possible to determine if a host application is ready for data.
So the DTR signal was mandatory and all I had to do was to add this to the interface configuration:
connection.controlTransfer(0x21, 0x22, 0x1, 0, null, 0, 0);
EDIT 4
If anybody is interested I finished the project and it's open source and published on my GitHub account. It's not stable all the time though (see the notes) and I don't plan working on it anymore, but it works. Feel free to use it for your own projects.
You can use UsbSerial Lib of from https://github.com/mik3y/usb-serial-for-android
My example code:
UsbManager usbManager = null;
UsbDeviceConnection connection = null;
UsbSerialDriver driver = null;
UsbSerialPort port = null;
usbManager = (UsbManager) context.getSystemService(Context.USB_SERVICE);
List<UsbSerialDriver> availableDrivers = UsbSerialProber.getDefaultProber().findAllDrivers(manager);
// Open a connection to the first available driver.
for (UsbSerialDriver usd : availableDrivers) {
UsbDevice udv = usd.getDevice();
if (udv.getVendorId()==0x067B || udv.getProductId()==2303){
driver = usd;
break;
}
}
connection = usbManager.openDevice(driver.getDevice());
port = driver.getPorts().get(0);
driver.getDevice().
}
if (connection == null) return;
try{
port.open(connection);
port.setParameters(4800, UsbSerialPort.DATABITS_8, UsbSerialPort.STOPBITS_1, UsbSerialPort.PARITY_NONE);
try{
byte buffer[] = new byte[250];
//Log.d("GPS_REQ", "->");
int numBytesRead = port.read(buffer, 500); //5000;
}catch (Exception e) {
Log.d("GPS_ERR", e.getLocalizedMessage());
}

Categories

Resources