package com.samknows.measurement.environment;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.json.JSONObject;
import android.annotation.SuppressLint;
import android.os.Build;
import android.telephony.CellInfo;
import android.telephony.CellInfoCdma;
import android.telephony.CellInfoGsm;
import android.telephony.CellInfoLte;
import android.telephony.CellInfoWcdma;
import android.telephony.CellLocation;
import android.telephony.NeighboringCellInfo;
import android.telephony.SignalStrength;
import android.telephony.cdma.CdmaCellLocation;
import android.telephony.gsm.GsmCellLocation;
import com.samknows.libcore.SKPorting;
import com.samknows.measurement.storage.PassiveMetric;
import com.samknows.measurement.util.DCSConvertorUtil;
import com.samknows.measurement.util.DCSStringBuilder;
import com.samknows.measurement.util.SKDateFormat;
import com.samknows.measurement.util.SKGsmSignalStrength;
public class CellTowersData implements DCSData{
private static final String ID = "CELLTOWER";
private static final String ID_NEIGHBOR = "CELLTOWERNEIGHBOR";
private static final String GSM = "GSM";
private static final String CDMA = "CDMA";
private static final String VERSION = ".2";
//JSONOutput for the neighbour cell tower
public static final String JSON_TYPE_CELL_ALL_CELL_INFO= "cell_info";
public static final String JSON_TYPE_CELL_TOWER_NEIGHBOUR= "cell_neighbour_tower_data";
public static final String JSON_CELL_TOWER_ID= "cell_tower_id";
public static final String JSON_LOCATION_AREA_CODE = "location_area_code";
public static final String JSON_UMTS_PSC = "umts_psc";
public static final String JSON_RSSI = "rssi";
public static final String JSON_NETWORK_TYPE = "network_type";
public static final String JSON_NETWORK_TYPE_CODE = "network_type_code";
public static final String JSON_TYPE_GSM_CELL_LOCATION = "gsm_cell_location";
public static final String JSON_TYPE_CDMA_CELL_LOCATION = "cdma_cell_location";
public static final String JSON_BASE_STATION_ID = "base_station_id";
public static final String JSON_BASE_STATION_LATITUDE = "base_station_latitude";
public static final String JSON_BASE_STATION_LONGITUDE = "base_station_longitude";
public static final String JSON_NETWORK_ID = "netwok_id";
public static final String JSON_SYSTEM_ID = "system_id";
public static final String JSON_SIGNAL_STRENGTH = "signal_strength";
public static final String JSON_BIT_ERROR_RATE = "bit_error_rate";
public static final String JSON_DBM = "dbm";
public static final String JSON_ECIO = "ecio";
private CellLocation cellLocation = null;
private List<CellInfo> mCellInfo = null;
private SignalStrength signal = null;
// time in millseconds
private long time = 0L;
public CellLocation getCellLocation() {
return cellLocation;
}
public SignalStrength getSignal() {
return signal;
}
// time in millseconds
public long getTime() {
return time;
}
public void setCellLocation(CellLocation value) {
// We might be passed null, if the location is not available currently.
// This is perfectly valid!
// SKLogger.sAssert(getClass(), value != null);
cellLocation = value;
}
public void setCellInfo(List<CellInfo> cellInfo) {
mCellInfo = cellInfo;
}
public void setSignal(SignalStrength value) {
// We might be passed null, if the signal is not available currently.
// This is perfectly valid!
// SKLogger.sAssert(getClass(), value != null);
signal = value;
}
// time in millseconds
public void setTime(long value) {
time = value;
}
// Note that this value is NEVER allowed to be set null.
private List<NeighboringCellInfo> neighbors = new ArrayList<>(); // TODO - remove me, for testing only!
public void setNeighbors(List<NeighboringCellInfo> inNeighbors) {
// We NEVER allow the neighbors member to be set null.
// Otherwise, tests might be mis-reported as failing.
// If we're supplied a null value, set to use an empty list.
if (inNeighbors == null) {
// ... we should trap this where possible in the debugger...
SKPorting.sAssert(getClass(), false);
neighbors = new ArrayList<>();
} else {
neighbors = inNeighbors;
}
}
public List<NeighboringCellInfo> getNeighbors() {
return neighbors;
}
public int network_type;
@Override
public List<String> convert() {
List<String> list = new ArrayList<>();
addCellData(list);
SKPorting.sAssert(getClass(), (neighbors != null));
if (neighbors != null) {
for (NeighboringCellInfo cellInfo : neighbors) {
addCellData(list, cellInfo);
}
}
return list;
}
private void addCellData(List<String> list, NeighboringCellInfo cellInfo) {
DCSStringBuilder builder = new DCSStringBuilder();
builder.append(ID_NEIGHBOR);
builder.append(time/1000);
builder.append(cellInfo.getCid());
builder.append(cellInfo.getLac());
builder.append(cellInfo.getPsc() );
builder.append(cellInfo.getRssi());
builder.append(DCSConvertorUtil.convertNetworkType(cellInfo.getNetworkType()));
list.add(builder.build());
}
@SuppressLint("NewApi")
private void addCellData(List<String> list) {
DCSStringBuilder builder = new DCSStringBuilder();
if (cellLocation == null) {
// No location information currently available!
} else if (cellLocation instanceof GsmCellLocation) {
GsmCellLocation gsmLocation = (GsmCellLocation) cellLocation;
builder.append(ID + GSM + VERSION);
builder.append(time/1000);
builder.append(GSM);
builder.append(gsmLocation.getCid());
builder.append(gsmLocation.getLac());
builder.append(Build.VERSION.SDK_INT >= 9 ? gsmLocation.getPsc() : -1 );
} else if (cellLocation instanceof CdmaCellLocation) {
CdmaCellLocation cdmaLocation = (CdmaCellLocation) cellLocation;
builder.append(ID + CDMA);
builder.append(time/1000);
builder.append(CDMA);
builder.append(cdmaLocation.getBaseStationId());
builder.append(cdmaLocation.getBaseStationLatitude());
builder.append(cdmaLocation.getBaseStationLongitude());
builder.append(cdmaLocation.getNetworkId());
builder.append(cdmaLocation.getSystemId());
}
if (signal == null) {
// No signal information currently available!
} else if (signal.isGsm()) {
builder.append(SKGsmSignalStrength.getGsmSignalStrength(signal));
builder.append(signal.getGsmBitErrorRate());
} else {
builder.append(signal.getCdmaDbm());
builder.append(signal.getCdmaEcio());
}
list.add(builder.build());
}
@Override
public List<JSONObject> getPassiveMetric() {
List<JSONObject> ret = new ArrayList<>();
if (cellLocation == null) {
// No location information currently available!
} else if(cellLocation instanceof GsmCellLocation){
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.GSMLAC,time,((GsmCellLocation) cellLocation).getLac()+""));
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.GSMCID,time,((GsmCellLocation) cellLocation).getCid()+""));
}else if(cellLocation instanceof CdmaCellLocation){
CdmaCellLocation cdmaLocation = (CdmaCellLocation) cellLocation;
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMABSID, time, cdmaLocation.getBaseStationId()+""));
if (cdmaLocation.getBaseStationLatitude() != Integer.MAX_VALUE) {
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMABSLAT, time,cdmaLocation.getBaseStationLatitude()+""));
}
if (cdmaLocation.getBaseStationLongitude() != Integer.MAX_VALUE) {
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMABSLNG, time, cdmaLocation.getBaseStationLongitude()+""));
}
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMANETWORKID,time,cdmaLocation.getNetworkId()+""));
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMASYSTEMID,time, cdmaLocation.getSystemId()+""));
}
if (signal == null) {
// No signal information currently available!
} else if (signal.isGsm()) {
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.GSMSIGNALSTRENGTH,time, DCSConvertorUtil.convertGsmSignalStrength(SKGsmSignalStrength.getGsmSignalStrength(signal))));
// ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.GSMBER, time, DCSConvertorUtil.convertGsmBitErroRate(signal.getGsmBitErrorRate())));
} else {
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMADBM,time, signal.getCdmaDbm()+""));
ret.add(PassiveMetric.create(PassiveMetric.METRIC_TYPE.CDMAECIO,time, signal.getCdmaEcio()+""));
}
return ret;
}
private String extractValueFromString(String string, String valueKey) {
String keyWithEquals = valueKey;
if (keyWithEquals.endsWith("=") == false) {
keyWithEquals = keyWithEquals + "=";
}
String[] valueArray = string.split(" ");
for (String item : valueArray) {
if (item.startsWith(keyWithEquals)) {
String berValue = item.substring(keyWithEquals.length());
return berValue;
}
}
return "";
}
// See https://android.googlesource.com/platform/frameworks/base.git/+/master/telephony/java/android/telephony/CellSignalStrengthWcdma.java
// See https://android.googlesource.com/platform/frameworks/base/+/master/telephony/java/android/telephony/CellSignalStrengthGsm.java
private String extractValueBer(String value) {
return extractValueFromString(value, "ber");
}
// Test mode!
// private void testDataExtraction() {
// String testSignalStringString = "CellSignalStrengthWcdma:" + " ss=" + (int)(99) + " ber=" + (int)(100);
// String testBerValue = extractValueBer(testSignalStringString);
// SKLogger.sAssert(testBerValue.equals("100"));
//
// String testSignalStringString = "CellSignalStrengthGsm:" + " ss=" + (int)(99) + " ber=" + (int)(100);
// String testBerValue = extractValueBer(testSignalStringString);
// SKLogger.sAssert(testBerValue.equals("100"));
// String testSignalStringString = "CellSignalStrengthLte:" + " ss=" + ((int)1) + " rsrp=" + ((int)2) + " rsrq=" + ((int)3) + " rssnr=" + ((int)4) + " cqi=" + ((int)5) + " ta=" + ((int)6);
// String testRsrpValue = extractValueFromString(testSignalStringString, "rsrp");
// SKLogger.sAssert(testRsrpValue.equals("1"));
// String testRsrqValue = extractValueFromString(testSignalStringString, "rsrq");
// SKLogger.sAssert(testRsrqValue.equals("2"));
// String testRssnrValue = extractValueFromString(testSignalStringString, "rssnr");
// SKLogger.sAssert(testRssnrValue.equals("3"));
// String testCqiValue = extractValueFromString(testSignalStringString, "cqi");
// SKLogger.sAssert(testCqiValue.equals("4"));
// }
@SuppressLint("NewApi")
@Override
public List<JSONObject> convertToJSON() {
List<JSONObject> ret = new ArrayList<>();
// Test mode!
//testDataExtraction();
if (cellLocation == null) {
// No location information currently available!
} else if(cellLocation instanceof GsmCellLocation){
GsmCellLocation l = (GsmCellLocation) cellLocation;
Map<String, Object> gsm = new HashMap<>();
gsm.put(JSON_TYPE, JSON_TYPE_GSM_CELL_LOCATION);
gsm.put(JSON_TIMESTAMP, time/1000);
gsm.put(JSON_DATETIME, SKDateFormat.sGetDateAsIso8601String(new java.util.Date(time)));
gsm.put(JSON_CELL_TOWER_ID, l.getCid());
gsm.put(JSON_LOCATION_AREA_CODE, l.getLac());
gsm.put(JSON_UMTS_PSC, Build.VERSION.SDK_INT >= 9 ? l.getPsc() : -1);
if (signal == null) {
SKPorting.sAssert(getClass(), false);
} else {
if(signal.isGsm()){
gsm.put(JSON_SIGNAL_STRENGTH, SKGsmSignalStrength.getGsmSignalStrength(signal));
}
}
ret.add(new JSONObject(gsm));
} else if(cellLocation instanceof CdmaCellLocation){
CdmaCellLocation l = (CdmaCellLocation) cellLocation;
Map<String, Object> cdma = new HashMap<>();
cdma.put(JSON_TYPE,JSON_TYPE_CDMA_CELL_LOCATION);
cdma.put(JSON_TIMESTAMP, time/1000);
cdma.put(JSON_DATETIME, SKDateFormat.sGetDateAsIso8601String(new java.util.Date(time)));
cdma.put(JSON_BASE_STATION_ID, l.getBaseStationId());
cdma.put(JSON_BASE_STATION_LATITUDE, l.getBaseStationLatitude());
cdma.put(JSON_BASE_STATION_LONGITUDE, l.getBaseStationLongitude());
cdma.put(JSON_SYSTEM_ID, l.getSystemId());
cdma.put(JSON_NETWORK_ID, l.getNetworkId());
if (signal == null) {
// No signal information currently available!
} else if(!signal.isGsm()) {
cdma.put(JSON_DBM, signal.getCdmaDbm());
cdma.put(JSON_ECIO, signal.getCdmaEcio());
}
ret.add(new JSONObject(cdma));
}
if (mCellInfo != null) {
for (CellInfo cellInfo : mCellInfo) {
Map<String, Object> cellInfoHashMap = new HashMap<>();
cellInfoHashMap.put(JSON_TYPE, JSON_TYPE_CELL_ALL_CELL_INFO);
cellInfoHashMap.put(JSON_TIMESTAMP, time/1000);
cellInfoHashMap.put(JSON_DATETIME, SKDateFormat.sGetDateAsIso8601String(new java.util.Date(time)));
cellInfoHashMap.put("isregistered",cellInfo.isRegistered());
if(cellInfo instanceof CellInfoCdma) {
CellInfoCdma cellInfoCdma = (CellInfoCdma)cellInfo;
cellInfoHashMap.put("cdma_basestationid", cellInfoCdma.getCellIdentity().getBasestationId());
cellInfoHashMap.put("cdma_latitude", cellInfoCdma.getCellIdentity().getLatitude());
cellInfoHashMap.put("cdma_longitude", cellInfoCdma.getCellIdentity().getLongitude());
cellInfoHashMap.put("cdma_networkid", cellInfoCdma.getCellIdentity().getNetworkId());
cellInfoHashMap.put("cdma_systemid", cellInfoCdma.getCellIdentity().getSystemId());
cellInfoHashMap.put("cdma_asulevel", cellInfoCdma.getCellSignalStrength().getAsuLevel());
cellInfoHashMap.put("cdma_cdmadbm", cellInfoCdma.getCellSignalStrength().getCdmaDbm());
cellInfoHashMap.put("cdma_cdmaecio", cellInfoCdma.getCellSignalStrength().getCdmaEcio());
cellInfoHashMap.put("cdma_cdmalevel", cellInfoCdma.getCellSignalStrength().getCdmaLevel());
cellInfoHashMap.put("cdma_dbm", cellInfoCdma.getCellSignalStrength().getDbm());
cellInfoHashMap.put("cdma_evdodbm", cellInfoCdma.getCellSignalStrength().getEvdoDbm());
cellInfoHashMap.put("cdma_evdoecio", cellInfoCdma.getCellSignalStrength().getEvdoEcio());
cellInfoHashMap.put("cdma_evdolevel", cellInfoCdma.getCellSignalStrength().getEvdoLevel());
cellInfoHashMap.put("cdma_evdosnr", cellInfoCdma.getCellSignalStrength().getEvdoSnr());
cellInfoHashMap.put("cdma_level", cellInfoCdma.getCellSignalStrength().getLevel());
} else if (cellInfo instanceof CellInfoGsm) {
CellInfoGsm cellInfoGsm = (CellInfoGsm)cellInfo;
cellInfoHashMap.put("gsm_cid", cellInfoGsm.getCellIdentity().getCid());
cellInfoHashMap.put("gsm_lac", cellInfoGsm.getCellIdentity().getLac());
cellInfoHashMap.put("gsm_mcc", cellInfoGsm.getCellIdentity().getMcc());
cellInfoHashMap.put("gsm_mnc", cellInfoGsm.getCellIdentity().getMnc());
cellInfoHashMap.put("gsm_asulevel", cellInfoGsm.getCellSignalStrength().getAsuLevel());
cellInfoHashMap.put("gsm_level", cellInfoGsm.getCellSignalStrength().getLevel());
cellInfoHashMap.put("gsm_dbm", cellInfoGsm.getCellSignalStrength().getDbm());
String signalStringString = cellInfoGsm.getCellSignalStrength().toString();
String berValue = extractValueBer(signalStringString);
if (berValue.isEmpty() == false) {
cellInfoHashMap.put("gsm_biterrorrate", berValue);
}
} else if (cellInfo instanceof CellInfoLte) {
CellInfoLte cellInfoLte = (CellInfoLte)cellInfo;
cellInfoHashMap.put("lte_ci", cellInfoLte.getCellIdentity().getCi());
cellInfoHashMap.put("lte_mcc", cellInfoLte.getCellIdentity().getMcc());
cellInfoHashMap.put("lte_mnc", cellInfoLte.getCellIdentity().getMnc());
cellInfoHashMap.put("lte_pci", cellInfoLte.getCellIdentity().getPci());
cellInfoHashMap.put("lte_tac", cellInfoLte.getCellIdentity().getTac());
cellInfoHashMap.put("lte_asulevel", cellInfoLte.getCellSignalStrength().getAsuLevel());
cellInfoHashMap.put("lte_dbm", cellInfoLte.getCellSignalStrength().getDbm());
cellInfoHashMap.put("lte_level", cellInfoLte.getCellSignalStrength().getLevel());
cellInfoHashMap.put("lte_timingadvance", cellInfoLte.getCellSignalStrength().getTimingAdvance());
//https://android.googlesource.com/platform/frameworks/base/+/master/telephony/java/android/telephony/CellSignalStrengthLte.java
String signalStringString = cellInfoLte.getCellSignalStrength().toString();
String rsrpValue = extractValueFromString(signalStringString, "rsrp");
if (rsrpValue.isEmpty() == false) {
cellInfoHashMap.put("lte_rsrp", rsrpValue);
}
String rsrqValue = extractValueFromString(signalStringString, "rsrq");
if (rsrqValue.isEmpty() == false) {
cellInfoHashMap.put("lte_rsrq", rsrqValue);
}
String rssnrValue = extractValueFromString(signalStringString, "rssnr");
if (rssnrValue.isEmpty() == false) {
cellInfoHashMap.put("lte_rssnr", rssnrValue);
}
String cqiValue = extractValueFromString(signalStringString, "cqi");
if (cqiValue.isEmpty() == false) {
cellInfoHashMap.put("lte_cqi", cqiValue);
}
} else if (cellInfo instanceof CellInfoWcdma) {
CellInfoWcdma cellInfoWcdma = (CellInfoWcdma)cellInfo;
cellInfoHashMap.put("wcdma_cid", cellInfoWcdma.getCellIdentity().getCid());
cellInfoHashMap.put("wcdma_lac", cellInfoWcdma.getCellIdentity().getLac());
cellInfoHashMap.put("wcdma_mcc", cellInfoWcdma.getCellIdentity().getMcc());
cellInfoHashMap.put("wcdma_mnc", cellInfoWcdma.getCellIdentity().getMnc());
cellInfoHashMap.put("wcdma_psc", cellInfoWcdma.getCellIdentity().getPsc());
cellInfoHashMap.put("wcdma_asulevel", cellInfoWcdma.getCellSignalStrength().getAsuLevel());
cellInfoHashMap.put("wcdma_dbm", cellInfoWcdma.getCellSignalStrength().getDbm());
cellInfoHashMap.put("wcdma_level", cellInfoWcdma.getCellSignalStrength().getLevel());
String signalStringString = cellInfoWcdma.getCellSignalStrength().toString();
String berValue = extractValueBer(signalStringString);
if (berValue.isEmpty() == false) {
cellInfoHashMap.put("wcdma_biterrorrate", berValue);
}
}
ret.add(new JSONObject(cellInfoHashMap));
}
}
//SKLogger.sAssert(getClass(), (neighbors != null));
if (neighbors != null) {
for (NeighboringCellInfo cellInfo : neighbors) {
Map<String, Object> neighbour = new HashMap<>();
neighbour.put(JSON_TYPE, JSON_TYPE_CELL_TOWER_NEIGHBOUR);
neighbour.put(JSON_TIMESTAMP, time/1000);
neighbour.put(JSON_DATETIME, SKDateFormat.sGetDateAsIso8601String(new java.util.Date(time)));
neighbour.put(JSON_NETWORK_TYPE_CODE,cellInfo.getNetworkType());
neighbour.put(JSON_NETWORK_TYPE, DCSConvertorUtil.convertNetworkType(cellInfo.getNetworkType()));
neighbour.put(JSON_RSSI, cellInfo.getRssi());
neighbour.put(JSON_UMTS_PSC, cellInfo.getPsc());
neighbour.put(JSON_CELL_TOWER_ID, cellInfo.getCid());
neighbour.put(JSON_LOCATION_AREA_CODE, cellInfo.getLac());
ret.add(new JSONObject(neighbour));
}
}
return ret;
}
}