package com.secupwn.aimsicd.utils;
import android.content.Context;
import android.content.SharedPreferences;
import android.os.Vibrator;
import android.preference.PreferenceManager;
import com.secupwn.aimsicd.R;
import com.secupwn.aimsicd.data.model.BaseTransceiverStation;
import com.secupwn.aimsicd.data.model.DefaultLocation;
import com.secupwn.aimsicd.data.model.Event;
import com.secupwn.aimsicd.data.model.GpsLocation;
import com.secupwn.aimsicd.data.model.Import;
import com.secupwn.aimsicd.data.model.Measure;
import com.secupwn.aimsicd.enums.Status;
import com.secupwn.aimsicd.service.CellTracker;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import au.com.bytecode.opencsv.CSVReader;
import au.com.bytecode.opencsv.CSVWriter;
import io.freefair.android.util.logging.AndroidLogger;
import io.freefair.android.util.logging.Logger;
import io.realm.Realm;
import io.realm.RealmQuery;
import io.realm.RealmResults;
/**
* This class handles all the AMISICD DataBase maintenance operations, like
* creation, population, updates, backup, restore and various selections.
*/
public final class RealmHelper {
private final Logger log = AndroidLogger.forClass(RealmHelper.class);
private Context mContext;
private SharedPreferences mPreferences;
public static String mExternalFilesDirPath;
public RealmHelper(Context context) {
mContext = context;
mPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
mExternalFilesDirPath = mContext.getExternalFilesDir(null) + File.separator;
//e.g. /storage/emulated/0/Android/data/com.SecUpwN.AIMSICD/
}
/**
* Returns Cell Information for contribution to the OpenCellID project
* by listing all rows from the {@link Measure} realm where submitted is not true.
*/
public RealmResults<Measure> getOCIDSubmitData(Realm realm) {
return realm.where(Measure.class)
.notEqualTo("submitted", true)
.findAll();
}
/**
* This is using the LAC found by API and comparing to LAC found from a
* previous measurement in the "DBi_measure". It then compares the API LAC
* to that of the DBi_Measure LAC. This is NOT depending on {@link Import}.
* <p/>
* This works for now, but we probably should consider populating "DBi_measure"
* as soon as the API gets a new LAC. Then the detection can be done by SQL,
* and by just comparing last 2 LAC entries for same CID.
*
* @return false if LAC is not OK (Cell's LAC differs from Cell's LAC previously stored value in DB)
*/
public boolean checkLAC(Realm realm, Cell cell) {
RealmResults<BaseTransceiverStation> baseStationRealmResults = realm.where(BaseTransceiverStation.class)
.equalTo("cellId", cell.getCellId())
.findAll();
for (BaseTransceiverStation baseStation : baseStationRealmResults) {
int lac = baseStation.getLocationAreaCode();
if (cell.getLocationAreaCode() != lac) {
log.info("ALERT: Changing LAC on CID: " + cell.getCellId()
+ " LAC(API): " + cell.getLocationAreaCode()
+ " LAC(DBi): " + lac);
return false;
} else {
log.verbose("LAC checked - no change on CID:" + cell.getCellId()
+ " LAC(API): " + cell.getLocationAreaCode()
+ " LAC(DBi): " + lac);
}
}
return true;
}
/**
* UPDATE {@link Measure} realm to indicate if OpenCellID DB contribution has been made
*/
public Realm.Transaction ocidProcessed() {
return new Realm.Transaction() {
@Override
public void execute(Realm realm) {
RealmResults<Measure> measures = realm.where(Measure.class).findAll();
for (int i = 0; i < measures.size(); i++) {
Measure measure = measures.get(i);
measure.setSubmitted(true);
}
}
};
}
/**
* This returns all {@link Import} by current sim card network rather
* than returning other bts from different networks and slowing down map view
*/
public RealmQuery<Import> returnOcidBtsByNetwork(Realm realm, int mcc, int mnc) {
return realm.where(Import.class)
.equalTo("mobileCountryCode", mcc)
.equalTo("mobileNetworkCode", mnc);
}
public GpsLocation getDefaultLocation(Realm realm, int mcc) {
return realm.where(DefaultLocation.class)
.equalTo("mobileCountryCode", mcc)
.findAll()
.first()
.getGpsLocation();
}
/**
* Remove all {@link BaseTransceiverStation BTS} with invalid {@link BaseTransceiverStation#cellId CID}
* @return The Transaction to execute
*/
public Realm.Transaction cleanseCellTable() {
return new Realm.Transaction() {
@Override
public void execute(Realm realm) {
realm.where(BaseTransceiverStation.class)
.equalTo("cellId", -1)
.or()
.equalTo("cellId", Integer.MAX_VALUE)
.findAll()
.clear();
}
};
}
/**
* Prepares the CSV file used to upload new data to the OCID server.
* <p/>
* OCID CSV upload format:
* <p/>
* "cellid" = CID (in UMTS long format)
* "measured_at" = time
* "rating" = gpsd_accu
* "act" = RAT (TEXT):
* 1xRTT, CDMA, eHRPD, IS95A, IS95B, EVDO_0, EVDO_A, EVDO_B,
* UMTS, HSPA+, HSDPA, HSUPA, HSPA, LTE, EDGE, GPRS, GSM
*/
public boolean prepareOpenCellUploadData(Realm realm) {
boolean result;
File dir = new File(mExternalFilesDirPath + "OpenCellID/");
if (!dir.exists()) {
result = dir.mkdirs();
if (!result) {
return false;
}
}
File file = new File(dir, "aimsicd-ocid-data.csv");
try {
// Get data not yet submitted:
RealmResults<Measure> c;
c = getOCIDSubmitData(realm);
// Check if we have something to upload:
if (c.size() > 0) {
if (!file.exists()) {
result = file.createNewFile();
if (!result) {
return false;
}
// OCID CSV upload format and items
// mcc,mnc,lac,cellid,lon,lat,signal,measured_at,rating,speed,direction,act,ta,psc,tac,pci,sid,nid,bid
CSVWriter csvWrite = new CSVWriter(new FileWriter(file));
// TODO: Add "act"
csvWrite.writeNext("mcc,mnc,lac,cellid,lon,lat,signal,measured_at,rating");
int size = c.size();
log.debug("OCID UPLOAD: row count = " + size);
for (Measure measure : c) {
csvWrite.writeNext(
String.valueOf(measure.getBaseStation().getMobileCountryCode()),
String.valueOf(measure.getBaseStation().getMobileNetworkCode()),
String.valueOf(measure.getBaseStation().getLocationAreaCode()),
String.valueOf(measure.getBaseStation().getCellId()),
String.valueOf(measure.getGpsLocation().getLongitude()),
String.valueOf(measure.getGpsLocation().getLatitude()),
String.valueOf(measure.getRxSignal()),
String.valueOf(measure.getTime().getTime()),
String.valueOf(measure.getGpsLocation().getAccuracy())
);
}
csvWrite.close();
}
return true;
}
return false;
} catch (Exception e) {
log.error("prepareOpenCellUploadData(): Error creating OpenCellID Upload Data: ", e);
return false;
}
}
/**
* Parses the downloaded CSV from OpenCellID and uses it to populate "Import" table.
* <p/>
* a) We do not include "rej_cause" in backups. set to 0 as default
* b) Unfortunately there are 2 important missing items in the OCID CSV file:
* - "time_first"
* - "time_last"
* <p/>
* c) In addition the OCID data often contain unexplained negative values for one or both of:
* - "samples"
* - "range"
* <p/>
* d) The difference between "Cellid" and "cid", is that "cellid" is the "Long CID",
* consisting of RNC and a multiplier:
* Long CID = 65536 * RNC + CID
* See FAQ.
* <p/>
* ========================================================================
* For details on available OpenCellID API DB values, see:
* http://wiki.opencellid.org/wiki/API
* http://wiki.opencellid.org/wiki/FAQ#Long_CellID_vs._short_Cell_ID
* ========================================================================
* # head -2 opencellid.csv
* lat,lon,mcc,mnc,lac,cellid,averageSignalStrength,range,samples,changeable,radio,rnc,cid,psc,tac,pci,sid,nid,bid
* <p/>
* 0 lat TEXT
* 1 lon TEXT
* 2 mcc INTEGER
* 3 mnc INTEGER
* 4 lac INTEGER
* 5 cellid INTEGER (Long CID) = 65536 * RNC + CID
* 6 averageSignalStrength INTEGER (rx_power)
* 7 range INTEGER (accu)
* 8 samples INTEGER
* 9 changeable INTEGER (isGPSexact)
* 10 radio TEXT (RAT)
* 11 rnc INTEGER
* 12 cid INTEGER CID (Short)= "Long CID" mod 65536
* 13 psc INTEGER
* --------- vvv See OCID API vvv ---------
* 14 tac -
* 15 pci -
* 16 sid -
* 17 nid -
* 18 bid -
* <p/>
* 54.63376,25.160243,246,3,20,1294,0,-1,1,1,GSM,,,,,,,,
* ========================================================================
*/
public boolean populateDBeImport(Realm realm) {
// This was not finding the file on a Samsung S5
// String fileName = Environment.getExternalStorageDirectory()+ "/AIMSICD/OpenCellID/opencellid.csv";
String fileName = mContext.getExternalFilesDir(null) + File.separator + "OpenCellID/opencellid.csv";
File file = new File(fileName);
try {
if (file.exists()) {
CSVReader csvReader = new CSVReader(new FileReader(file));
List<String[]> csvCellID = new ArrayList<>();
String next[];
while ((next = csvReader.readNext()) != null) {
csvCellID.add(next);
}
if (!csvCellID.isEmpty()) {
int lines = csvCellID.size();
log.info("UpdateOpenCellID: OCID CSV size (lines): " + lines);
int rowCounter;
for (rowCounter = 1; rowCounter < lines; rowCounter++) {
// Insert details into OpenCellID Database using: insertDBeImport()
// Beware of negative values of "range" and "samples"!!
String lat = csvCellID.get(rowCounter)[0], //TEXT
lon = csvCellID.get(rowCounter)[1], //TEXT
mcc = csvCellID.get(rowCounter)[2], //int
mnc = csvCellID.get(rowCounter)[3], //int
lac = csvCellID.get(rowCounter)[4], //int
cellid = csvCellID.get(rowCounter)[5], //int long CID [>65535]
range = csvCellID.get(rowCounter)[6], //int
avg_sig = csvCellID.get(rowCounter)[7], //int
samples = csvCellID.get(rowCounter)[8], //int
change = csvCellID.get(rowCounter)[9], //int
radio = csvCellID.get(rowCounter)[10], //TEXT
// rnc = csvCellID.get(rowCounter)[11], //int
// cid = csvCellID.get(rowCounter)[12], //int short CID [<65536]
psc = csvCellID.get(rowCounter)[13]; //int
// Some OCID data may not contain PSC so we indicate this with an out-of-range
// PSC value. Should be -1 but hey people already imported so we're stuck with
// this.
int iPsc = 666;
if (psc != null && !psc.isEmpty()) {
iPsc = Integer.parseInt(psc);
}
//Reverse order 1 = 0 & 0 = 1
// what if ichange is 4? ~ agilob
int ichange = Integer.parseInt(change);
ichange = (ichange == 0 ? 1 : 0);
Realm.Transaction transaction = insertDBeImport(
"OCID", // DBsource
radio, // RAT
Integer.parseInt(mcc), // MCC
Integer.parseInt(mnc), // MNC
Integer.parseInt(lac), // LAC
Integer.parseInt(cellid), // CID (cellid) ?
iPsc, // psc
Double.parseDouble(lat), // gps_lat
Double.parseDouble(lon), // gps_lon
ichange == 0, // isGPSexact
Integer.parseInt(avg_sig), // avg_signal [dBm]
Integer.parseInt(range), // avg_range [m]
Integer.parseInt(samples), // samples
new Date(), // time_first (not in OCID)
new Date() // time_last (not in OCID)
);
realm.executeTransaction(transaction);
}
log.debug("PopulateDBeImport(): inserted " + rowCounter + " cells.");
}
} else {
log.error("Opencellid.csv file does not exist!");
}
return true;
} catch (Exception e) {
log.error("Error parsing OpenCellID data: " + e.getMessage());
return false;
} finally {
try {
Thread.sleep(1000); // wait 1 second to allow user to see progress bar.
} catch (InterruptedException ex) {
Thread.currentThread().interrupt();
}
}
}
/**
* This is the {@link Import} data consistency check wich checks each
* imported BTS data for consistency and correctness according to general
* 3GPP LAC/CID/RAT rules and according to the app settings:
* <p/>
* tf_settings (currently hard-coded)
* min_gps_precision (currently hard-coded)
* <p/>
* So there are really two steps in this procedure:
* a) Remove bad {@link Import Imports} from Realm
* b) Mark unsafe {@link Import Imports} with "rej_cause" value.
* <p/>
* The formula for the long cell ID is as follows:
* Long CID = 65536 * RNC + CID
* <p/>
* If you have the Long CID, you can get RNC and CID in the following way:
* RNC = Long CID / 65536 (integer division)
* CID = Long CID mod 65536 (modulo operation)
*/
public Realm.Transaction checkDBe() {
return new Realm.Transaction() {
@Override
public void execute(Realm realm) {
// We hard-code these for now, but should be in the settings eventually
// int tf_settings = 30; // [days] Minimum acceptable number of days since "time_first" seen.
int min_gps_precision = 50; // [m] Minimum acceptable GPS accuracy in meters.
//=============================================================
//=== DELETE bad cells from BTS data
//=============================================================
log.debug("CheckDBe() Attempting to delete bad import data from Imports database...");
// =========== samples ===========
realm.where(Import.class).lessThan("samples", 1).findAll().clear();
// =========== avg_range ===========
// TODO: OCID data marks many good BTS with a negative range so we can't use this yet.
// TODO: Also delete cells where the avg_range is way too large, say > 2000 meter
/*realm.where(Import.class)
.not()
.between("avgRange", 1, 2000)
.findAll().clear();*/
// =========== LAC ===========
realm.where(Import.class).lessThan("locationAreaCode", 1).findAll().clear();
// We should delete cells with CDMA (4) LAC not in [1,65534] but we can simplify this to:
// Delete ANY cells with a LAC not in [1,65534]
realm.where(Import.class).greaterThan("locationAreaCode", 65534).findAll().clear();
// Delete cells with GSM/UMTS/LTE (1/2/3/13 ??) (or all others?) LAC not in [1,65533]
/*realm.where(Import.class)
.notEqualTo("radioAccessTechnology", "CDMA")
.greaterThan("locationAreaCode", 65533)
.findAll().clear();*/
// =========== CID ===========
realm.where(Import.class).lessThan("cell", 1).findAll().clear();
// We should delete cells with UMTS/LTE (3,13) CID not in [1,268435455] (0xFFF FFFF) but
// we can simplify this to:
// Delete ANY cells with a CID not in [1,268435455]
realm.where(Import.class).greaterThan("cellId", 268435455).findAll().clear();
// Delete cells with GSM/CDMA (1-3,4) CID not in [1,65534]
realm.where(Import.class)
.greaterThan("cellId", 65534)
.beginGroup()
.equalTo("radioAccessTechnology", "GSM")
.or()
.equalTo("radioAccessTechnology", "CDMA")
.endGroup()
.findAll().clear();
log.info("CheckDBe() Deleted BTS entries from Import realm with bad LAC/CID...");
//=============================================================
//=== UPDATE "rej_cause" in Import-Data
//=============================================================
// =========== isGPSexact ===========
// Increase rej_cause, when: the GPS position of the BTS is not exact:
// NOTE: In OCID: "changeable"=1 ==> isGPSexact=0
for (Import i : realm.where(Import.class).equalTo("gpsExact", false).findAll()) {
i.setRejCause(i.getRejCause() + 3);
}
// =========== avg_range ===========
// Increase rej_cause, when: the average range is < a minimum GPS precision
for (Import i : realm.where(Import.class).lessThan("avgRange", min_gps_precision).findAll()) {
i.setRejCause(i.getRejCause() + 3);
}
// =========== time_first ===========
// Increase rej_cause, when: the time first seen is less than a number of days.
// TODO: We need to convert tf_settings to seconds since epoch/unix time...
// int tf_settings = current_time[s] - (3600 * 24 * tf_settings) ???
//sqlQuery = "UPDATE DBe_import SET rej_cause = rej_cause + 1 WHERE time_first < " + tf_settings;
//mDb.execSQL(sqlQuery);
}
};
}
public int getAverageSignalStrength(Realm realm, int cellID) {
return (int) realm.where(Measure.class)
.equalTo("baseStation.cellId", cellID)
.average("rxSignal");
}
/**
* This method is used to insert and populate the downloaded or previously
* backed up OCID details into the {@link Import} realm table.
* <p/>
* It also prevents adding multiple entries of the same cell-id, when OCID
* downloads are repeated.
*/
public Realm.Transaction insertDBeImport(
final String db_src,
final String rat,
final int mcc,
final int mnc,
final int lac,
final int cid,
final int psc,
final double lat,
final double lon,
final boolean isGpsExact,
final int avg_range,
final int avg_signal,
final int samples,
final Date time_first,
final Date time_last
) {
return new Realm.Transaction() {
@Override
public void execute(Realm realm) {
long count = realm.where(Import.class)
.equalTo("locationAreaCode", lac)
.equalTo("cellId", cid).count();
if (count <= 0) {
Import anImport = realm.createObject(Import.class);
anImport.setDbSource(db_src);
anImport.setRadioAccessTechnology(rat);
anImport.setMobileCountryCode(mcc);
anImport.setMobileNetworkCode(mnc);
anImport.setLocationAreaCode(lac);
anImport.setCellId(cid);
anImport.setPrimaryScramblingCode(psc);
GpsLocation gpsLocation = realm.createObject(GpsLocation.class);
gpsLocation.setLatitude(lat);
gpsLocation.setLongitude(lon);
anImport.setGpsLocation(gpsLocation);
anImport.setGpsExact(isGpsExact);
anImport.setAvgRange(avg_range);
anImport.setAvgSignal(avg_signal);
anImport.setSamples(samples);
anImport.setTimeFirst(time_first);
anImport.setTimeLast(time_last);
}
}
};
}
/**
* Created this because we don't need to insert all the data in this table
* since we don't yet have items like TMSI etc.
*/
public void insertBTS(Realm realm, Cell cell) {
// If LAC and CID are not already in BTS realm, then add them.
if (!cellInDbiBts(realm, cell.getLocationAreaCode(), cell.getCellId())) {
realm.beginTransaction();
BaseTransceiverStation baseStation = realm.createObject(BaseTransceiverStation.class);
baseStation.setMobileCountryCode(cell.getMobileCountryCode());
baseStation.setMobileNetworkCode(cell.getMobileNetworkCode());
baseStation.setLocationAreaCode(cell.getLocationAreaCode());
baseStation.setCellId(cell.getCellId());
baseStation.setPrimaryScramblingCode(cell.getPrimaryScramblingCode());
baseStation.setTimeFirst(new Date());
baseStation.setTimeLast(new Date());
GpsLocation gpsLocation = realm.createObject(GpsLocation.class);
gpsLocation.setLatitude(cell.getLat()); // TODO NO! These should be exact GPS from Import or by manual addition!
gpsLocation.setLongitude(cell.getLon()); // TODO NO! These should be exact GPS from Import or by manual addition!
baseStation.setGpsLocation(gpsLocation);
realm.commitTransaction();
} else {
// If cell is already in the DB, update it to last time seen and
// update its GPS coordinates, if not 0.0
BaseTransceiverStation baseStation = realm.where(BaseTransceiverStation.class).equalTo("cellId", cell.getCellId()).findFirst();
realm.beginTransaction();
baseStation.setTimeLast(new Date());
// TODO NO! These should be exact GPS from Import or by manual addition!
// Only update if GPS coordinates are good
if (Double.doubleToRawLongBits(cell.getLat()) != 0
&& Double.doubleToRawLongBits(cell.getLat()) != 0
&& Double.doubleToRawLongBits(cell.getLon()) != 0
&& Double.doubleToRawLongBits(cell.getLon()) != 0) {
if (baseStation.getGpsLocation() == null) {
baseStation.setGpsLocation(realm.createObject(GpsLocation.class));
}
baseStation.getGpsLocation().setLatitude(cell.getLat());
baseStation.getGpsLocation().setLongitude(cell.getLon());
}
realm.commitTransaction();
log.info("BTS updated: CID=" + cell.getCellId() + " LAC=" + cell.getLocationAreaCode());
}
// TODO: This doesn't make sense, if it's in DBi_bts it IS part of DBi_measure!
// Checking to see if CID (now bts_id) is already in DBi_measure, if not add it.
if (!cellInDbiMeasure(realm, cell.getCellId())) {
realm.beginTransaction();
Measure measure = realm.createObject(Measure.class);
BaseTransceiverStation baseStation = realm.where(BaseTransceiverStation.class).equalTo("cellId", cell.getCellId()).findFirst();
measure.setBaseStation(baseStation);
measure.setTime(new Date());
GpsLocation gpsLocation = realm.createObject(GpsLocation.class);
gpsLocation.setLatitude(cell.getLat());
gpsLocation.setLongitude(cell.getLon());
gpsLocation.setAccuracy(cell.getAccuracy());
measure.setGpsLocation(gpsLocation);
measure.setRxSignal(cell.getDbm());
measure.setRadioAccessTechnology(String.valueOf(cell.getRat()));
measure.setTimingAdvance(cell.getTimingAdvance()); //TODO does this actually get timing advance?
measure.setSubmitted(false);
measure.setNeighbor(false);
realm.commitTransaction();
log.info("Measure inserted cellId=" + cell.getCellId());
} else {
// Updating DBi_measure tables if already exists.
realm.beginTransaction();
RealmResults<Measure> all = realm.where(Measure.class)
.equalTo("baseStation.cellId", cell.getCellId())
.findAll();
for (int i = 0; i < all.size(); i++) {
Measure measure = all.get(i);
if (Double.doubleToRawLongBits(cell.getLat()) != 0
&& Double.doubleToRawLongBits(cell.getLon()) != 0) {
measure.getGpsLocation().setLatitude(cell.getLat());
measure.getGpsLocation().setLongitude(cell.getLon());
}
if (Double.doubleToRawLongBits(cell.getAccuracy()) != 0
&& cell.getAccuracy() > 0) {
measure.getGpsLocation().setAccuracy(cell.getAccuracy());
}
if (cell.getDbm() > 0) {
measure.setRxSignal(cell.getDbm());
}
if (cell.getTimingAdvance() > 0) {
measure.setTimingAdvance(cell.getTimingAdvance()); // Only available on API >16 on LTE
}
}
realm.commitTransaction();
log.info("DBi_measure updated bts_id=" + cell.getCellId());
}
}
/**
* Defining a new simpler version of insertEventLog for use in CellTracker.
* Please note, that in AMSICDDbAdapter (here) it is also used to backup DB,
* in which case we can not use this simpler version!
*/
public void toEventLog(Realm realm, final int DF_id, final String DF_desc) {
final Date timestamp = new Date();
final int lac = CellTracker.monitorCell.getLocationAreaCode();
final int cid = CellTracker.monitorCell.getCellId();
final int psc = CellTracker.monitorCell.getPrimaryScramblingCode(); //[UMTS,LTE]
final double gpsd_lat = CellTracker.monitorCell.getLat();
final double gpsd_lon = CellTracker.monitorCell.getLon();
final double gpsd_accu = CellTracker.monitorCell.getAccuracy();
realm.executeTransactionAsync(new Realm.Transaction() {
@Override
public void execute(Realm realm) {
// skip CID/LAC of "-1" (due to crappy API, Roaming or Air-Plane Mode)
if (cid != -1 || lac != -1) {
// Check if LAST entry is the same!
RealmResults<Event> events = realm.where(Event.class).findAllSorted("timestamp");
boolean insertData;
if (events.isEmpty()) {
insertData = true;
} else {
Event lastEvent = events.last();
insertData = !(lastEvent.getCellId() == cid && lastEvent.getLocationAreaCode() == lac && lastEvent.getPrimaryScramblingCode() == psc && lastEvent.getDfId() == DF_id);
}
// WARNING: By skipping duplicate events, we might be missing counts of Type-0 SMS etc.
if (insertData) {
Event event = realm.createObject(Event.class);
event.setTimestamp(timestamp);
event.setLocationAreaCode(lac);
event.setCellId(cid);
event.setPrimaryScramblingCode(psc);
GpsLocation gpsLocation = realm.createObject(GpsLocation.class);
gpsLocation.setLatitude(gpsd_lat);
gpsLocation.setLongitude(gpsd_lon);
gpsLocation.setAccuracy(gpsd_accu);
event.setGpsLocation(gpsLocation);
event.setDfId(DF_id);
event.setDfDescription(DF_desc);
}
}
}
}, new Realm.Transaction.OnSuccess() {
@Override
public void onSuccess() {
log.info("ToEventLog(): Added new event: id=" + DF_id + " time=" + timestamp + " cid=" + cid);
// Short 100 ms Vibration
// TODO not elegant solution, vibrator invocation should be moved somewhere else imho
boolean vibrationEnabled = mPreferences.getBoolean(mContext.getString(R.string.pref_notification_vibrate_enable), true);
int thresholdLevel = Integer.valueOf(mPreferences.getString(mContext.getString(R.string.pref_notification_vibrate_min_level), String.valueOf(Status.MEDIUM.ordinal())));
boolean higherLevelThanThreshold = Status.MEDIUM.ordinal() <= thresholdLevel;
if (vibrationEnabled && higherLevelThanThreshold) {
Vibrator v = (Vibrator) mContext.getSystemService(Context.VIBRATOR_SERVICE);
v.vibrate(100);
}
// Short sound:
// TODO see issue #15
}
});
}
/**
* This checks if a cell with a given CID already exists in the {@link Import} realm.
*/
public boolean openCellExists(Realm realm, int cellID) {
return realm.where(Import.class).equalTo("cellId", cellID).count() > 0;
}
/**
* Check if {@link BaseTransceiverStation#cellId CID} and {@link BaseTransceiverStation#locationAreaCode LAC} is already in {@link BaseTransceiverStation} realm
*/
public boolean cellInDbiBts(Realm realm, int lac, int cellID) {
long count = realm.where(BaseTransceiverStation.class)
.equalTo("locationAreaCode", lac)
.equalTo("cellId", cellID)
.count();
return count > 0;
}
/**
* Check if {@link BaseTransceiverStation#cellId CID} is already in the {@link Measure} realm
*
* @param realm The realm to use
* @param cellId The {@link BaseTransceiverStation#cellId cellId} to look for
* @return true if a {@link Measure} is found with the given cellId
*/
public boolean cellInDbiMeasure(Realm realm, int cellId) {
long count = realm.where(Measure.class)
.equalTo("baseStation.cellId", cellId)
.count();
return count > 0;
}
}