This commit is contained in:
14Sandee
2023-10-23 18:22:06 +05:30
parent 8fd739dbb9
commit d3d3aa9f9a
12 changed files with 295 additions and 34 deletions

View File

@@ -1,6 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="deploymentTargetDropDown">
<targetSelectedWithDropDown>
<Target>
<type value="QUICK_BOOT_TARGET" />
<deviceKey>
<Key>
<type value="VIRTUAL_DEVICE_PATH" />
<value value="$USER_HOME$/.android/avd/Pixel_7_Pro_API_33.avd" />
</Key>
</deviceKey>
</Target>
</targetSelectedWithDropDown>
<timeTargetWasSelectedWithDropDown value="2023-10-23T11:50:58.381874Z" />
<targetsSelectedWithDialog>
<Target>
<type value="QUICK_BOOT_TARGET" />

1
.idea/misc.xml generated
View File

@@ -1,4 +1,3 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ExternalStorageConfigurationManager" enabled="true" />
<component name="ProjectRootManager" version="2" languageLevel="JDK_17" default="true" project-jdk-name="jbr-17" project-jdk-type="JavaSDK">

View File

@@ -6,8 +6,9 @@
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION"/>
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<!-- permissions for app blocking -->
<uses-permission
@@ -215,6 +216,9 @@
</intent-filter>
</service>
<service android:name=".locationupdates.LocationService"
android:foregroundServiceType="location"/>
<receiver android:name=".patientgeofencing.GeoFenceBroadcastReceiver" />
<receiver android:name=".patientgeofencing.PatientLocationUpdatesReceiver"/>

View File

@@ -1,10 +1,15 @@
package com.app.simplitend.apputils;
import static com.app.simplitend.locationupdates.LocationService.LOCATION_NOTIFICATION_CHANNEL_ID;
import android.app.Application;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;
import android.provider.Telephony;
import android.util.Log;
@@ -40,6 +45,16 @@ public class SimpliTendApp extends Application {
}
}));
// creating notification channel for location share location updates from patient side
// using a foreground service
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O){
NotificationChannel channel = new NotificationChannel(LOCATION_NOTIFICATION_CHANNEL_ID,
"Location updates",
NotificationManager.IMPORTANCE_LOW);
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
notificationManager.createNotificationChannel(channel);
}
}
}

View File

@@ -0,0 +1,86 @@
package com.app.simplitend.locationupdates;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_REQUEST_TAG;
import android.Manifest;
import android.content.Context;
import android.content.pm.PackageManager;
import android.location.Location;
import android.location.LocationManager;
import android.os.Looper;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import com.google.android.gms.location.FusedLocationProviderClient;
import com.google.android.gms.location.LocationCallback;
import com.google.android.gms.location.LocationRequest;
import com.google.android.gms.location.LocationResult;
import com.google.android.gms.location.Priority;
public class DefaultLocationClient implements LocationClient{
private final Context context;
private final FusedLocationProviderClient fusedLocationProviderClient;
private LocationRequest locationRequest;
private LocationCallback locationCallback;
public DefaultLocationClient(Context context, FusedLocationProviderClient fusedLocationProviderClient) {
this.context = context;
this.fusedLocationProviderClient = fusedLocationProviderClient;
}
@Override
public void getLocationUpdates(long interval, @NonNull DefaultLocationUpdates defaultLocationUpdates) throws LocationException {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED
|| ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.e(LOCATION_REQUEST_TAG, "getLocationUpdates: NO LOCATION PERMISSION");
throw new LocationException("NO LOCATION PERMISSION FROM USER");
}
LocationManager locationManager = (LocationManager) context.getSystemService(Context.LOCATION_SERVICE);
boolean isGpsEnabled = locationManager.isProviderEnabled(LocationManager.GPS_PROVIDER);
boolean isNetworkEnabled = locationManager.isProviderEnabled(LocationManager.NETWORK_PROVIDER);
if (!isGpsEnabled && !isNetworkEnabled) {
LocationException locationException = new LocationException("GPS is off");
Log.e(LOCATION_REQUEST_TAG, "getLocationUpdates: ", locationException);
throw locationException;
}
locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, interval)
.build();
locationCallback = new LocationCallback() {
@Override
public void onLocationResult(@NonNull LocationResult locationResult) {
super.onLocationResult(locationResult);
Location location;
if (locationResult.getLocations().isEmpty()) {
location = null;
} else {
location = locationResult.getLocations().get(locationResult.getLocations().size() - 1);
}
defaultLocationUpdates.locationUpdates(location);
}
};
fusedLocationProviderClient.requestLocationUpdates(locationRequest,
locationCallback, Looper.getMainLooper());
Log.d(LOCATION_REQUEST_TAG, "getLocationUpdates: RECEIVING LOCATION UPDATES AT EVERY " + interval + " millis");
}
public void removeLocationUpdates(){
if (locationRequest != null && fusedLocationProviderClient != null && locationCallback != null){
fusedLocationProviderClient.removeLocationUpdates(locationCallback)
.addOnCompleteListener(task -> {
if (task.isSuccessful()) {
Log.v(LOCATION_REQUEST_TAG, "onComplete: LOCATION UPDATES REMOVED");
}
});
}
}
}

View File

@@ -0,0 +1,21 @@
package com.app.simplitend.locationupdates;
import android.location.Location;
import androidx.annotation.NonNull;
import kotlinx.coroutines.flow.Flow;
public interface LocationClient {
void getLocationUpdates(long interval, @NonNull DefaultLocationUpdates defaultLocationUpdates) throws LocationException;
class LocationException extends Exception{
public LocationException(String message){
super(message);
}
}
interface DefaultLocationUpdates{
void locationUpdates(Location location);
}
}

View File

@@ -0,0 +1,112 @@
package com.app.simplitend.locationupdates;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_EXTRA_KEY;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_REQUEST_TAG;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
import android.content.Intent;
import android.location.Location;
import android.os.IBinder;
import android.util.Log;
import androidx.annotation.Nullable;
import androidx.core.app.NotificationCompat;
import com.app.simplitend.R;
import com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver;
import com.google.android.gms.location.LocationServices;
public class LocationService extends Service implements LocationClient.DefaultLocationUpdates {
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 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;
private DefaultLocationClient locationClient;
@Override
public void onCreate() {
super.onCreate();
locationClient = new DefaultLocationClient(this,
LocationServices.getFusedLocationProviderClient(this));
}
@Override
public int onStartCommand(Intent intent, int flags, int startId) {
if (intent != null && intent.getAction() != null){
switch (intent.getAction()){
case ACTION_START_LOCATION_UPDATES:
int minInterval = intent.getIntExtra(LOCATION_UPDATE_MIN_INTERVAL, 0);
if (minInterval != 0){
removeLocationUpdates();
startLocationUpdates(minInterval);
}
break;
case ACTION_STOP_LOCATION_UPDATES:
stopLocationUpdates();
break;
}
}
return super.onStartCommand(intent, flags, startId);
}
private void stopLocationUpdates() {
stopForeground(true);
stopSelf();
removeLocationUpdates();
}
private void startLocationUpdates(int minInterval){
Notification notification = new NotificationCompat.Builder(this, LOCATION_NOTIFICATION_CHANNEL_ID)
.setContentTitle("SimpliTend is sharing your current location")
.setSmallIcon(R.mipmap.ic_launcher_round)
.setOngoing(true)
.build();
NotificationManager notificationManager = (NotificationManager) getSystemService(NOTIFICATION_SERVICE);
try {
locationClient.getLocationUpdates(minInterval, this);
} catch (LocationClient.LocationException e) {
// do nothing
}
startForeground(1, notification);
notificationManager.notify(1, notification);
}
@Override
public void onDestroy() {
super.onDestroy();
Log.d(LOCATION_REQUEST_TAG, "onDestroy: SERVICE DESTROYED");
// stop the location updates
stopForeground(true);
stopSelf();
removeLocationUpdates();
}
public void removeLocationUpdates(){
if (locationClient != null){
locationClient.removeLocationUpdates();
}
}
@Nullable
@Override
public IBinder onBind(Intent intent) {
return null;
}
@Override
public void locationUpdates(Location location) {
Intent intent = new Intent(this, PatientLocationUpdatesReceiver.class);
intent.putExtra(LOCATION_EXTRA_KEY, location);
sendBroadcast(intent);
}
}

View File

@@ -24,6 +24,7 @@ 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 {
@@ -60,6 +61,9 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra
} else {
setGeofenceAndLocationUpdates();
}
// getting location updates
viewModel.addLocationUpdates(this);
} else {
// permission denied
AppUtil.showAlert(this,
@@ -106,15 +110,9 @@ public class DashBoardActivity extends AppCompatActivity implements CgHomeContra
viewModel.getGeoFenceDetails(AppUtil.getPatientUid(this) + "",
"", "Bearer " + AppUtil.getPatientToken(this),
this);
if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
return;
}
viewModel.addLocationUpdates(this);
}
private void validateAndAddGeofence(GeoFenceDetails geoFenceDetails) {
public void validateAndAddGeofence(GeoFenceDetails geoFenceDetails) {
if (geoFenceDetails.radius != null && geoFenceDetails.type != null) {
PatientDataCache.getPatientData(this, (patientData -> {
if (patientData != null) {

View File

@@ -1,5 +1,8 @@
package com.app.simplitend.patient_dashboard;
import static android.content.Context.*;
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.GeoFenceHelper.GEOFENCE_ID;
import static com.app.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver.LOCATION_REQUEST_TAG;
@@ -7,13 +10,16 @@ import static com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceive
import android.Manifest;
import android.app.Activity;
import android.app.ActivityManager;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;
@@ -28,6 +34,7 @@ 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.locationupdates.LocationService;
import com.app.simplitend.patientgeofencing.GeoFenceHelper;
import com.app.simplitend.patientgeofencing.PatientLocationUpdatesReceiver;
import com.app.simplitend.patientprofile.PatientProfileAPIService;
@@ -99,31 +106,24 @@ public class PatientMainViewModel extends ViewModel {
@RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
public void addLocationUpdates(Activity activity) {
Log.d(LOCATION_REQUEST_TAG, "REQUESTING LOCATION UPDATES");
FusedLocationProviderClient fusedLocationClient = LocationServices.getFusedLocationProviderClient(activity);
LocationRequest locationRequest = new LocationRequest();
locationRequest.setInterval(10_000);
locationRequest.setSmallestDisplacement(15);
locationRequest.setPriority(LocationRequest.PRIORITY_HIGH_ACCURACY);
Intent intent = new Intent(activity, PatientLocationUpdatesReceiver.class);
PendingIntent pendingIntent ;
if(Build.VERSION.SDK_INT > 30){
pendingIntent = PendingIntent.getBroadcast(activity, LOCATION_UPDATES_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
} else{
pendingIntent = PendingIntent.getBroadcast(activity, LOCATION_UPDATES_REQUEST_CODE, intent, PendingIntent.FLAG_UPDATE_CURRENT);
if (!isLocationServiceRunning(activity)) {
Log.d(LOCATION_REQUEST_TAG, "REQUESTING LOCATION UPDATES");
Toast.makeText(activity, "Location updates started", Toast.LENGTH_SHORT).show();
Intent intent = new Intent(activity, LocationService.class);
intent.setAction(LocationService.ACTION_START_LOCATION_UPDATES);
intent.putExtra(LOCATION_UPDATE_MIN_INTERVAL, LOCATION_INTERVAL_BASE_TIME);
activity.startService(intent);
}
}
fusedLocationClient.requestLocationUpdates(locationRequest, pendingIntent)
.addOnCompleteListener(task -> {
if (task.isSuccessful() && task.getException() == null){
Log.d(LOCATION_REQUEST_TAG, "LOCATION UPDATES ADDED");
}else{
Log.d(LOCATION_REQUEST_TAG, "CANNOT ADD LOCATION UPDATES " + task.getException());
}
});
public boolean isLocationServiceRunning(Activity activity){
ActivityManager activityManager = (ActivityManager) activity.getSystemService(ACTIVITY_SERVICE);
for(ActivityManager.RunningServiceInfo service: activityManager.getRunningServices(Integer.MAX_VALUE)) {
if(LocationService.class.getName().equals(service.service.getClassName())) {
return true;
}
}
return false;
}
public void getGeoFenceDetails(String p_id,

View File

@@ -5,6 +5,7 @@ import android.content.Context;
import android.content.Intent;
import android.util.Log;
import com.app.simplitend.locationupdates.LocationService;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import com.app.simplitend.apputils.AppUtil;
@@ -12,6 +13,8 @@ import com.app.simplitend.apputils.RetrofitHelper;
import com.app.simplitend.caregiverdashboard.mvvm.NotificationApiService;
import com.app.simplitend.welcome.welcomepatient.mvvm.models.CallResponse;
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.GeoFenceHelper.GEOFENCE_TAG;
import java.util.HashMap;
@@ -40,6 +43,11 @@ public class GeoFenceBroadcastReceiver extends BroadcastReceiver {
break;
case Geofence.GEOFENCE_TRANSITION_ENTER:
Log.d(GEOFENCE_TAG, "onReceive: ENTER");
Intent locationServiceIntent = new Intent(context, LocationService.class);
locationServiceIntent.setAction(LocationService.ACTION_START_LOCATION_UPDATES);
locationServiceIntent.putExtra(LOCATION_UPDATE_MIN_INTERVAL, LOCATION_INTERVAL_BASE_TIME
);
context.startService(locationServiceIntent);
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
Log.d(GEOFENCE_TAG, "onReceive: EXIT");
@@ -72,5 +80,11 @@ 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, 10 * 1000); // every 10 seconds
context.startService(intent);
}
}

View File

@@ -26,7 +26,7 @@ import retrofit2.Response;
public class PatientLocationUpdatesReceiver extends BroadcastReceiver {
public static final String LOCATION_REQUEST_TAG = "LOCATION_REQUEST_TAG";
private static final String LOCATION_EXTRA_KEY = "com.google.android.location.LOCATION";
public static final String LOCATION_EXTRA_KEY = "com.google.android.location.LOCATION";
public static final int LOCATION_UPDATES_REQUEST_CODE = 1010;
@Override

View File

@@ -36,7 +36,7 @@
<ImageView
android:id="@+id/anim_iv"
android:layout_width="match_parent"
android:layout_height="@dimen/_250sdp"
android:layout_height="@dimen/_200sdp"
android:layout_gravity="center_horizontal"
android:layout_marginHorizontal="15dp"
android:layout_marginTop="@dimen/_15sdp"