diff --git a/app/src/main/AndroidManifest.xml b/app/src/main/AndroidManifest.xml index f713a29..a91a979 100644 --- a/app/src/main/AndroidManifest.xml +++ b/app/src/main/AndroidManifest.xml @@ -8,10 +8,10 @@ + + + diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java index 4eb38f5..5cfea16 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/MainActivity.java @@ -45,6 +45,7 @@ public class MainActivity extends AppCompatActivity { bottomNavigation(); checkLocationPermission(); + checkBackgroundLocationPermission(); } private void bottomNavigation() { viewPagerAdapter = new ViewPagerAdapter(this); @@ -92,24 +93,39 @@ public class MainActivity extends AppCompatActivity { requestForPermission(); } } + + private void checkBackgroundLocationPermission(){ + if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_BACKGROUND_LOCATION) != PackageManager.PERMISSION_GRANTED){ + AlertDialog.Builder builder = new AlertDialog.Builder(this); + + builder.setMessage("Vui lòng cho phép ứng dụng truy cập vị mọi lúc để hoạt động tốt nhất!") + .setCancelable(false) + .setPositiveButton("Ok", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + openSettings(); + finishAffinity(); + System.exit(0); + } + }) + .setNegativeButton("Thoát", new DialogInterface.OnClickListener() { + @Override + public void onClick(DialogInterface dialog, int which) { + dialog.cancel(); + finishAffinity(); + System.exit(0); + } + }); + + AlertDialog alertDialog = builder.create(); + alertDialog.setTitle("Thông báo!"); + alertDialog.show(); + } + } private void requestForPermission() { ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - - if(requestCode == LOCATION_REQUEST_CODE){ - if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ - Toast.makeText(this, "Đã cấp quyền thành công!", Toast.LENGTH_SHORT).show(); - } else { - showDialogPermission(); - } - } - } - private void showDialogPermission() { AlertDialog.Builder builder = new AlertDialog.Builder(this); diff --git a/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java b/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java index f27fa32..c429294 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Activity/OrderDetailActivity.java @@ -1,8 +1,18 @@ package com.capstone.foodify.shipper.Activity; +import static com.capstone.foodify.shipper.Common.ACTION_START_LOCATION_SERVICE; +import static com.capstone.foodify.shipper.Common.ACTION_STOP_LOCATION_SERVICE; +import static com.capstone.foodify.shipper.Common.FASTEST_UPDATE_IN_MILLISECONDS; +import static com.capstone.foodify.shipper.Common.LOCATION_REQUEST_CODE; +import static com.capstone.foodify.shipper.Common.MAX_WAIT_TIME_IN_MILLISECONDS; +import static com.capstone.foodify.shipper.Common.REQUEST_CHECK_SETTINGS; +import static com.capstone.foodify.shipper.Common.UPDATE_INTERVAL_IN_MILLISECONDS; + import android.Manifest; import android.annotation.SuppressLint; +import android.app.ActivityManager; import android.app.PendingIntent; +import android.content.Context; import android.content.DialogInterface; import android.content.Intent; import android.content.IntentSender; @@ -35,6 +45,7 @@ import com.capstone.foodify.shipper.Adapter.OrderDetailAdapter; import com.capstone.foodify.shipper.BuildConfig; import com.capstone.foodify.shipper.Common; import com.capstone.foodify.shipper.GoogleMap.GeofenceHelper; +import com.capstone.foodify.shipper.LocationService; import com.capstone.foodify.shipper.Model.CustomResponse; import com.capstone.foodify.shipper.Model.GoogleMap.GoogleMapResponse; import com.capstone.foodify.shipper.Model.Order; @@ -88,11 +99,6 @@ public class OrderDetailActivity extends AppCompatActivity { private float GEOFENCE_RADIUS = 150; private String GEOFENCE_ID = "SOME_GEOFENCE_ID"; //Location - private static final int REQUEST_CHECK_SETTINGS = 100; - private static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; - private static final long FASTEST_UPDATE_IN_MILLISECONDS = 3000; - private static final long MAX_WAIT_TIME_IN_MILLISECONDS = 1000; - private static final int LOCATION_REQUEST_CODE = 100; private FusedLocationProviderClient mFusedLocationClient; private SettingsClient mSettingClient; private LocationRequest mLocationRequest; @@ -126,9 +132,6 @@ public class OrderDetailActivity extends AppCompatActivity { initData(); - - progressLayout.setVisibility(View.GONE); - LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false); rcv_list_order.setLayoutManager(linearLayoutManager); @@ -151,6 +154,8 @@ public class OrderDetailActivity extends AppCompatActivity { Common.CURRENT_ORDER = order; + startLocationService(); + Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse("google.navigation:q=" + order.getLat() + "," + order.getLng() + "&mode=l")); intent.setPackage("com.google.android.apps.maps"); @@ -171,6 +176,7 @@ public class OrderDetailActivity extends AppCompatActivity { @Override public void onClick(View view) { changeOrderStatus(COMPLETE_STATUS); + stopLocationService(); } }); @@ -338,10 +344,9 @@ public class OrderDetailActivity extends AppCompatActivity { * Math.sin(dLon / 2); double c = 2 * Math.asin(Math.sqrt(a)); double valueResult = Radius * c; - double km = valueResult / 1; DecimalFormat newFormat = new DecimalFormat("####"); - return Integer.valueOf(newFormat.format(km)); + return Integer.parseInt(newFormat.format(valueResult)); } /** calculates the distance between two locations in MILES */ @@ -367,6 +372,39 @@ public class OrderDetailActivity extends AppCompatActivity { //Location + @SuppressWarnings("deprecation") + private boolean isLocationServiceRunning(){ + ActivityManager activityManager = (ActivityManager) getSystemService(Context.ACTIVITY_SERVICE); + if(activityManager != null){ + for(ActivityManager.RunningServiceInfo service: + activityManager.getRunningServices(Integer.MAX_VALUE)){ + if(LocationService.class.getName().equals(service.service.getClassName())){ + if(service.foreground){ + return true; + } + } + } + return false; + } + return false; + } + + private void startLocationService(){ + if(!isLocationServiceRunning()){ + Intent intent = new Intent(getApplicationContext(), LocationService.class); + intent.setAction(ACTION_START_LOCATION_SERVICE); + startService(intent); + } + } + + private void stopLocationService(){ + if(isLocationServiceRunning()){ + Intent intent = new Intent(getApplicationContext(), LocationService.class); + intent.setAction(ACTION_STOP_LOCATION_SERVICE); + startService(intent); + } + } + private void getLocation() { mFusedLocationClient = LocationServices.getFusedLocationProviderClient(this); mSettingClient = LocationServices.getSettingsClient(this); @@ -376,31 +414,21 @@ public class OrderDetailActivity extends AppCompatActivity { public void onLocationResult(@NonNull LocationResult locationResult) { super.onLocationResult(locationResult); + stopLocationUpdates(); mCurrentLocation = locationResult.getLastLocation(); Common.CURRENT_LOCATION = mCurrentLocation; getDistanceAndCalculateShipCost(order.getAddress()); - double lat1 = mCurrentLocation.getLatitude(); - double lng1 = mCurrentLocation.getLongitude(); - double lat2 = order.getLat(); - double lng2 = order.getLng(); - - if(distance(lat1, lng1, lat2, lng2) < 0.2){ - btn_shipping.setVisibility(View.GONE); - layoutConfirmOrder.setVisibility(View.VISIBLE); - } else { - btn_shipping.setVisibility(View.VISIBLE); - layoutConfirmOrder.setVisibility(View.GONE); - } + changeLayoutButton(mCurrentLocation.getLatitude(), mCurrentLocation.getLongitude()); progressLayout.setVisibility(View.GONE); } }; - mLocationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, UPDATE_INTERVAL_IN_MILLISECONDS) + mLocationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 4000) .setWaitForAccurateLocation(false) - .setMinUpdateDistanceMeters(FASTEST_UPDATE_IN_MILLISECONDS) + .setMinUpdateIntervalMillis(2000) .setMaxUpdateDelayMillis(MAX_WAIT_TIME_IN_MILLISECONDS) .build(); @@ -408,71 +436,19 @@ public class OrderDetailActivity extends AppCompatActivity { builder.addLocationRequest(mLocationRequest); mLocationSettingsRequest = builder.build(); - checkLocationPermission(); + startLocationUpdates(); } - private void checkLocationPermission(){ - if(ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && - ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED){ - - requestForPermission(); - - }else { - //Get location - mRequestingLocationUpdates = true; - startLocationUpdates(); + private void changeLayoutButton(double lat1, double lng1) { + if(distance(lat1, lng1, order.getLat(), order.getLng()) < 0.2){ + btn_shipping.setVisibility(View.GONE); + layoutConfirmOrder.setVisibility(View.VISIBLE); + } else { + btn_shipping.setVisibility(View.VISIBLE); + layoutConfirmOrder.setVisibility(View.GONE); } } - private void requestForPermission() { - ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE); - } - - @Override - public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { - super.onRequestPermissionsResult(requestCode, permissions, grantResults); - - if(requestCode == LOCATION_REQUEST_CODE){ - if(grantResults[0] == PackageManager.PERMISSION_GRANTED){ - Toast.makeText(this, "Đã cấp quyền thành công!", Toast.LENGTH_SHORT).show(); - } else { - showDialogPermission(); - } - } - } - - private void showDialogPermission() { - AlertDialog.Builder builder = new AlertDialog.Builder(this); - - builder.setMessage("Hãy cho ứng dụng truy cập vào vị trí của bạn để trải nghiệm tốt hơn!") - .setCancelable(false) - .setPositiveButton("Ok", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - openSettings(); - dialog.cancel(); - } - }) - .setNegativeButton("Để sau", new DialogInterface.OnClickListener() { - @Override - public void onClick(DialogInterface dialog, int which) { - dialog.cancel(); - } - }); - - AlertDialog alertDialog = builder.create(); - alertDialog.setTitle("Thông báo!"); - alertDialog.show(); - } - private void openSettings(){ - Intent intent = new Intent(); - intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); - Uri uri = Uri.fromParts("package", BuildConfig.APPLICATION_ID, null); - intent.setData(uri); - intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); - startActivity(intent); - } - private void startLocationUpdates(){ mSettingClient.checkLocationSettings(mLocationSettingsRequest) .addOnSuccessListener(this, new OnSuccessListener() { @@ -511,25 +487,12 @@ public class OrderDetailActivity extends AppCompatActivity { mFusedLocationClient.removeLocationUpdates(mLocationCallBack).addOnCompleteListener(this, task -> Log.d(TAG, "Location stop update!")); } - private boolean checkPermissions(){ - int permissionState = ContextCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION); - return permissionState == PackageManager.PERMISSION_GRANTED; - } - @Override protected void onResume() { super.onResume(); - progressLayout.setVisibility(View.VISIBLE); - if(mRequestingLocationUpdates && checkPermissions()){ - startLocationUpdates(); - } - } - @Override - protected void onPause() { - super.onPause(); - if(mRequestingLocationUpdates){ - stopLocationUpdates(); + if(Common.CURRENT_LOCATION != null){ + changeLayoutButton(Common.CURRENT_LOCATION.getLatitude(), Common.CURRENT_LOCATION.getLongitude()); } } } \ No newline at end of file diff --git a/app/src/main/java/com/capstone/foodify/shipper/Common.java b/app/src/main/java/com/capstone/foodify/shipper/Common.java index 78f76d8..486cb3e 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Common.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Common.java @@ -35,7 +35,14 @@ public class Common { public static final String ERROR_CONNECT_SERVER = "Đã có lỗi kết nối đến hệ thống!"; public static final List LIST_ORDER = new ArrayList<>(); public static final String SHIPPING_COMPLETED = "1"; - + public static final int REQUEST_CHECK_SETTINGS = 100; + public static final long UPDATE_INTERVAL_IN_MILLISECONDS = 10000; + public static final long FASTEST_UPDATE_IN_MILLISECONDS = 3000; + public static final long MAX_WAIT_TIME_IN_MILLISECONDS = 1000; + public static final int LOCATION_REQUEST_CODE = 100; + public static final int LOCATION_SERVICE_ID = 175; + public static final String ACTION_START_LOCATION_SERVICE = "startLocationService"; + public static final String ACTION_STOP_LOCATION_SERVICE = "stopLocationService"; public static Typeface setFontBebas(AssetManager assetManager){ return Typeface.createFromAsset(assetManager, "font/bebas.ttf"); } diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java index 3230222..8c7c52e 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/CompletedOrder.java @@ -56,6 +56,7 @@ public class CompletedOrder extends Fragment { orderAdapter = new OrderAdapter(getActivity()); + CURRENT_PAGE = 0; getListOrder(); diff --git a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java index f1f91c9..2a3c5ef 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java +++ b/app/src/main/java/com/capstone/foodify/shipper/Fragment/Order/ShippingOrder.java @@ -56,6 +56,7 @@ public class ShippingOrder extends Fragment { orderAdapter = new OrderAdapter(getActivity()); + CURRENT_PAGE = 0; getListOrder(); diff --git a/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java b/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java index 233f8bd..bcaf9a6 100644 --- a/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java +++ b/app/src/main/java/com/capstone/foodify/shipper/GoogleMap/GeofenceBroadcastReceiver.java @@ -5,6 +5,7 @@ import android.content.ComponentName; import android.content.Context; import android.content.Intent; import android.content.pm.PackageManager; +import android.location.Location; import android.net.Uri; import android.util.Log; import android.widget.Toast; @@ -14,13 +15,14 @@ import com.capstone.foodify.shipper.Common; import com.capstone.foodify.shipper.Model.Order; import com.google.android.gms.location.Geofence; import com.google.android.gms.location.GeofencingEvent; +import com.google.android.gms.location.LocationResult; import java.util.List; public class GeofenceBroadcastReceiver extends BroadcastReceiver { private static final String TAG = "GeofenceBroadcastReceive"; - + public static final String ACTION_PROCESS_UPDATE = "com.capstone.foodify.shipper.GoogleMap.UPDATE_LOCATION"; @Override public void onReceive(Context context, Intent intent) { diff --git a/app/src/main/java/com/capstone/foodify/shipper/LocationService.java b/app/src/main/java/com/capstone/foodify/shipper/LocationService.java new file mode 100644 index 0000000..b568615 --- /dev/null +++ b/app/src/main/java/com/capstone/foodify/shipper/LocationService.java @@ -0,0 +1,118 @@ +package com.capstone.foodify.shipper; + +import static com.capstone.foodify.shipper.Common.ACTION_START_LOCATION_SERVICE; +import static com.capstone.foodify.shipper.Common.ACTION_STOP_LOCATION_SERVICE; +import static com.capstone.foodify.shipper.Common.FASTEST_UPDATE_IN_MILLISECONDS; +import static com.capstone.foodify.shipper.Common.LOCATION_SERVICE_ID; +import static com.capstone.foodify.shipper.Common.MAX_WAIT_TIME_IN_MILLISECONDS; +import static com.capstone.foodify.shipper.Common.UPDATE_INTERVAL_IN_MILLISECONDS; + +import android.Manifest; +import android.app.NotificationChannel; +import android.app.NotificationManager; +import android.app.PendingIntent; +import android.app.Service; +import android.content.Context; +import android.content.Intent; +import android.content.pm.PackageManager; +import android.os.Build; +import android.os.IBinder; +import android.os.Looper; +import android.util.Log; + +import androidx.annotation.NonNull; +import androidx.annotation.Nullable; +import androidx.core.app.ActivityCompat; +import androidx.core.app.NotificationCompat; + +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.LocationServices; +import com.google.android.gms.location.Priority; + +public class LocationService extends Service { + private static final String TAG = "LocationService"; + + + private final LocationCallback locationCallback = new LocationCallback() { + @Override + public void onLocationResult(@NonNull LocationResult locationResult) { + super.onLocationResult(locationResult); + if(locationResult.getLastLocation() != null){ + double lat = locationResult.getLastLocation().getLatitude(); + double lng = locationResult.getLastLocation().getLongitude(); + + Log.d(TAG, lat + ", " + lng); + + Common.CURRENT_LOCATION = locationResult.getLastLocation(); + } + } + }; + + @Nullable + @Override + public IBinder onBind(Intent intent) { + return null; + } + + private void startLocationService() { + String channelId = "location_notification_channel"; + NotificationManager notificationManager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE); + Intent resultIntent = new Intent(); + PendingIntent pendingIntent = PendingIntent.getActivity(getApplicationContext(), 0, resultIntent, PendingIntent.FLAG_UPDATE_CURRENT); + NotificationCompat.Builder builder = new NotificationCompat.Builder(getApplicationContext(), channelId); + builder.setSmallIcon(R.mipmap.ic_launcher); + builder.setContentTitle("Foodify Shipper"); + builder.setDefaults(NotificationCompat.DEFAULT_ALL); + builder.setContentText("Ứng dụng đang lấy vị trí của bạn!"); + builder.setContentIntent(pendingIntent); + builder.setAutoCancel(false); + builder.setPriority(NotificationCompat.PRIORITY_MAX); + + if (notificationManager != null && notificationManager.getNotificationChannel(channelId) == null) { + NotificationChannel notificationChannel = new NotificationChannel( + channelId, + "Location Service", + NotificationManager.IMPORTANCE_HIGH + ); + notificationChannel.setDescription("This channel is used by location service"); + notificationManager.createNotificationChannel(notificationChannel); + } + + LocationRequest locationRequest = new LocationRequest.Builder(Priority.PRIORITY_HIGH_ACCURACY, 4000) + .setWaitForAccurateLocation(false) + .setMinUpdateIntervalMillis(5000) + .setMaxUpdateDelayMillis(MAX_WAIT_TIME_IN_MILLISECONDS) + .build(); + + if (ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) { + return; + } + LocationServices.getFusedLocationProviderClient(this) + .requestLocationUpdates(locationRequest, locationCallback, Looper.myLooper()); + startForeground(LOCATION_SERVICE_ID, builder.build()); + } + + private void stopLocationService(){ + LocationServices.getFusedLocationProviderClient(this) + .removeLocationUpdates(locationCallback); + stopForeground(true); + stopSelf(); + } + + @Override + public int onStartCommand(Intent intent, int flags, int startId) { + if(intent != null){ + String action = intent.getAction(); + if(action != null){ + if(action.equals(ACTION_START_LOCATION_SERVICE)){ + startLocationService(); + } else if(action.equals(ACTION_STOP_LOCATION_SERVICE)){ + stopLocationService(); + } + } + } + return super.onStartCommand(intent, flags, startId); + } +}