/* * Copyright (c) 2017. Mathias Ciliberto, Francisco Javier OrdoƱez Morales, * Hristijan Gjoreski, Daniel Roggen * * Permission is hereby granted, free of charge, to any person obtaining a copy of * this software and associated documentation files (the "Software"), to deal in * the Software without restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do so, * subject to the following conditions: * * The above copyright notice and this permission notice shall be included in all * copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */ package uk.ac.sussex.wear.android.datalogger.collector; import android.content.Context; import android.os.Handler; import android.os.SystemClock; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.SignalStrength; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.util.Log; import java.io.File; import java.util.Date; import uk.ac.sussex.wear.android.datalogger.log.CustomLogger; public class Depr_CellsInfoDataCollector extends AbstractDataCollector { private static final String TAG = Depr_CellsInfoDataCollector.class.getSimpleName(); private CustomLogger logger = null; // The telephony manager reference private TelephonyManager mTelephonyManager = null; // Listener class for monitoring changes in telephony states private CellInfoListener mCellInfoListener = null; // Timer to manage specific sampling rates private Handler mTimerHandler = null; private Runnable mTimerRunnable = null; public Depr_CellsInfoDataCollector(Context context, String sessionName, String sensorName, long nanosOffset, int logFileMaxSize){ mSensorName = sensorName; String path = sessionName + File.separator + mSensorName + "_" + sessionName; logger = new CustomLogger(context, path, sessionName, mSensorName, "txt", false, mNanosOffset, logFileMaxSize); //Object to provide access to information about the telephony services on the device mTelephonyManager = (TelephonyManager) context.getSystemService(Context.TELEPHONY_SERVICE); // Offset to match timestamps both in master and slaves devices mNanosOffset = nanosOffset; mCellInfoListener = new CellInfoListener(); } @Override public void start() { Log.i(TAG, "start:: Starting listener for sensor: " + getSensorName()); logger.start(); mTelephonyManager.listen(mCellInfoListener, PhoneStateListener.LISTEN_SIGNAL_STRENGTHS); } @Override public void stop() { Log.i(TAG,"stop:: Stopping listener for sensor " + getSensorName()); mTelephonyManager.listen(mCellInfoListener, PhoneStateListener.LISTEN_NONE); logger.stop(); } @Override public void haltAndRestartLogging() { logger.stop(); logger.resetByteCounter(); logger.start(); } @Override public void updateNanosOffset(long nanosOffset) { mNanosOffset = nanosOffset; } private static String networkTypeGeneral(int networkType) { switch (networkType) { case TelephonyManager.NETWORK_TYPE_EHRPD: case TelephonyManager.NETWORK_TYPE_LTE: return "4G"; case TelephonyManager.NETWORK_TYPE_HSDPA: case TelephonyManager.NETWORK_TYPE_HSPA: case TelephonyManager.NETWORK_TYPE_HSPAP: case TelephonyManager.NETWORK_TYPE_HSUPA: case TelephonyManager.NETWORK_TYPE_UMTS: return "3G"; case TelephonyManager.NETWORK_TYPE_EDGE: case TelephonyManager.NETWORK_TYPE_GPRS: case TelephonyManager.NETWORK_TYPE_IDEN: return "2G"; case TelephonyManager.NETWORK_TYPE_1xRTT: case TelephonyManager.NETWORK_TYPE_CDMA: case TelephonyManager.NETWORK_TYPE_EVDO_0: case TelephonyManager.NETWORK_TYPE_EVDO_A: case TelephonyManager.NETWORK_TYPE_EVDO_B: return "CDMA"; case TelephonyManager.NETWORK_TYPE_UNKNOWN: default: return "Unknown"; } } private String getCellInfoString(SignalStrength signalStrength) { // Timestamp in system nanoseconds since boot, including time spent in sleep. long nanoTime = SystemClock.elapsedRealtimeNanos() + mNanosOffset; // System local time in millis long currentMillis = (new Date()).getTime(); String message = String.format("%s", currentMillis) + ";" + String.format("%s", nanoTime) + ";" + String.format("%s", mNanosOffset) + ";"; CellLocation cell = mTelephonyManager.getCellLocation(); if (cell instanceof GsmCellLocation) { int lac, cid, dbm; lac = ((GsmCellLocation) cell).getLac(); cid = ((GsmCellLocation) cell).getCid(); String generalNetworkType = networkTypeGeneral(mTelephonyManager.getNetworkType()); // "SignalStrength: mGsmSignalStrength mGsmBitErrorRate mCdmaDbm mCdmaEcio mEvdoDbm // mEvdoEcio mEvdoSnr mLteSignalStrength mLteRsrp mLteRsrq mLteRssnr mLteCqi // (isGsm ? "gsm|lte" : "cdma")); String ssignal = signalStrength.toString(); String[] parts = ssignal.split(" "); // If the signal is not the right signal in db (a signal below -2) fallback // Fallbacks will be triggered whenever generalNetworkType changes if (generalNetworkType.equals("4G")) { dbm = Integer.parseInt(parts[11]); if (dbm >= -2) { if (Integer.parseInt(parts[3]) < -2) { dbm = Integer.parseInt(parts[3]); } else { dbm = signalStrength.getGsmSignalStrength(); } } } else if (generalNetworkType.equals("3G")) { dbm = Integer.parseInt(parts[3]); if (dbm >= -2) { if (Integer.parseInt(parts[11]) < -2) { dbm = Integer.parseInt(parts[11]); } else { dbm = signalStrength.getGsmSignalStrength(); } } } else { dbm = signalStrength.getGsmSignalStrength(); if (dbm >= -2) { if (Integer.parseInt(parts[3]) < -2) { dbm = Integer.parseInt(parts[3]); } else { dbm = Integer.parseInt(parts[11]); } } } // Returns the numeric name (MCC+MNC) of current registered operator. String mccMnc = mTelephonyManager.getNetworkOperator(); String mcc, mnc; if (mccMnc != null && mccMnc.length() >= 4) { mcc = mccMnc.substring(0, 3); mnc = mccMnc.substring(3); } else { mcc = "NaN"; mnc = "NaN"; } if (dbm < -2) { message += mTelephonyManager.getNetworkType() + ";" + cid + ";" + lac + ";" + dbm + ";" + mcc + ";" + mnc; } else { message += mTelephonyManager.getNetworkType() + ";" + cid + ";" + lac + ";" + "NaN" + ";" + mcc + ";" + mnc; } } // // Deprecated behavior, not collecting data // List<NeighboringCellInfo> neighboringCellInfoList = mTelephonyManager.getNeighboringCellInfo(); // for (NeighboringCellInfo neighboringCellInfo : neighboringCellInfoList){ // } return message; } private void logCellInfo(String message){ if (logger != null) { Log.d(TAG,message); logger.log(message); logger.log(System.lineSeparator()); } } /** * A listener class for monitoring changes in specific telephony states on the device, * including service state, signal strength, message waiting indicator (voicemail), and others. */ private class CellInfoListener extends PhoneStateListener { @Override public void onSignalStrengthsChanged(SignalStrength signalStrength) { super.onSignalStrengthsChanged(signalStrength); logCellInfo(getCellInfoString(signalStrength)); } } }