Java tutorial
/* * ------------------------------------------------------------------------------ * The MIT License (MIT) * * Copyright (c) 2015 Walter Bronzi [wbronzi@gmail.com], [walter.bronzi@uni.lu] * * 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 com.snt.bt.recon.activities; import android.app.Activity; import android.app.AlertDialog; import android.app.NotificationManager; import android.bluetooth.BluetoothAdapter; import android.bluetooth.BluetoothDevice; import android.bluetooth.le.ScanCallback; import android.bluetooth.le.ScanResult; import android.content.BroadcastReceiver; import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentFilter; import android.content.SharedPreferences; import android.content.pm.ActivityInfo; import android.content.pm.PackageInfo; import android.graphics.Color; import android.location.Location; import android.location.LocationListener; import android.location.LocationManager; import android.location.LocationProvider; import android.net.ConnectivityManager; import android.net.NetworkInfo; import android.os.Bundle; import android.os.Handler; import android.os.PowerManager; import android.preference.PreferenceManager; import android.provider.Settings; import android.support.v7.app.AppCompatActivity; import android.telephony.TelephonyManager; import android.text.TextUtils; import android.text.method.ScrollingMovementMethod; import android.util.Log; import android.view.Menu; import android.view.MenuItem; import android.view.View; import android.view.WindowManager; import android.widget.AdapterView; import android.widget.ArrayAdapter; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.ListView; import android.widget.TextView; import android.widget.Toast; import com.google.android.gms.location.DetectedActivity; import com.loopj.android.http.AsyncHttpClient; import com.loopj.android.http.AsyncHttpResponseHandler; import com.loopj.android.http.MySSLSocketFactory; import com.loopj.android.http.RequestParams; import com.snt.bt.bluetoothlelib.device.BluetoothLeDevice; import com.snt.bt.bluetoothlelib.device.adrecord.AdRecord; import com.snt.bt.recon.BuildConfig; import com.snt.bt.recon.R; import com.snt.bt.recon.containers.BluetoothClassicDeviceStore; import com.snt.bt.recon.containers.BluetoothLeDeviceStore; import com.snt.bt.recon.database.BluetoothClassicEntry; import com.snt.bt.recon.database.BluetoothLowEnergyEntry; import com.snt.bt.recon.database.DBHandler; import com.snt.bt.recon.database.Trip; import com.snt.bt.recon.database.GPSLocation; import com.snt.bt.recon.services.BcScanService; import com.snt.bt.recon.util.ActivityRecognitionUtil; import com.snt.bt.recon.util.BluetoothLeScanner; import com.snt.bt.recon.util.BluetoothUtils; import java.text.SimpleDateFormat; import java.util.ArrayList; import butterknife.Bind; import butterknife.ButterKnife; import com.snt.bt.bluetoothlelib.util.ByteUtils; import com.snt.bt.recon.adapters.LeDeviceListAdapter; import com.snt.bt.recon.adapters.BcDeviceListAdapter; import com.snt.bt.recon.util.AppEULA; import com.snt.bt.recon.util.TransportMode; import org.json.JSONArray; import org.json.JSONException; import org.json.JSONObject; import cz.msebera.android.httpclient.Header; import uk.co.alt236.easycursor.objectcursor.EasyObjectCursor; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.List; import java.util.Locale; import java.util.UUID; public class MainActivity extends AppCompatActivity implements AdapterView.OnItemClickListener { @Bind(com.snt.bt.recon.R.id.tvBluetoothLe) protected TextView mTvBluetoothLeStatus; @Bind(com.snt.bt.recon.R.id.tvBluetoothStatus) protected TextView mTvBluetoothStatus; @Bind(R.id.tvActivity) protected TextView mTvActivity; @Bind(R.id.tvScanning) protected TextView mTvScanning; @Bind(com.snt.bt.recon.R.id.tvItemCount) protected TextView mTvItemCount; @Bind(com.snt.bt.recon.R.id.list1) protected ListView mList1; @Bind(com.snt.bt.recon.R.id.list2) protected ListView mList2; @Bind(R.id.debug_text) protected TextView mDebugText; //wake lock private PowerManager.WakeLock wl; //session id private UUID sessionId; //location id private UUID locationId; //gps LocationManager locationManager; LocationListener locationListener; float currentLatitude = 0.0f; float currentLongtitude = 0.0f; float currentSpeed = 0; float currentBearing = 0; float currentAltitude = 0.0f; float currentAccuracy = 0; //menu object for server sync private Menu menu; //Device id TelephonyManager telephonyManager; //to check for connectivity ConnectivityManager cm; //Bt private BluetoothUtils mBluetoothUtils; //Ble private BluetoothLeScanner mLeScanner; private LeDeviceListAdapter mLeDeviceListAdapter; private BluetoothLeDeviceStore mLeDeviceStore; //bc private ArrayAdapter<BluetoothClassicDeviceStore> mBcDeviceListAdapter; private ArrayList<BluetoothClassicDeviceStore> mBcDeviceList; //Activity recognition private ActivityRecognitionUtil mActivityRecognitionScan; private final ScanCallback mLeScanCallback = new ScanCallback() { @Override public void onScanResult(int callbackType, ScanResult result) { BluetoothDevice device = result.getDevice(); String advBytes = "Unknown"; final BluetoothLeDevice deviceLe = new BluetoothLeDevice(result.getDevice(), result.getRssi(), result.getScanRecord().getBytes(), System.currentTimeMillis()); //Get advertisement data final Collection<AdRecord> adRecords = deviceLe.getAdRecordStore().getRecordsAsCollection(); if (adRecords.size() > 0) { for (final AdRecord record : adRecords) { if (record.getType() == 255) { //255 manufacturer specific data, 9 name,1 flags advBytes = ByteUtils.byteArrayToHexString(record.getData()) + ""; } } } if (locationId != null) { db.addBleEntry(new BluetoothLowEnergyEntry(sessionId, locationId, getDateTime(), device.getAddress(), result.getRssi(), device.getName(), advBytes, "no")); } mLeDeviceStore.addDevice(deviceLe); final EasyObjectCursor<BluetoothLeDevice> c = mLeDeviceStore.getDeviceCursor(); runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.swapCursor(c); } }); } }; //DATABASE DBHandler db = new DBHandler(this); public <T> void syncSQLiteMySQLDB(final Class<T> cl, final String postString, final String postURL) { //Create AsycHttpClient object AsyncHttpClient client = new AsyncHttpClient(); RequestParams params = new RequestParams(); //Sync Trips try { List<T> list = db.getAll(cl); if (list.size() != 0) { if (db.dbSyncCount(cl) != 0) { if (menu != null) menu.findItem(R.id.menu_refresh_server) .setActionView(R.layout.actionbar_progress_indeterminate); params.put(postString, db.composeJSONfromSQLite(cl)); // using a socket factory that allows self-signed SSL certificates. client.setSSLSocketFactory(MySSLSocketFactory.getFixedSocketFactory()); client.post(postURL, params, new AsyncHttpResponseHandler() { @Override public void onSuccess(int i, Header[] headers, byte[] response) { logDebug("DatabaseTest", "Server response " + postString + " : " + new String(response)); try { JSONArray arr = new JSONArray(new String(response)); for (int x = 0; x < arr.length(); x++) { JSONObject obj = (JSONObject) arr.get(x); db.updateSyncStatus(cl, obj); } logDebug("DatabaseTest", postString + " : DB Sync completed!"); T inst = cl.newInstance(); if (sessionId != null && inst instanceof Trip) { logDebug("DatabaseTest", "Session in progress -> Deleting old trips.."); db.deleteOldTrips(sessionId); } if (menu != null) menu.findItem(R.id.menu_refresh_server).setActionView(null); } catch (JSONException e) { logDebug("DatabaseTest", postString + " : Error Occured [Server's JSON response might be invalid]!"); e.printStackTrace(); } catch (InstantiationException | IllegalAccessException | NullPointerException e) { e.printStackTrace(); } } @Override public void onFailure(int statusCode, Header[] headers, byte[] response, Throwable e) { if (statusCode == 404) { logDebug("DatabaseTest", postString + " : Requested resource not found"); } else if (statusCode == 500) { logDebug("DatabaseTest", postString + " : Something went wrong at server end"); } else { logDebug("DatabaseTest", postString + " : Unexpected Error occcured! [Most common Error: Device might not be connected to Internet]"); } try { if (menu != null) menu.findItem(R.id.menu_refresh_server).setActionView(null); } catch (NullPointerException error) { error.printStackTrace(); } } }); } else { logDebug("DatabaseTest", postString + " : SQLite and Remote MySQL DBs are in Sync!"); } } else { logDebug("DatabaseTest", postString + " : No data in DB, nothing to Sync"); } } catch (InstantiationException | IllegalAccessException | NullPointerException e) { e.printStackTrace(); } } @Override protected void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(com.snt.bt.recon.R.layout.activity_main); ButterKnife.bind(this); logDebug("Activity", "######################## On Create ########################"); //Lock orientation setRequestedOrientation(ActivityInfo.SCREEN_ORIENTATION_PORTRAIT); //Leave screen on getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON); //leave cpu on wl = ((PowerManager) getSystemService(Context.POWER_SERVICE)).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "wlTag"); wl.acquire(); //For device id telephonyManager = (TelephonyManager) getSystemService(Context.TELEPHONY_SERVICE); //for connectivity cm = (ConnectivityManager) getSystemService(Context.CONNECTIVITY_SERVICE); try { logDebug("DatabaseTest", "Reading all trips.."); List<Trip> trips = db.getAll(Trip.class); for (Trip trip : trips) { String log = "session id: " + trip.getSessionId() + " imei: " + trip.getImei() + " transport: " + trip.getTransport() + " TS: " + trip.getTimestampStart() + " TE: " + trip.getTimestampEnd() + " upload status: " + trip.getUploadStatus(); logDebug("DatabaseTest", log); } logDebug("DatabaseTest", "Reading all locations.."); List<GPSLocation> locs = db.getAll(GPSLocation.class); for (GPSLocation loc : locs) { String log = "loc id: " + loc.getLocationId() + " sess id: " + loc.getSessionId() + " timestamp: " + loc.getTimestamp() + " upload status: " + loc.getUploadStatus(); logDebug("DatabaseTest", log); } logDebug("DatabaseTest", "Reading all bc.."); List<BluetoothClassicEntry> bcs = db.getAll(BluetoothClassicEntry.class); for (BluetoothClassicEntry bc : bcs) { String log = "sess id: " + bc.getSessionId() + " loc id: " + bc.getLocationId() + " upload status: " + bc.getUploadStatus(); logDebug("DatabaseTest", log); } logDebug("DatabaseTest", "Reading all ble.."); List<BluetoothLowEnergyEntry> bles = db.getAll(BluetoothLowEnergyEntry.class); for (BluetoothLowEnergyEntry ble : bles) { String log = "sess id: " + ble.getSessionId() + " loc id: " + ble.getLocationId() + " upload status: " + ble.getUploadStatus(); logDebug("DatabaseTest", log); } } catch (InstantiationException | IllegalAccessException e) { e.printStackTrace(); } //Show select transpot mode new TransportMode(this).show(); // Show EULA new AppEULA(this).show(); //displayFeedbackDialog(); //avtivity recognition start mActivityRecognitionScan = new ActivityRecognitionUtil(this); mActivityRecognitionScan.startActivityRecognitionScan(); //Filter the Intent and register broadcast receiver registerReceiver(ActivityRecognitionReceiver, new IntentFilter("ImActive")); //gps gpsStatusCheck(); locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); locationListener = new MyLocationListener(); locationManager.requestLocationUpdates(LocationManager.GPS_PROVIDER, 3000, 3, locationListener); //bt mBluetoothUtils = new BluetoothUtils(this); //ble mLeDeviceStore = new BluetoothLeDeviceStore(); mLeScanner = new BluetoothLeScanner(mLeScanCallback, mBluetoothUtils); //bc mBcDeviceList = new ArrayList<>(); final Handler h = new Handler(); final int delay = 60000; h.postDelayed(new Runnable() { public void run() { syncServerDatabase(); h.postDelayed(this, delay); } }, delay); //Clean BLE table in case device last timestamp is > 10 seconds final Handler h2 = new Handler(); h2.postDelayed(new Runnable() { public void run() { //clear old ble devices for (BluetoothLeDevice device : mLeDeviceStore.getDeviceList()) { long diff = System.currentTimeMillis() - device.getTimestamp(); if (diff > 10000) { mLeDeviceStore.removeDevice(device); //Refresh the listview final EasyObjectCursor<BluetoothLeDevice> c = mLeDeviceStore.getDeviceCursor(); runOnUiThread(new Runnable() { @Override public void run() { mLeDeviceListAdapter.swapCursor(c); } }); } } h2.postDelayed(this, 1000);//1 sec } }, 1000); } public void syncServerDatabase() { //check for connectivity NetworkInfo activeNetwork = cm.getActiveNetworkInfo(); boolean isConnected = activeNetwork != null && activeNetwork.isConnectedOrConnecting(); SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(getBaseContext()); //sync database if (isConnected) { boolean wifiOnly = sp.getBoolean("preferred_sync", false); boolean isWiFi = activeNetwork.getType() == ConnectivityManager.TYPE_WIFI; if (!isWiFi && wifiOnly) { logDebug("syncServerDatabase", "Phone isConnected - Not Synchronizing upon user request because connection is not WiFi"); } else { logDebug("syncServerDatabase", "Phone isConnected - Synchronizing"); syncSQLiteMySQLDB(Trip.class, "tripsJSON", "https://.../api/insert_trip.php");//TODO syncSQLiteMySQLDB(GPSLocation.class, "locationsJSON", "https://.../api/insert_locations.php");//TODO syncSQLiteMySQLDB(BluetoothClassicEntry.class, "bcJSON", "https://.../api/insert_bc.php");//TODO syncSQLiteMySQLDB(BluetoothLowEnergyEntry.class, "bleJSON", "https://.../api/insert_ble.php");//TODO } } else { logDebug("syncServerDatabase", "Phone isNotConnected"); } } @Override public boolean onCreateOptionsMenu(final Menu menu) { getMenuInflater().inflate(R.menu.main, menu); this.menu = menu; if (!mLeScanner.isScanning()) { mTvScanning.setText("Off"); mTvScanning.setTextColor(Color.RED); } else { mTvScanning.setText("On"); mTvScanning.setTextColor(Color.parseColor("#00B100")); //dark green } return true; } @Override public void onItemClick(AdapterView<?> adapterView, View view, int position, long l) { } @Override public boolean onOptionsItemSelected(final MenuItem item) { switch (item.getItemId()) { case R.id.menu_settings: Intent i = new Intent(this, MyPreferencesActivity.class); startActivity(i); break; } return true; } @Override protected void onPause() { super.onPause(); } private Boolean exit = false; @Override public void onBackPressed() { if (exit) { finish(); // finish activity } else { Toast.makeText(this, "Press Back again to Exit.", Toast.LENGTH_SHORT).show(); exit = true; new Handler().postDelayed(new Runnable() { @Override public void run() { exit = false; } }, 3 * 1000); } } @Override public void onDestroy() { if (mLeScanner.isScanning()) db.updateTripEnd(sessionId, getDateTime()); stopScan(); //stop activity recognizing mActivityRecognitionScan.stopActivityRecognitionScan(); unregisterReceiver(ActivityRecognitionReceiver); cancelNotification(this, 1); //WAKE LOCK if (wl != null && wl.isHeld()) { wl.release(); } super.onDestroy(); } public static void cancelNotification(Context ctx, int notifyId) { String ns = Context.NOTIFICATION_SERVICE; NotificationManager nMgr = (NotificationManager) ctx.getSystemService(ns); nMgr.cancel(notifyId); } @Override public void onResume() { super.onResume(); //initial sync syncServerDatabase(); final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn(); final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported(); if (mIsBluetoothOn) { mTvBluetoothStatus.setText(com.snt.bt.recon.R.string.on); } else { mTvBluetoothStatus.setText(com.snt.bt.recon.R.string.off); } if (mIsBluetoothLePresent) { mTvBluetoothLeStatus.setText(com.snt.bt.recon.R.string.supported); } else { mTvBluetoothLeStatus.setText(com.snt.bt.recon.R.string.not_supported); } if (!mLeScanner.isScanning()) { mTvScanning.setText("Off"); mTvScanning.setTextColor(Color.RED); } else { mTvScanning.setText("On"); mTvScanning.setTextColor(Color.parseColor("#00B100")); } invalidateOptionsMenu(); } private boolean startScan() { //Toast.makeText(getApplicationContext(), "Start scan", Toast.LENGTH_SHORT).show(); logDebug("Activity", "######################## startScan ########################"); final boolean mIsBluetoothOn = mBluetoothUtils.isBluetoothOn(); final boolean mIsBluetoothLePresent = mBluetoothUtils.isBluetoothLeSupported(); //enable bt adapter mBluetoothUtils.getBluetoothAdapter().enable(); //mBluetoothUtils.askUserToEnableBluetoothIfNeeded(); registerReceiver(BluetoothAdapterReceiver, new IntentFilter(BluetoothAdapter.ACTION_STATE_CHANGED)); //BLE mLeDeviceStore.clear(); mLeDeviceListAdapter = new LeDeviceListAdapter(this, mLeDeviceStore.getDeviceCursor()); mList1.setAdapter(mLeDeviceListAdapter); //BC mBcDeviceListAdapter = new BcDeviceListAdapter(this, mBcDeviceList); //BC Addon mList2.setAdapter(mBcDeviceListAdapter); mBcDeviceListAdapter.clear(); if (mIsBluetoothOn && mIsBluetoothLePresent && gpsStatusCheck()) { //sessionid sessionId = UUID.randomUUID(); //save trip to database db.addTrip(new Trip(sessionId, telephonyManager.getDeviceId(), new TransportMode(this).getTransportMode(), getDateTime(), "0", BuildConfig.VERSION_CODE + " (" + BuildConfig.VERSION_NAME + ")", "no")); //BLE mLeScanner.scanLeDevice(-1, true); //BC // Register receiver to get message from BtServiceReceiver registerReceiver(BtScanServiceReceiver, new IntentFilter(BcScanService.ACTION_START_SCAN)); Intent newIntent = new Intent(this, BcScanService.class); newIntent.setAction(BcScanService.ACTION_START_SCAN); newIntent.putExtra(BcScanService.EXTRA_SID, sessionId.toString()); startService(newIntent); BcScanService.IS_SERVICE_RUNNING = true; //reset location id in case old are still stored locationId = null; BcScanService.locationId = null; Toast.makeText(getApplicationContext(), "Starting BC Service...", Toast.LENGTH_SHORT).show(); invalidateOptionsMenu(); return true; } return false; } private void stopScan() { logDebug("Activity", "######################## stopScan ########################"); syncServerDatabase(); //stop BLE mLeScanner.scanLeDevice(-1, false); mList1.setAdapter(null); mLeDeviceStore.clear(); //stop BC BcScanService.IS_SERVICE_RUNNING = false; stopService(new Intent(this, BcScanService.class)); mBluetoothUtils.getBluetoothAdapter().cancelDiscovery(); mList2.setAdapter(null);//mBtDeviceListAdapter.clear(); try { //unregister Bt classic service receiver unregisterReceiver(BtScanServiceReceiver); //Unregister Bluetooth adapter receiver unregisterReceiver(BluetoothAdapterReceiver); } catch (IllegalArgumentException e) { } invalidateOptionsMenu(); } private BroadcastReceiver BtScanServiceReceiver = new BroadcastReceiver() { public void onReceive(Context context, Intent intent) { Bundle b = intent.getExtras(); if (b != null) { if (b.getString(BcScanService.BT_ACTION, null).equals(BluetoothDevice.ACTION_FOUND)) { // Create a new device item //Log.e("TEST", b.getString(BtScanService.DEVICE_CLASS)); BluetoothClassicDeviceStore newDevice = new BluetoothClassicDeviceStore( b.getString(BcScanService.DEVICE_NAME), b.getString(BcScanService.DEVICE_ADDR), b.getString(BcScanService.DEVICE_RSSI), b.getString(BcScanService.DEVICE_TYPE), b.getString(BcScanService.DEVICE_CLASS), "false"); mBcDeviceListAdapter.add(newDevice); mBcDeviceListAdapter.notifyDataSetChanged(); } else if (b.getString(BcScanService.BT_ACTION, null) .equals(BluetoothAdapter.ACTION_DISCOVERY_FINISHED)) { mBcDeviceListAdapter.clear(); } } } }; private final BroadcastReceiver BluetoothAdapterReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { String action = intent.getAction(); // It means the user has changed his bluetooth state. if (action.equals(BluetoothAdapter.ACTION_STATE_CHANGED)) { if (mBluetoothUtils.getBluetoothAdapter().getState() == BluetoothAdapter.STATE_TURNING_OFF) { // The user bluetooth is turning off yet, but it is not disabled yet. if (mLeScanner.isScanning()) { Toast.makeText(getApplicationContext(), "Looks like the Bluetooth was disabled, recording will stop now!", Toast.LENGTH_SHORT).show(); //update Trip end timestamp db.updateTripEnd(sessionId, getDateTime()); stopScan(); } return; } if (mBluetoothUtils.getBluetoothAdapter().getState() == BluetoothAdapter.STATE_OFF) { // The user bluetooth is already disabled. return; } } } }; private final static int INTERVAL = 1000 * 60 * 3; //3 minutes private final static int MONITORED_ACTIVITY = 0; //IN VEHCILE int mostProbableActivity; Handler mHandler = new Handler(); private volatile List<Integer> activitiesList = new ArrayList<>(); private volatile HashMap<Integer, Integer> detectedActivitiesMap = new HashMap<>(); private BroadcastReceiver ActivityRecognitionReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mostProbableActivity = intent.getExtras().getInt("activity"); int mostProbableActivityConfidence = intent.getExtras().getInt("confidence"); mTvActivity.setText(getActivityName(mostProbableActivity) + " " + mostProbableActivityConfidence + "%"); ArrayList<DetectedActivity> detectedActivities = intent.getParcelableArrayListExtra("activities"); for (DetectedActivity activity : detectedActivities) { detectedActivitiesMap.put(activity.getType(), activity.getConfidence()); activitiesList.add(activity.getType()); } logDebug("ActivityRecognition", "activitiesList " + TextUtils.join(", ", activitiesList)); logDebug("ActivityRecognition", "detectedActivities " + TextUtils.join(", ", detectedActivities)); //0 = IN VEHICLE int vehicleConfidence = detectedActivitiesMap.containsKey(MONITORED_ACTIVITY) ? detectedActivitiesMap.get(MONITORED_ACTIVITY) : 0; if ((vehicleConfidence > 90) && !mLeScanner.isScanning() && !BcScanService.IS_SERVICE_RUNNING && new TransportMode((Activity) context).getTransportMode() != null && gpsStatusCheck()) { //start scanning - if scanning started then also start logging activities logDebug("ActivityRecognition", "In Vehicle > 90%"); if (startScan()) { logDebug("ActivityRecognition", "startScan successfully called"); activitiesList.clear(); activitiesList.add(MONITORED_ACTIVITY);// add first one just o make sure it does not stop immediately mHandlerTask.run(); } } detectedActivitiesMap.clear(); if (!mLeScanner.isScanning() && !BcScanService.IS_SERVICE_RUNNING) activitiesList.clear(); } }; Runnable mHandlerTask = new Runnable() { @Override public void run() { try { logDebug("ActivityRecognition", "List " + TextUtils.join(", ", activitiesList)); int retval = Double.compare( (double) Collections.frequency(activitiesList, MONITORED_ACTIVITY) / activitiesList.size(), 0.2); //if occurencies <20% if (retval < 0 && mostProbableActivity != MONITORED_ACTIVITY) { logDebug("ActivityRecognition", "no longer in vehicle - stopping"); //update Trip end timestamp db.updateTripEnd(sessionId, getDateTime()); stopScan(); activitiesList.clear(); //stop task mHandler.removeCallbacks(mHandlerTask); } else { logDebug("ActivityRecognition", "still in vehicle - continuing"); //Delete all aside from last one activitiesList.subList(0, activitiesList.size() - 1).clear(); mHandler.postDelayed(mHandlerTask, INTERVAL); } } catch (Exception e) { e.printStackTrace(); } } }; //Get the activity name private String getActivityName(int type) { switch (type) { case DetectedActivity.IN_VEHICLE: return "In Vehicle"; case DetectedActivity.ON_BICYCLE: return "On Bicycle"; case DetectedActivity.ON_FOOT: return "On Foot"; case DetectedActivity.WALKING: return "Walking"; case DetectedActivity.STILL: return "Still"; case DetectedActivity.TILTING: return "Tilting"; case DetectedActivity.RUNNING: return "Running"; case DetectedActivity.UNKNOWN: return "Unknown"; } return "N/A"; } private class MyLocationListener implements LocationListener { @Override public void onLocationChanged(Location loc) { //save location to database currentLatitude = (float) loc.getLatitude(); currentLongtitude = (float) loc.getLongitude(); currentSpeed = loc.getSpeed(); currentBearing = loc.getBearing(); currentAltitude = (float) loc.getAltitude(); currentAccuracy = loc.getAccuracy(); locationId = UUID.randomUUID(); if (mLeScanner.isScanning()) db.addLocation(new GPSLocation(locationId, sessionId, getDateTime(), currentLatitude, currentLongtitude, currentSpeed, currentBearing, currentAltitude, currentAccuracy, "no")); //Send updated data to BC service if (BcScanService.IS_SERVICE_RUNNING) { BcScanService.locationId = locationId; } mTvItemCount.setText("Last Location: " + currentLatitude + "," + currentLongtitude + " Speed: " + String.format("%.2f", currentSpeed)); } @Override public void onStatusChanged(String provider, int status, Bundle extras) { //int: OUT_OF_SERVICE if the provider is out of service, and this is not expected to change in the near future; TEMPORARILY_UNAVAILABLE //if the provider is temporarily unavailable but is expected to be available shortly; and AVAILABLE if the provider is currently available. if (status == LocationProvider.OUT_OF_SERVICE) { locationId = null; //Send updated data to BC service if (BcScanService.IS_SERVICE_RUNNING) { BcScanService.locationId = null; } } logDebug("LocationDebug", "On status changed " + status); } @Override public void onProviderEnabled(String provider) { //logDebug("LocationDebug", "On provider enabled"); } @Override public void onProviderDisabled(String provider) { //logDebug("LocationDebug", "On provider disabled"); if (mLeScanner.isScanning() && BcScanService.IS_SERVICE_RUNNING) { locationId = null; //Send updated data to BC service BcScanService.locationId = null; Toast.makeText(getApplicationContext(), "Looks like the GPS was disabled, the App will now quit!", Toast.LENGTH_SHORT).show(); //ouhgou final Handler handler = new Handler(); handler.postDelayed(new Runnable() { @Override public void run() { finishAffinity(); } }, 3000); } } } public boolean gpsStatusCheck() { final LocationManager manager = (LocationManager) getSystemService(Context.LOCATION_SERVICE); if (!manager.isProviderEnabled(LocationManager.GPS_PROVIDER)) { buildAlertMessageNoGps(); return false; } else return true; } private void buildAlertMessageNoGps() { final AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("Your GPS is currently disabled, do you want to manually enable it?") .setCancelable(false).setPositiveButton("Yes", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { startActivity(new Intent(Settings.ACTION_LOCATION_SOURCE_SETTINGS)); } }).setNegativeButton("No", new DialogInterface.OnClickListener() { public void onClick(final DialogInterface dialog, final int id) { dialog.cancel(); //close app finishAffinity(); } }); final AlertDialog alert = builder.create(); alert.show(); } private void logDebug(String tag, String content) { Log.d(tag, content); } private String getDateTime() { SimpleDateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault()); Date date = new Date(); return dateFormat.format(date); } //Method to trim textview in case its too long! private final static int MAX_LINE = 50; public void writeTextFile(String data) { mDebugText.append(data); // Erase excessive lines int excessLineNumber = mDebugText.getLineCount() - MAX_LINE; if (excessLineNumber > 0) { int eolIndex = -1; CharSequence charSequence = mDebugText.getText(); for (int i = 0; i < excessLineNumber; i++) { do { eolIndex++; } while (eolIndex < charSequence.length() && charSequence.charAt(eolIndex) != '\n'); } if (eolIndex < charSequence.length()) { mDebugText.getEditableText().delete(0, eolIndex + 1); } else { mDebugText.setText(""); } } } }