diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml
index 4c2bddd..12c4891 100644
--- a/app/src/main/AndroidManifest.xml
+++ b/app/src/main/AndroidManifest.xml
@@ -6,6 +6,7 @@
+
@@ -239,6 +240,12 @@
+
+
+
+
+
= 0){
AppUtil.updateSeniorOutOfGeofence(iNotificationReceivedEvent.getContext(), false);
- AppUtil.updatePatientGeofence(iNotificationReceivedEvent.getContext(),
- lat+"", lng+"",
- radius+"", "kms", message);
+ Intent geofenceIntent = new Intent(iNotificationReceivedEvent.getContext(), LocationService.class);
+ geofenceIntent.setAction(LocationService.ACTION_START_GEOFENCE);
+ ContextCompat.startForegroundService(iNotificationReceivedEvent.getContext(), geofenceIntent);
}
}catch (Exception e){
Log.e(GEOFENCE_TAG, "COULDN'T UPDATE GEOFENCE DETAILS FROM THE NOTIFICATION: " + e);
diff --git a/app/src/main/java/com/app/simplitend/locationupdates/DefaultLocationClient.java b/app/src/main/java/com/app/simplitend/locationupdates/DefaultLocationClient.java
index 27efa6b..65754e3 100644
--- a/app/src/main/java/com/app/simplitend/locationupdates/DefaultLocationClient.java
+++ b/app/src/main/java/com/app/simplitend/locationupdates/DefaultLocationClient.java
@@ -52,7 +52,8 @@ public class DefaultLocationClient implements LocationClient{
}
locationRequest = new LocationRequest.Builder(PRIORITY_HIGH_ACCURACY, interval)
- .setMinUpdateDistanceMeters(50) // receive updates only if user has moved over 100 meters
+ .setMinUpdateDistanceMeters(100) // receive updates only if user has moved over 100 meters
+ .setMinUpdateIntervalMillis(10_000) // fastest update to receive every 10 secs
.setPriority(PRIORITY_HIGH_ACCURACY)
.build();
diff --git a/app/src/main/java/com/app/simplitend/locationupdates/LocationService.java b/app/src/main/java/com/app/simplitend/locationupdates/LocationService.java
index f08a024..436ca29 100644
--- a/app/src/main/java/com/app/simplitend/locationupdates/LocationService.java
+++ b/app/src/main/java/com/app/simplitend/locationupdates/LocationService.java
@@ -1,17 +1,21 @@
package com.app.simplitend.locationupdates;
import static android.content.Intent.ACTION_BATTERY_CHANGED;
+import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_ID;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_EXTRA_KEY;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_REQUEST_TAG;
+import android.Manifest;
import android.app.Notification;
import android.app.NotificationManager;
+import android.app.PendingIntent;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
+import android.content.pm.PackageManager;
import android.location.Location;
import android.os.BatteryManager;
import android.os.IBinder;
@@ -19,17 +23,29 @@ import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
+import androidx.annotation.RequiresPermission;
+import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import com.app.simplitend.BuildConfig;
import com.app.simplitend.R;
import com.app.simplitend.apputils.AppUtil;
+import com.app.simplitend.apputils.PatientDataCache;
import com.app.simplitend.apputils.RetrofitHelper;
+import com.app.simplitend.caregiverdashboard.mvvm.CgHomeContracts;
+import com.app.simplitend.caregiverdashboard.mvvm.CgHomeRepository;
import com.app.simplitend.caregiverdashboard.mvvm.NotificationApiService;
+import com.app.simplitend.caregiverdashboard.mvvm.models.GeoFenceDetails;
import com.app.simplitend.chats.SocketHelper;
+import com.app.simplitend.patientgeofencing.GeoFenceHelper;
import com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver;
import com.app.simplitend.welcome.welcomepatient.mvvm.models.CallResponse;
+import com.app.simplitend.welcome.welcomepatient.mvvm.models.PatientData;
+import com.google.android.gms.location.Geofence;
+import com.google.android.gms.location.GeofencingClient;
+import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.location.LocationServices;
+import com.google.android.gms.maps.model.LatLng;
import java.util.HashMap;
import java.util.Locale;
@@ -42,15 +58,16 @@ import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
-public class LocationService extends Service implements LocationClient.DefaultLocationUpdates {
+public class LocationService extends Service implements LocationClient.DefaultLocationUpdates, CgHomeContracts.GetGeoFenceCallback {
public static final String ACTION_START_LOCATION_UPDATES = "com.simplitent.action_start_lu";
public static final String ACTION_STOP_LOCATION_UPDATES = "com.simplitent.action.stop_lu";
+ public static final String ACTION_START_GEOFENCE = "com.simplitent.action.start_geofence";
public static final String LOCATION_NOTIFICATION_CHANNEL_ID = "location";
public static final String LOCATION_UPDATE_MIN_INTERVAL = "min_interval";
- public static final int LOCATION_INTERVAL_BASE_TIME = 25 * 1000;
+ public static final int LOCATION_INTERVAL_BASE_TIME = 2 * 60 * 1000;
private static final int LOCATION_UPDATES_NOTIFICATION_ID = 112;
@@ -62,6 +79,18 @@ public class LocationService extends Service implements LocationClient.DefaultLo
public void onCreate() {
super.onCreate();
Log.d(LOCATION_REQUEST_TAG, "onCreate: SERVICE STARTED");
+
+ Notification notification = new NotificationCompat.Builder(this, LOCATION_NOTIFICATION_CHANNEL_ID)
+ .setContentTitle("Your phone is connected to your caregiver")
+ .setSmallIcon(R.mipmap.ic_launcher_round)
+ .setPriority(Notification.PRIORITY_HIGH)
+ .setOngoing(true)
+ .build();
+
+ NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
+ startForeground(LOCATION_UPDATES_NOTIFICATION_ID, notification);
+ notificationManager.notify(LOCATION_UPDATES_NOTIFICATION_ID, notification);
+
locationClient = new DefaultLocationClient(this,
LocationServices.getFusedLocationProviderClient(this));
@@ -91,8 +120,11 @@ public class LocationService extends Service implements LocationClient.DefaultLo
if (intent != null && intent.getAction() != null) {
switch (intent.getAction()) {
case ACTION_START_LOCATION_UPDATES:
- removeLocationUpdates();
- startLocationUpdates(10_000); // 10 seconds interval
+ int minInterval = intent.getIntExtra(LOCATION_UPDATE_MIN_INTERVAL, 0);
+ if (minInterval != 0){
+ removeLocationUpdates();
+ startLocationUpdates(minInterval);
+ }
break;
case ACTION_STOP_LOCATION_UPDATES:
stopLocationUpdates();
@@ -100,6 +132,9 @@ public class LocationService extends Service implements LocationClient.DefaultLo
// setting that senior is at home for start
AppUtil.updateSeniorOutOfGeofence(this, false);
break;
+ case ACTION_START_GEOFENCE:
+ setGeofence();
+ break;
}
}
@@ -116,23 +151,11 @@ public class LocationService extends Service implements LocationClient.DefaultLo
private void startLocationUpdates(int minInterval) {
SocketHelper.getInstance().establishConnection(null);
- Notification notification = new NotificationCompat.Builder(this, LOCATION_NOTIFICATION_CHANNEL_ID)
- .setContentTitle("Your phone is connected to your caregiver")
- .setSmallIcon(R.mipmap.ic_launcher_round)
- .setPriority(Notification.PRIORITY_HIGH)
- .setOngoing(true)
- .build();
-
- NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
-
try {
locationClient.getLocationUpdates(minInterval, this);
} catch (LocationClient.LocationException e) {
// do nothing
}
-
- startForeground(LOCATION_UPDATES_NOTIFICATION_ID, notification);
- notificationManager.notify(LOCATION_UPDATES_NOTIFICATION_ID, notification);
}
@Override
@@ -324,4 +347,85 @@ public class LocationService extends Service implements LocationClient.DefaultLo
}
});
}
+
+ // geofence functions
+ private void setGeofence() {
+ // retrieving geofence
+ CgHomeRepository.getHomeRepository().getGeoFenceDetails(AppUtil.getPatientUid(this) + "",
+ "", "Bearer " + AppUtil.getPatientToken(this),
+ this);
+ }
+
+ public void validateAndAddGeofence(GeoFenceDetails geoFenceDetails) {
+ if (geoFenceDetails.radius != null && geoFenceDetails.type != null) {
+ PatientDataCache.setPatientData(null); // for fresh data
+ PatientDataCache.getPatientData(this, (patientData -> {
+ if (patientData != null) {
+ if (AppUtil.shouldAddPatientGeofence(this,
+ geoFenceDetails.radius, geoFenceDetails.type, patientData)) {
+ // should add a geofence
+ setGeofence(this, geoFenceDetails, patientData);
+ } else {
+ Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetched: should not add patient geofence because GEOFENCE DETAILS: " + geoFenceDetails + " PATIENT DETAILS: " + patientData);
+ }
+ }
+ }), false);
+ }
+
+ }
+
+ public void setGeofence(Context activity, GeoFenceDetails geoFenceDetails, PatientData patientData) {
+ LatLng latLng;
+ float radius;
+ try {
+ latLng = new LatLng(Double.parseDouble(patientData.lat), Double.parseDouble(patientData.lng));
+ radius = Float.parseFloat(geoFenceDetails.radius);
+ } catch (Exception e) {
+ latLng = null;
+ radius = 0;
+ }
+
+ if (latLng != null && radius != 0) {
+ if (ActivityCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
+ Log.d(GEOFENCE_TAG, "setGeofence: NO FINE LOCATION PERMISSION" );
+ return;
+ }
+
+ addGeoFence(latLng, radius, activity, geoFenceDetails.type, geoFenceDetails.message);
+ }
+ }
+
+ @RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
+ private void addGeoFence(@NonNull LatLng latLng, float GEOFENCING_RADIUS , Context activity, String unit, String message) {
+ AppUtil.removeGeofence(activity);
+
+ GeoFenceHelper geoFenceHelper = new GeoFenceHelper(activity);
+ GeofencingClient geofencingClient = LocationServices.getGeofencingClient(activity);
+
+ Geofence geofence = geoFenceHelper.getGeoFence(GEOFENCE_ID, latLng, GEOFENCING_RADIUS,
+ Geofence.GEOFENCE_TRANSITION_ENTER | Geofence.GEOFENCE_TRANSITION_EXIT);
+ GeofencingRequest geofencingRequest = geoFenceHelper.getGeoFencingRequest(geofence);
+ PendingIntent pendingIntent = geoFenceHelper.getPendingIntent();
+
+ geofencingClient.addGeofences(geofencingRequest, pendingIntent)
+ .addOnSuccessListener(aVoid -> {
+ Log.d(GEOFENCE_TAG, "Geofence added successfully. " + latLng + " Radius: " + GEOFENCING_RADIUS + " meters");
+ AppUtil.updatePatientGeofence(activity, latLng.latitude+"", latLng.longitude+"",
+ GEOFENCING_RADIUS+"", unit, message);
+ })
+ .addOnFailureListener(e -> {
+ Log.d(GEOFENCE_TAG, "onFailure: Geofence couldn't be added: " + e.getLocalizedMessage() + " " + latLng + " Radius: " + GEOFENCING_RADIUS);
+ });
+
+ }
+
+ @Override
+ public void onGeofenceDetailsFetched(@NonNull GeoFenceDetails geoFenceDetails) {
+ validateAndAddGeofence(geoFenceDetails);
+ }
+ @Override
+ public void onGeofenceDetailsFetchFailed(Throwable throwable, String message) {
+ Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetchFailed: " + message);
+
+ }
}
diff --git a/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java b/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java
index 3af0169..db455df 100644
--- a/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java
+++ b/app/src/main/java/com/app/simplitend/patient_dashboard/DashBoardActivity.java
@@ -1,7 +1,5 @@
package com.app.simplitend.patient_dashboard;
-import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
-
import android.Manifest;
import android.app.role.RoleManager;
import android.content.Context;
@@ -11,26 +9,25 @@ import android.content.res.Configuration;
import android.os.Build;
import android.os.Bundle;
import android.telecom.TelecomManager;
-import android.util.Log;
+import android.widget.Toast;
import androidx.activity.result.ActivityResultLauncher;
import androidx.activity.result.contract.ActivityResultContracts;
-import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.core.app.ActivityCompat;
+import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModelProvider;
import com.app.simplitend.R;
import com.app.simplitend.apputils.AppUtil;
-import com.app.simplitend.apputils.PatientDataCache;
-import com.app.simplitend.caregiverdashboard.mvvm.CgHomeContracts;
-import com.app.simplitend.caregiverdashboard.mvvm.models.GeoFenceDetails;
+import com.app.simplitend.locationupdates.LocationService;
-public class DashBoardActivity extends AppCompatActivity implements CgHomeContracts.GetGeoFenceCallback {
+public class DashBoardActivity extends AppCompatActivity {
protected PatientMainViewModel viewModel;
protected ActivityResultLauncher finePermissionLauncher;
+ protected ActivityResultLauncher backgroundPermissionLauncher;
@Override
protected void onCreate(Bundle savedInstanceState) {
@@ -39,17 +36,40 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra
viewModel = new ViewModelProvider(this).get(PatientMainViewModel.class);
- updateGeofenceDetails();
+ backgroundPermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
+ isGranted -> {
+ if (isGranted) {
+ setGeofenceAndLocationUpdates();
+ }
+ });
finePermissionLauncher = registerForActivityResult(new ActivityResultContracts.RequestPermission(),
isGranted -> {
if (isGranted) {
// getting location updates
- if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
- return;
+ if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) == PackageManager.PERMISSION_GRANTED) {
+ viewModel.addLocationUpdates(this);
+ }
+
+ // fine location permission is granted
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
+ if (checkSelfPermission(Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED){
+ AppUtil.showSOSDecision(this,
+ "To enable caregivers to receive notifications even when the app is closed, go to the settings menu and select allow all the time",
+ "Settings", "No thanks", view -> {
+ // Settings click
+ backgroundPermissionLauncher.launch(Manifest.permission.ACCESS_BACKGROUND_LOCATION);
+ }, view -> {
+ // No thanks click
+ Toast.makeText(this, "Geofencing is off.", Toast.LENGTH_SHORT).show();
+ });
+ }else{
+ setGeofenceAndLocationUpdates();
+ }
+ } else {
+ setGeofenceAndLocationUpdates();
}
- viewModel.addLocationUpdates(this);
} else {
// permission denied
AppUtil.showAlert(this,
@@ -62,6 +82,8 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra
}
});
+
+
registerForActivityResult(new ActivityResultContracts.RequestPermission(),
result -> {
@@ -86,6 +108,12 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra
}
+ private void setGeofenceAndLocationUpdates() {
+ Intent intent = new Intent(this, LocationService.class);
+ intent.setAction(LocationService.ACTION_START_GEOFENCE);
+ ContextCompat.startForegroundService(this, intent);
+ }
+
@Override
protected void attachBaseContext(Context newBase) {
final Configuration configuration = new Configuration(newBase.getResources().getConfiguration());
@@ -93,41 +121,4 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra
applyOverrideConfiguration(configuration);
super.attachBaseContext(newBase);
}
-
- // saves the geofence details
- private void updateGeofenceDetails() {
- // retrieving geofence
- viewModel.getGeoFenceDetails(AppUtil.getPatientUid(this) + "",
- "", "Bearer " + AppUtil.getPatientToken(this),
- this);
- }
-
- public void validateAndAddGeofence(GeoFenceDetails geoFenceDetails) {
- if (geoFenceDetails.radius != null && geoFenceDetails.type != null) {
- PatientDataCache.getPatientData(this, (patientData -> {
- if (patientData != null) {
- if (AppUtil.shouldAddPatientGeofence(this,
- geoFenceDetails.radius, geoFenceDetails.type, patientData)) {
- // should add a geofence
- AppUtil.updatePatientGeofence(this, patientData.lat, patientData.lng,
- geoFenceDetails.radius, geoFenceDetails.type, geoFenceDetails.message);
- } else {
- Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetched: GEOFENCE DATA UP TO DATE");
- }
- }
- }), false);
- }
-
- }
-
- @Override
- public void onGeofenceDetailsFetched(@NonNull GeoFenceDetails geoFenceDetails) {
- validateAndAddGeofence(geoFenceDetails);
- }
-
- @Override
- public void onGeofenceDetailsFetchFailed(Throwable throwable, String message) {
- Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetchFailed: " + message);
-
- }
}
\ No newline at end of file
diff --git a/app/src/main/java/com/app/simplitend/patient_dashboard/PatientMainViewModel.java b/app/src/main/java/com/app/simplitend/patient_dashboard/PatientMainViewModel.java
index 001547f..414eb35 100644
--- a/app/src/main/java/com/app/simplitend/patient_dashboard/PatientMainViewModel.java
+++ b/app/src/main/java/com/app/simplitend/patient_dashboard/PatientMainViewModel.java
@@ -1,13 +1,11 @@
package com.app.simplitend.patient_dashboard;
-import static android.content.Context.ACTIVITY_SERVICE;
import static com.app.simplitend.locationupdates.LocationService.LOCATION_INTERVAL_BASE_TIME;
import static com.app.simplitend.locationupdates.LocationService.LOCATION_UPDATE_MIN_INTERVAL;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_REQUEST_TAG;
import android.Manifest;
import android.app.Activity;
-import android.app.ActivityManager;
import android.content.Intent;
import android.os.Build;
import android.os.Handler;
diff --git a/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceBroadcastReceiver.java b/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceBroadcastReceiver.java
index e9613b0..c6a1f12 100644
--- a/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceBroadcastReceiver.java
+++ b/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceBroadcastReceiver.java
@@ -79,17 +79,8 @@ public class GeoFenceBroadcastReceiver extends BroadcastReceiver {
break;
case Geofence.GEOFENCE_TRANSITION_ENTER:
Log.d(GEOFENCE_TAG, "onReceive: ENTER");
- Notification notification = new NotificationCompat.Builder(context, LOCATION_NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.mipmap.ic_launcher_round)
- .setContentTitle("Geofence entered")
- .setPriority(NotificationCompat.PRIORITY_HIGH).build();
- NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);
-
- if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
- return;
- }
- notificationManager.notify(1023, notification);
+ AppUtil.updateSeniorOutOfGeofence(context, false);
Intent locationServiceIntent = new Intent(context, LocationService.class);
locationServiceIntent.setAction(LocationService.ACTION_START_LOCATION_UPDATES);
@@ -103,17 +94,15 @@ public class GeoFenceBroadcastReceiver extends BroadcastReceiver {
case Geofence.GEOFENCE_TRANSITION_EXIT:
Log.d(GEOFENCE_TAG, "onReceive: EXIT");
- Notification notification1 = new NotificationCompat.Builder(context, LOCATION_NOTIFICATION_CHANNEL_ID)
- .setSmallIcon(R.mipmap.ic_launcher_round)
- .setContentTitle("Geofence exited")
- .setPriority(NotificationCompat.PRIORITY_HIGH).build();
-
- NotificationManagerCompat notificationManager1 = NotificationManagerCompat.from(context);
-
- if (ActivityCompat.checkSelfPermission(context, Manifest.permission.POST_NOTIFICATIONS) != PackageManager.PERMISSION_GRANTED) {
- return;
+ if (AppUtil.isSeniorOutOfGeofence(context)){
+ // already out of geofence
+ // meaning the location updates were received early than the geofence trigger
+ // and the caregiver has already been sent notifications
+ // thus, not sending them again
+ break;
}
- notificationManager1.notify(1032, notification1);
+
+ AppUtil.updateSeniorOutOfGeofence(context, true);
notifyOutOfGeofence(context, String.format(Locale.getDefault(), "%.2f", distance));
@@ -221,7 +210,7 @@ public class GeoFenceBroadcastReceiver extends BroadcastReceiver {
// getting faster location updates as patient is out of geofence
Intent intent = new Intent(context, LocationService.class);
intent.setAction(LocationService.ACTION_START_LOCATION_UPDATES);
- intent.putExtra(LOCATION_UPDATE_MIN_INTERVAL, 5 * 1000); // every 5 seconds
+ intent.putExtra(LOCATION_UPDATE_MIN_INTERVAL, 10 * 1000); // every 10 seconds
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
context.startForegroundService(intent);
} else {
diff --git a/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceHelper.java b/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceHelper.java
index 995e3d9..0a83b23 100644
--- a/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceHelper.java
+++ b/app/src/main/java/com/app/simplitend/patientgeofencing/GeoFenceHelper.java
@@ -40,7 +40,6 @@ public class GeoFenceHelper extends ContextWrapper {
.setRequestId(GEOFENCE_ID)
.setTransitionTypes(transitionType)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
- .setLoiteringDelay(5000) // This does nothing if the transition is not DWELL
.build();
}