/** * */ package com.uc.dca.service; import java.io.IOException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Date; import java.util.HashMap; import java.util.List; import org.apache.http.NameValuePair; import org.apache.http.message.BasicNameValuePair; import org.json.JSONException; import org.json.JSONObject; import com.uc.dca.util.HttpHandler; import com.uc.dca.content.IncidentReport; import android.app.Service; import android.content.BroadcastReceiver; import android.content.ContentValues; import android.content.Context; import android.content.Intent; import android.content.IntentFilter; import android.location.Location; import android.location.LocationManager; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.net.Uri; import android.net.NetworkInfo.DetailedState; import android.net.wifi.WifiInfo; import android.net.wifi.WifiManager; import android.os.BatteryManager; import android.os.Binder; import android.os.IBinder; import android.telephony.CellLocation; import android.telephony.PhoneStateListener; import android.telephony.ServiceState; import android.telephony.TelephonyManager; import android.telephony.gsm.GsmCellLocation; import android.util.Log; import android.widget.Toast; /** * @author muthu * */ public class IRService extends Service { static private final String TAG = "IRService"; private final IBinder localBinder = new LocalBinder(); private PhoneStateListener phoneStateListener; private TelephonyManager telephonyManager; private LocationManager locationManager; private WifiManager wifiManager; private String batteryInfo; private BroadcastReceiver batteryChangedReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { // TODO Auto-generated method stub int level = intent.getIntExtra("level", 0); batteryInfo = "Battery Level = "+String.valueOf(level) + "%"; Log.i("BatteryStatus: ", batteryInfo); int health = intent.getIntExtra("health", BatteryManager.BATTERY_HEALTH_UNKNOWN); switch (health){ case BatteryManager.BATTERY_HEALTH_GOOD: batteryInfo = batteryInfo.concat(" Health = Good"); break; case BatteryManager.BATTERY_HEALTH_DEAD: batteryInfo = batteryInfo.concat(" Health = Dead"); break; case BatteryManager.BATTERY_HEALTH_OVER_VOLTAGE: batteryInfo = batteryInfo.concat(" Health = OverVoltage"); break; case BatteryManager.BATTERY_HEALTH_OVERHEAT: batteryInfo = batteryInfo.concat(" Health = Overheat"); break; case BatteryManager.BATTERY_HEALTH_UNKNOWN: batteryInfo = batteryInfo.concat(" Health = Unknown"); break; case BatteryManager.BATTERY_HEALTH_UNSPECIFIED_FAILURE: batteryInfo = batteryInfo.concat(" Health = Unspecified Failure"); break; } } }; /** * Class for clients to access. Because we know this service always runs in * the same process as its clients, we don't need to deal with IPC. */ public class LocalBinder extends Binder { public IRService getService() { return IRService.this; } } /* * (non-Javadoc) * * @see android.app.Service#onBind(android.content.Intent) */ @Override public IBinder onBind(Intent intent) { // TODO Auto-generated method stub return localBinder; } /* * (non-Javadoc) * * @see android.app.Service#onStart(android.content.Intent, int) */ @Override public void onStart(Intent intent, int startId) { // TODO Auto-generated method stub super.onStart(intent, startId); startIncidentReports(startId); } /* (non-Javadoc) * @see android.app.Service#onCreate() */ @Override public void onCreate() { // TODO Auto-generated method stub super.onCreate(); this.registerReceiver(batteryChangedReceiver, new IntentFilter( Intent.ACTION_BATTERY_CHANGED)); } /* (non-Javadoc) * @see android.app.Service#onDestroy() */ @Override public void onDestroy() { // TODO Auto-generated method stub super.onDestroy(); this.unregisterReceiver(batteryChangedReceiver); } /** * */ private void initManagers() { telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); locationManager = (LocationManager) getSystemService(LOCATION_SERVICE); wifiManager = (WifiManager) getSystemService(WIFI_SERVICE); } /** * @param startId */ private void startIncidentReports(int startId) { Log.i(TAG, "Service started - " + startId); if (null == phoneStateListener) { initManagers(); registerPhoneStateListener(); } } private void registerPhoneStateListener() { Log.i(TAG, "PhoneStateListener registered with TelephonyManager "); phoneStateListener = new PhoneStateListener() { /* * (non-Javadoc) * * @see android.telephony.PhoneStateListener#onCallStateChanged(int, * java.lang.String) */ @Override public void onCallStateChanged(int state, String incomingNumber) { // TODO Auto-generated method stub super.onCallStateChanged(state, incomingNumber); Log .i("onCallStateChanged: ", " ==> =================================================================== <=="); switch (state) { case TelephonyManager.CALL_STATE_IDLE: Log.i("onCallStateChanged: ", "==> No Call Activity"); storeCallStateChange("IDLE - No Call activity."); break; case TelephonyManager.CALL_STATE_OFFHOOK: Log.i("onCallStateChanged: ", "==> Call in Progress"); storeCallStateChange("OFF-HOOK - At least one call exists that is dialing, active, or on hold, and no calls are ringing or waiting."); break; case TelephonyManager.CALL_STATE_RINGING: Log .i("onCallStateChanged: ", "==> Incoming Call - Ringing"); storeCallStateChange("RINGING - A new call arrived and is ringing or waiting. In the latter case, another call is already active."); break; } Log .i("onCallStateChanged: ", " ==> =================================================================== <=="); } /* * (non-Javadoc) * * @see android.telephony.PhoneStateListener#onCellLocationChanged * (android.telephony.CellLocation) */ @Override public void onCellLocationChanged(CellLocation location) { // TODO Auto-generated method stub super.onCellLocationChanged(location); GsmCellLocation gsmCellLocation = (GsmCellLocation) location; Log.i("onCellLocationChanged: ", gsmCellLocation.getCid() + " <==> " + gsmCellLocation.getLac()); } /* * (non-Javadoc) * * @see * android.telephony.PhoneStateListener#onDataConnectionStateChanged * (int) */ @Override public void onDataConnectionStateChanged(int state) { // TODO Auto-generated method stub super.onDataConnectionStateChanged(state); Log .i("onDataConnectionStateChanged: ", " ==> =================================================================== <=="); switch (state) { case TelephonyManager.DATA_DISCONNECTED: Log.i("onDataConnectionStateChanged: ", "==> Data is DISCONNECTED"); storeDataConnectionStateChange("DISCONNECTED"); break; case TelephonyManager.DATA_CONNECTED: Log.i("onDataConnectionStateChanged: ", "==> Data is CONNECTED"); storeDataConnectionStateChange("CONNECTED"); break; case TelephonyManager.DATA_CONNECTING: Log.i("onDataConnectionStateChanged: ", "==> Data is CONNECTING"); storeDataConnectionStateChange("CONNECTING"); break; case TelephonyManager.DATA_SUSPENDED: Log.i("onDataConnectionStateChanged: ", "==> Data is SUSPENDED"); storeDataConnectionStateChange("SUSPENDED"); break; } // collectTelephonyManagerStats(); Log .i("onDataConnectionStateChanged: ", " ==> =================================================================== <=="); } /* * (non-Javadoc) * * @see android.telephony.PhoneStateListener#onServiceStateChanged * (android.telephony.ServiceState) */ @Override public void onServiceStateChanged(ServiceState serviceState) { // TODO Auto-generated method stub super.onServiceStateChanged(serviceState); Log .i("onServiceStateChanged: ", " ==> =================================================================== <=="); storeServiceStateChange(serviceState); Log .i("onServiceStateChanged: ", " ==> =================================================================== <=="); } /* * (non-Javadoc) * * @see android.telephony.PhoneStateListener#onSignalStrengthChanged * (int) */ @Override public void onSignalStrengthChanged(int asu) { // TODO Auto-generated method stub super.onSignalStrengthChanged(asu); storeSignalStrengthChange(asu); } /* * (non-Javadoc) * * @seeandroid.telephony.PhoneStateListener# * onCallForwardingIndicatorChanged(boolean) */ @Override public void onCallForwardingIndicatorChanged(boolean cfi) { // TODO Auto-generated method stub super.onCallForwardingIndicatorChanged(cfi); } /* * (non-Javadoc) * * @see android.telephony.PhoneStateListener#onDataActivity(int) */ @Override public void onDataActivity(int direction) { // TODO Auto-generated method stub super.onDataActivity(direction); } /* * (non-Javadoc) * * @seeandroid.telephony.PhoneStateListener# * onMessageWaitingIndicatorChanged(boolean) */ @Override public void onMessageWaitingIndicatorChanged(boolean mwi) { // TODO Auto-generated method stub super.onMessageWaitingIndicatorChanged(mwi); } }; telephonyManager.listen(phoneStateListener, PhoneStateListener.LISTEN_CALL_STATE | PhoneStateListener.LISTEN_CELL_LOCATION | PhoneStateListener.LISTEN_SERVICE_STATE | PhoneStateListener.LISTEN_SIGNAL_STRENGTH | PhoneStateListener.LISTEN_DATA_CONNECTION_STATE | PhoneStateListener.LISTEN_DATA_ACTIVITY); } private String collectLocationStats() { String currentKnownLocation = null; Location lm = locationManager .getLastKnownLocation(LocationManager.GPS_PROVIDER); if (null == lm) { Log.i("Location: ", " NO LOCATION provided by GPS"); lm = locationManager .getLastKnownLocation(LocationManager.NETWORK_PROVIDER); } if (null == lm) { Log.i("Location: ", " NO LOCATION provided by Network"); } else { currentKnownLocation = lm.toString(); Log.i("Location: ", currentKnownLocation); } return currentKnownLocation; } private String collectWiFiStats() { String info = "WiFi: NOT Connected"; WifiInfo wifiInfo = wifiManager.getConnectionInfo(); wifiInfo.describeContents(); int id = wifiInfo.getNetworkId(); Log.i("WiFiInfo: ", wifiInfo.toString()); if (-1 == id) { Log.i("WiFi: ", "NOT Connected"); } else { Log.i("WiFi: ", "Network id = " + id); info = wifiInfo.toString(); } return info; } private HashMap<String, String> collectConnectivityManagerStats() { HashMap<String, String> stats = new HashMap<String, String>(); ConnectivityManager connectivityManager = (ConnectivityManager) getApplicationContext() .getSystemService(Context.CONNECTIVITY_SERVICE); NetworkInfo networkInfo = connectivityManager .getNetworkInfo(ConnectivityManager.TYPE_MOBILE); DetailedState detailedState = networkInfo.getDetailedState(); Log.i("ConnectivityManager: ", detailedState.toString()); stats.put("Network Detailed State", detailedState.toString()); /* networkInfo = connectivityManager.getActiveNetworkInfo(); Log.i("Connected state: ", networkInfo.getState().toString()); */ if (networkInfo.isConnected()) { Log.i("Connected: ", networkInfo.toString()); stats.put("Network Info", networkInfo.toString()); } return stats; } /** * @return * */ private HashMap<String, String> collectTelephonyManagerStats() { HashMap<String,String> stats = new HashMap<String, String>(); Log.i("TelephonyManager: ", " ==> Collecting TelephonyManager stats <=="); stats.put("Subscriber Id", telephonyManager.getSubscriberId()); stats.put("Line1 Number", telephonyManager.getLine1Number()); String timenow = SimpleDateFormat.getDateTimeInstance().format(new Date(System.currentTimeMillis())); stats.put("Time", timenow); stats.put("Location", collectLocationStats()); Log.i("TelephonyManager: ", " device id => " + telephonyManager.getDeviceId()); stats.put("Device Id", telephonyManager.getDeviceId()); Log.i("TelephonyManager: ", " device software version => " + telephonyManager.getDeviceSoftwareVersion()); stats.put("Device software version", telephonyManager.getDeviceSoftwareVersion()); stats.putAll(collectConnectivityManagerStats()); stats.put("WiFi", collectWiFiStats()); // todo: collect battery information synchronously for storing in db stats.put("Battery", batteryInfo); Log.i("TelephonyManager: ", " subscriber id => " + telephonyManager.getSubscriberId()); int nt = telephonyManager.getNetworkType(); switch (nt) { case TelephonyManager.NETWORK_TYPE_EDGE: Log.i("TelephonyManager: ", " ==> EDGE Network <=="); stats.put("Network type", "EDGE"); break; case TelephonyManager.NETWORK_TYPE_GPRS: Log.i("TelephonyManager: ", " ==> GPRS Network <=="); stats.put("Network type", "GPRS"); break; case TelephonyManager.NETWORK_TYPE_UMTS: Log.i("TelephonyManager: ", " ==> UMTS Network <=="); stats.put("Network type", "UMTS"); break; case TelephonyManager.NETWORK_TYPE_UNKNOWN: Log.i("TelephonyManager: ", " ==> Unknown Network <=="); stats.put("Network type", "UNKNOWN"); break; } int pt = telephonyManager.getPhoneType(); switch (pt) { case TelephonyManager.PHONE_TYPE_GSM: Log.i("TelephonyManager: ", " ==> PHONE IS GSM TYPE <=="); stats.put("Phone type", "GSM"); break; case TelephonyManager.PHONE_TYPE_NONE: Log.i("TelephonyManager: ", " ==> PHONE TYPE IS UNKNOWN <=="); break; } int ss = telephonyManager.getSimState(); switch (ss) { case TelephonyManager.SIM_STATE_ABSENT: Log.i("TelephonyManager: ", " ==> SIM STATE ABSENT <=="); stats.put("SIM State", "Absent"); break; case TelephonyManager.SIM_STATE_NETWORK_LOCKED: Log.i("TelephonyManager: ", " ==> SIM STATE NETWORK LOCKED <=="); stats.put("SIM State", "Network Locked"); break; case TelephonyManager.SIM_STATE_PIN_REQUIRED: Log.i("TelephonyManager: ", " ==> SIM STATE PIN REQUIRED <=="); stats.put("SIM State", "PIN Required"); break; case TelephonyManager.SIM_STATE_PUK_REQUIRED: Log.i("TelephonyManager: ", " ==> SIM STATE PUK REQUIRED <=="); stats.put("SIM State", "PUK Required"); break; case TelephonyManager.SIM_STATE_READY: Log.i("TelephonyManager: ", " ==> SIM STATE READY <=="); stats.put("SIM State", "Ready"); break; case TelephonyManager.SIM_STATE_UNKNOWN: Log.i("TelephonyManager: ", " ==> SIM STATE UNKNOWN <=="); stats.put("SIM State", "Unknown"); break; } int da = telephonyManager.getDataActivity(); switch (da) { case TelephonyManager.DATA_ACTIVITY_IN: Log.i("TelephonyManager: ", " ==> Data being Downloaded <=="); break; case TelephonyManager.DATA_ACTIVITY_OUT: Log.i("TelephonyManager: ", " ==> Data being Uploaded <=="); break; case TelephonyManager.DATA_ACTIVITY_INOUT: Log.i("TelephonyManager: ", " ==> Data being Downloaded & Uploaded <=="); break; case TelephonyManager.DATA_ACTIVITY_NONE: Log.i("TelephonyManager: ", " ==> No Data Activity <=="); break; } return stats; } /** * @param serviceState * @return */ private HashMap<String, String> collectServiceStateStats(ServiceState serviceState) { HashMap<String, String>stats = new HashMap<String, String>(); Log.i("ServiceState: ", serviceState.toString()); stats.put("ServiceState", serviceState.toString()); String oplong = serviceState.getOperatorAlphaLong(); stats.put("Operator", oplong); Log.i("ServiceState: ", oplong); Log.i("ServiceState: ", " is roaming => " + serviceState.getRoaming()); stats.put("Roaming", Boolean.toString(serviceState.getRoaming())); Log.i("ServiceState: ", " manual network selection => " + serviceState.getIsManualSelection()); stats.put("Manual Network selection", Boolean.toString(serviceState.getIsManualSelection())); int state = serviceState.getState(); parseSignalState(stats, state); return stats; } /** * @param stats * @param state */ private void parseSignalState(HashMap<String, String> stats, int state) { // signal strength can also be parsed for state // makes separate entry for signal strength here.. might not apply for state // todo: check if this is correct stats.put("Signal Strength", state+"asu"); switch (state) { case ServiceState.STATE_IN_SERVICE: Log.i("ServiceState: ", " ==> IN SERVICE <=="); stats.put("State", "IN SERVICE"); break; case ServiceState.STATE_OUT_OF_SERVICE: Log.i("ServiceState: ", " ==> OUT OF SERVICE <=="); stats.put("State", "OUT OF SERVICE"); break; case ServiceState.STATE_EMERGENCY_ONLY: Log.i("ServiceState: ", " ==> EMERGENCY ONLY <=="); stats.put("State", "EMERGENCY ONLY"); break; case ServiceState.STATE_POWER_OFF: Log.i("ServiceState: ", " ==> POWER OFF <=="); stats.put("State", "POWER OFF"); break; } } /** * @param serviceState */ private void storeServiceStateChange(ServiceState serviceState) { Log.i("IRService#storeServiceStateChange: ", " ==> Collecting ServiceState stats <=="); HashMap<String,String> stats = new HashMap<String, String>(); stats.put("Event", "Service State Change"); stats.putAll(collectTelephonyManagerStats()); stats.putAll(collectServiceStateStats(serviceState)); storeStatsInDB(stats); } private void storeDataConnectionStateChange (String reason){ HashMap<String,String> stats = new HashMap<String, String>(); stats.put("Event", "DataConnection State Change"); stats.put("Data Connection", reason); stats.putAll(collectTelephonyManagerStats()); storeStatsInDB(stats); } /** * @param asu */ private void storeSignalStrengthChange(int asu) { HashMap<String, String> stats = new HashMap<String, String>(); stats.put("Event", "Signal Strength Change"); parseSignalState(stats, asu); stats.putAll(collectTelephonyManagerStats()); storeStatsInDB(stats); } private void storeCallStateChange (String reason){ HashMap<String,String> stats = new HashMap<String, String>(); stats.put("Event", "Call State Change"); stats.put("Call State", reason); stats.putAll(collectTelephonyManagerStats()); storeStatsInDB(stats); } /** * @param stats */ private void storeStatsInDB(HashMap<String, String> stats) { JSONObject serviceStateDetails = new JSONObject(stats); ContentValues contentValues = new ContentValues(); contentValues.put(IncidentReport.Details.ID, stats.get("Subscriber Id")); try { contentValues.put(IncidentReport.Details.DETAILS, serviceStateDetails.toString(2)); Uri uri = getContentResolver().insert(IncidentReport.Details.CONTENT_URI, contentValues); Log.d("IRService#storeStatsInDB: ", uri.toString()); } catch (JSONException e) { // TODO Auto-generated catch block e.printStackTrace(); Log.e(TAG, "IRService#storeStatsInDB: failed to extract JSON data"); } // also uploads to server - realtime // todo: change this to timed update uploadStatsToServer(stats); } private void uploadStatsToServer (HashMap<String, String> stats){ HttpHandler httpHandler = new HttpHandler(); List<NameValuePair> nvps = new ArrayList<NameValuePair>(); try { JSONObject serviceStateDetails = new JSONObject(stats); nvps.add(new BasicNameValuePair("content", serviceStateDetails.toString(2))); String response = httpHandler.post("http://ibt.appspot.com/upload", nvps); Log.i(TAG, ">"+response+"<"); if ("OK".equalsIgnoreCase(response.trim())) { Log.i(TAG, "Successfully Uploaded to Server"); } else { Log.e(TAG, "Failed to Upload to Server"); } } catch (IOException e) { Log.e(TAG, e.getMessage(), e); } catch (JSONException e) { Log.e(TAG, e.getMessage(), e); } } }