I am building an android firebase chat app that doesn't require a server setup, I've already built everything for it and found a couple of YouTube tutorials on how to do what I'm having trouble with right now, I'm trying to get the app itself to send a push notification to the device its sending the message to, I'm using Volley to send the notification, the problem that I'm facing is the other device is not getting or showing the notification, can you please tell me what I'm doing wrong and how to fix it?
build.gradle
implementation 'com.google.firebase:firebase-auth:20.0.4'
implementation 'com.google.firebase:firebase-database:19.7.0'
implementation platform('com.google.firebase:firebase-bom:27.0.0')
implementation 'com.google.firebase:firebase-analytics'
implementation 'com.google.firebase:firebase-messaging:20.0.1'
implementation 'com.android.volley:volley:1.1.1'
AndroidManifest
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
...
<service
android:name=".MyFirebaseMessagingService"
android:permission="com.google.android.c2dm.permission.SEND">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
</intent-filter>
</service>
<service
android:name=".MyFirebaseInstanceIDService">
<intent-filter>
<action android:name="com.google.firebase.INSTANCE_ID_EVENT" />
</intent-filter>
</service>
MyFirebaseInstanceIDService
public class MyFirebaseInstanceIDService extends FirebaseInstanceIdService {
private static final String TAG = "mFirebaseIIDService";
#Override
public void onTokenRefresh() {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
final String token = FirebaseInstanceId.getInstance().getToken();
FirebaseInstallations.getInstance().getToken(false)
.addOnCompleteListener(new OnCompleteListener<InstallationTokenResult>() {
#Override
public void onComplete(#NonNull Task<InstallationTokenResult> task) {
FirebaseUser user = FirebaseAuth.getInstance().getCurrentUser();
FirebaseMessaging.getInstance().subscribeToTopic(user.getUid());
Log.i("TAG", "onTokenRefresh completed with token: " + task.getResult().getToken());
}
});
}
}
MyFirebaseMessagingService
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private final String ADMIN_CHANNEL_ID = "admin_channel";
#Override
public void onMessageReceived(#NonNull RemoteMessage remoteMessage) {
final Intent intent = new Intent(this, MainActivity.class);
NotificationManager notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
int notificationID = new Random().nextInt(85-65);
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
setupChannels(notificationManager);
}
intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
PendingIntent pendingIntent = PendingIntent.getActivity(this , 0, intent,
PendingIntent.FLAG_ONE_SHOT);
NotificationCompat.Builder notificationBuilder = new NotificationCompat.Builder(this, ADMIN_CHANNEL_ID)
.setContentTitle(remoteMessage.getData().get("title"))
.setContentText(remoteMessage.getData().get("message"))
.setAutoCancel(true)
.setSound(notificationSoundUri)
.setContentIntent(pendingIntent);
notificationManager.notify(notificationID, notificationBuilder.build());
}
#RequiresApi(api = Build.VERSION_CODES.O)
private void setupChannels(NotificationManager notificationManager){
CharSequence adminChannelName = "New notification";
String adminChannelDescription = "Device to device notification";
NotificationChannel adminChannel;
adminChannel = new NotificationChannel(ADMIN_CHANNEL_ID, adminChannelName, NotificationManager.IMPORTANCE_HIGH);
adminChannel.setDescription(adminChannelDescription);
adminChannel.enableLights(true);
adminChannel.setLightColor(Color.RED);
adminChannel.enableVibration(true);
if (notificationManager != null) {
notificationManager.createNotificationChannel(adminChannel);
}
}
}
MessageActivity
final private String FCM_API = "https://fcm.googleapis.com/fcm/send";
final private String serverKey = "key=MY_KEY";
final private String contentType = "application/json";
final String TAG = "NOTIFICATION TAG";
...
sendBtn.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
String msg = msg_editText.getText().toString();
if (!msg.equals("")) {
sendMessage(fuser.getUid(), userid, msg);
JSONObject notification = getStructure(fuser.getUid(), userid, msg);
sendNotification(notification);
}
msg_editText.setText("");
}
});
...
private JSONObject getStructure(String senderId, String receiverId, String msg) {
JSONObject notification = new JSONObject();
JSONObject notificationBody = new JSONObject();
try {
notificationBody.put("title", "App Test");
notificationBody.put("message", "This is a test notification from the app");
notification.put("to", "/topics/" + receiverId);
notification.put("data", notificationBody);
} catch (JSONException e) {
e.printStackTrace();
}
return notification;
}
...
private void sendNotification(JSONObject notification) {
JsonObjectRequest jsonObjectRequest = new JsonObjectRequest(FCM_API, notification,
new Response.Listener<JSONObject>() {
#Override
public void onResponse(JSONObject response) {
Log.i(TAG, "onResponse: " + response.toString());
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(MessageActivity.this, "Request error", Toast.LENGTH_SHORT).show();
Log.i(TAG, "onErrorResponse: Didn't work");
}
}) {
#Override
public Map<String, String> getHeaders() throws AuthFailureError {
Map<String, String> params = new HashMap<>();
params.put("Authorization", serverKey);
params.put("Content-Type", contentType);
return params;
}
};
MySingleton.getInstance(getApplicationContext()).addToRequestQueue(jsonObjectRequest);
}
MySingleton
public class MySingleton {
private static MySingleton instance;
private RequestQueue requestQueue;
private Context ctx;
public MySingleton(Context ctx) {
this.ctx = ctx;
requestQueue = getRequestQueue();
}
public static synchronized MySingleton getInstance(Context context) {
if (instance == null) {
instance = new MySingleton(context);
}
return instance;
}
public RequestQueue getRequestQueue() {
if (requestQueue == null) {
requestQueue = Volley.newRequestQueue(ctx.getApplicationContext());
}
return requestQueue;
}
public <T> void addToRequestQueue(Request<T> req) {
getRequestQueue().add(req);
}
}
Related
android fcm notification not received and while the device which supposed to receivethe notification shows this message in Logcat (Received from FCM TITLE: null, Received from FCM BODY: null). I have already checked that notification is not being received in both <26 and >26 SDK Versions
====================MyFirebaseMessagingService===============================
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String channel_id = "the_id";
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
updateTokenToFirebase(s);
}
private void updateTokenToFirebase(String token) {
IDrinkShopAPI mService = Common.getAPI();
mService.updateToken("SERVER_01",token,"0")
.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("DEBUG_TOKEN",response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("DEBUG_TOKEN",t.getMessage());
}
});
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if(remoteMessage.getData() != null){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
sendNotification26(remoteMessage);
else
sendNotification(remoteMessage);
}
}
private void sendNotification26(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
NotificationHelper helper ;
Notification.Builder builder;
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
helper = new NotificationHelper(this);
builder = helper.getDrinkShopNotification(title,message,defaultSoundUri);
helper.getManager().notify(new Random().nextInt(),builder.build());
}
private void sendNotification(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setSound(defaultSoundUri);
NotificationManager mn =(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
mn.notify(new Random().nextInt(),builder.build());
}
}
=========================NotificationHelper =================================
//this class is used to implement notification for all android versions
public class NotificationHelper extends ContextWrapper {
private static final String CHANNEL_ID = "the_id";
private static final String CHANNEL_NAME = "Drink_Shop";
private NotificationManager notificationManager;
public NotificationHelper(Context base) {
super(base);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createChannel();
}
#TargetApi(Build.VERSION_CODES.O)
private void createChannel() {
NotificationChannel nc = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT);
nc.enableLights(false);
nc.enableVibration(true);
nc.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(nc);
}
public NotificationManager getManager() {
if(notificationManager == null)
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
return notificationManager;
}
#TargetApi(Build.VERSION_CODES.O)
public Notification.Builder getDrinkShopNotification(String title,
String message,
Uri soundUri)
{
return new Notification.Builder(getApplicationContext(),CHANNEL_ID)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(soundUri)
.setChannelId(CHANNEL_ID)
.setAutoCancel(true);
}
}
=============================Manifest=======================================
<service
android:name=".Services.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
============================Build.gradle====================================
implementation 'com.google.firebase:firebase-messaging:20.0.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
===========================IFCMService=======================================
public interface IFCMService {
#Headers({
"Content-Type:application/json",
"Authorization:mytoken"
})
#POST("fcm/send")
Call<MyResponse> sendNotification(#Body DataMessage body);
}
==========================sendNotificationToServer===============================
// this method used to send the notification to server device
private void sendNotificationToServer(OrderResult orderResult) {
mService.getToken("SERVER_01", "1")
.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
Map<String,String> contentSend = new HashMap<>();
contentSend.put("title","NEW ORDER");
contentSend.put("message","You have got new order" + orderResult.getOrderId());
DataMessage dataMessage = new DataMessage();
if(response.body().getToken() != null)
dataMessage.setTo(response.body().getToken());
dataMessage.setData(contentSend);
IFCMService ifcmService = Common.getFCMService();
ifcmService.sendNotification(dataMessage)
.enqueue(new Callback<MyResponse>() {
#Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
if(response.code() == 200){
if(response.body().success == 1){
Toast.makeText(CartActivity.this,
getResources().getString(R.string.order_submitted), Toast.LENGTH_SHORT)
.show();
//Clear Carts From Room Database
Common.cartRepository.emptyCart();
//finish();
}
else {
Toast.makeText(CartActivity.this, "Send Notification Failed", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onFailure(Call<MyResponse> call, Throwable t) {
Toast.makeText(CartActivity.this, ""+t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
Toast.makeText(CartActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
I have solved this issue by downgrading firebase-messaging library as follow (implementation 'com.google.firebase:firebase-messaging:17.3.4') as will as .setColor(ContextCompat.getColor(this, R.color.colorAccent)) in NotificationCompat. However this has solved the issue for me for SDK version lower than 26. Anyone knows why it is still cashing on APIs higher than 26 ?! help me please
When the App is running in background the notification is received in the system tray, and when is tapped, the intent is sended to your activity default, with the notification with payload of content of it.
When your application is running in front, the notification is received with the FirebaseMessagingService and the logic that you overrided.
I think you should add the logic of the first point, when the app is running in background
Check here more information
Handling messages
Android fcm notification is being received on android with APIs lower than 26 however APIs 26(Oreo 8.0) it doesn't and it cause app to be crashed
====================MyFirebaseMessagingService===============================
public class MyFirebaseMessagingService extends FirebaseMessagingService {
private static final String channel_id = "the_id";
#Override
public void onNewToken(String s) {
super.onNewToken(s);
Log.e("NEW_TOKEN",s);
updateTokenToFirebase(s);
}
private void updateTokenToFirebase(String token) {
IDrinkShopAPI mService = Common.getAPI();
mService.updateToken("SERVER_01",token,"0")
.enqueue(new Callback<String>() {
#Override
public void onResponse(Call<String> call, Response<String> response) {
Log.d("DEBUG_TOKEN",response.body());
}
#Override
public void onFailure(Call<String> call, Throwable t) {
Log.d("DEBUG_TOKEN",t.getMessage());
}
});
}
#Override
public void onMessageReceived(RemoteMessage remoteMessage) {
super.onMessageReceived(remoteMessage);
if(remoteMessage.getData() != null){
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
sendNotification26(remoteMessage);
else
sendNotification(remoteMessage);
}
}
private void sendNotification26(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
NotificationHelper helper ;
Notification.Builder builder;
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
helper = new NotificationHelper(this);
builder = helper.getDrinkShopNotification(title,message,defaultSoundUri);
helper.getManager().notify(new Random().nextInt(),builder.build());
}
private void sendNotification(RemoteMessage remoteMessage) {
Map<String,String> data = remoteMessage.getData();
String title = data.get("title");
String message = data.get("message");
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this)
.setSmallIcon(R.mipmap.ic_launcher)
.setContentTitle(title)
.setContentText(message)
.setAutoCancel(true)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setSound(defaultSoundUri);
NotificationManager mn =(NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
mn.notify(new Random().nextInt(),builder.build());
}
}
=========================NotificationHelper =================================
//this class is used to implement notification for APIs 26+
public class NotificationHelper extends ContextWrapper {
private static final String CHANNEL_ID = "the_id";
private static final String CHANNEL_NAME = "Drink_Shop";
private NotificationManager notificationManager;
public NotificationHelper(Context base) {
super(base);
if(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
createChannel();
}
#TargetApi(Build.VERSION_CODES.O)
private void createChannel() {
NotificationChannel nc = new NotificationChannel(CHANNEL_ID,CHANNEL_NAME,
NotificationManager.IMPORTANCE_DEFAULT);
nc.enableLights(false);
nc.enableVibration(true);
nc.setLockscreenVisibility(Notification.VISIBILITY_PRIVATE);
getManager().createNotificationChannel(nc);
}
public NotificationManager getManager() {
if(notificationManager == null)
notificationManager = (NotificationManager)getSystemService(Context.NOTIFICATION_SERVICE);
return notificationManager;
}
#TargetApi(Build.VERSION_CODES.O)
public Notification.Builder getDrinkShopNotification(String title,
String message,
Uri soundUri)
{
return new Notification.Builder(getApplicationContext(),CHANNEL_ID)
.setContentTitle(title)
.setContentText(message)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(soundUri)
.setChannelId(CHANNEL_ID)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setAutoCancel(true);
}
}
=============================Manifest=======================================
<service
android:name=".Services.MyFirebaseMessagingService"
android:enabled="true"
android:exported="true">
<intent-filter>
<action android:name="com.google.firebase.MESSAGING_EVENT" />
</intent-filter>
</service>
============================Build.gradle====================================
implementation 'com.google.firebase:firebase-messaging:20.0.0'
implementation 'com.google.firebase:firebase-core:17.2.1'
implementation 'com.google.android.gms:play-services-auth:17.0.0'
===========================IFCMService=======================================
public interface IFCMService {
#Headers({
"Content-Type:application/json",
"Authorization:mytoken"
})
#POST("fcm/send")
Call<MyResponse> sendNotification(#Body DataMessage body);
}
==========================sendNotificationToServer===============================
// this method used to send the notification to server app
private void sendNotificationToServer(OrderResult orderResult) {
mService.getToken("SERVER_01", "1")
.enqueue(new Callback<Token>() {
#Override
public void onResponse(Call<Token> call, Response<Token> response) {
Map<String,String> contentSend = new HashMap<>();
contentSend.put("title","NEW ORDER");
contentSend.put("message","You have got new order" + orderResult.getOrderId());
DataMessage dataMessage = new DataMessage();
if(response.body().getToken() != null)
dataMessage.setTo(response.body().getToken());
dataMessage.setData(contentSend);
IFCMService ifcmService = Common.getFCMService();
ifcmService.sendNotification(dataMessage)
.enqueue(new Callback<MyResponse>() {
#Override
public void onResponse(Call<MyResponse> call, Response<MyResponse> response) {
if(response.code() == 200){
if(response.body().success == 1){
Toast.makeText(CartActivity.this,
getResources().getString(R.string.order_submitted), Toast.LENGTH_SHORT)
.show();
//Clear Carts From Room Database
Common.cartRepository.emptyCart();
//finish();
}
else {
Toast.makeText(CartActivity.this, "Send Notification Failed", Toast.LENGTH_SHORT).show();
}
}
}
#Override
public void onFailure(Call<MyResponse> call, Throwable t) {
Toast.makeText(CartActivity.this, ""+t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
#Override
public void onFailure(Call<Token> call, Throwable t) {
Toast.makeText(CartActivity.this, t.getMessage(), Toast.LENGTH_SHORT).show();
}
});
}
I think you are making the code unnecessarily complicated.
Try this below code
private void createNotification(String title, String message) {
NotificationManager manager = (NotificationManager) getSystemService(Context.NOTIFICATION_SERVICE);
// only create notification channel if SDK >= 26
if (android.os.Build.VERSION.SDK_INT >= 26) {
NotificationChannel channel = new NotificationChannel(CHANNEL_ID, CHANNEL_NAME, NotificationManager.IMPORTANCE_DEFAULT);
channel.enableLights(false);
channel.enableVibration(true);
channel.setDescription(CHANNEL_DESC);
manager.createNotificationChannel(channel);
}
Uri defaultSoundUri = RingtoneManager.getDefaultUri(RingtoneManager.TYPE_NOTIFICATION);
NotificationCompat.Builder builder = new NotificationCompat.Builder(this, CHANNEL_ID)
.setSmallIcon(android.R.drawable.stat_notify_more)
.setContentTitle(title)
.setSmallIcon(R.mipmap.ic_launcher)
.setSound(defaultSoundUri)
.setColor(ContextCompat.getColor(this, R.color.colorAccent))
.setContentText(message);
manager.notify(new Random().nextInt(), builder.build());
}
I am developing an application that must read a confirmation code by SMS exactly as on registration on Whatsapp. It works well for Android versions 5 and below, but from version 6 the application does not read the sms.
Below is the class called in the main function. It reads received SMS messages automatically:
public class SmsReceiver extends BroadcastReceiver {
private static SmsListener mListener;
//add...
private static final String
TAG = SmsReceiver.class.getSimpleName();
public static final String pdu_type = "pdus";
//add..
#TargetApi(Build.VERSION_CODES.M)
#Override
public void onReceive(Context context, Intent intent) {
Bundle data = intent.getExtras();
Object[] pdus = (Object[]) data.get("pdus");
String format = data.getString("format");
//Toast.makeText(context,"coollll:" + pdus,Toast.LENGTH_LONG).show();
if (pdus!=null){
//
Toast.makeText(context,"noooooooo",Toast.LENGTH_LONG).show();
boolean isVersionM= (Build.VERSION.SDK_INT >=
Build.VERSION_CODES.M);
for (int i=0; i<pdus.length; i++){
if (isVersionM){
SmsMessage smsMessage =
SmsMessage.createFromPdu((byte[]) pdus[i],format);
String sender = smsMessage.getDisplayOriginatingAddress();
if(sender.equals("myProjet")){
String messageBody = smsMessage.getMessageBody();
mListener.messageReceived(messageBody);
}
}else {
SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
String sender = smsMessage.getDisplayOriginatingAddress();
if(sender.equals("projet")){
String messageBody = smsMessage.getMessageBody();
mListener.messageReceived(messageBody);
}
}
}
}
}
public static void bindListerner(SmsListener listener){
mListener = listener;
}
}
Below is the SmsListener.java interface which listens for incoming messages:
public interface SmsListener {
public void messageReceived(String messageText);
}
And below is the activity that processes the received SMS:
public class CodeConfirmation extends Activity {
private String telephone;
private TextView tel, textcode, textCount, textSendAgainSms;
private RequestQueue requestQueue;
private StringRequest stringRequest;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_code_confirmation);
final Pinview pin = (Pinview) findViewById(R.id.pinview);
pin.setPinBackgroundRes(R.drawable.sample_background);
countTime();
requestQueue= Volley.newRequestQueue(this);
Intent intent= getIntent();
final String codeGenere=
getIntent().getExtras().getString("code");
telephone= getIntent().getExtras().getString("telephone");
Toast.makeText(CodeConfirmation.this, codeGenere,
Toast.LENGTH_SHORT).show();
// on affiche le numéro de l'utilisateur dans la vue
tel =(TextView)findViewById(R.id.my_number);
textcode=(TextView)findViewById(R.id.text);
tel.setText(getString(R.string.your_tel)+ telephone);
textcode.setText(getString(R.string.code_confirmation));
textCount=(TextView)findViewById(R.id.textCount);
textSendAgainSms=(TextView)findViewById(R.id.send_code_agent);
textSendAgainSms.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View v) {
textSendAgainSms.setText(null);
countTime();
}
});
SmsReceiver.bindListerner(new SmsListener() {
#Override
public void messageReceived(String messageText) {
Toast.makeText(CodeConfirmation.this,"Message:" + messageText,Toast.LENGTH_LONG).show();
if (messageText.compareToIgnoreCase(codeGenere)==0){
pin.setValue(messageText);
Toast.makeText(CodeConfirmation.this, getString(R.string.succes_code), Toast.LENGTH_SHORT).show();
finish();
startActivity(new Intent(getApplicationContext(), LoginActivity.class));
}
}
});
/*
*Lorsque l'utilisateur entre le code à 5 chiffres
*/
pin.setPinViewEventListener(new
Pinview.PinViewEventListener() {
#Override
public void onDataEntered(Pinview pinview, boolean b) {
final String code= pinview.getValue();
//Toast.makeText(CodeConfirmation.this, code, Toast.LENGTH_SHORT).show();
if (code.compareToIgnoreCase(codeGenere)==0){
Toast.makeText(CodeConfirmation.this,getString(R.string.succes_code), Toast.LENGTH_SHORT).show();
finish();
startActivity(new Intent(getApplicationContext(),LoginActivity.class));
}
else{
Toast.makeText(CodeConfirmation.this,getString(R.string.wrong_code), Toast.LENGTH_SHORT).show();
}
}
});
}
public void countTime(){
new CountDownTimer(30000, 1000) {
#Override
public void onTick(long millisUntilFinished) {
textCount.setText(getString(R.string.TimeCount)+":"+millisUntilFinished/1000);
}
#Override
public void onFinish() {
textSendAgainSms.setText(getString(R.string.send_code_agent));
}
}.start();
}
public void CheckNumber(final String telephone){
stringRequest= new StringRequest(Request.Method.POST, BuildConfig.server + "register", new Response.Listener<String>() {
#Override
public void onResponse(String response) {
try {
JSONObject jsonObject = new JSONObject(response);
String objetJson= jsonObject.getString("success");
//Toast.makeText(getApplicationContext(),"response-> : "+jsonObject.getString("success"), Toast.LENGTH_SHORT).show();
if(objetJson.equals("true")){
/*Toast.makeText(getApplicationContext(), "code-> "+jsonObject.getString("code"), Toast.LENGTH_LONG).show();
Toast.makeText(getApplicationContext(), "telephone-> "+jsonObject.getString("telephone"), Toast.LENGTH_LONG).show();*/
//startActivity(new Intent(getApplicationContext(),CodeConfirmation.class));
}
else if(objetJson.equals("false")){
Toast.makeText(getApplicationContext(),"error", Toast.LENGTH_SHORT).show();
}
} catch (JSONException e) {
e.printStackTrace();
}
}
}, new Response.ErrorListener() {
#Override
public void onErrorResponse(VolleyError error) {
Toast.makeText(getApplicationContext(),"Aucune connexion internet " ,Toast.LENGTH_SHORT).show();
}
}){
#Override
protected Map<String, String> getParams() throws AuthFailureError {
HashMap<String, String> hashMap = new HashMap<String, String>();
hashMap.put("telephone", telephone);
return hashMap;
}
};
requestQueue.add(stringRequest);
}
}
This is what my AndroidManifest.xml file looks like:
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission
android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission
android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_SMS"/>
<uses-permission android:name="android.permission.SEND_SMS"/>
<application
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity
android:name=".connexion.LoginActivity"
android:label="#string/title_activity_login"
android:theme="#style/AppTheme.NoActionBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".connexion.CodeConfirmation"
android:label="#string/title_activity_code_confirmation" />
<receiver
android:name=".sms.SmsReceiver"
android:enabled="true"
android:exported="true">
<intent-filter>
<action
android:name="android.provider.Telephony.SMS_RECEIVED"/>
</intent-filter>
</receiver>
</application>
</manifest>
in the new android api, you need of course permission on Manifest, but you need implement runtime permissions, maybe you can put it in your first Activity.
Look this link
Examples to do runtime permission
When I update the app to a new version, the service that was installed with the previous app version is still running. When I update the app the second time, the updated service is running properly.
However, after first update, whenever i close the app or restart the phone the service from the previous version is running.
How can i force the new service to run as soon as the app is updated.
Here is my code
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.djuro.updateservicewithappupdate">
<application
android:name=".App"
android:allowBackup="true"
android:icon="#mipmap/ic_launcher"
android:label="#string/app_name"
android:roundIcon="#mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="#style/AppTheme">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<service
android:name=".MyService"
android:process=":myService" />
<receiver android:name=".PackageReplacedReceiver">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REMOVED" />
<data android:scheme="package" android:path="com.djuro.updateservicewithappupdate"/>
</intent-filter>
</receiver>
</application>
</manifest>
App.java
public class App extends Application {
private static final String TAG = App.class.getName();
private static App mInstance;
private Messenger myServiceMessenger;
private boolean isBound;
private Messenger replyMessenger = new Messenger(new IncomingHandler());
#Override
public void onCreate() {
super.onCreate();
if (mInstance == null) {
mInstance = this;
startMyService();
}
isBound = false;
// start the chore service (if it is not running) and bind to it
}
public void startMyService() {
startService(new Intent(mInstance, MyService.class));
doBindService();
}
public void stopMyService() {
doUnBindService(true);
stopService(new Intent(mInstance, MyService.class));
}
public static App getInstance() {
return mInstance;
}
public static Context getContext() {
return mInstance.getApplicationContext();
}
public static Messenger getChoreMessenger() {return mInstance.myServiceMessenger;}
#Override
public void onTerminate() {
doUnBindService(false);
super.onTerminate();
}
private void doBindService() {
if (!isBound) {
Log.d(TAG, "Binding ChoreService.");
bindService(new Intent(this, MyService.class), myServiceConnection, Context.BIND_AUTO_CREATE);
isBound = true;
}
}
private void doUnBindService(boolean restartService) {
if (isBound) {
Log.d(TAG, "Unbinding ChoreService.");
if (myServiceMessenger != null) {
try {
Message msg = Message.obtain(null, MyService.UNREGISTER_CLIENT);
msg.replyTo = replyMessenger;
replyMessenger.send(msg);
}
catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
if (restartService) {
try {
Message msg = Message.obtain(null, MyService.STOP_SERVICE_ON_UNBIND);
msg.replyTo = replyMessenger;
replyMessenger.send(msg);
}
catch (RemoteException e) {
// There is nothing special we need to do if the service has crashed.
}
}
unbindService(myServiceConnection);
isBound = false;
} else if (restartService) {
stopService(new Intent(mInstance, MyService.class));
}
}
private ServiceConnection myServiceConnection = new ServiceConnection() {
public void onServiceConnected(ComponentName className, IBinder service) {
myServiceMessenger = new Messenger(service);
Log.d(TAG, "connected to service");
try {
Message msg = Message.obtain(null, MyService.REGISTER_CLIENT);
msg.replyTo = replyMessenger;
myServiceMessenger.send(msg);
}
catch (RemoteException e) {
// In this case the service has crashed before we could even do anything with it
}
}
public void onServiceDisconnected(ComponentName className) {
myServiceMessenger = null;
Log.d(TAG, "disconnected from ChoreService");
}
};
class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
}
}
}
MyService.java
public class MyService extends Service {
private static final String TAG = MyService.class.getName();
public static final int UNREGISTER_CLIENT = 1;
public static final int REGISTER_CLIENT = 2;
public static final int STOP_SERVICE_ON_UNBIND = 3;
final Messenger messenger = new Messenger(new IncomingHandler());
private String appVersion;
private boolean stopOnUnbind;
private int boundCount = 0;
// called when the intent starts the Service
#Override
public int onStartCommand(Intent intent, int flags, int startId) {
//return super.onStartCommand(intent, flags, startId);
Log.d(TAG, "onStartCommand()");
getVersion();
return START_STICKY;
}
// called once at creation (before onStartCommand)
#Override
public void onCreate() {
super.onCreate();
Log.d(TAG, "onCreate");
}
// used to bind intent to service
#Nullable
#Override
public IBinder onBind(Intent intent) {
//doStopForeground();
boundCount ++;
Log.d(TAG, "bound count: " + boundCount);
return messenger.getBinder();
}
#Override
public boolean onUnbind(Intent intent) {
boundCount --;
Log.d(TAG, "bound count: " + boundCount);
boolean result = super.onUnbind(intent);
if (stopOnUnbind) {
Log.d(TAG, "stopSelf()");
stopSelf();
}
return result;
}
// called when the service is destroyed
#Override
public void onDestroy() {
Log.d(TAG, "onDestroy()");
super.onDestroy();
}
public void getVersion() {
try {
PackageInfo pInfo = this.getPackageManager().getPackageInfo(getPackageName(), 0);
appVersion = pInfo.versionName;
Log.d(TAG, "appVersion: " + appVersion);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
}
private class IncomingHandler extends Handler {
#Override
public void handleMessage(Message msg) {
Log.d(TAG, "IncomingHandler handling message. msg.what= " + msg.what);
switch (msg.what) {
case STOP_SERVICE_ON_UNBIND:
stopOnUnbind = true;
break;
default:
super.handleMessage(msg);
break;
}
}
}
}
PackageReplacedReceiver.java
public class PackageReplacedReceiver extends BroadcastReceiver {
private static final String TAG = PackageReplacedReceiver.class.getName();
#Override
public void onReceive(Context context, Intent intent) {
Log.d(TAG, "package updated");
App.getInstance().stopMyService();
}
}
Use android.intent.action.MY_PACKAGE_REPLACED action in your intent filer and stop your service from broadcast receiver.
<receiver android:name=".PackageReplacedReceiver" android:enabled="#bool/is_at_least_api_12" > <intent-filter>
<action android:name="android.intent.action.MY_PACKAGE_REPLACED" />
</intent-filter>
</receiver>
Im trying to add notifications to my android app. So I decided to implement GCM.
I have used the sample code from the official documentation
https://developer.android.com/google/gcm/client.html
and the sample application
https://code.google.com/p/gcm/source/browse/samples/gcm-demo-client/src/com/google/android/gcm/demo/app/
Here is my implementation
public class RegisterActivity extends Activity implements SurfaceHolder.Callback{
public static final String PROPERTY_REG_ID = "registration_id";
private static final String PROPERTY_APP_VERSION = "appVersion";
private static final int PLAY_SERVICES_RESOLUTION_REQUEST = 9000;
String SENDER_ID = "210822831159";
GoogleCloudMessaging gcm;
AtomicInteger msgId = new AtomicInteger();
Context context;
String regid;
#Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_register);
context = getApplicationContext();
if (checkPlayServices())
{
gcm = GoogleCloudMessaging.getInstance(this);
regid = getRegistrationId(context);
if (regid.isEmpty())
{
registerInBackground();
}
else
{
//"No valid Google Play Services APK found."
}
}
//...
}
#Override
protected void onResume() {
super.onResume();
// Check device for Play Services APK.
checkPlayServices();
}
private boolean checkPlayServices() {
int resultCode = GooglePlayServicesUtil.isGooglePlayServicesAvailable(this);
if (resultCode != ConnectionResult.SUCCESS) {
if (GooglePlayServicesUtil.isUserRecoverableError(resultCode)) {
GooglePlayServicesUtil.getErrorDialog(resultCode, this,
PLAY_SERVICES_RESOLUTION_REQUEST).show();
} else {
finish();
}
return false;
}
return true;
}
private void storeRegistrationId(Context context, String regId) {
final SharedPreferences prefs = getGcmPreferences(context);
int appVersion = getAppVersion(context);
SharedPreferences.Editor editor = prefs.edit();
editor.putString(PROPERTY_REG_ID, regId);
editor.putInt(PROPERTY_APP_VERSION, appVersion);
editor.commit();
}
private String getRegistrationId(Context context) {
final SharedPreferences prefs = getGcmPreferences(context);
String registrationId = prefs.getString(PROPERTY_REG_ID, "");
if (registrationId.isEmpty()) {
return "";
}
int registeredVersion = prefs.getInt(PROPERTY_APP_VERSION, Integer.MIN_VALUE);
int currentVersion = getAppVersion(context);
if (registeredVersion != currentVersion) {
return "";
}
return registrationId;
}
private void registerInBackground() {
new AsyncTask<Void, Void, String>() {
#Override
protected String doInBackground(Void... params) {
String msg = "";
try {
if (gcm == null) {
gcm = GoogleCloudMessaging.getInstance(context);
}
regid = gcm.register(SENDER_ID);
msg = "Device registered, registration ID=" + regid;
sendRegistrationIdToBackend();
storeRegistrationId(context, regid);
} catch (IOException ex) {
msg = "Error :" + ex.getMessage();
}
return msg;
}
#Override
protected void onPostExecute(String msg) {
//...
}
}.execute(null, null, null);
}
private static int getAppVersion(Context context) {
try {
PackageInfo packageInfo = context.getPackageManager()
.getPackageInfo(context.getPackageName(), 0);
return packageInfo.versionCode;
} catch (PackageManager.NameNotFoundException e) {
// should never happen
throw new RuntimeException("Could not get package name: " + e);
}
}
private SharedPreferences getGcmPreferences(Context context) {
return getSharedPreferences(RegisterActivity.class.getSimpleName(),
Context.MODE_PRIVATE);
}
private void sendRegistrationIdToBackend() {
// TODO
}
//...
}
The Broadcaster:
public class GcmBroadcastReceiver extends WakefulBroadcastReceiver {
#Override
public void onReceive(Context context, Intent intent) {
// Explicitly specify that GcmIntentService will handle the intent.
ComponentName comp = new ComponentName(context.getPackageName(),
GcmIntentService.class.getName());
// Start the service, keeping the device awake while it is launching.
startWakefulService(context, (intent.setComponent(comp)));
setResultCode(Activity.RESULT_OK);
}
}
Intent Service:
public class GcmIntentService extends IntentService {
public static final int NOTIFICATION_ID = 1;
private NotificationManager mNotificationManager;
NotificationCompat.Builder builder;
public GcmIntentService() {
super("GcmIntentService");
}
#Override
protected void onHandleIntent(Intent intent) {
Bundle extras = intent.getExtras();
GoogleCloudMessaging gcm = GoogleCloudMessaging.getInstance(this);
// The getMessageType() intent parameter must be the intent you received
// in your BroadcastReceiver.
String messageType = gcm.getMessageType(intent);
if (!extras.isEmpty()) { // has effect of unparcelling Bundle
/*
* Filter messages based on message type. Since it is likely that GCM
* will be extended in the future with new message types, just ignore
* any message types you're not interested in, or that you don't
* recognize.
*/
if (GoogleCloudMessaging.
MESSAGE_TYPE_SEND_ERROR.equals(messageType)) {
sendNotification("Send error: " + extras.toString());
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_DELETED.equals(messageType)) {
sendNotification("Deleted messages on server: " +
extras.toString());
// If it's a regular GCM message, do some work.
} else if (GoogleCloudMessaging.
MESSAGE_TYPE_MESSAGE.equals(messageType)) {
// This loop represents the service doing some work.
for (int i=0; i<5; i++) {
try {
Thread.sleep(5000);
} catch (InterruptedException e) {
}
}
// Post notification of received message.
sendNotification("Received: " + extras.toString());
}
}
// Release the wake lock provided by the WakefulBroadcastReceiver.
GcmBroadcastReceiver.completeWakefulIntent(intent);
}
// Put the message into a notification and post it.
// This is just one simple example of what you might choose to do with
// a GCM message.
private void sendNotification(String msg) {
mNotificationManager = (NotificationManager)
this.getSystemService(Context.NOTIFICATION_SERVICE);
PendingIntent contentIntent = PendingIntent.getActivity(this, 0,
new Intent(this, HomeActivity.class), 0);
NotificationCompat.Builder mBuilder =
new NotificationCompat.Builder(this)
.setContentTitle("GCM Notification")
.setStyle(new NotificationCompat.BigTextStyle()
.bigText(msg))
.setContentText(msg);
mBuilder.setContentIntent(contentIntent);
mNotificationManager.notify(NOTIFICATION_ID, mBuilder.build());
}
}
Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.HBM.sample" >
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.WAKE_LOCK" />
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="com.google.android.c2dm.permission.RECEIVE" />
<permission android:name="com.HBM.sample.permission.C2D_MESSAGE"
android:protectionLevel="signature" />
<uses-permission android:name="com.HBM.sample.permission.C2D_MESSAGE" />
<application
android:allowBackup="true"
android:icon="#drawable/ic_launcher"
android:label="#string/app_name"
android:theme="#style/AppTheme" >
<receiver
android:name=".GcmBroadcastReceiver"
android:permission="com.google.android.c2dm.permission.SEND" >
<intent-filter>
<action android:name="com.google.android.c2dm.intent.RECEIVE" />
<category android:name="com.HBM.sample" />
</intent-filter>
</receiver>
<service
android:name=".GcmIntentService"
android:enabled="true" />
<activity
android:name=".RegisterActivity"
android:windowSoftInputMode="stateHidden|adjustResize" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name=".HomeActivity"
android:windowSoftInputMode="stateHidden|adjustResize" >
android:label="#string/title_activity_home" >
</activity>
<meta-data android:name="com.google.android.gms.version"
android:value="#integer/google_play_services_version" />
</application>
</manifest>
The app compiles fine and when I set a breakpoint in registerInBackground after:
regid = gcm.register(SENDER_ID);
the client registers fine and I get the registration id that looks something like this:
APA91bEdxx0UyqtX6qoVuhYNSeJkuAITIpdkbCkBCCsOyX5-lpbtNAJBvvGqIGKqxGhW24-y-tWbj2EDKJAiyvzVhP7jhMevZBr-o-Y6Eli0uG24oWXjFOWa1Sj9vjNXaO5wbWs7WodC4Oq4QOFaPQscF_v44Z_kyg
After that I created a GCM Server application and send a notification to the registrationId
Here is the json response:
{"multicast_id":5827029040432755439,"success":1,"failure":0,"canonical_ids":0,"results":[{"message_id":"0:1407451852374547%913f6fe1f9fd7ecd"}]}
It looks like the app registers fine and the notifications are pushed successfully. But onReceive never fires and I dont get any notifications o_O
I have tried the app on two different phones and different networks. But Im not sure what Im doing wrong. I hope someone can help me. I would really appreciate it.