This commit is contained in:
2023-09-28 18:06:10 +05:30
parent 7c4c2c54a7
commit 5530f587f0
16 changed files with 672 additions and 140 deletions

View File

@@ -1,5 +1,8 @@
package com.ssb.simplitend.apputils;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_ID;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import android.app.Activity;
import android.app.AlertDialog;
import android.content.Context;
@@ -18,12 +21,18 @@ import androidx.annotation.NonNull;
import androidx.annotation.RawRes;
import com.bumptech.glide.Glide;
import com.google.android.gms.location.GeofencingClient;
import com.google.android.gms.location.LocationServices;
import com.google.android.material.bottomsheet.BottomSheetDialog;
import com.onesignal.OneSignal;
import com.ssb.simplitend.R;
import com.ssb.simplitend.appblocking.MySharedPref;
import com.ssb.simplitend.caregiverdashboard.mvvm.models.GeoFenceDetails;
import com.ssb.simplitend.databinding.BottomSheetAlertBinding;
import com.ssb.simplitend.databinding.DecisionBottomsheetBinding;
import com.ssb.simplitend.databinding.DoneBottomsheetBinding;
import com.ssb.simplitend.patient_dashboard.DashBoardActivity;
import com.ssb.simplitend.welcome.welcomepatient.mvvm.models.PatientData;
import org.json.JSONArray;
import org.json.JSONObject;
@@ -33,6 +42,8 @@ import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Set;
public abstract class AppUtil {
@@ -209,86 +220,6 @@ public abstract class AppUtil {
}
// user data utils
public static void savePatientData(String token, int patient_uid, Context context, boolean isLoggedIn){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(PATIENT_TOKEN, token);
editor.putInt(PATIENT_UID, patient_uid);
editor.putBoolean(IS_PATIENT_LOGGED_IN, isLoggedIn);
editor.apply();
Log.d(TAG, "saveToken: user token saved successful");
}
public static String getPatientToken(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getString(PATIENT_TOKEN, "");
}
public static int getPatientUid(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getInt(PATIENT_UID, -1);
}
public static boolean isPatientLoggedIn(Context context) {
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getBoolean(IS_PATIENT_LOGGED_IN, false);
}
public static void patientSignOut(Context context){
AppUtil.savePatientData(null, -1, context, false);
MySharedPref mySharedPref = new MySharedPref(context);
Set<String> appList = mySharedPref.getArrayList("APP_LIST");
if (appList != null) {
appList.clear();
mySharedPref.setArrayList("APP_LIST", appList);
}
}
public static void saveCgData(String token, int patient_id, Context context){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(CAREGIVER_TOKEN, token);
editor.apply();
// now saving patient data
// This is important as there are instances where patient data such as patient id and patient_token is required
savePatientData(token, patient_id, context, false);
Log.d(TAG, "saveToken: caregiver token saved successful");
}
public static String getCgToken(Context context){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
return sp.getString(CAREGIVER_TOKEN, null);
}
public static void setWantSecurityFlag(Context context, int watSecurity){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putInt(CG_APP_SECURITY, watSecurity);
editor.apply();
}
public static int getWantSecurityFlag(Context context){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
return sp.getInt(CG_APP_SECURITY, NOT_ASKED_CG_SECURITY);
}
public static void cgSignOut(Context context){
saveCgData(null, -1, context);
setWantSecurityFlag(context, NOT_ASKED_CG_SECURITY);
}
public static void dialPhone(Context activity, String phone_number) {
Intent intent = new Intent(Intent.ACTION_DIAL, Uri.fromParts("tel",
phone_number, null));
@@ -382,4 +313,180 @@ public abstract class AppUtil {
binding.btn.setText(btn_text);
binding.btn.setOnClickListener(btn_clickListener);
}
// ********************* USER DATA UTILS ******************************************
public static void savePatientData(String token, int patient_uid, Context context, boolean isLoggedIn){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(PATIENT_TOKEN, token);
editor.putInt(PATIENT_UID, patient_uid);
editor.putBoolean(IS_PATIENT_LOGGED_IN, isLoggedIn);
editor.apply();
Log.d(TAG, "saveToken: user token saved successful");
}
public static String getPatientToken(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getString(PATIENT_TOKEN, "");
}
public static int getPatientUid(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getInt(PATIENT_UID, -1);
}
public static boolean isPatientLoggedIn(Context context) {
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getBoolean(IS_PATIENT_LOGGED_IN, false);
}
public static void patientSignOut(Context context){
AppUtil.savePatientData(null, -1, context, false);
// app block list clear
MySharedPref mySharedPref = new MySharedPref(context);
Set<String> appList = mySharedPref.getArrayList("APP_LIST");
if (appList != null) {
appList.clear();
mySharedPref.setArrayList("APP_LIST", appList);
}
// geofence details clear
updatePatientGeofence(context, null, null, null, null);
// removing geofence
GeofencingClient geofencingClient = LocationServices.getGeofencingClient(context);
geofencingClient.removeGeofences(Collections.singletonList(GEOFENCE_ID)).addOnSuccessListener(v -> {
Log.d(GEOFENCE_TAG, "patientSignOut: GEOFENCE REMOVED");
}).addOnFailureListener(v -> {
Log.d(GEOFENCE_TAG, "patientSignOut: GEOFENCE COULDN'T BE REMOVE " + v);
});
// closing notifications
OneSignal.getUser().getPushSubscription().optOut();
}
public static void saveCgData(String token, int patient_id, Context context){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(CAREGIVER_TOKEN, token);
editor.apply();
// now saving patient data
// This is important as there are instances where patient data such as patient id and patient_token is required
savePatientData(token, patient_id, context, false);
Log.d(TAG, "saveToken: caregiver token saved successful");
}
public static String getCgToken(Context context){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
return sp.getString(CAREGIVER_TOKEN, null);
}
public static void setWantSecurityFlag(Context context, int watSecurity){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putInt(CG_APP_SECURITY, watSecurity);
editor.apply();
}
public static int getWantSecurityFlag(Context context){
SharedPreferences sp = context.getSharedPreferences(CAREGIVER_DETAILS, Context.MODE_PRIVATE);
return sp.getInt(CG_APP_SECURITY, NOT_ASKED_CG_SECURITY);
}
public static void cgSignOut(Context context){
saveCgData(null, -1, context);
setWantSecurityFlag(context, NOT_ASKED_CG_SECURITY);
// closing notification
OneSignal.getUser().getPushSubscription().optOut();
}
// patient geofencing
private static final String PATIENT_GEOFENCE_RADIUS = "patient_geofence_radius";
private static final String PATIENT_GEOFENCE_RADIUS_UNIT = "patient_geofence_radius_unit";
private static final String PATIENT_GEOFENCE_LATITUDE = "patient_geofence_latitude";
private static final String PATIENT_GEOFENCE_LONGITUDE = "patient_geofence_longitude";
public static void updatePatientGeofence(Context context, String lat, String lng, String radius, String radius_unit){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putString(PATIENT_GEOFENCE_LATITUDE, lat);
editor.putString(PATIENT_GEOFENCE_LONGITUDE, lng);
editor.putString(PATIENT_GEOFENCE_RADIUS, radius);
editor.putString(PATIENT_GEOFENCE_RADIUS_UNIT, radius_unit);
editor.apply();
Log.d(GEOFENCE_TAG, "updatePatientGeofence: UPDATED");
}
public static String[] getPatientLatLng(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return new String[]{sp.getString(PATIENT_GEOFENCE_LATITUDE, null), sp.getString(PATIENT_GEOFENCE_LONGITUDE, null)};
}
public static String getPatientGeofenceRadius(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getString(PATIENT_GEOFENCE_RADIUS, null);
}
public static String getPatientGeofenceRadiusUnit(Context context){
SharedPreferences sp = context.getSharedPreferences(PATIENT_DETAILS, Context.MODE_PRIVATE);
return sp.getString(PATIENT_GEOFENCE_RADIUS_UNIT, null);
}
public static boolean shouldAddPatientGeofence(@NonNull Context context,
@NonNull String remote_radius,
@NonNull String remote_radius_unit,
@NonNull PatientData data) {
String local_radius = getPatientGeofenceRadius(context);
if (local_radius != null){
try {
float local_radius_f = Float.parseFloat(local_radius);
float remote_radius_f = Float.parseFloat(remote_radius);
if (local_radius_f != remote_radius_f){
// radius' are different
// thus, should add geofence
return true;
}
}catch (Exception e){
// do nothing
}
}
// radius is equal thus, checking for unit of the radius
String local_radius_unit = getPatientGeofenceRadiusUnit(context);
if (!remote_radius_unit.equals(local_radius_unit)){
// remote radius units are different
// thus, should add geofence
return true;
}
// checking for lat lng
String[] local_lat_lng = getPatientLatLng(context);
if (data.lat != null && data.lng != null) {
if (!data.lat.equals(local_lat_lng[0]) || !data.lng.equals(local_lat_lng[1])){
// remote lat lng has changed
return true;
}
}
return false;
}
}

View File

@@ -1,11 +1,29 @@
package com.ssb.simplitend.apputils;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_ID;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import android.Manifest;
import android.app.PendingIntent;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
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 com.onesignal.notifications.INotificationReceivedEvent;
import com.onesignal.notifications.INotificationServiceExtension;
import com.ssb.simplitend.patientgeofencing.GeoFenceHelper;
import org.json.JSONException;
import org.json.JSONObject;
@@ -20,7 +38,7 @@ public class NotificationService implements INotificationServiceExtension {
public void onNotificationReceived(@NonNull INotificationReceivedEvent iNotificationReceivedEvent) {
JSONObject extras = iNotificationReceivedEvent.getNotification().getAdditionalData();
String content_type = null;
if (extras != null){
if (extras != null) {
try {
content_type = extras.getString("content_type");
} catch (JSONException e) {
@@ -34,5 +52,49 @@ public class NotificationService implements INotificationServiceExtension {
intent.putExtra(NOTIFICATION_TITLE_KEY, iNotificationReceivedEvent.getNotification().getTitle());
iNotificationReceivedEvent.getContext().sendBroadcast(intent);
if (Constants.GEOFENCING_RADIUS_UPDATED.equals(content_type) || Constants.HOME_LOCATION_UPDATED.equals(content_type)) {
if (AppUtil.isPatientLoggedIn(iNotificationReceivedEvent.getContext())){
// Either Geofence radius or Patient's location has changed.
Log.d(GEOFENCE_TAG, "Adding geo fence...");
if (ActivityCompat.checkSelfPermission(iNotificationReceivedEvent.getContext(), Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.d(GEOFENCE_TAG, "No location permission");
return;
}
// addGeoFence(new LatLng(18.933154827942843, 72.82790520714602),
// 200, iNotificationReceivedEvent.getContext());
}else{
Log.d(GEOFENCE_TAG, "onNotificationReceived of PATIENT GEOFENCE CHANGED. BUT PATIENT IS LOGGED OUT.");
}
}
}
@RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
private void addGeoFence(@NonNull LatLng latLng, float GEOFENCING_RADIUS , Context context) {
GeoFenceHelper geoFenceHelper = new GeoFenceHelper(context);
GeofencingClient geofencingClient = LocationServices.getGeofencingClient(context);
// checking for background location updates for API level 29 and above
if (Build.VERSION.SDK_INT >= 29) {
if (ContextCompat.checkSelfPermission(context, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.d(GEOFENCE_TAG, "addGeoFence: No background location permission");
return;
}
}
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.");
AppUtil.updatePatientGeofence(context, latLng.latitude+"", latLng.longitude+"",
GEOFENCING_RADIUS+"", "kms");
})
.addOnFailureListener(e -> Log.d(GEOFENCE_TAG, "onFailure: Geofence couldn't be added: " + e.getLocalizedMessage()));
}
}

View File

@@ -199,6 +199,8 @@ public class CaregiverDashActivity extends AppCompatActivity implements
// initializing dashboard fragment
replaceFragment(new CgDashBoardFragment(), "dashboard");
OneSignal.getUser().getPushSubscription().optIn();
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) {
// requestPermission will show the native Android notification permission prompt.
OneSignal.getNotifications().requestPermission(true, Continue.with(r -> {

View File

@@ -32,6 +32,7 @@ import com.google.android.gms.maps.model.MarkerOptions;
import com.ssb.simplitend.R;
import com.ssb.simplitend.apputils.AppUtil;
import com.ssb.simplitend.apputils.CaregiverDataCache;
import com.ssb.simplitend.apputils.Constants;
import com.ssb.simplitend.articles.ArticleContracts;
import com.ssb.simplitend.articles.ArticleResult;
import com.ssb.simplitend.articles.ArticleShowerActivity;
@@ -94,14 +95,12 @@ public class CgDashBoardFragment extends Fragment implements
@Override
public void onReceive(Context context, Intent intent) {
String content_type = intent.getStringExtra(CONTENT_TYPE_KEY);
loadReminders();
loadActivities();
// if (Constants.ACTIVITY_TIME.equals(content_type)){
// loadArticles();
// }else if (Constants.MEDICINE_TIME.equals(content_type)){
// loadReminders();
// }
if (Constants.ACTIVITY_TIME.equals(content_type)){
loadActivities();
}else if (Constants.MEDICINE_TIME.equals(content_type)){
loadReminders();
}
}
};
@@ -317,7 +316,8 @@ public class CgDashBoardFragment extends Fragment implements
progressDialog.setCancelable(false);
progressDialog.show();
viewModel.getGeoFenceDetails(careGiverData.caregiver_xid,
viewModel.getGeoFenceDetails("",
careGiverData.caregiver_xid + "",
"Bearer " + AppUtil.getCgToken(requireContext()),
this);
@@ -354,6 +354,7 @@ public class CgDashBoardFragment extends Fragment implements
.position(latLng)
.title(patient_name);
mGoogleMap.clear();
mGoogleMap.addMarker(markerOptions);
mGoogleMap.animateCamera(CameraUpdateFactory.newLatLngZoom(latLng, 16));;
}

View File

@@ -118,7 +118,8 @@ public class MyPatientFragment extends Fragment implements CgHomeContracts.GetGe
progressDialog.setCancelable(false);
progressDialog.show();
viewModel.getGeoFenceDetails(careGiverData.caregiver_xid,
viewModel.getGeoFenceDetails("",
careGiverData.caregiver_xid + "",
"Bearer " + AppUtil.getCgToken(requireContext()),
this);

View File

@@ -64,10 +64,11 @@ public class CaregiverMainViewModel extends ViewModel {
cgHomeRepository.saveGeoFenceDetails(geoFenceDetails, token, geoFenceCallback);
}
public void getGeoFenceDetails(int cg_xid,
public void getGeoFenceDetails(String p_id,
String cg_xid,
@NonNull String token,
@NonNull CgHomeContracts.GetGeoFenceCallback getGeoFenceCallback){
cgHomeRepository.getGeoFenceDetails(cg_xid, token, getGeoFenceCallback);
cgHomeRepository.getGeoFenceDetails(p_id, cg_xid, token, getGeoFenceCallback);
}
public void updateCaregiverData(int cg_xid,

View File

@@ -18,11 +18,13 @@ import retrofit2.http.POST;
import retrofit2.http.Part;
import retrofit2.http.PartMap;
import retrofit2.http.Path;
import retrofit2.http.Query;
public interface CgDashboardApiService {
@GET("api/get-caregiver-patient-location-link/{id}")
Call<CallResponse<GeoFenceDetails>> getGeofenceDetails(@Path("id") int id,
@GET("api/get-caregiver-patient-location-link")
Call<CallResponse<GeoFenceDetails>> getGeofenceDetails(@Query("patientId") String p_id,
@Query("caregiverId") String c_id,
@Header("Authorization") String token);
@POST("api/caregiver-patient-location-link")

View File

@@ -28,44 +28,45 @@ public class CgHomeRepository {
private final CgDashboardApiService dash_apiService;
private CgHomeRepository(){
private CgHomeRepository() {
dash_apiService = RetrofitHelper.getRetrofit().create(CgDashboardApiService.class);
}
public static synchronized CgHomeRepository getHomeRepository(){
if (cgHomeRepository == null){
public static synchronized CgHomeRepository getHomeRepository() {
if (cgHomeRepository == null) {
cgHomeRepository = new CgHomeRepository();
}
return cgHomeRepository;
}
public void getArticles(@NonNull ArticleContracts.GetArticleCallback getArticleCallback){
public void getArticles(@NonNull ArticleContracts.GetArticleCallback getArticleCallback) {
ArticlePresenter articlePresenter = ArticlePresenter.getArticlePresenter();
articlePresenter.getArticles(getArticleCallback);
}
public void getGeoFenceDetails(int cg_xid,
public void getGeoFenceDetails(String p_id,
String cg_xid,
@NonNull String token,
@NonNull CgHomeContracts.GetGeoFenceCallback getGeoFenceCallback){
@NonNull CgHomeContracts.GetGeoFenceCallback getGeoFenceCallback) {
dash_apiService.getGeofenceDetails(cg_xid, token)
dash_apiService.getGeofenceDetails(p_id, cg_xid, token)
.enqueue(new Callback<CallResponse<GeoFenceDetails>>() {
@Override
public void onResponse(Call<CallResponse<GeoFenceDetails>> call, Response<CallResponse<GeoFenceDetails>> response) {
if (response.body() != null){
if (response.body().status != 200){
if (response.body() != null) {
if (response.body().status != 200) {
getGeoFenceCallback.onGeofenceDetailsFetchFailed(new Exception(), response.body().message);
return;
}
if (response.body().result == null){
if (response.body().result == null) {
getGeoFenceCallback.onGeofenceDetailsFetched(new GeoFenceDetails());
}else{
} else {
getGeoFenceCallback.onGeofenceDetailsFetched(response.body().result);
}
}else{
} else {
getGeoFenceCallback.onGeofenceDetailsFetchFailed(new Exception(), "Couldn't load GeoFence.");
}
}
@@ -80,20 +81,20 @@ public class CgHomeRepository {
public void saveGeoFenceDetails(@NonNull GeoFenceDetails geoFenceDetails,
@NonNull String token,
@NonNull CgHomeContracts.SaveGeoFenceCallback geoFenceCallback){
@NonNull CgHomeContracts.SaveGeoFenceCallback geoFenceCallback) {
dash_apiService.saveGeoFenceDetails(geoFenceDetails, token)
.enqueue(new Callback<CallResponse<GeoFenceDetails>>() {
@Override
public void onResponse(Call<CallResponse<GeoFenceDetails>> call, Response<CallResponse<GeoFenceDetails>> response) {
if (response.body() != null){
if (response.body().status != 200 || response.body().result == null){
if (response.body() != null) {
if (response.body().status != 200 || response.body().result == null) {
geoFenceCallback.onGeofenceDetailsSaveFailed(new Exception(), response.body().message);
return;
}
geoFenceCallback.onGeofenceDetailsSaved(response.body().result);
}else{
} else {
geoFenceCallback.onGeofenceDetailsSaveFailed(new Exception(), "Please try again later.");
}
}
@@ -110,19 +111,19 @@ public class CgHomeRepository {
Map<String, RequestBody> body,
MultipartBody.Part photo,
@NonNull String token,
@NonNull CgHomeContracts.UpdateCaregiverDataCallback updateCaregiverDataCallback){
@NonNull CgHomeContracts.UpdateCaregiverDataCallback updateCaregiverDataCallback) {
dash_apiService.updateCaregiverData(cg_xid, body, photo, token)
.enqueue(new Callback<CallResponse<CareGiverData>>() {
@Override
public void onResponse(Call<CallResponse<CareGiverData>> call, Response<CallResponse<CareGiverData>> response) {
if (response.body() != null){
if (response.body().status != 200 || response.body().result == null){
if (response.body() != null) {
if (response.body().status != 200 || response.body().result == null) {
updateCaregiverDataCallback.onCaregiverDateUpdateFailed(new Exception(), response.body().message);
return;
}
updateCaregiverDataCallback.onCaregiverDataUpdated(response.body().result);
}else{
} else {
updateCaregiverDataCallback.onCaregiverDateUpdateFailed(new Exception(), "Please try again later.");
}
}
@@ -138,19 +139,19 @@ public class CgHomeRepository {
Map<String, RequestBody> body,
MultipartBody.Part photo,
String token,
@NonNull CgHomeContracts.UpdatePatientDataCallback patientDataCallback){
@NonNull CgHomeContracts.UpdatePatientDataCallback patientDataCallback) {
dash_apiService.updatePatientData(patient_xid, body, photo, token)
.enqueue(new Callback<CallResponse<PatientData>>() {
@Override
public void onResponse(Call<CallResponse<PatientData>> call, Response<CallResponse<PatientData>> response) {
if (response.body() != null){
if (response.body().status != 200 || response.body().result == null){
if (response.body() != null) {
if (response.body().status != 200 || response.body().result == null) {
patientDataCallback.onPatientDataUpdateFailed(new Exception(), response.body().message);
return;
}
patientDataCallback.onPatientDataUpdated(response.body().result);
}else{
} else {
patientDataCallback.onPatientDataUpdateFailed(new Exception(), "Please try again later.");
}
}
@@ -165,19 +166,19 @@ public class CgHomeRepository {
public void updatePatientAddress(int pat_id,
Map<String, String> body,
@NonNull String token,
@NonNull CgHomeContracts.UpdatePatientAddressCallback patientAddressCallback){
@NonNull CgHomeContracts.UpdatePatientAddressCallback patientAddressCallback) {
dash_apiService.updatePatientAddress(pat_id, body, token)
.enqueue(new Callback<CallResponse<PatientData>>() {
@Override
public void onResponse(Call<CallResponse<PatientData>> call, Response<CallResponse<PatientData>> response) {
if (response.body() != null){
if (response.body().status != 200 || response.body().result == null){
if (response.body() != null) {
if (response.body().status != 200 || response.body().result == null) {
patientAddressCallback.onPatientAddressUpdateFailed(new Exception(), response.body().message);
return;
}
patientAddressCallback.onPatientAddressUpdated(response.body().result);
}else{
} else {
patientAddressCallback.onPatientAddressUpdateFailed(new Exception(), "Please try again later.");
}
}
@@ -190,22 +191,22 @@ public class CgHomeRepository {
}
public void updateCgPassword(int cg_xid,
Map<String, RequestBody> body,
@NonNull String token,
@NonNull CgHomeContracts.UpdateCgPasswordCallback passwordCallback){
Map<String, RequestBody> body,
@NonNull String token,
@NonNull CgHomeContracts.UpdateCgPasswordCallback passwordCallback) {
dash_apiService.updateCgPassword(cg_xid, body, token)
.enqueue(new Callback<CallResponse<CareGiverData>>() {
@Override
public void onResponse(Call<CallResponse<CareGiverData>> call, Response<CallResponse<CareGiverData>> response) {
if (response.body() != null){
if (response.body().status != 200 || response.body().result == null){
if (response.body() != null) {
if (response.body().status != 200 || response.body().result == null) {
passwordCallback.onPasswordUpdateFailed(new Exception(), response.body().message);
return;
}
passwordCallback.onPasswordUpdated(response.body().result);
}else{
} else {
passwordCallback.onPasswordUpdateFailed(new Exception(), "Please try again later.");
}
}
@@ -219,19 +220,19 @@ public class CgHomeRepository {
}
public void signOut(String token,
@NonNull CgHomeContracts.SignOutCallback signOutCallback){
@NonNull CgHomeContracts.SignOutCallback signOutCallback) {
dash_apiService.signOut(token)
.enqueue(new Callback<CallResponse<Object>>() {
@Override
public void onResponse(Call<CallResponse<Object>> call, Response<CallResponse<Object>> response) {
if (response.body() != null){
if (response.body().status != 200){
if (response.body() != null) {
if (response.body().status != 200) {
signOutCallback.onSignOutFailed(new Exception(), response.body().message);
return;
}
signOutCallback.onSignOutSuccess();
}else{
} else {
signOutCallback.onSignOutFailed(new Exception(), "Please try again later.");
}
}

View File

@@ -0,0 +1,18 @@
package com.ssb.simplitend.caregiverdashboard.mvvm;
import com.ssb.simplitend.welcome.welcomepatient.mvvm.models.CallResponse;
import java.util.Map;
import retrofit2.Call;
import retrofit2.http.Body;
import retrofit2.http.Header;
import retrofit2.http.POST;
public interface NotificationApiService {
@POST("api/send-out-of-geofence-notification")
Call<CallResponse<Object>> notifyOutOfGeoFence(@Body Map<String, String> body,
@Header("Authorization") String token);
}

View File

@@ -14,4 +14,19 @@ public class GeoFenceDetails implements Serializable {
public String updated_at;
public GeoFenceDetails(){}
@Override
public String toString() {
return "GeoFenceDetails{" +
"id=" + id +
", caregiver_xid='" + caregiver_xid + '\'' +
", patient_xid='" + patient_xid + '\'' +
", location_name='" + location_name + '\'' +
", radius='" + radius + '\'' +
", type='" + type + '\'' +
", message='" + message + '\'' +
", created_at='" + created_at + '\'' +
", updated_at='" + updated_at + '\'' +
'}';
}
}

View File

@@ -450,6 +450,7 @@ public class CgGeoFencingActivity extends AppCompatActivity implements OnMapRead
public void onPatientAddressUpdated(@NonNull PatientData patientData) {
binding.updateBtnsView.setVisibility(View.GONE);
this.careGiverData.patientDetails = patientData;
this.patientData = patientData;
CaregiverDataCache.setCareGiverData(this.careGiverData);
progressDialog.dismiss();
Toast.makeText(this, "Patient's location updated.", Toast.LENGTH_SHORT).show();

View File

@@ -1,33 +1,104 @@
package com.ssb.simplitend.patient_dashboard;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import android.content.pm.PackageManager;
import android.os.Build;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AppCompatActivity;
import androidx.lifecycle.ViewModelProvider;
import com.onesignal.Continue;
import com.onesignal.OneSignal;
import com.ssb.simplitend.R;
import com.ssb.simplitend.apputils.AppUtil;
import com.ssb.simplitend.apputils.PatientDataCache;
import com.ssb.simplitend.caregiverdashboard.mvvm.CgHomeContracts;
import com.ssb.simplitend.caregiverdashboard.mvvm.models.GeoFenceDetails;
public class DashBoardActivity extends AppCompatActivity implements CgHomeContracts.GetGeoFenceCallback {
protected PatientMainViewModel viewModel;
public static final int LOCATION_REQUEST_CODE = 1001;
private GeoFenceDetails geoFenceDetails;
private boolean geofencing_verified = false;
public class DashBoardActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_dash_board_cp);
viewModel = new ViewModelProvider(this).get(PatientMainViewModel.class);
// requestPermission will show the native Android notification permission prompt.
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU){
// requestPermission will show the native Android notification permission prompt.
geofencing_verified = false;
OneSignal.getNotifications().requestPermission(true, Continue.with(r -> {
geofencing_verified = true;
if (r.isSuccess()) {
if (r.getData() != null) {
// `requestPermission` completed successfully and the user has accepted permission
}
else {
// `requestPermission` completed successfully but the user has rejected permission
}
viewModel.getGeoFenceDetails("" + AppUtil.getPatientUid(this),
"", "Bearer " + AppUtil.getPatientToken(this),
this);
}
}));
if (!geofencing_verified){
viewModel.getGeoFenceDetails("" + AppUtil.getPatientUid(this),
"", "Bearer " + AppUtil.getPatientToken(this),
this);
}
}else{
viewModel.getGeoFenceDetails("" + AppUtil.getPatientUid(this),
"", "Bearer " + AppUtil.getPatientToken(this),
this);
}
}
private 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
viewModel.setGeofence(this, geoFenceDetails, patientData);
}else{
Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetched: should not add patient geofence because GEOFENCE DETAILS: " + geoFenceDetails + " PATIENT DETAILS: " + patientData);
}
}
}), false);
}
}
@Override
public void onGeofenceDetailsFetched(@NonNull GeoFenceDetails geoFenceDetails) {
this.geoFenceDetails = geoFenceDetails;
validateAndAddGeofence(geoFenceDetails);
}
@Override
public void onGeofenceDetailsFetchFailed(Throwable throwable, String message) {
Log.d(GEOFENCE_TAG, "onGeofenceDetailsFetchFailed: " + message);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
if (requestCode == LOCATION_REQUEST_CODE){
if (grantResults.length > 0 && grantResults[0] == PackageManager.PERMISSION_GRANTED){
Log.d(GEOFENCE_TAG, "onRequestPermissionsResult: PERMISSION GRANTED");
if (geoFenceDetails != null){
validateAndAddGeofence(geoFenceDetails);
}
}
}
}
}

View File

@@ -0,0 +1,107 @@
package com.ssb.simplitend.patient_dashboard;
import static com.ssb.simplitend.patient_dashboard.DashBoardActivity.LOCATION_REQUEST_CODE;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_ID;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import android.Manifest;
import android.app.Activity;
import android.app.PendingIntent;
import android.content.pm.PackageManager;
import android.os.Build;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.annotation.RequiresPermission;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.lifecycle.ViewModel;
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 com.ssb.simplitend.apputils.AppUtil;
import com.ssb.simplitend.caregiverdashboard.mvvm.CgHomeContracts;
import com.ssb.simplitend.caregiverdashboard.mvvm.CgHomeRepository;
import com.ssb.simplitend.caregiverdashboard.mvvm.models.GeoFenceDetails;
import com.ssb.simplitend.patientgeofencing.GeoFenceHelper;
import com.ssb.simplitend.welcome.welcomepatient.mvvm.models.PatientData;
public class PatientMainViewModel extends ViewModel {
private final CgHomeRepository cgHomeRepository;
public PatientMainViewModel() {
cgHomeRepository = CgHomeRepository.getHomeRepository();
}
public void setGeofence(Activity 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: REQUESTING FINE LOCATION PERMISSION" );
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE);
return;
}
addGeoFence(latLng, radius, activity, geoFenceDetails.type);
}
}
public void getGeoFenceDetails(String p_id,
String cg_xid,
@NonNull String token,
@NonNull CgHomeContracts.GetGeoFenceCallback getGeoFenceCallback){
cgHomeRepository.getGeoFenceDetails(p_id, cg_xid, token, getGeoFenceCallback);
}
@RequiresPermission(Manifest.permission.ACCESS_FINE_LOCATION)
private void addGeoFence(@NonNull LatLng latLng, float GEOFENCING_RADIUS , Activity activity, String unit) {
GeoFenceHelper geoFenceHelper = new GeoFenceHelper(activity);
GeofencingClient geofencingClient = LocationServices.getGeofencingClient(activity);
// checking for background location updates for API level 29 and above
if (Build.VERSION.SDK_INT >= 29) {
if (ContextCompat.checkSelfPermission(activity, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED) {
Log.d(GEOFENCE_TAG, "setGeofence: REQUESTING BACKGROUND LOCATION PERMISSION" );
AppUtil.showSOSDecision(activity,
"We understand your privacy.\nTo enable Geofencing we need to access your location while the app is closed.\nKindly click on the Settings button below and select \"Allow all the time\"",
"Settings", "No thanks", view -> {
// No thanks click
ActivityCompat.requestPermissions(activity, new String[]{Manifest.permission.ACCESS_BACKGROUND_LOCATION}, LOCATION_REQUEST_CODE);
}, view -> {
// Settings click
Toast.makeText(activity, "Geofencing is off.", Toast.LENGTH_SHORT).show();
Log.d(GEOFENCE_TAG, "setGeofence: User chose not to allow background location.");
});
return;
}
}
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.");
AppUtil.updatePatientGeofence(activity, latLng.latitude+"", latLng.longitude+"",
GEOFENCING_RADIUS+"", unit);
})
.addOnFailureListener(e -> Log.d(GEOFENCE_TAG, "onFailure: Geofence couldn't be added: " + e.getLocalizedMessage()));
}
}

View File

@@ -0,0 +1,77 @@
package com.ssb.simplitend.patientgeofencing;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingEvent;
import com.ssb.simplitend.apputils.AppUtil;
import com.ssb.simplitend.apputils.RetrofitHelper;
import com.ssb.simplitend.caregiverdashboard.mvvm.NotificationApiService;
import com.ssb.simplitend.welcome.welcomepatient.mvvm.models.CallResponse;
import static com.ssb.simplitend.patientgeofencing.GeoFenceHelper.GEOFENCE_TAG;
import java.util.HashMap;
import java.util.Map;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class GeoFenceBroadcastReceiver extends BroadcastReceiver {
@Override
public void onReceive(Context context, Intent intent) {
GeofencingEvent geofencingEvent = GeofencingEvent.fromIntent(intent);
if (geofencingEvent == null || geofencingEvent.hasError()) {
Log.d(GEOFENCE_TAG, "onReceive: Couldn't add geofence");
return;
}
int transition_type = geofencingEvent.getGeofenceTransition();
switch (transition_type) {
case Geofence.GEOFENCE_TRANSITION_DWELL:
Log.d(GEOFENCE_TAG, "onReceive: DWELL");
break;
case Geofence.GEOFENCE_TRANSITION_ENTER:
Log.d(GEOFENCE_TAG, "onReceive: ENTER");
break;
case Geofence.GEOFENCE_TRANSITION_EXIT:
Log.d(GEOFENCE_TAG, "onReceive: EXIT");
notifyOutOfGeofence(context);
break;
}
}
private void notifyOutOfGeofence(Context context) {
Log.d(GEOFENCE_TAG, "Sending notification to patient");
NotificationApiService apiService = RetrofitHelper.getRetrofit().create(NotificationApiService.class);
Map<String, String> body = new HashMap<>();
body.put("patient_id", AppUtil.getPatientUid(context) + "");
apiService.notifyOutOfGeoFence(body, "Bearer " + AppUtil.getPatientToken(context))
.enqueue(new Callback<CallResponse<Object>>() {
@Override
public void onResponse(Call<CallResponse<Object>> call, Response<CallResponse<Object>> response) {
if (response.code() == 200){
Log.d(GEOFENCE_TAG, "OUT OF GEOFENCE NOTIFICATION SENT SUCCESSFULLY.");
}else{
Log.d(GEOFENCE_TAG, "Couldn't notify patient " + response.message());
}
}
@Override
public void onFailure(Call<CallResponse<Object>> call, Throwable t) {
Log.d(GEOFENCE_TAG, "Couldn't notify patient due to " + t);
}
});
}
}

View File

@@ -0,0 +1,63 @@
package com.ssb.simplitend.patientgeofencing;
import android.app.PendingIntent;
import android.content.Context;
import android.content.ContextWrapper;
import android.content.Intent;
import android.os.Build;
import androidx.annotation.NonNull;
import com.google.android.gms.location.Geofence;
import com.google.android.gms.location.GeofencingRequest;
import com.google.android.gms.maps.model.LatLng;
public class GeoFenceHelper extends ContextWrapper {
public static final String GEOFENCE_TAG = "PATIENT_GEOFENCE";
private PendingIntent pendingIntent;
public static final int BROADCAST_REQUEST_CODE = 10001;
public static final String GEOFENCE_ACTION = "com.simplitend.ACTION_GEOFENCE";
public static final String GEOFENCE_ID = "com.simplitent.PATIENT_GEOFENCE";
public GeoFenceHelper(Context base) {
super(base);
}
public GeofencingRequest getGeoFencingRequest(Geofence geofence){
return new GeofencingRequest.Builder()
.addGeofence(geofence)
.setInitialTrigger(GeofencingRequest.INITIAL_TRIGGER_EXIT)
.build();
}
public Geofence getGeoFence(@NonNull String GEOFENCE_ID,
@NonNull LatLng latLng, float radius, int transitionType){
return new Geofence.Builder()
.setCircularRegion(latLng.latitude, latLng.longitude, radius)
.setRequestId(GEOFENCE_ID)
.setTransitionTypes(transitionType)
.setExpirationDuration(Geofence.NEVER_EXPIRE)
.setLoiteringDelay(5000) // This does nothing if the transition is not DWELL
.build();
}
public synchronized PendingIntent getPendingIntent(){
if (pendingIntent != null){
return pendingIntent;
}
Intent intent = new Intent(this, GeoFenceBroadcastReceiver.class);
intent.setAction(GEOFENCE_ACTION);
if(Build.VERSION.SDK_INT > 30){
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT | PendingIntent.FLAG_MUTABLE);
} else{
pendingIntent = PendingIntent.getBroadcast(this, 0, intent, PendingIntent.FLAG_UPDATE_CURRENT);
}
return pendingIntent;
}
}