diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index 5ccbfb9..03c49a3 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -53,12 +53,17 @@ android:name=".activity.SettingsActivity" android:screenOrientation="portrait" android:configChanges="keyboardHidden|orientation|screenSize"/> - + providers = new ArrayList(); - private LocationListener[] mLocationListeners; private CircularFifoQueue coordinatesHistory = new CircularFifoQueue(coordinatesHistoryLength); - private LocationManager mLocationManager = null; private Handler mHandler = new Handler(); private Runnable mStatusChecker; private FusedLocationProviderClient mFusedLocationClient; @@ -80,12 +71,6 @@ public class BackgroundLocalizationService extends Service { providers.add(LocationManager.GPS_PROVIDER); providers.add(LocationManager.NETWORK_PROVIDER); providers.add(LocationManager.PASSIVE_PROVIDER); - - mLocationListeners = new LocationListener[]{ - new LocationListener(LocationManager.GPS_PROVIDER), - new LocationListener(LocationManager.NETWORK_PROVIDER), - new LocationListener(LocationManager.PASSIVE_PROVIDER) - }; } @Override @@ -129,7 +114,6 @@ public class BackgroundLocalizationService extends Service { mStatusChecker = () -> { try { mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); - initializeLocationManager(); getLocalizationFromListeners(); changeBackgroundMode(); } finally { @@ -192,10 +176,6 @@ public class BackgroundLocalizationService extends Service { return; } - List providers1 = mLocationManager.getProviders(true); - Location bestLocation = null; - AtomicReference triggerAnotherLocationListener = new AtomicReference<>(false); - mFusedLocationClient.getLastLocation().addOnSuccessListener( location -> { if (location != null) { @@ -204,24 +184,8 @@ public class BackgroundLocalizationService extends Service { sendCoordinateToBackend(location); } - triggerAnotherLocationListener.set(true); }); - if (triggerAnotherLocationListener.get()) { - for (String provider : providers1) { - Location location = mLocationManager.getLastKnownLocation(provider); - - if (location == null) { - continue; - } - if (bestLocation == null || location.getAccuracy() < bestLocation.getAccuracy()) { - bestLocation = location; - } - } - - coordinatesHistory.add(bestLocation); - } - } private void sendCoordinateToBackend(Location location) { @@ -238,48 +202,10 @@ public class BackgroundLocalizationService extends Service { } private void destroyLocationListeners(){ - if (mLocationManager != null) { - for (LocationListener listener : mLocationListeners) { - try { - if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { - return; - } - mLocationManager.removeUpdates(listener); - } catch (Exception ex) { - Log.i(TAG, "fail to remove location listener, ignore", ex); - } - } - } + } - private void initializeLocationManager() { - Log.e(TAG, "initializeLocationManager - LOCATION_INTERVAL: " + notify_interval + " LOCATION_DISTANCE: " + LOCATION_DISTANCE); - - if (mLocationManager == null) { - mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE); - } - - Integer providerIndex = 0; - - for (LocationListener listener : mLocationListeners) { - try { - mLocationManager.requestLocationUpdates( - providers.get(providerIndex), - notify_interval, - LOCATION_DISTANCE, - listener - ); - - } catch (java.lang.SecurityException ex) { - Log.i(TAG, "fail to request location update, ignore", ex); - } catch (IllegalArgumentException ex) { - Log.d(TAG, "network provider does not exist, " + ex.getMessage()); - } - - providerIndex++; - } - } private class LocationListener implements android.location.LocationListener { diff --git a/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundService.java b/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundService.java new file mode 100644 index 0000000..23f25f2 --- /dev/null +++ b/app/src/main/java/com/uam/wmi/findmytutor/service/BackgroundService.java @@ -0,0 +1,264 @@ +package com.uam.wmi.findmytutor.service; + +import android.Manifest; +import android.annotation.SuppressLint; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.location.Location; +import android.location.LocationListener; +import android.os.Binder; +import android.os.Bundle; +import android.os.IBinder; +import android.os.PowerManager; +import android.provider.SyncStateContract; +import android.support.v4.app.ActivityCompat; +import android.util.Log; + +import com.google.android.gms.common.ConnectionResult; +import com.google.android.gms.common.GooglePlayServicesUtil; +import com.google.android.gms.common.api.GoogleApiClient; +import com.google.android.gms.location.LocationRequest; +import com.google.android.gms.location.LocationServices; + +import java.text.DateFormat; +import java.util.Date; + +import static com.uam.wmi.findmytutor.utils.Const.onlineBackgroundLocationInterval; + + +public class BackgroundService extends Service implements + GoogleApiClient.ConnectionCallbacks, + GoogleApiClient.OnConnectionFailedListener, + LocationListener { + + IBinder mBinder = new LocalBinder(); + private static final String TAG = "MyLocationService"; + + private GoogleApiClient mGoogleApiClient; + private PowerManager.WakeLock mWakeLock; + private LocationRequest mLocationRequest; + // Flag that indicates if a request is underway. + private boolean mInProgress; + private static long notify_interval = onlineBackgroundLocationInterval; + + private Boolean servicesAvailable = false; + + public class LocalBinder extends Binder { + public BackgroundService getServerInstance() { + return BackgroundService.this; + } + } + + @Override + public void onCreate() { + super.onCreate(); + + + mInProgress = false; + // Create the LocationRequest object + mLocationRequest = LocationRequest.create(); + // Use high accuracy + mLocationRequest.setPriority(LocationRequest.PRIORITY_BALANCED_POWER_ACCURACY); + // Set the update interval to 5 seconds + mLocationRequest.setInterval(notify_interval); + // Set the fastest update interval to 1 second + mLocationRequest.setFastestInterval(notify_interval); + + servicesAvailable = servicesConnected(); + + /* + * Create a new location client, using the enclosing class to + * handle callbacks. + */ + setUpLocationClientIfNeeded(); + + + } + + /* + * Create a new location client, using the enclosing class to + * handle callbacks. + */ + protected synchronized void buildGoogleApiClient() { + this.mGoogleApiClient = new GoogleApiClient.Builder(this) + .addConnectionCallbacks(this) + .addOnConnectionFailedListener(this) + .addApi(LocationServices.API) + .build(); + } + + private boolean servicesConnected() { + + // Check that Google Play services is available + int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this); + + // If Google Play services is available + if (ConnectionResult.SUCCESS == resultCode) { + + return true; + } else { + + return false; + } + } + + @SuppressLint("InvalidWakeLockTag") + public int onStartCommand(Intent intent, int flags, int startId) { + super.onStartCommand(intent, flags, startId); + + PowerManager mgr = (PowerManager) getSystemService(Context.POWER_SERVICE); + + /* + WakeLock is reference counted so we don't want to create multiple WakeLocks. So do a check before initializing and acquiring. + + This will fix the "java.lang.Exception: WakeLock finalized while still held: MyWakeLock" error that you may find. + */ + /* if (this.mWakeLock == null) { //**Added this + this.mWakeLock = mgr.newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "MyWakeLock"); + } + + if (!this.mWakeLock.isHeld()) { //**Added this + this.mWakeLock.acquire(10*60*1000L *//*10 minutes*//*); + }*/ + + if (!servicesAvailable || mGoogleApiClient.isConnected() || mInProgress) + return START_STICKY; + + setUpLocationClientIfNeeded(); + if (!mGoogleApiClient.isConnected() || !mGoogleApiClient.isConnecting() && !mInProgress) { + mInProgress = true; + mGoogleApiClient.connect(); + } + + return START_STICKY; + } + + + private void setUpLocationClientIfNeeded() { + if (mGoogleApiClient == null) + buildGoogleApiClient(); + } + + // Define the callback method that receives location updates + @Override + public void onLocationChanged(Location location) { + // Report to the UI that the location was updated + String msg = Double.toString(location.getLatitude()) + "," + + Double.toString(location.getLongitude()); + Log.d("debug", msg); + Log.e(TAG, "onLocationChanged: " + location); + + // Toast.makeText(this, msg, Toast.LENGTH_SHORT).show(); + } + + @Override + public void onStatusChanged(String s, int i, Bundle bundle) { + + } + + @Override + public void onProviderEnabled(String s) { + + } + + @Override + public void onProviderDisabled(String s) { + + } + + @Override + public IBinder onBind(Intent intent) { + return mBinder; + } + + @Override + public void onDestroy() { + // Turn off the request flag + this.mInProgress = false; + + if (this.servicesAvailable && this.mGoogleApiClient != null) { + this.mGoogleApiClient.unregisterConnectionCallbacks(this); + this.mGoogleApiClient.unregisterConnectionFailedListener(this); + this.mGoogleApiClient.disconnect(); + // Destroy the current location client + this.mGoogleApiClient = null; + } + // Display the connection status + // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": + // Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); + + if (this.mWakeLock != null) { + this.mWakeLock.release(); + this.mWakeLock = null; + } + + super.onDestroy(); + } + + /* + * Called by Location Services when the request to connect the + * client finishes successfully. At this point, you can + * request the current location or start periodic updates + */ + @Override + public void onConnected(Bundle bundle) { + + // Request location updates using static settings + //Intent intent = new Intent(this, LocationReceiver.class); + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + // TODO: Consider calling + // ActivityCompat#requestPermissions + // here to request the missing permissions, and then overriding + // public void onRequestPermissionsResult(int requestCode, String[] permissions, + // int[] grantResults) + // to handle the case where the user grants the permission. See the documentation + // for ActivityCompat#requestPermissions for more details. + return; + } + + LocationServices.getFusedLocationProviderClient(this); + LocationServices.FusedLocationApi.requestLocationUpdates(mGoogleApiClient, mLocationRequest, (com.google.android.gms.location.LocationListener) this); + + /* .requestLocationUpdates(this.mGoogleApiClient, + mLocationRequest, (com.google.android.gms.location.LocationListener) this); // This is the changed line.*/ + + } + + /* + * Called by Location Services if the connection to the + * location client drops because of an error. + */ + @Override + public void onConnectionSuspended(int i) { + // Turn off the request flag + mInProgress = false; + // Destroy the current location client + mGoogleApiClient = null; + // Display the connection status + // Toast.makeText(this, DateFormat.getDateTimeInstance().format(new Date()) + ": Disconnected. Please re-connect.", Toast.LENGTH_SHORT).show(); + } + + /* + * Called by Location Services if the attempt to + * Location Services fails. + */ + @Override + public void onConnectionFailed(ConnectionResult connectionResult) { + mInProgress = false; + + /* + * Google Play services can resolve some errors it detects. + * If the error has a resolution, try sending an Intent to + * start a Google Play services activity that can resolve + * error. + */ + if (connectionResult.hasResolution()) { + + // If no resolution is available, display an error dialog + } else { + + } + } +} diff --git a/app/src/main/res/layout/tutors_list_tabs.xml b/app/src/main/res/layout/tutors_list_tabs.xml new file mode 100644 index 0000000..c09a3b2 --- /dev/null +++ b/app/src/main/res/layout/tutors_list_tabs.xml @@ -0,0 +1,56 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file