/* Android IMSI-Catcher Detector | (c) AIMSICD Privacy Project
* -----------------------------------------------------------
* LICENSE: http://git.io/vki47 | TERMS: http://git.io/vki4o
* -----------------------------------------------------------
*/
package com.secupwn.aimsicd.utils;
import android.content.Context;
import android.os.Parcel;
import android.os.Parcelable;
import android.os.SystemClock;
import android.telephony.TelephonyManager;
import com.secupwn.aimsicd.R;
import lombok.Getter;
import lombok.Setter;
@Getter
public class Cell implements Parcelable {
public static final String INVALID_PSC = "invalid";
// Cell Specific Variables
/**
* Current Cell ID
* Cell Identification code
*/
@Setter
private int cellId;
/**
* Location Area Code
*/
@Setter
private int locationAreaCode;
/**
* Mobile Country Code
*/
@Setter
private int mobileCountryCode;
/**
* Mobile Network Code
*/
@Setter
private int mobileNetworkCode;
/**
* [dBm] RX signal "power"
* Signal Strength Measurement (dBm)
*/
@Setter
private int dbm;
/**
* Primary Scrambling Code
*/
private int primaryScramblingCode;
/**
* Relative Signal Strength Indicator [dBm, asu etc.]
* Received Signal Strength Indicator (RSSI)
*/
private int rssi;
/**
* Timing Advance [LTE,GSM]
* LTE Timing Advance or Integer.MAX_VALUE if unavailable
*/
@Setter
private int timingAdvance;
/**
* Cell-ID for [CDMA]
*
* CDMA System ID
*
* @return System ID or Integer.MAX_VALUE if not supported
*/
@Setter
private int sid;
/**
* Timestamp of current cell information
*/
@Setter
private long timestamp;
// Tracked Cell Specific Variables
/**
* Current Network Type
*/
@Setter
private int netType;
/**
* Current ground speed in metres/second
*/
@Setter
private double speed;
/**
* Location accuracy in metres or 0.0 if unavailable
*/
@Setter
private double accuracy;
@Setter
private double bearing;
/**
* Longitude Geolocation
*/
@Setter
private double lon;
/**
* Latitude
*/
@Setter
private double lat;
{
cellId = Integer.MAX_VALUE;
locationAreaCode = Integer.MAX_VALUE;
mobileCountryCode = Integer.MAX_VALUE;
mobileNetworkCode = Integer.MAX_VALUE;
dbm = Integer.MAX_VALUE;
primaryScramblingCode = Integer.MAX_VALUE;
rssi = Integer.MAX_VALUE;
timingAdvance = Integer.MAX_VALUE;
sid = Integer.MAX_VALUE;
netType = Integer.MAX_VALUE;
lon = 0.0;
lat = 0.0;
speed = 0.0;
accuracy = 0.0;
bearing = 0.0;
}
public Cell() {
}
public Cell(int CID, int locationAreaCode, int mobileCountryCode, int mobileNetworkCode, int dbm, long timestamp) {
super();
this.cellId = CID;
this.locationAreaCode = locationAreaCode;
this.mobileCountryCode = mobileCountryCode;
this.mobileNetworkCode = mobileNetworkCode;
this.dbm = dbm;
this.rssi = Integer.MAX_VALUE;
this.primaryScramblingCode = Integer.MAX_VALUE;
this.timestamp = timestamp;
this.timingAdvance = Integer.MAX_VALUE;
this.sid = Integer.MAX_VALUE;
this.netType = Integer.MAX_VALUE;
this.lon = 0.0;
this.lat = 0.0;
this.speed = 0.0;
this.accuracy = 0.0;
this.bearing = 0.0;
}
public Cell(int CID, int locationAreaCode, int signal, int primaryScramblingCode, int netType, boolean dbm) {
this.cellId = CID;
this.locationAreaCode = locationAreaCode;
this.mobileCountryCode = Integer.MAX_VALUE;
this.mobileNetworkCode = Integer.MAX_VALUE;
if (dbm) {
this.dbm = signal;
} else {
this.rssi = signal;
}
this.primaryScramblingCode = primaryScramblingCode;
this.netType = netType;
this.timingAdvance = Integer.MAX_VALUE;
this.sid = Integer.MAX_VALUE;
this.lon = 0.0;
this.lat = 0.0;
this.speed = 0.0;
this.accuracy = 0.0;
this.bearing = 0.0;
this.timestamp = SystemClock.currentThreadTimeMillis();
}
public Cell(int cellId, int locationAreaCode, int mobileCountryCode, int mobileNetworkCode, int dbm, double accuracy, double speed,
double bearing, int netType, long timestamp) {
this.cellId = cellId;
this.locationAreaCode = locationAreaCode;
this.mobileCountryCode = mobileCountryCode;
this.mobileNetworkCode = mobileNetworkCode;
this.dbm = dbm;
this.rssi = Integer.MAX_VALUE;
this.timingAdvance = Integer.MAX_VALUE;
this.sid = Integer.MAX_VALUE;
this.accuracy = accuracy;
this.speed = speed;
this.bearing = bearing;
this.netType = netType;
this.timestamp = timestamp;
}
/**
* Set Primary Scrambling Code (PSC) of current Cell
*
* @param primaryScramblingCode Primary Scrambling Code
*/
public void setPrimaryScramblingCode(int primaryScramblingCode) {
if (primaryScramblingCode == -1) {
this.primaryScramblingCode = Integer.MAX_VALUE;
} else {
this.primaryScramblingCode = primaryScramblingCode;
}
}
/**
* Radio Access Technology (RAT)
*
* Some places in the app refers to this as the Network Type.
*
* For our purposes, network types displayed to the user is referred to as RAT.
*
* @return Current cell's Radio Access Technology (e.g. UMTS, GSM) or null if not known
*/
public String getRat() {
return getRatFromInt(this.netType);
}
@Override
public int hashCode() {
final int prime = 31;
int result = 1;
result = prime * result + cellId;
result = prime * result + locationAreaCode;
result = prime * result + mobileCountryCode;
result = prime * result + mobileNetworkCode;
if (primaryScramblingCode != -1) {
result = prime * result + primaryScramblingCode;
}
return result;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (((Object) this).getClass() != obj.getClass()) {
return false;
}
Cell other = (Cell) obj;
if (this.primaryScramblingCode != Integer.MAX_VALUE) {
return this.cellId == other.getCellId() && this.locationAreaCode == other.getLocationAreaCode() && this.mobileCountryCode == other
.getMobileCountryCode() && this.mobileNetworkCode == other.getMobileNetworkCode() && this.primaryScramblingCode == other.getPrimaryScramblingCode();
} else {
return this.cellId == other.getCellId() && this.locationAreaCode == other.getLocationAreaCode() && this.mobileCountryCode == other
.getMobileCountryCode() && this.mobileNetworkCode == other.getMobileNetworkCode();
}
}
public String toString() {
StringBuilder result = new StringBuilder();
result.append("cid - ").append(cellId).append("\n");
result.append("LAC - ").append(locationAreaCode).append("\n");
result.append("MCC - ").append(mobileCountryCode).append("\n");
result.append("MNC - ").append(mobileNetworkCode).append("\n");
result.append("DBm - ").append(dbm).append("\n");
result.append("PSC - ").append(validatePscValue(primaryScramblingCode)).append("\n");
result.append("Type - ").append(netType).append("\n");
result.append("Lon - ").append(lon).append("\n");
result.append("Lat - ").append(lat).append("\n");
return result.toString();
}
public boolean isValid() {
return this.getCellId() != Integer.MAX_VALUE && this.getLocationAreaCode() != Integer.MAX_VALUE;
}
/**
* Get a human-readable string of RAT/Network Type
*
* Frustratingly it looks like the app uses RAT & Network Type interchangably with both either
* being an integer representation (TelephonyManager's constants) or a human-readable string.
*
* @param netType The integer representation of the network type, via TelephonyManager
* @return Human-readable representation of network type (e.g. "EDGE", "LTE")
*/
public static String getRatFromInt(int netType) {
switch (netType) {
case TelephonyManager.NETWORK_TYPE_1xRTT:
return "1xRTT";
case TelephonyManager.NETWORK_TYPE_CDMA:
return "CDMA";
case TelephonyManager.NETWORK_TYPE_EDGE:
return "EDGE";
case TelephonyManager.NETWORK_TYPE_EHRPD:
return "eHRPD";
case TelephonyManager.NETWORK_TYPE_EVDO_0:
return "EVDO rev. 0";
case TelephonyManager.NETWORK_TYPE_EVDO_A:
return "EVDO rev. A";
case TelephonyManager.NETWORK_TYPE_EVDO_B:
return "EVDO rev. B";
case TelephonyManager.NETWORK_TYPE_GPRS:
return "GPRS";
case TelephonyManager.NETWORK_TYPE_HSDPA:
return "HSDPA";
case TelephonyManager.NETWORK_TYPE_HSPA:
return "HSPA";
case TelephonyManager.NETWORK_TYPE_HSPAP:
return "HSPA+";
case TelephonyManager.NETWORK_TYPE_HSUPA:
return "HSUPA";
case TelephonyManager.NETWORK_TYPE_IDEN:
return "iDen";
case TelephonyManager.NETWORK_TYPE_LTE:
return "LTE";
case TelephonyManager.NETWORK_TYPE_UMTS:
return "UMTS";
case TelephonyManager.NETWORK_TYPE_UNKNOWN:
return "Unknown";
default:
return String.valueOf(netType);
}
}
public static String validatePscValue(Context c, String psc) {
return validatePscValue(c, Integer.parseInt(psc));
}
/**
* Validate PSC is in bounds, return i18n'd "Unknown" if invalid
*
* @see #validatePscValue(int)
*
* @param c Used for getString translations
* @param psc
* @return PSC or "Unknown "if invalid
*/
public static String validatePscValue(Context c, int psc) {
String s = validatePscValue(psc);
if (s.equals(INVALID_PSC)) {
return c.getString(R.string.unknown);
}
return s;
}
public static String validatePscValue(String psc) {
return validatePscValue(Integer.parseInt(psc));
}
/**
* Validate PSC is in bounds
*
* Database import stores cell's PSC as "666" if its absent in OCID. This method will return
* "invalid" instead.
*
* Use this method to translate/i18n a cell's missing PSC value.
*
* @param psc
* @return PSC or "invalid" untranslated string if invalid
*/
public static String validatePscValue(int psc) {
if (psc < 0 || psc > 511) {
return INVALID_PSC;
}
return String.valueOf(psc);
}
// Parcelling
public Cell(Parcel in) {
String[] data = new String[15];
in.readStringArray(data);
cellId = Integer.valueOf(data[0]);
locationAreaCode = Integer.valueOf(data[1]);
mobileCountryCode = Integer.valueOf(data[2]);
mobileNetworkCode = Integer.valueOf(data[3]);
dbm = Integer.valueOf(data[4]);
primaryScramblingCode = Integer.valueOf(data[5]);
rssi = Integer.valueOf(data[6]);
timingAdvance = Integer.valueOf(data[7]);
sid = Integer.valueOf(data[8]);
netType = Integer.valueOf(data[9]);
lon = Double.valueOf(data[10]);
lat = Double.valueOf(data[11]);
speed = Double.valueOf(data[12]);
accuracy = Double.valueOf(data[13]);
bearing = Double.valueOf(data[14]);
}
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(Parcel dest, int flags) {
dest.writeStringArray(new String[]{
String.valueOf(this.cellId),
String.valueOf(this.locationAreaCode),
String.valueOf(this.mobileCountryCode),
String.valueOf(this.mobileNetworkCode),
String.valueOf(this.dbm),
String.valueOf(this.primaryScramblingCode),
String.valueOf(this.rssi),
String.valueOf(this.timingAdvance),
String.valueOf(this.sid),
String.valueOf(this.netType),
String.valueOf(this.lon),
String.valueOf(this.lat),
String.valueOf(this.speed),
String.valueOf(this.accuracy),
String.valueOf(this.bearing)});
}
public static final Parcelable.Creator CREATOR = new Parcelable.Creator() {
public Cell createFromParcel(Parcel in) {
return new Cell(in);
}
public Cell[] newArray(int size) {
return new Cell[size];
}
};
}