Add notification shipper

This commit is contained in:
Nezumi
2023-04-10 20:28:59 +07:00
parent 280e3674aa
commit fe675e272d
48 changed files with 477 additions and 71 deletions
+1
View File
@@ -45,6 +45,7 @@ dependencies {
implementation 'com.google.firebase:firebase-storage:20.0.1'
implementation 'com.google.android.gms:play-services-maps:18.1.0'
implementation 'com.google.firebase:firebase-database:20.0.4'
implementation 'com.google.firebase:firebase-messaging:23.0.3'
testImplementation 'junit:junit:4.13.2'
androidTestImplementation 'androidx.test.ext:junit:1.1.5'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
+10
View File
@@ -3,12 +3,14 @@
xmlns:tools="http://schemas.android.com/tools">
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
<uses-permission android:name="android.permission.ACCESS_BACKGROUND_LOCATION" />
<uses-permission android:name="android.permission.POST_NOTIFICATIONS" />
<uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW" />
<uses-permission android:name="android.permission.FOREGROUND_SERVICE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<application
android:allowBackup="true"
@@ -55,6 +57,14 @@
<activity
android:name=".Activity.MainActivity"
android:exported="false" />
<service
android:name=".NotificationService"
android:exported="false">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
</application>
</manifest>
Binary file not shown.

After

Width:  |  Height:  |  Size: 400 KiB

@@ -0,0 +1,28 @@
package com.capstone.foodify.shipper.API;
import com.capstone.foodify.shipper.Model.FirebaseMessaging.FirebaseMessaging;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.gson.GsonConverterFactory;
import retrofit2.http.Body;
import retrofit2.http.Headers;
import retrofit2.http.POST;
public interface FirebaseMessagingAPI {
Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss dd-MM-yyyy").setLenient().create();
FirebaseMessagingAPI apiService = new Retrofit.Builder()
.baseUrl("https://fcm.googleapis.com/").addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(FirebaseMessagingAPI.class);
@Headers({
"Content-Type: application/json",
"Authorization: Bearer AAAAMcAdgF0:APA91bE9OPI9SBgvFV_8KijtnWEQ5nx4PyOhrY61u8BRv5xKnPzhiqCqcLvz4WVYSgVNLHWjUiOJBaxhIiwhwB6YsAPXDn1aNfbKx-q8FvypzW7lmiKC8vOxFpYUAh8YaItk4Vf-eZ_F"
})
@POST("fcm/send")
Call<FirebaseMessaging> sendNotification(@Body FirebaseMessaging content);
}
@@ -1,5 +1,6 @@
package com.capstone.foodify.shipper.API;
import com.capstone.foodify.shipper.Common;
import com.capstone.foodify.shipper.Model.Shipper;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
@@ -15,7 +16,7 @@ public interface FoodApi {
Gson gson = new GsonBuilder().setDateFormat("HH:mm:ss dd-MM-yyyy").setLenient().create();
FoodApi apiService = new Retrofit.Builder()
.baseUrl("http://192.168.1.183:8080/api/").addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(Common.BASE_URL).addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(FoodApi.class);
@@ -39,7 +39,7 @@ public interface FoodApiToken {
FoodApiToken apiService = new Retrofit.Builder()
.client(client)
.baseUrl("http://192.168.1.183:8080/api/").addConverterFactory(GsonConverterFactory.create(gson))
.baseUrl(Common.BASE_URL).addConverterFactory(GsonConverterFactory.create(gson))
.build()
.create(FoodApiToken.class);
@@ -56,4 +56,6 @@ public interface FoodApiToken {
@PUT("users/{userId}/orders/{orderId}/status")
Call<CustomResponse> changeStatusOrder(@Path("userId") int userId, @Path("orderId") int orderId, @Query("status") String status);
@PUT("users/{userId}/update/fcm")
Call<CustomResponse> updateFCMToken(@Path("userId") int userId, @Body String token);
}
@@ -0,0 +1,20 @@
package com.capstone.foodify.shipper.API;
import com.capstone.foodify.shipper.Common;
import retrofit2.Call;
import retrofit2.Retrofit;
import retrofit2.converter.scalars.ScalarsConverterFactory;
import retrofit2.http.GET;
import retrofit2.http.Path;
public interface TokenFCMFirebaseAPI {
TokenFCMFirebaseAPI apiService = new Retrofit.Builder()
.baseUrl(Common.BASE_URL).addConverterFactory(ScalarsConverterFactory.create())
.build()
.create(TokenFCMFirebaseAPI.class);
@GET("users/{userId}/fcm")
Call<String> getTokenFCM(@Path("userId") int userId);
}
@@ -14,15 +14,12 @@ import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.view.View;
import android.webkit.MimeTypeMap;
import android.widget.Button;
import android.widget.DatePicker;
import android.widget.EditText;
import android.widget.ImageView;
import android.widget.LinearLayout;
import android.widget.TextView;
import android.widget.Toast;
import com.capstone.foodify.shipper.API.FoodApiToken;
@@ -42,10 +39,6 @@ import com.google.firebase.storage.StorageReference;
import com.google.firebase.storage.UploadTask;
import com.makeramen.roundedimageview.RoundedImageView;
import com.squareup.picasso.Picasso;
import com.thecode.aestheticdialogs.AestheticDialog;
import com.thecode.aestheticdialogs.DialogAnimation;
import com.thecode.aestheticdialogs.DialogStyle;
import com.thecode.aestheticdialogs.DialogType;
import java.text.SimpleDateFormat;
import java.util.Calendar;
@@ -225,7 +218,7 @@ public class AccountAndProfileActivity extends AppCompatActivity {
@Override
public void onFailure(Call<User> call, Throwable t) {
Common.showErrorServerNotification(AccountAndProfileActivity.this, "Không thể cập nhật thông tin, vui lòng thử lại sau!");
Common.showErrorDialog(AccountAndProfileActivity.this, "Không thể cập nhật thông tin, vui lòng thử lại sau!");
progressLayout.setVisibility(View.GONE);
}
});
@@ -2,12 +2,19 @@ package com.capstone.foodify.shipper.Activity;
import android.Manifest;
import android.annotation.SuppressLint;
import android.content.ComponentName;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.content.res.ColorStateList;
import android.net.Uri;
import android.os.Build;
import android.os.Bundle;
import android.provider.Settings;
import android.util.Log;
import android.view.MenuItem;
import android.view.View;
import android.widget.Toast;
@@ -15,18 +22,34 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.appcompat.widget.AppCompatCheckBox;
import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.core.content.ContextCompat;
import androidx.viewpager2.widget.ViewPager2;
import com.capstone.foodify.shipper.API.FoodApiToken;
import com.capstone.foodify.shipper.BuildConfig;
import com.capstone.foodify.shipper.Common;
import com.capstone.foodify.shipper.Model.CustomResponse;
import com.capstone.foodify.shipper.R;
import com.capstone.foodify.shipper.ViewPagerAdapter;
import com.google.android.gms.tasks.OnCompleteListener;
import com.google.android.gms.tasks.Task;
import com.google.android.material.bottomnavigation.BottomNavigationView;
import com.google.android.material.navigation.NavigationBarView;
import com.google.firebase.messaging.FirebaseMessaging;
import java.util.Arrays;
import java.util.List;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class MainActivity extends AppCompatActivity {
private static final String TAG = "MainActivity";
ViewPager2 viewPager2;
ViewPagerAdapter viewPagerAdapter;
BottomNavigationView bottomNavigationView;
@@ -46,6 +69,9 @@ public class MainActivity extends AppCompatActivity {
bottomNavigation();
checkLocationPermission();
checkBackgroundLocationPermission();
checkNotificationPermission();
startPowerSaverIntent(this);
getTokenFCM();
}
private void bottomNavigation() {
viewPagerAdapter = new ViewPagerAdapter(this);
@@ -85,7 +111,71 @@ public class MainActivity extends AppCompatActivity {
});
}
//Location
private void getTokenFCM(){
FirebaseMessaging.getInstance().getToken()
.addOnCompleteListener(new OnCompleteListener<String>() {
@Override
public void onComplete(@NonNull Task<String> task) {
if(!task.isSuccessful()){
Log.d(TAG, "Failed to registration token!");
return;
}
String token = task.getResult();
Common.FCM_TOKEN_SHIPPER = token;
FoodApiToken.apiService.updateFCMToken(Common.CURRENT_USER.getId(), token).enqueue(new Callback<CustomResponse>() {
@Override
public void onResponse(Call<CustomResponse> call, Response<CustomResponse> response) {
if(response.code() != 200)
Toast.makeText(MainActivity.this, "Không thể cập nhật FCM Token. Mã lỗi: " + response.code(), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<CustomResponse> call, Throwable t) {
Toast.makeText(MainActivity.this, "Đã có lỗi khi kết nối đến hệ thống!", Toast.LENGTH_SHORT).show();
}
});
Log.d(TAG, "Token: " + token);
}
});
}
//Check notification
private void checkNotificationPermission(){
if(!NotificationManagerCompat.from(this).areNotificationsEnabled()){
showDialogNotificationPermission();
}
}
private void showDialogNotificationPermission() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Vui lòng bật quyền thông báo trên thiết bị của bạn để có thể cập nhật đơn một cách " +
"nhanh nhất!")
.setCancelable(false)
.setPositiveButton("Ok", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
openSettings();
dialog.cancel();
}
})
.setNegativeButton("Thoát", 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();
}
//Check location permission
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){
@@ -124,33 +214,7 @@ public class MainActivity extends AppCompatActivity {
}
private void requestForPermission() {
ActivityCompat.requestPermissions(this, new String[] {Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE);
}
private void showDialogPermission() {
AlertDialog.Builder builder = new AlertDialog.Builder(this);
builder.setMessage("Ứng dụng này cần quyền truy cập vị trí để hoạt động. Xin vui lòng cấp quyền cho ứng dụng!")
.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();
ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.ACCESS_COARSE_LOCATION, Manifest.permission.ACCESS_FINE_LOCATION}, LOCATION_REQUEST_CODE);
}
private void openSettings() {
@@ -167,4 +231,62 @@ public class MainActivity extends AppCompatActivity {
}
//Check auto start permission
public static List<Intent> POWER_MANAGER_INTENTS = Arrays.asList(
new Intent().setComponent(new ComponentName("com.miui.securitycenter", "com.miui.permcenter.autostart.AutoStartManagementActivity")),
new Intent().setComponent(new ComponentName("com.letv.android.letvsafe", "com.letv.android.letvsafe.AutobootManageActivity")),
new Intent().setComponent(new ComponentName("com.huawei.systemmanager", "com.huawei.systemmanager.optimize.process.ProtectActivity")),
new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.permission.startup.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.coloros.safecenter", "com.coloros.safecenter.startupapp.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.oppo.safe", "com.oppo.safe.permission.startup.StartupAppListActivity")),
new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.AddWhiteListActivity")),
new Intent().setComponent(new ComponentName("com.iqoo.secure", "com.iqoo.secure.ui.phoneoptimize.BgStartUpManager")),
new Intent().setComponent(new ComponentName("com.vivo.permissionmanager", "com.vivo.permissionmanager.activity.BgStartUpManagerActivity")),
new Intent().setComponent(new ComponentName("com.asus.mobilemanager", "com.asus.mobilemanager.entry.FunctionActivity")).setData(android.net.Uri.parse("mobilemanager://function/entry/AutoStart"))
);
public void startPowerSaverIntent(Context context) {
SharedPreferences settings = context.getSharedPreferences("ProtectedApps", Context.MODE_PRIVATE);
boolean skipMessage = settings.getBoolean("skipProtectedAppCheck", false);
if (!skipMessage) {
final SharedPreferences.Editor editor = settings.edit();
boolean foundCorrectIntent = false;
for (Intent intent : POWER_MANAGER_INTENTS) {
if (isCallable(context, intent)) {
foundCorrectIntent = true;
final AppCompatCheckBox dontShowAgain = new AppCompatCheckBox(context);
dontShowAgain.setText("Không hiện hộp thoại này nữa!");
dontShowAgain.setButtonTintList(ColorStateList.valueOf(getResources().getColor(R.color.primaryColor, null)));
dontShowAgain.setOnCheckedChangeListener((buttonView, isChecked) -> {
editor.putBoolean("skipProtectedAppCheck", isChecked);
editor.apply();
});
new AlertDialog.Builder(context)
.setTitle("Phát hiện máy " + Build.MANUFACTURER + "!")
.setMessage(String.format("Vì một số dòng máy Trung Quốc tự động tắt chế độ chạy nền của app %s, nên cần bạn " +
"cho phép ứng dụng luôn tự khởi chạy ở cài đặt ứng dụng để có thể không bỏ lỡ bất kỳ thông báo nào!%n", context.getString(R.string.app_name)))
.setView(dontShowAgain)
.setPositiveButton("Đi đến cài đặt", (dialog, which) -> context.startActivity(intent))
.setNegativeButton("Đóng", null)
.show();
break;
}
}
if (!foundCorrectIntent) {
editor.putBoolean("skipProtectedAppCheck", true);
editor.apply();
}
}
}
private static boolean isCallable(Context context, Intent intent) {
List<ResolveInfo> list = context.getPackageManager().queryIntentActivities(intent,
PackageManager.MATCH_DEFAULT_ONLY);
return list.size() > 0;
}
}
@@ -2,27 +2,20 @@ 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;
import android.content.pm.PackageManager;
import android.location.Location;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.provider.Settings;
import android.util.Log;
import android.view.View;
import android.widget.Button;
@@ -32,18 +25,15 @@ import android.widget.TextView;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.app.AlertDialog;
import androidx.appcompat.app.AppCompatActivity;
import androidx.constraintlayout.widget.ConstraintLayout;
import androidx.core.app.ActivityCompat;
import androidx.core.content.ContextCompat;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import com.capstone.foodify.shipper.API.FoodApiToken;
import com.capstone.foodify.shipper.API.GoogleMapApi;
import com.capstone.foodify.shipper.API.TokenFCMFirebaseAPI;
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;
@@ -75,8 +65,6 @@ import com.thecode.aestheticdialogs.DialogType;
import com.thecode.aestheticdialogs.OnDialogClickListener;
import java.text.DecimalFormat;
import java.util.Timer;
import java.util.TimerTask;
import retrofit2.Call;
import retrofit2.Callback;
@@ -97,7 +85,7 @@ public class OrderDetailActivity extends AppCompatActivity {
LinearLayout layoutConfirmOrder;
private GeofencingClient geofencingClient;
private GeofenceHelper geofenceHelper;
private float GEOFENCE_RADIUS = 150;
private float GEOFENCE_RADIUS = 200;
private String GEOFENCE_ID = "SOME_GEOFENCE_ID";
//Location
private FusedLocationProviderClient mFusedLocationClient;
@@ -117,7 +105,7 @@ public class OrderDetailActivity extends AppCompatActivity {
order = (Order) getIntent().getSerializableExtra("order");
}
//Set data order when shipper return back the app from Google Map
if (order == null && Common.CURRENT_ORDER != null) {
order = Common.CURRENT_ORDER;
}
@@ -131,6 +119,8 @@ public class OrderDetailActivity extends AppCompatActivity {
initComponent();
initData();
getFCMTokenUser();
LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this, RecyclerView.VERTICAL, false);
rcv_list_order.setLayoutManager(linearLayoutManager);
@@ -162,6 +152,8 @@ public class OrderDetailActivity extends AppCompatActivity {
Uri.parse("google.navigation:q=" + order.getLat() + "," + order.getLng() + "&mode=l"));
intent.setPackage("com.google.android.apps.maps");
startActivity(intent);
} else{
Common.showErrorDialog(OrderDetailActivity.this, "Không thể lấy được thông tin đơn, vui lòng thử lại sau!");
}
}
});
@@ -216,6 +208,25 @@ public class OrderDetailActivity extends AppCompatActivity {
}
}
private void getFCMTokenUser(){
TokenFCMFirebaseAPI.apiService.getTokenFCM(order.getUser().getId()).enqueue(new Callback<String>() {
@Override
public void onResponse(Call<String> call, Response<String> response) {
if(response.code() == 200){
String tempToken = response.body();
assert tempToken != null;
Common.FCM_TOKEN_USER = tempToken.replace("\"", "");
} else {
Toast.makeText(OrderDetailActivity.this, "Error code: " + response.code(), Toast.LENGTH_SHORT).show();
}
}
@Override
public void onFailure(Call<String> call, Throwable t) {
Toast.makeText(OrderDetailActivity.this, Common.ERROR_CONNECT_SERVER, Toast.LENGTH_SHORT).show();
}
});
}
private void updateStatus(String status) {
Common.CURRENT_LOCATION = null;
changeOrderStatus(status);
@@ -514,4 +525,12 @@ public class OrderDetailActivity extends AppCompatActivity {
changeLayoutButton(Common.CURRENT_LOCATION.getLatitude(), Common.CURRENT_LOCATION.getLongitude());
}
}
@Override
protected void onDestroy() {
super.onDestroy();
stopLocationService();
Common.CURRENT_ORDER = null;
Common.FCM_TOKEN_USER = null;
}
}
@@ -5,7 +5,6 @@ import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.widget.Button;
import android.widget.Toast;
import androidx.annotation.NonNull;
@@ -207,7 +206,7 @@ public class SignInActivity extends AppCompatActivity {
@Override
public void onFailure(Call<User> call, Throwable t) {
System.out.println("ERROR: " + t);
Common.showErrorServerNotification(SignInActivity.this, "Không thể đăng nhập tài khoản! Vui lòng thử lại sau!");
Common.showErrorDialog(SignInActivity.this, "Không thể đăng nhập tài khoản! Vui lòng thử lại sau!");
}
});
} else {
@@ -25,7 +25,10 @@ public class Common {
public static Shipper CURRENT_SHIPPER = null;
public static Order CURRENT_ORDER = null;
public static String TOKEN = null;
public static String FCM_TOKEN_SHIPPER = null;
public static String FCM_TOKEN_USER = null;
public static Location CURRENT_LOCATION = null;
public static final String BASE_URL = "http://192.168.1.183:8080/api/";
public static final String MAP_API = "AIzaSyAY14Ic32UP26Hg6GILznOfbBihiY5BUxw";
public static final String FORMAT_DATE="dd-MM-yyyy";
public static final String VALID_EMAIL_ADDRESS_REGEX = "^[A-Z0-9._%+-]+@[A-Z0-9.-]+\\.[A-Z]{2,6}$";
@@ -51,7 +54,7 @@ public class Common {
return Typeface.createFromAsset(assetManager, "font/opensans.ttf");
}
public static void showErrorServerNotification(Activity activity, String message){
public static void showErrorDialog(Activity activity, String message){
new AestheticDialog.Builder(activity, DialogStyle.RAINBOW, DialogType.ERROR)
.setTitle("LỖI!")
.setMessage(message)
@@ -86,6 +86,7 @@ public class ShippingOrder extends Fragment {
public void onResponse(Call<Orders> call, Response<Orders> response) {
if(response.code() == 200){
assert response.body() != null;
listOrders.addAll(response.body().getOrders());
orderAdapter.setData(listOrders);
@@ -1,28 +1,27 @@
package com.capstone.foodify.shipper.GoogleMap;
import android.content.BroadcastReceiver;
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;
import com.capstone.foodify.shipper.API.FirebaseMessagingAPI;
import com.capstone.foodify.shipper.Activity.OrderDetailActivity;
import com.capstone.foodify.shipper.Common;
import com.capstone.foodify.shipper.Model.Order;
import com.capstone.foodify.shipper.Model.FirebaseMessaging.FirebaseMessaging;
import com.capstone.foodify.shipper.Model.FirebaseMessaging.Notification;
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;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
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) {
@@ -43,9 +42,31 @@ public class GeofenceBroadcastReceiver extends BroadcastReceiver {
if(transitionType == Geofence.GEOFENCE_TRANSITION_ENTER){
notificationHelper.sendHighPriorityNotification("Đã tới khu vực giao!", "Nhấp vào đây để quay về app!", OrderDetailActivity.class);
if(Common.FCM_TOKEN_USER != null)
sendNotification();
}
}
private void sendNotification(){
Notification notification = new Notification("Thông báo!", "Đơn hàng đang gần đến bạn!");
FirebaseMessaging firebaseMessaging = new FirebaseMessaging();
firebaseMessaging.setTo(Common.FCM_TOKEN_USER);
firebaseMessaging.setNotification(notification);
FirebaseMessagingAPI.apiService.sendNotification(firebaseMessaging).enqueue(new Callback<FirebaseMessaging>() {
@Override
public void onResponse(Call<FirebaseMessaging> call, Response<FirebaseMessaging> response) {
if(response.code() != 200){
Log.d(TAG, "Error to send notification. Code: " + response.code());
}
}
@Override
public void onFailure(Call<FirebaseMessaging> call, Throwable t) {
Log.e(TAG, "Error to connect FCM Messaging!");
}
});
}
}
@@ -0,0 +1,22 @@
package com.capstone.foodify.shipper.Model.FirebaseMessaging;
public class FirebaseMessaging {
private String to;
private Notification notification;
public String getTo() {
return to;
}
public void setTo(String to) {
this.to = to;
}
public Notification getNotification() {
return notification;
}
public void setNotification(Notification notification) {
this.notification = notification;
}
}
@@ -0,0 +1,47 @@
package com.capstone.foodify.shipper.Model.FirebaseMessaging;
public class Notification {
private String title;
private String body;
private String sound;
private String android_channel_id;
public Notification(String title, String body) {
this.title = title;
this.body = body;
this.sound = "notificationsound.mp3";
this.android_channel_id = "foodify-notification";
}
public String getTitle() {
return title;
}
public void setTitle(String title) {
this.title = title;
}
public String getBody() {
return body;
}
public void setBody(String body) {
this.body = body;
}
public String getSound() {
return sound;
}
public void setSound(String sound) {
this.sound = sound;
}
public String getAndroid_channel_id() {
return android_channel_id;
}
public void setAndroid_channel_id(String android_channel_id) {
this.android_channel_id = android_channel_id;
}
}
@@ -0,0 +1,115 @@
package com.capstone.foodify.shipper;
import android.app.NotificationChannel;
import android.app.NotificationManager;
import android.app.PendingIntent;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.media.AudioAttributes;
import android.media.RingtoneManager;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.core.app.NotificationCompat;
import com.capstone.foodify.shipper.API.FoodApiToken;
import com.capstone.foodify.shipper.Activity.MainActivity;
import com.capstone.foodify.shipper.Model.CustomResponse;
import com.google.firebase.messaging.FirebaseMessagingService;
import com.google.firebase.messaging.RemoteMessage;
import retrofit2.Call;
import retrofit2.Callback;
import retrofit2.Response;
public class NotificationService extends FirebaseMessagingService {
private static final String TAG = "NotificationService";
public static final String channelId = "foodify-notification";
@Override
public void onMessageReceived(RemoteMessage remoteMessage) {
// TODO(developer): Handle FCM messages here.
// Not getting messages here? See why this may be: https://goo.gl/39bRNJ
Log.d(TAG, "From: " + remoteMessage.getFrom());
// Check if message contains a notification payload.
if (remoteMessage.getNotification() != null) {
Log.d(TAG, "Message notification Body: " + remoteMessage.getNotification().getBody());
}
// Also if you intend on generating your own notifications as a result of a received FCM
// message, here is where that should be initiated. See sendNotification method below.
sendNotification(remoteMessage.getNotification().getTitle() , remoteMessage.getNotification().getBody());
}
private void sendNotification(String title, String messageBody) {
Intent intent = new Intent(this, MainActivity.class);
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this, 0 /* Request code */, intent,
PendingIntent.FLAG_IMMUTABLE);
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder notificationBuilder =
new NotificationCompat.Builder(this, channelId)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(messageBody)
.setAutoCancel(true)
.setSound(defaultSoundUri)
.setContentIntent(pendingIntent);
NotificationManager notificationManager =
(NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
createNotificationChannel(notificationManager);
notificationManager.notify(0 /* ID of notification */, notificationBuilder.build());
}
private void createNotificationChannel(NotificationManager notificationManager) {
Uri sound = Uri.parse(ContentResolver.SCHEME_ANDROID_RESOURCE + "://" + this.getPackageName() + "/" + R.raw.notificationsound); //Here is FILE_NAME is the name of file that you want to play
// Create the NotificationChannel, but only on API 26+ because
// the NotificationChannel class is new and not in the support library
CharSequence name = "Notification";
String description = "testing";
int importance = NotificationManager.IMPORTANCE_HIGH;
AudioAttributes audioAttributes = new AudioAttributes.Builder()
.setContentType(AudioAttributes.CONTENT_TYPE_SONIFICATION)
.setUsage(AudioAttributes.USAGE_ALARM)
.build();
NotificationChannel channel = new NotificationChannel(channelId, name, importance);
channel.setDescription(description);
channel.enableLights(true); channel.enableVibration(true);
channel.setSound(sound, audioAttributes);
notificationManager.createNotificationChannel(channel);
}
@Override
public void onNewToken(@NonNull String token) {
super.onNewToken(token);
if(Common.CURRENT_USER != null){
FoodApiToken.apiService.updateFCMToken(Common.CURRENT_USER.getId(), token).enqueue(new Callback<CustomResponse>() {
@Override
public void onResponse(Call<CustomResponse> call, Response<CustomResponse> response) {
if(response.code() != 200)
Toast.makeText(NotificationService.this, "Không thể cập nhật FCM Token. Mã lỗi: " + response.code(), Toast.LENGTH_SHORT).show();
}
@Override
public void onFailure(Call<CustomResponse> call, Throwable t) {
Toast.makeText(NotificationService.this, "Đã có lỗi khi kết nối đến hệ thống!", Toast.LENGTH_SHORT).show();
}
});
}
Log.d(TAG, "Renew token: " + token);
}
}
Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 471 KiB

@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
@@ -1,6 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<adaptive-icon xmlns:android="http://schemas.android.com/apk/res/android">
<background android:drawable="@drawable/ic_launcher_background" />
<foreground android:drawable="@drawable/ic_launcher_foreground" />
<monochrome android:drawable="@drawable/ic_launcher_foreground" />
<background android:drawable="@color/ic_launcher_background"/>
<foreground android:drawable="@mipmap/ic_launcher_foreground"/>
</adaptive-icon>
Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 982 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.6 KiB

Binary file not shown.
@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<color name="ic_launcher_background">#00C0FE</color>
</resources>
+1 -1
View File
@@ -2,7 +2,7 @@
<resources>
<style name="Theme.FoodifyShipper.SplashScreen" parent="Theme.SplashScreen">
<item name="windowSplashScreenBackground">#FFFFFF</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/icon_shipper_with_background</item>
<item name="windowSplashScreenAnimatedIcon">@drawable/logo</item>
<item name="postSplashScreenTheme">@style/Theme.FoodifyShipper</item>
</style>
</resources>