Java tutorial
/* * TeleStax, Open Source Cloud Communications * Copyright 2011-2016, Telestax Inc and individual contributors * by the @authors tag. * * This program is free software: you can redistribute it and/or modify * under the terms of the GNU Affero General Public License as * published by the Free Software Foundation; either version 3 of * the License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> * * For questions related to commercial use licensing, please contact sales@telestax.com. * */ package org.restcomm.app.qoslib.Services.Events; import java.io.IOException; import java.net.SocketTimeoutException; import java.net.UnknownHostException; import java.util.ArrayList; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.concurrent.ConcurrentLinkedQueue; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import org.restcomm.app.qoslib.MainService; import org.restcomm.app.qoslib.UtilsOld.TrendStringGenerator; import android.content.SharedPreferences; import android.content.pm.PackageManager.NameNotFoundException; import android.database.Cursor; import android.location.Location; import android.net.Uri; import android.preference.PreferenceManager; import android.provider.BaseColumns; import org.restcomm.app.utillib.ContentProvider.Tables; import org.restcomm.app.utillib.ContentProvider.UriMatch; import org.restcomm.app.utillib.CoverageSamples.CoverageSamplesSend; import org.restcomm.app.utillib.DataObjects.PhoneState; import org.restcomm.app.utillib.Reporters.ReportManager; import org.restcomm.app.utillib.Reporters.ReportManager.EventKeys; import org.restcomm.app.utillib.Reporters.LocalStorageReporter.LocalStorageReporter.Events; import org.restcomm.app.utillib.DataObjects.DeviceInfo; import org.restcomm.app.utillib.Utils.DeviceInfoOld; import org.restcomm.app.utillib.DataObjects.EventType; import org.restcomm.app.utillib.Utils.LoggerUtil; import org.restcomm.app.utillib.Utils.PreferenceKeys; import org.restcomm.app.utillib.DataObjects.EventData; import org.restcomm.app.utillib.DataObjects.EventDataEnvelope; import org.restcomm.app.utillib.DataObjects.EventCouple; import org.restcomm.app.utillib.DataObjects.EventObj; import org.restcomm.app.utillib.DataObjects.EventTypeGenre; import com.google.gson.Gson; import org.restcomm.app.qoslib.R; /** * This class can be used to upload an event to the server. Everything in this * class happens in a separate thread. * @author Brad * */ public class EventUploader implements Runnable { /** * This is the maximum time (in milliseconds) after an event occurs that the location * received would be considered valid for the event. * This means than for an event that occurs at timestamp T (in milliseconds) would use as * its location the first location received in the interval (T, T+{@value #EVENT_LOCATION_MAXIMUM_TIME_OFFSET}] * (in milliseconds). */ public static final int EVENT_LOCATION_MAXIMUM_TIME_OFFSET = 180000; //in milliseconds /** * This is the maximum time (in milliseconds) before or after an event occurs that the base station * received would be considered valid for the event. * This means than for an event that occurs at timestamp T (in milliseconds) would use as * its base station the closest location received (temporally) in the interval * (T-{@value #EVENT_LOCATION_MAXIMUM_TIME_OFFSET}, T+{@value #EVENT_LOCATION_MAXIMUM_TIME_OFFSET}] (in milliseconds). */ public static final int EVENT_BASE_STATION_MAXIMUM_TIME_OFFSET = 180000; //in milliseconds private static final String TAG = EventUploader.class.getSimpleName(); public EventObj event = null; // so that scheduler can check if event = null private EventObj complimentaryEvent = null; private List<EventCouple> ongoingEventCouples = null; public MainService owner = null; private boolean bReportLinux = false; private TrendStringGenerator trendStringGenerator = new TrendStringGenerator(); /** * Constructor */ public EventUploader(EventObj _event, EventObj _complimentaryEvent, MainService context, boolean bLocal) { this.ongoingEventCouples = context.getEventManager().getOngoingEventCouples(); this.event = _event; this.complimentaryEvent = _complimentaryEvent; // hold reference to this event until event is sent this.owner = context; // decide whether to report event yet, set event = null to postpone if (bLocal) // not being sent to server yet, don't postpone return; // IF TRYING TO SEND FIRST PART OF COUPLE, POSTPONE UNTIL 2ND PART OF COUPLE IS READY /* * If the complimentary event is null or its uri is null, then this event is either a * singleton or it is the starting end of an event couple. In the later case, * the event should not be uploaded to the server just yet. */ //iterate over the ongoing event couples if the complimentaryEvent is null or its uri is null if (_complimentaryEvent == null) { if (ongoingEventCouples != null && _event != null) { for (EventCouple eventCouple : ongoingEventCouples) { //check if this event is the "starting end" of an event couple //if so, then this is not the right time to be uploading this event if (eventCouple.getStartEventType() == _event.getEventType()) { //this is not the right time to be uploading this event event = null; return; } } } } // NO start-of-couple is going to get uploaded by itself // (should have been caught above, except can happen if end-of-couple is 'on stage' and was removed from ongoing if (_event != null && _event.getEventType().getGenre() == EventTypeGenre.START_OF_COUPLE) { event = null; return; } } @Override public void run() { report(false, null); // report not local (to internet) } public void report(boolean local, Location location) { try { //now create a list of eventData variables List<EventData> eventDataList = new ArrayList<EventData>(); String strPhone = ""; long duration = 0; EventDataEnvelope eventDataEnvelope = null; if (event != null) { // Dont send an unconfirmed Travel event if (event.getEventType() == EventType.TRAVEL_CHECK && owner.getTravelDetector().isConfirmed() == false) { LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "report", "skip unconfirmed travel event"); return; } EventData eventData = generateEventDataFromEvent(event, local); if (eventData == null) return; //MMCLogger.logToFile(MMCLogger.Level.DEBUG, TAG, "run", "reporting event type=" + event.getEventType() + ",lat:" + eventData.getFltEventLat() + ",local=" + local); if (eventData.getFltEventLat() == 0 && location != null) { eventData.setFltEventLat((float) location.getLatitude()); eventData.setFltEventLng((float) location.getLongitude()); eventData.setiUncertainty((int) location.getAccuracy()); } eventData.setCallID(event.getLocalID()); EventData eventData2 = null; eventDataList.add(eventData); if (event.getEventType() == EventType.APP_MONITORING && event.getDownloadSpeed() > 0 && event.getUploadSpeed() > 0) { //App throughput was getting stored twice boolean stored = PreferenceManager.getDefaultSharedPreferences(owner) .getBoolean(PreferenceKeys.Miscellaneous.THROUGHPUT_STORED, false); if (!stored) { owner.getReportManager().storeEvent(eventData); PreferenceManager.getDefaultSharedPreferences(owner).edit() .putBoolean(PreferenceKeys.Miscellaneous.THROUGHPUT_STORED, true).commit(); } else PreferenceManager.getDefaultSharedPreferences(owner).edit() .putBoolean(PreferenceKeys.Miscellaneous.THROUGHPUT_STORED, false).commit(); ; } if (event.getEventType() == EventType.MAN_PLOTTING) { eventData.setLookupid1(event.getBuildingID()); eventData.setRunningApps(event.getAppData()); // contains user's polyline } // Event is 'reported' locally before GPS sampling is complete // to make it show up on the map as soon as it gets a first fix //if (local == true && ((event.getEventType() != EventType.MAN_SPEEDTEST && event.getEventType() != EventType.LATENCY_TEST && event.getEventType() != EventType.APP_MONITORING) || event.latency != 0)) //if (local == true && (event.getEventType().waitsForSpeed() == false || event.getLatency() != 0)) // (local == false && event.getEventType() == EventType.MAN_SPEEDTEST)) // but for speedtest, wait until complete if ((event.getEventType().waitsForSpeed() == false || event.getLatency() != 0)) { if (event.getLocalID() > 0 && eventData.getFltEventLng() != 0) { owner.getReportManager().updateEventField(event.getLocalID(), Events.KEY_LATITUDE, String.valueOf(eventData.getFltEventLat())); owner.getReportManager().updateEventField(event.getLocalID(), Events.KEY_LONGITUDE, String.valueOf(eventData.getFltEventLng())); } else if (event.getLocalID() == 0) { int evtID = owner.getReportManager().storeEvent(eventData); // .reportEvent (eventData, event, local, location); event.setLocalID(evtID); eventData.setCallID(evtID); } if (complimentaryEvent != null) { if (complimentaryEvent.getLocalID() > 0 && location != null) { owner.getReportManager().updateEventField(complimentaryEvent.getLocalID(), Events.KEY_LATITUDE, String.valueOf(location.getLatitude())); owner.getReportManager().updateEventField(complimentaryEvent.getLocalID(), Events.KEY_LONGITUDE, String.valueOf(location.getLongitude())); } else if (complimentaryEvent.getLocalID() == 0) { int evtID = owner.getReportManager().storeEvent(eventData); //(eventData2, complimentaryEvent, local, location); complimentaryEvent.setLocalID(evtID); } } } if (local) return; //if the complimentary event is not null, then this event must be //the "starting end" of an event couple. If so, then this event should //be uploaded alongside the main event if (complimentaryEvent != null && local == false) { eventData2 = generateEventDataFromEvent(complimentaryEvent, local); if (eventData2 != null) { //complimentaryEvent.setFlag (EventObj.SERVER_SENDING, true); eventData2.setCallID(complimentaryEvent.getLocalID()); eventDataList.add(eventData2); } } //now create the eventDataEnvelope to wrap the list of eventData variables //along with other required variables String phoneNumFirst4 = ""; if (strPhone != null && strPhone.length() > 4) phoneNumFirst4 = strPhone.substring(0, 4); eventDataEnvelope = generateEventDataEnvFromEventList(eventDataList, phoneNumFirst4); // when event is filled in, travel and fillin would like to see it before sending if (owner.isServiceRunning() && owner.getTravelDetector() != null) owner.getTravelDetector().eventCompleted(event); } else // null event create dummy event envelope to trigger sending the event queue (without adding a new event) eventDataEnvelope = new EventDataEnvelope(); boolean bSent = false, bFromQueue = false, bAddedQueue = false; loadEventsQueue(); // only loads if queue hasn't loaded yet (ensure loaded) ConcurrentLinkedQueue<EventDataEnvelope> eventQueue = owner.getEventManager().getEventQueue(); // Send this event and any other events that were in the queue, as long as it didn't fail to send while (eventDataEnvelope != null) { bSent = uploadEventEnvelope(eventDataEnvelope, bFromQueue); // as long as event was sent to server, it sent (even if server had an error) if (!bSent) { //if (!bFromQueue) { bAddedQueue = true; eventQueue.add(eventDataEnvelope); while (eventQueue.size() > 200) eventQueue.poll(); } break; } else { eventDataEnvelope = eventQueue.poll(); bFromQueue = true; } } // persist the queue every 3 hrs in case something happens if (event != null && (event.isCheckin || bAddedQueue)) saveEvents(eventQueue); } finally { if (!local) { //LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "report(false)", "uploadingEvent(false)"); owner.uploadingEvent(false); } } } /* * Uploads the EVentEnvelope as a JSON packet using wsManager * and then updates that event in the database with the result of sending * return bSent = true if it reaches the server */ private boolean uploadEventEnvelope(EventDataEnvelope eventDataEnvelope, boolean queued) { //now upload the eventDataEnvelope to the server int eventTypeId = 0; int eventId = 0; EventType eventType = null; EventData eventData = null; int eventFlags = 0; boolean bForceSend = false; // if this is just a dummy event, pretend it was sent so it goes on to the next queued event if (eventDataEnvelope.getlStartTime() == 0l) return true; Iterator<EventData> iterator = null; try { iterator = eventDataEnvelope.getoEventData().iterator(); // Last chance to update fields on an event before its about to be sent to server // read the event from the disk-based SQLite events database to see if the event type changed due to dropped call confirmation for (; iterator.hasNext();) { eventData = iterator.next(); eventTypeId = eventData.getEventType(); eventType = EventType.get(eventTypeId); eventId = (int) eventData.getCallID(); // local SQLite database id of the event eventFlags = eventData.getFlags(); if (eventId > 0 && (eventTypeId == 4 || eventTypeId == 6 || eventTypeId == 1 || eventTypeId == 7)) { HashMap<String, String> event = ReportManager.getInstance(owner).getEventDetails(eventId); if (event != null && event.containsKey(EventKeys.RATING)) { int newType = Integer.parseInt(event.get(EventKeys.TYPE)); int rating = Integer.parseInt(event.get(EventKeys.RATING)); eventData.setEventType(newType); eventData.setEventIndex(rating); } } if (eventType == EventType.MAN_SPEEDTEST || eventType == EventType.EVT_STARTUP || eventType == EventType.EVT_SHUTDOWN) bForceSend = true; // Force send TroubleTweets else if (eventType.getIntValue() >= 30 && eventType.getIntValue() <= 39) bForceSend = true; else if (eventType == EventType.EVT_VQ_CALL || eventType == EventType.VIDEO_TEST || eventType == EventType.AUDIO_TEST || eventType == EventType.WEBPAGE_TEST) bForceSend = true; } } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "uploadEventEnvelope", "exception reading the event type", e); return true; } boolean bSent = false; boolean allowRoaming = PreferenceManager.getDefaultSharedPreferences(owner) .getBoolean(PreferenceKeys.Miscellaneous.DATA_ROAMING, false); boolean defaultWifi = false; String noConfirm = (owner.getResources().getString(R.string.WIFI_DEFAULT)); if (noConfirm.equals("1")) defaultWifi = true; // don't even allow confirmation buttons on drilled down event boolean sendOnWifi = PreferenceManager.getDefaultSharedPreferences(owner) .getBoolean(PreferenceKeys.Miscellaneous.SEND_ON_WIFI, defaultWifi); int resultflag = EventObj.SERVER_ERROR; if (queued && (eventType == EventType.TRAVEL_CHECK || eventType == EventType.EVT_STARTUP)) { LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "not send queued event of type=" + eventType + " id=" + eventId); return true; } if (!owner.isOnline() || owner.getPhoneState().isCallConnected()) // if no connectivity, send event be sent later? { resultflag = EventObj.SERVER_NODATA; if (!owner.isOnline()) LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "offline, unable to send event type=" + eventType + " id=" + eventId); else if (owner.getPhoneState().isCallConnected()) LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "call in progress, not yet sending event type=" + eventType + " id=" + eventId); } else if (!owner.isServiceRunning() && eventType != EventType.EVT_SHUTDOWN) { resultflag = EventObj.SERVER_NODATA; LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "service was stopped, queueing event " + eventType + " id=" + eventId); } else if (!allowRoaming && owner.getPhoneState().isRoaming() && !PhoneState.isNetworkWifi(owner) && !bForceSend) { resultflag = EventObj.SERVER_NODATA; LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "roaming no-wifi, unable to send event type=" + eventType + " id=" + eventId); } else if (sendOnWifi && !PhoneState.isNetworkWifi(owner) && !bForceSend) { resultflag = EventObj.SERVER_NODATA; LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "queuing no-wifi, unable to send event type=" + eventType + " id=" + eventId); } else { String responseJSON = null; //synchronized (owner) { try { int allowSpeedTest = 0; if (!PhoneState.isNetworkWifi(owner) && !queued) allowSpeedTest = owner.getUsageLimits().allowSpeedTest(100000); eventDataEnvelope.setAllowSpeedTest(allowSpeedTest); //MMCLogger.logToFile(MMCLogger.Level.DEBUG, TAG, "run", "uploading staged event type=" + eventType + " id=" + eventId); Gson gson = new Gson(); String eventJSON = gson.toJson(eventDataEnvelope); responseJSON = owner.getReportManager().submitEvent(eventJSON); EventResponse eventResponse = gson.fromJson(responseJSON, EventResponse.class); if (eventResponse != null) { eventResponse.init(); eventResponse.handleEventResponse(owner, false); long[] eventids = eventResponse.getEventIds(); int d = 0; iterator = eventDataEnvelope.getoEventData().iterator(); // Last chance to update fields on an event before its about to be sent to server // read the event from the disk-based SQLite events database to see if the event type changed due to dropped call confirmation for (; iterator.hasNext();) { eventData = iterator.next(); eventId = (int) eventData.getCallID(); // local SQLite database id of the event ReportManager reportManager = ReportManager.getInstance(owner.getApplicationContext()); long svrEventID = eventData.getEventId(); // if (d == 0 && event != null) // svrEventID = event.getEventID(); // if (d == 1 && complimentaryEvent != null) // svrEventID = complimentaryEvent.getEventID(); if (svrEventID == 0) svrEventID = eventids[d]; LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "uploaded eventtype=" + eventType + " eventid=" + svrEventID); reportManager.updateEventField(eventId, "eventid", Long.toString(svrEventID)); if (eventData.getEventType() == EventType.EVT_VQ_CALL.getIntValue() || eventData.getEventType() == EventType.SIP_VQ_CALL.getIntValue() || eventData.getEventType() == EventType.CONNECTION_FAILED.getIntValue()) reportManager.updateEventField(eventId, Events.KEY_TYPE, Integer.toString(eventData.getEventType())); d++; } } resultflag = EventObj.SERVER_SENT; bSent = true; LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "run", "uploaded staged event type=" + eventType + " id=" + eventId); } catch (Exception e) { if (e instanceof UnknownHostException || e instanceof IOException || e instanceof SocketTimeoutException) bSent = false; else bSent = true; LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "uploadEventEnvelope", "exception uploading event type=" + eventType + " id=" + eventId, e); } } } try { eventDataEnvelope.getoEventData(); eventData.setFlags(eventData.getFlags() | resultflag); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "run", "error updating sent event", e); } return bSent; } /** * Loads event requests from storage, and adds it to the queue */ protected void loadEventsQueue() { ConcurrentLinkedQueue<EventDataEnvelope> eventQueue = owner.getEventManager().getEventQueue(); if (eventQueue == null) { eventQueue = new ConcurrentLinkedQueue<EventDataEnvelope>(); owner.getEventManager().setEventQueue(eventQueue); } else return; Gson gson = new Gson(); SharedPreferences secureSettings = MainService.getSecurePreferences(owner); if (secureSettings.contains(PreferenceKeys.Miscellaneous.EVENTS_QUEUE)) { try { String strQueue = secureSettings.getString(PreferenceKeys.Miscellaneous.EVENTS_QUEUE, ""); //LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "loadQueue", strQueue); if (strQueue.length() < 100) return; JSONArray jsonqueue = new JSONArray(strQueue); for (int i = 0; i < jsonqueue.length(); i++) { JSONObject jsonRequest = jsonqueue.getJSONObject(i); //if(jsonRequest.getString("type").equals(EventDataEnvelope.TAG)) { EventDataEnvelope request = gson.fromJson(jsonRequest.toString(), EventDataEnvelope.class); //EventDataEnvelope request = new EventDataEnvelope(jsonRequest); eventQueue.add(request); } } // remove the oldest events until queue is below 1000 while (eventQueue.size() > 300) eventQueue.poll(); } catch (JSONException e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "loadEventsQueue", "JSONException loading events from storage", e); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "loadEventsQueue", "Exception loading events from storage", e); } } } /** * Persists the queue of events to the phone's preferences */ protected void saveEvents(ConcurrentLinkedQueue<EventDataEnvelope> eventQueue) { //JSONArray jsonQueue= new JSONArray(); if (eventQueue == null) return; StringBuffer sb = new StringBuffer(); sb.append("["); Gson gson = new Gson(); // remove the oldest events until queue is below 400 while (eventQueue.size() > 300) eventQueue.poll(); for (EventDataEnvelope eventEnv : eventQueue) { try { String strJSON = gson.toJson(eventEnv); sb.append(strJSON); sb.append(","); //JSONObject evtJSON = new JSONObject(strJSON); //jsonQueue.put(evtJSON); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "persistQueue", "failed to persist event request", e); } } sb.deleteCharAt(sb.length() - 1); sb.append("]"); SharedPreferences preferenceSettings = MainService.getSecurePreferences(owner); String stringQueue = sb.toString();// jsonQueue.toString(); preferenceSettings.edit().putString(PreferenceKeys.Miscellaneous.EVENTS_QUEUE, stringQueue).commit(); } /** * Uses the provided event instance to generate a {@link EventData} instance. * @param _event * @return */ private EventData generateEventDataFromEvent(EventObj _event, boolean local) { Cursor cellDataCursor = null; Cursor locationDataCursor = null; Cursor signalDataCursor = null; boolean bTroubleTweet = false; if (_event.getEventType().getIntValue() >= EventType.TT_DROP.getIntValue() && _event.getEventType().getIntValue() <= EventType.TT_NO_SVC.getIntValue()) bTroubleTweet = true; try { if (!bTroubleTweet) { String accuracyWhere = ""; if (_event.getEventType() == EventType.MAN_PLOTTING || (_event.getFlags() & EventObj.MANUAL_SAMPLES) > 0) { accuracyWhere = " and accuracy = -1 or accuracy = -2"; } else if (_event.getEventType() == EventType.MAN_TRANSIT) { accuracyWhere = " and accuracy = -3 or accuracy = -4"; } else { accuracyWhere = " and accuracy <> -1"; } cellDataCursor = getCellsAssociatedWithEvent(_event); locationDataCursor = getLocationsAssociatedWithEvent(_event, accuracyWhere); signalDataCursor = getSignalStrengthsAssociatedWithEvent(_event); } int MCCMNC[] = owner.getMCCMNC(); int mcc = 0; int mnc = 0; if (MCCMNC != null && MCCMNC.length > 1) { mcc = MCCMNC[0]; mnc = MCCMNC[1]; } int localId = 0; if (_event.getUri() != null) localId = Integer.parseInt(_event.getUri().getLastPathSegment()); //if(owner.getLastMMCSignal() != null) { // Integer signal = owner.getLastMMCSignal().getDbmValue(owner.getNetworkType(), owner.getPhoneType()); //Marking the rssi unknown with -256 // rssi = signal != null ? (int)signal : -256; //} CoverageSamplesSend covSamples = null; String neighbors = ""; String connections = ""; String trend2 = ""; String Stats = ""; String APs = ""; String Apps = ""; String ThroughputStats = ""; String latency = "fail"; long lookupid1 = 0; long lookupid2 = 0; String transitAccel = ""; boolean check = false; if (local == false && !bTroubleTweet) { try { covSamples = trendStringGenerator.generateSamples( //trend string (primary) cellDataCursor, locationDataCursor, signalDataCursor, owner, _event); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "generateEventDataFromEvent", "exception occured trying to generate trend string ", e); } if (locationDataCursor == null || locationDataCursor.getCount() == 0) { // failed to get GPS location, send a little GPS diagnosis boolean gpsEnabled = owner.getGpsManager().isLocationEnabled(); if (!gpsEnabled) trend2 = "GPS=disabled,"; else trend2 = "GPS=enabled,"; } if (_event.getEventType() == EventType.COV_UPDATE) { { int intervalDM = PreferenceManager.getDefaultSharedPreferences(owner) .getInt(PreferenceKeys.Miscellaneous.MANAGE_DATAMONITOR, 0); if (intervalDM > 0) // if enabled { int sleepHandoffs = owner.getUsageLimits().handleCheckin(true); trend2 += "IdleHandoffs=" + sleepHandoffs + ","; SharedPreferences preferenceSettings = PreferenceManager .getDefaultSharedPreferences(owner); int allowDM = preferenceSettings.getInt(PreferenceKeys.Miscellaneous.MANAGE_DATAMONITOR, 0); if (allowDM > 0) { //DataMonitorDBReader dbReader = new DataMonitorDBReader(); //DataMonitorDBWriter dbWriter = new DataMonitorDBWriter(); try { //get Stats, APs, and Apps strings Stats = "[" + owner.getDataMonitorStats().getStatsString() + "]"; APs = "5,type,start,dur,id,sig," + owner.getAccessPointHistory().toString(); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "generateEventDataFromEvent", "exception in getStatsString: ", e); } try { owner.getAccessPointHistory().clearAccessPointsHistory(); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "generateEventDataFromEvent", "exception in clearAccessPointsHistory: ", e); } try { Apps = owner.getDataMonitorStats().getRunningAppsString(true); //cleanup owner.getDataMonitorStats().cleanupStatsDB(); } catch (Exception e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "generateEventDataFromEvent", "exception in getRunningAppsString: ", e); } } } } } if (_event.getEventType() == EventType.MAN_TRANSIT) { lookupid1 = _event.getLookupid1(); lookupid2 = _event.getLookupid2(); Apps = _event.getAppData(); if (lookupid1 == 0 || lookupid2 == 0) return null; } if (_event.getEventType() == EventType.EVT_VQ_CALL) { //Apps = _event.getAppData(); } if (_event.getJSONResult() != null) { _event.setTcpStatsToJSON(); Stats = _event.getJSONResult(); } lookupid2 = _event.getLookupid2(); lookupid1 = _event.getLookupid1(); long startTimestamp = _event.getEventTimestamp() - _event.getEventType().getPreEventStageTime(); //get the starting timestamp of the trend string neighbors = owner.getCellHistory().getNeighborHistory(startTimestamp, _event.getEventTimestamp()); connections = owner.getConnectionHistory().getHistory(startTimestamp, _event.getEventTimestamp(), _event.getStageTimestamp() + 5000, _event); String servicemode = owner.getConnectionHistory().getServiceModeHistory(startTimestamp, _event.getEventTimestamp(), _event.getStageTimestamp() + 5000, _event.getEventType()); if (servicemode != null && servicemode.length() > 10) trend2 = servicemode; } String apiKey = MainService.getApiKey(owner); int iUserID = MainService.getUserID(owner); if (iUserID == 0) iUserID = -1; Location location = _event.getLocation(); if (location == null) { location = new Location(""); if (_event.getEventType() == EventType.MAN_TRANSIT) { String loc = PreferenceManager.getDefaultSharedPreferences(owner).getString("transitEvent", null); if (loc != null) { String[] locs = loc.split(","); int lat = Integer.valueOf(locs[0]); int lon = Integer.valueOf(locs[1]); location = new Location(""); location.setLatitude(lat / 1000000.0); location.setLongitude(lon / 1000000.0); PreferenceManager.getDefaultSharedPreferences(owner).edit().putString("transitEvent", null) .commit(); } } } int bsHigh = 0, bsLow = 0, bsMid = 0, bsCode = 0; if (_event.getCell() != null) { bsHigh = _event.getCell().getBSHigh(); bsLow = _event.getCell().getBSLow(); bsMid = _event.getCell().getBSMid(); bsCode = _event.getCell().getBSCode(); } Integer signalDB = -255; if (_event.getSignal() != null) signalDB = _event.getSignal().getDbmValue(owner.getPhoneState().getNetworkType(), owner.getPhoneState().getPhoneType()); // unknown signal? server sees that as -255 if (signalDB == null || signalDB == 0) signalDB = -255; EventData eventData = new EventData(0, // 1 would allow the server to request an auto speed test _event.getConnectTime(), //ConnectTime "", //phone number owner.getPhoneState().getNetworkOperatorName(), String.format("Android %s,%s,%s", DeviceInfoOld.getManufacturer(), DeviceInfoOld.getPhoneModel(), DeviceInfoOld.getDevice()), _event.getDuration(), // the duration between the event and last complementary event covSamples, // trend string trend2, //trend string (secondary) neighbors, connections, _event.getEventTimestamp() / 1000, location.getTime() / 1000, //timestamp of the gps fix used for this event (will be filled later) 0L, //lStartTime (will be filled later) (float) location.getLongitude(), //fltEventLng is the unscaled latitude (float) location.getLatitude(), //fltEventLat is the unscaled longitude _event.getEventType().getIntValue(), _event.getEventID(), //we don't know the server side event id yet 0L, //This is generated by the server so we don't worry about it just yet (int) _event.getEventIndex(), 0, //sample interval is deprecated (int) location.getAltitude(), //altitude (will be filled later) (int) location.getAccuracy(), //uncertainty (will be filled later) (int) location.getSpeed(), //speed (will be filled later) (int) location.getBearing(), //heading (will be filled later) _event.getSatellites(), //number of satellites signalDB, //signal strengh (will be filled later) bsLow, // cellId at the time of the event bsMid, //nid bsCode, //previous cell (will be filled later) getAppVersionCode(), _event.getBattery(), // battery level 0, // ec/i0 may be filled in later _event.getFlags(), // flags localId, //CallId is internal to the server iUserID, mcc, mnc, bsHigh, //LAC _event.getCause(), // cause of dropped call apiKey, DeviceInfo.getIPAddress(), Stats, APs, Apps, latency, lookupid1, lookupid2); eventData.setAppName(_event.getAppName()); if (_event.getEventType().waitsForSpeed()) { eventData.setLatency(_event.getLatency()); eventData.setDownloadSpeed(_event.getDownloadSpeed()); eventData.setUploadSpeed(_event.getUploadSpeed()); eventData.setDownloadSize(_event.getDownloadSize()); eventData.setUploadSize(_event.getUploadSize()); eventData.setTier(_event.getTier()); if (_event.getEventType() == EventType.LATENCY_TEST && _event.getLatency() < 0) eventData.setDownloadSpeed(-_event.getLatency()); } if (_event.getEventType() == EventType.APP_MONITORING && !local) { if (_event.getAppData() != null) { eventData.setRunningApps(_event.getAppData()); LoggerUtil.logToFile(LoggerUtil.Level.DEBUG, TAG, "generateEventDataFromEvent", "AppData: " + _event.getAppData()); } } if (_event.getEventID() > 0) eventData.setEventId(_event.getEventID()); eventData.setWifi(_event.getWifiInfo(), _event.getWifiConfig()); return eventData; } catch (Exception ex) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "generateEventDataFromEvent", "exception occured trying to generate event data ", ex); } finally { //now close the cursors if (cellDataCursor != null) cellDataCursor.close(); if (locationDataCursor != null) locationDataCursor.close(); if (signalDataCursor != null) signalDataCursor.close(); } return null; } /** * Uses the provided event data list to generate a {@link EventDataEnvelope} instance. * @param eventDataList * @return */ private EventDataEnvelope generateEventDataEnvFromEventList(List<EventData> eventDataList, String phoneNumber) { try { //SharedPreferences serviceSetting = PreferenceManager.getDefaultSharedPreferences(owner); int userID = MainService.getUserID(owner); if (userID <= 0 && !owner.isServiceRunning()) userID = owner.getLastUserID(); // have the userid if the user logged out and service is closing String apikey = MainService.getApiKey(owner); int MCCMNC[] = owner.getMCCMNC(); int mcc = 0; int mnc = 0; if (MCCMNC != null && MCCMNC.length > 1) { mcc = MCCMNC[0]; mnc = MCCMNC[1]; } DeviceInfo mmcdev = owner.getDevice(); EventDataEnvelope eventDataEnvelope = new EventDataEnvelope(0, //qos rating. This is deprecated 0, //deprecated getAppVersionCode(), 0, //TODO 1 if the call was dropped, 0 otherwise 0, //TODO 1 if dataspeed test is allowed, 0 otherwise userID, owner.getPhoneState().getNetworkOperatorName(), String.format(Locale.US, "Android %s,%s,%s", DeviceInfoOld.getManufacturer(), DeviceInfoOld.getPhoneModel(), DeviceInfoOld.getDevice()), eventDataList.get(0).getlTimestamp(), 0, //deprecated 0, //deprecated phoneNumber, DeviceInfoOld.battery, String.format(Locale.US, "Android %d", DeviceInfoOld.getAndroidVersion()), owner.getPhoneState().getPhoneType(), owner.getPhoneState().getNetworkType(), owner.getPhoneState().isRoaming(), DeviceInfo.getIPAddress(), mcc, mnc, mmcdev.getIMSI(), apikey, eventDataList); return eventDataEnvelope; } catch (Exception ex) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "generateEventDataFromEvent", "exception occured trying to generate trend string: " + ex.getMessage()); } return null; } private int getAppVersionCode() { try { return owner.getPackageManager().getPackageInfo(owner.getPackageName(), 0).versionCode; } catch (NameNotFoundException e) { LoggerUtil.logToFile(LoggerUtil.Level.ERROR, TAG, "getAppVersionCode", "Could not find app version" + e.getMessage()); } return -1; } /** * This method gets a cursor that contains all the location objects that are associated with the * given event. * @return */ private Cursor getLocationsAssociatedWithEvent(EventObj _event, String accuracy) { long startTime = _event.getEventTimestamp(); //MMCLogger.logToFile(MMCLogger.Level.DEBUG, TAG, "getLocationsAssociatedWithEvent", "startTime="+startTime); Cursor cursor = owner.getDBProvider().query(UriMatch.LOCATIONS.getContentUri(), null, Tables.Locations.TIMESTAMP + ">=?" + accuracy, new String[] { String.valueOf(startTime) }, Tables.Locations.TIMESTAMP + " ASC"); cursor.moveToFirst(); long gpsTime = 0; if (!cursor.isBeforeFirst()) { gpsTime = cursor.getLong(1); //MMCLogger.logToFile(MMCLogger.Level.DEBUG, TAG, "getLocationsAssociatedWithEvent", "time="+gpsTime); } return cursor; } /** * This method gets a cursor that contains all the baseStation rows that are associated with the given * event. * @return */ private Cursor getCellsAssociatedWithEvent(EventObj _event) { Uri baseStationTable = (UriMatch.BASE_STATIONS.getContentUri() /*owner.getPhoneType() == TelephonyManager.PHONE_TYPE_CDMA ? UriMatch.BASE_STATIONS_CDMA.getContentUri() : UriMatch.BASE_STATIONS_GSM.getContentUri()*/ ); // If we go back to 15 minutes before the event for cellid changes, then it will walk forward to find the latest change before the event long startTime = _event.getEventTimestamp() - _event.getEventType().getPreEventStageTime() - 900000; Cursor cursor = owner.getDBProvider().query(baseStationTable, null, Tables.BaseStations.TIMESTAMP + ">?", new String[] { String.valueOf(startTime) }, Tables.BaseStations.TIMESTAMP + " ASC"); return cursor; } /** * This method gets a cursor that contains all the signal strength rows that are associated with the given * event. It gets signal strength well before event, but only the last one before 30 seconds before event will be the start * @return */ private Cursor getSignalStrengthsAssociatedWithEvent(EventObj _event) { // Single signal strength table now Uri signalStrengthTable = UriMatch.SIGNAL_STRENGTHS.getContentUri(); String[] projection = new String[] { BaseColumns._ID, Tables.TIMESTAMP_COLUMN_NAME, Tables.SignalStrengths.SIGNAL, Tables.SignalStrengths.ECI0, Tables.SignalStrengths.SNR, Tables.SignalStrengths.BER, Tables.SignalStrengths.RSCP, Tables.SignalStrengths.SIGNAL2G, Tables.SignalStrengths.LTE_SIGNAL, Tables.SignalStrengths.LTE_RSRP, Tables.SignalStrengths.LTE_RSRQ, Tables.SignalStrengths.LTE_SNR, Tables.SignalStrengths.LTE_CQI, Tables.SignalStrengths.SIGNALBARS, Tables.SignalStrengths.ECN0, Tables.SignalStrengths.WIFISIGNAL, Tables.SignalStrengths.COVERAGE }; long startTime = _event.getEventTimestamp() - _event.getEventType().getPreEventStageTime() - 300000; Cursor cursor = owner.getDBProvider().query(signalStrengthTable, projection, Tables.SignalStrengths.TIMESTAMP + ">?", new String[] { String.valueOf(startTime) }, Tables.SignalStrengths.TIMESTAMP + " ASC"); return cursor; } }